diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000000000000000000000000000000000000..59eb89be2e3ed040f5303fa138d814bd90fcb4d7 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,22 @@ +name: Pages +on: + push: + branches: + - master +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-python@v2 + - uses: actions/checkout@master + with: + fetch-depth: 0 # otherwise, you will failed to push refs to dest repo + - name: Build and Commit + uses: sphinx-notes/pages@v2 + with: + requirements_path: ./docs/requirements.txt + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: gh-pages \ No newline at end of file diff --git a/.gitignore b/.gitignore index fc6f6f49ab8833ad839524e8eb13e52b9e1e1043..6769e21d99a63338394e47bc4c7d0aba1e88d5a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,160 @@ -*~ -*__pycache__* -.vscode -docs/_build +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2486223eaf9b86fb7dda0fedbe6e927036de7242..98fda7dece3062da0befe82344f9fdb50455f043 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -80,7 +80,7 @@ run-functional-tests: # Thus, we need to override the command so that the server is run on port 8080. - docker run --name $TESTS_CONTAINER_NAME -d -e "UVICORN_PORT=8080" $TMP_IMAGE # Install everything required for the tests. - - docker exec -i $TESTS_CONTAINER_NAME /bin/bash -c "pip install -r dev-requirements.txt" + - docker exec -i $TESTS_CONTAINER_NAME /bin/bash -c "pip install -r requirements.txt" # Run the tests. - docker exec -i $TESTS_CONTAINER_NAME /bin/bash -c "python -m pytest" # Stop the tests container. diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a83fae56dc39d959ba8ba3a020cf158ab586b0bd --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,29 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + # You can also specify other tool versions: + # nodejs: "19" + # rust: "1.64" + # golang: "1.19" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# If using Sphinx, optionally build your docs in additional formats such as PDF +# formats: +# - pdf + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: docs/requirements.txt \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..07b18dd254201ea8bb522d1fb986dc0a091ad5c2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: MC Synthesis", + "type": "python", + "request": "launch", + "module": "mc_openapi", + "justMyCode": true, + "args": [ + "-d", "tests/doml/openstack_template.domlx", + "--synth" + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..9b388533ae2b0b526768b898c911b1a364096bf9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index bfdfb934d99907633722c02ff2c6d5f31d906017..91058b6e1cc012d8f53da9c33d1ee4b9a885162e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN pip install --upgrade pip \ && pip install -r /opt/mc_openapi/requirements.txt WORKDIR /opt/mc_openapi -ENV UVICORN_PORT=80 \ +ENV UVICORN_PORT=8080 \ UVICORN_HOST=0.0.0.0 CMD ["uvicorn", "--interface", "wsgi", "mc_openapi.app_config:app"] diff --git a/README.md b/README.md index 42e6b9b4ae2f082ecc6f5cf2a7a5137a6639f262..12333fd089a0b00d89c683d15378b51ff492c716 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,50 @@ +[](https://piacere-model-checker.readthedocs.io/en/latest/?badge=latest) + # PIACERE Model Checker +**📖 You can read the [docs here](https://piacere-model-checker.readthedocs.io/en/latest/) for more details. 📖** + The DOML Model Checker is a component of the [PIACERE](https://www.piacere-project.eu/) framework in charge of checking the correctness and consistency of [DOML](https://www.piacere-doml.deib.polimi.it/) models. -This project is packaged with [Poetry](https://python-poetry.org/). + We provide a `requirements.txt` file for CI/CD purposes. + + If you add a new package, regenerate it by running: + + ```sh + pip freeze > requirements.txt + ``` -## Build and Run +## Setup -Build with +Activate the Python Virtual Environment with: ```sh -poetry install +source .venv/bin/activate ``` -then run with +Install the required packages with: ```sh -poetry run python -m mc_openapi +pip install -r requirements.txt ``` -Run tests with: +## Run the model checker web server ```sh -poetry run python -m pytest +python -m mc_openapi ``` - ## Run with Uvicorn The project may be run with [Uvicorn](https://www.uvicorn.org/) as follows: ```sh uvicorn --port 8080 --host 0.0.0.0 --interface wsgi --workers 2 mc_openapi.app_config:app ``` +## Run tests + +Run tests with: +```sh +python -m pytest +``` ## Run with Docker @@ -42,21 +57,18 @@ And then run it with ```sh docker run -d wp4/dmc ``` -The Uvicorn server will be running and listening on port 80 of the container. -To use it locally, you may e.g. bind it with port 8080 of `localhost` -by adding `-p 127.0.0.1:8080:80/tcp` to the `docker run` command. +The Uvicorn server will be running and listening on port `8080` of the container. +To use it locally, you may bind it with port `8080` of `localhost` +by adding `-p 127.0.0.1:8080:8080/tcp` to the `docker run` command. ## Building the Documentation The documentation has been written in [Sphinx](https://www.sphinx-doc.org/) and covers both usage through the PIACERE IDE and the REST APIs. +You can read the latest version at [readthedocs.io](https://piacere-model-checker.readthedocs.io/en/latest/) -To build it, type -```sh -poetry shell -``` -and then +If you want to build the documentation manually, run: ```sh cd docs make html diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index e411cde070bc961d66cc31ed5ba228dbb2c6ea5a..0000000000000000000000000000000000000000 --- a/dev-requirements.txt +++ /dev/null @@ -1,95 +0,0 @@ -alabaster==0.7.12 ; python_version >= "3.9" and python_version < "4.0" -anyio==3.6.1 ; python_version >= "3.9" and python_version < "4.0" -appnope==0.1.3 ; python_version >= "3.9" and python_version < "4.0" and platform_system == "Darwin" or python_version >= "3.9" and python_version < "4.0" and sys_platform == "darwin" -asttokens==2.0.8 ; python_version >= "3.9" and python_version < "4.0" -attrs==22.1.0 ; python_version >= "3.9" and python_version < "4.0" -babel==2.10.3 ; python_version >= "3.9" and python_version < "4.0" -backcall==0.2.0 ; python_version >= "3.9" and python_version < "4.0" -certifi==2022.9.24 ; python_version >= "3.9" and python_version < "4" -cffi==1.15.1 ; python_version >= "3.9" and python_version < "4.0" and implementation_name == "pypy" -charset-normalizer==2.1.1 ; python_version >= "3.9" and python_version < "4" -click==8.1.3 ; python_version >= "3.9" and python_version < "4.0" -clickclick==20.10.2 ; python_version >= "3.9" and python_version < "4.0" -colorama==0.4.5 ; python_version >= "3.9" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.9" and python_version < "4.0" and platform_system == "Windows" -colorful==0.5.4 ; python_version >= "3.9" and python_version < "4.0" -connexion[swagger-ui]==2.14.1 ; python_version >= "3.9" and python_version < "4.0" -debugpy==1.6.3 ; python_version >= "3.9" and python_version < "4.0" -decorator==5.1.1 ; python_version >= "3.9" and python_version < "4.0" -docutils==0.17.1 ; python_version >= "3.9" and python_version < "4.0" -entrypoints==0.4 ; python_version >= "3.9" and python_version < "4.0" -executing==1.1.0 ; python_version >= "3.9" and python_version < "4.0" -flask==2.2.2 ; python_version >= "3.9" and python_version < "4.0" -future-fstrings==1.2.0 ; python_version >= "3.9" and python_version < "4.0" -h11==0.14.0 ; python_version >= "3.9" and python_version < "4.0" -httptools==0.5.0 ; python_version >= "3.9" and python_version < "4.0" -idna==3.4 ; python_version >= "3.9" and python_version < "4" -imagesize==1.4.1 ; python_version >= "3.9" and python_version < "4.0" -importlib-metadata==5.0.0 ; python_version >= "3.9" and python_version < "3.10" -inflection==0.5.1 ; python_version >= "3.9" and python_version < "4.0" -iniconfig==1.1.1 ; python_version >= "3.9" and python_version < "4.0" -ipykernel==6.16.0 ; python_version >= "3.9" and python_version < "4.0" -ipython==8.5.0 ; python_version >= "3.9" and python_version < "4.0" -itsdangerous==2.1.2 ; python_version >= "3.9" and python_version < "4.0" -jedi==0.18.1 ; python_version >= "3.9" and python_version < "4.0" -jinja2==3.1.2 ; python_version >= "3.9" and python_version < "4.0" -joblib==1.2.0 ; python_version >= "3.9" and python_version < "4.0" -jsonschema==4.16.0 ; python_version >= "3.9" and python_version < "4.0" -jupyter-client==7.3.5 ; python_version >= "3.9" and python_version < "4.0" -jupyter-core==4.11.1 ; python_version >= "3.9" and python_version < "4.0" -lxml==4.9.1 ; python_version >= "3.9" and python_version < "4.0" -markupsafe==2.1.1 ; python_version >= "3.9" and python_version < "4.0" -matplotlib-inline==0.1.6 ; python_version >= "3.9" and python_version < "4.0" -nest-asyncio==1.5.6 ; python_version >= "3.9" and python_version < "4.0" -networkx==2.8.7 ; python_version >= "3.9" and python_version < "4.0" -ordered-set==4.1.0 ; python_version >= "3.9" and python_version < "4.0" -packaging==21.3 ; python_version >= "3.9" and python_version < "4.0" -parso==0.8.3 ; python_version >= "3.9" and python_version < "4.0" -pexpect==4.8.0 ; python_version >= "3.9" and python_version < "4.0" and sys_platform != "win32" -pickleshare==0.7.5 ; python_version >= "3.9" and python_version < "4.0" -pluggy==1.0.0 ; python_version >= "3.9" and python_version < "4.0" -prettyprinter==0.18.0 ; python_version >= "3.9" and python_version < "4.0" -prompt-toolkit==3.0.31 ; python_version >= "3.9" and python_version < "4.0" -psutil==5.9.2 ; python_version >= "3.9" and python_version < "4.0" -ptyprocess==0.7.0 ; python_version >= "3.9" and python_version < "4.0" and sys_platform != "win32" -pure-eval==0.2.2 ; python_version >= "3.9" and python_version < "4.0" -py==1.11.0 ; python_version >= "3.9" and python_version < "4.0" -pycparser==2.21 ; python_version >= "3.9" and python_version < "4.0" and implementation_name == "pypy" -pyecore==0.12.2 ; python_version >= "3.9" and python_version < "4.0" -pygments==2.13.0 ; python_version >= "3.9" and python_version < "4.0" -pyparsing==3.0.9 ; python_version >= "3.9" and python_version < "4.0" -pyrsistent==0.18.1 ; python_version >= "3.9" and python_version < "4.0" -pytest==7.1.3 ; python_version >= "3.9" and python_version < "4.0" -python-dateutil==2.8.2 ; python_version >= "3.9" and python_version < "4.0" -python-dotenv==0.21.0 ; python_version >= "3.9" and python_version < "4.0" -pytz==2022.4 ; python_version >= "3.9" and python_version < "4.0" -pywin32==304 ; sys_platform == "win32" and platform_python_implementation != "PyPy" and python_version >= "3.9" and python_version < "4.0" -pyyaml==6.0 ; python_version >= "3.9" and python_version < "4.0" -pyzmq==24.0.1 ; python_version >= "3.9" and python_version < "4.0" -requests==2.28.1 ; python_version >= "3.9" and python_version < "4" -restrictedpython==5.0 ; python_version >= "3.9" and python_version < "4.0" -setuptools==65.4.1 ; python_version >= "3.9" and python_version < "4.0" -six==1.16.0 ; python_version >= "3.9" and python_version < "4.0" -sniffio==1.3.0 ; python_version >= "3.9" and python_version < "4.0" -snowballstemmer==2.2.0 ; python_version >= "3.9" and python_version < "4.0" -sphinx-rtd-theme==1.0.0 ; python_version >= "3.9" and python_version < "4.0" -sphinx==5.2.3 ; python_version >= "3.9" and python_version < "4.0" -sphinxcontrib-applehelp==1.0.2 ; python_version >= "3.9" and python_version < "4.0" -sphinxcontrib-devhelp==1.0.2 ; python_version >= "3.9" and python_version < "4.0" -sphinxcontrib-htmlhelp==2.0.0 ; python_version >= "3.9" and python_version < "4.0" -sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.9" and python_version < "4.0" -sphinxcontrib-qthelp==1.0.3 ; python_version >= "3.9" and python_version < "4.0" -sphinxcontrib-serializinghtml==1.1.5 ; python_version >= "3.9" and python_version < "4.0" -stack-data==0.5.1 ; python_version >= "3.9" and python_version < "4.0" -swagger-ui-bundle==0.0.9 ; python_version >= "3.9" and python_version < "4.0" -tomli==2.0.1 ; python_version >= "3.9" and python_version < "4.0" -tornado==6.2 ; python_version >= "3.9" and python_version < "4.0" -traitlets==5.4.0 ; python_version >= "3.9" and python_version < "4.0" -urllib3==1.26.12 ; python_version >= "3.9" and python_version < "4" -uvicorn[standard]==0.18.3 ; python_version >= "3.9" and python_version < "4.0" -uvloop==0.17.0 ; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" and python_version >= "3.9" and python_version < "4.0" -watchfiles==0.17.0 ; python_version >= "3.9" and python_version < "4.0" -wcwidth==0.2.5 ; python_version >= "3.9" and python_version < "4.0" -websockets==10.3 ; python_version >= "3.9" and python_version < "4.0" -werkzeug==2.2.2 ; python_version >= "3.9" and python_version < "4.0" -z3-solver==4.11.2.0 ; python_version >= "3.9" and python_version < "4.0" -zipp==3.8.1 ; python_version >= "3.9" and python_version < "3.10" diff --git a/docker-compose.yaml b/docker-compose.yaml index c2c1b74739367efc21a07f847a418bbf49f8d1f0..2bbf5c3aaebf132d4a7ccf5a80818e779532008c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,8 +3,8 @@ services: dmc: build: . ports: - - "8080:80" + - "8080:8080" environment: - UVICORN_PORT: 80 + UVICORN_PORT: 8080 UVICORN_HOST: "0.0.0.0" UVICORN_WORKERS: 2 diff --git a/docs/PIACERE_logo.png b/docs/PIACERE_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8225ccc44d7c081e988f3de5e93695d155e8a919 Binary files /dev/null and b/docs/PIACERE_logo.png differ diff --git a/docs/conf.py b/docs/conf.py index fadcaeb668b0220b440d553067858c47450ecdd1..2efa10453c1433dff2ec21e3105175944cf00f50 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,17 +13,17 @@ # import os # import sys # sys.path.insert(0, os.path.abspath('.')) -import sphinx_rtd_theme +# import sphinx_rtd_theme # -- Project information ----------------------------------------------------- project = 'DOML Model Checker' -copyright = '2022, Michele Chiari and Michele De Pascalis' -author = 'Michele Chiari and Michele De Pascalis' +copyright = '2022, Michele Chiari, Michele De Pascalis, Andrea Franchini' +author = 'Michele Chiari, Michele De Pascalis, Andrea Franchini' # The full version, including alpha/beta/rc tags -release = '1.1.0' +release = '2.0.0' # -- General configuration --------------------------------------------------- @@ -32,7 +32,7 @@ release = '1.1.0' # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx_rtd_theme' + # 'sphinx_rtd_theme' ] # Add any paths that contain templates here, relative to this directory. @@ -41,7 +41,7 @@ templates_path = [] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'requirements.txt'] # -- Options for HTML output ------------------------------------------------- @@ -49,8 +49,9 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' - +# html_theme = 'sphinx_rtd_theme' +html_theme = 'furo' +html_logo = "PIACERE_logo.png" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". diff --git a/docs/dict_reference.rst b/docs/dict_reference.rst new file mode 100644 index 0000000000000000000000000000000000000000..f081c0ae71596cee72ea04bc90f9fb25211feeee --- /dev/null +++ b/docs/dict_reference.rst @@ -0,0 +1,171 @@ +Reference for Attributes, Association and Classes keys +====================================================== + +Attributes +---------- + +commons_DOMLElement::name +commons_DOMLElement::description +commons_Property::key +commons_IProperty::value +commons_SProperty::value +commons_FProperty::value +commons_BProperty::value +application_SoftwareComponent::isPersistent +application_SoftwareComponent::licenseCost +application_SoftwareComponent::configFile +application_SaaS::licenseCost +application_SoftwareInterface::endPoint +infrastructure_ComputingNode::architecture +infrastructure_ComputingNode::os +infrastructure_ComputingNode::memory_mb +infrastructure_ComputingNode::memory_kb +infrastructure_ComputingNode::storage +infrastructure_ComputingNode::cpu_count +infrastructure_ComputingNode::cost +infrastructure_VirtualMachine::sizeDescription +infrastructure_Location::region +infrastructure_Location::zone +infrastructure_ComputingNodeGenerator::uri +infrastructure_ComputingNodeGenerator::kind +infrastructure_AutoScalingGroup::min +infrastructure_AutoScalingGroup::max +infrastructure_AutoScalingGroup::loadBalancer +infrastructure_Storage::label +infrastructure_Storage::size_gb +infrastructure_Storage::cost +infrastructure_FunctionAsAService::cost +infrastructure_Network::protocol +infrastructure_Network::address_lb +infrastructure_Network::address_ub +infrastructure_NetworkInterface::endPoint +infrastructure_NetworkInterface::speed +infrastructure_Rule::kind +infrastructure_Rule::protocol +infrastructure_Rule::fromPort +infrastructure_Rule::toPort +infrastructure_Rule::cidr +infrastructure_KeyPair::user +infrastructure_KeyPair::keyfile +infrastructure_KeyPair::algorithm +infrastructure_KeyPair::bits +infrastructure_UserPass::username +infrastructure_UserPass::password +infrastructure_SwarmRole::kind +concrete_ConcreteElement::configurationScript + +Associations +------------ + +commons_DOMLElement::annotations +commons_Property::reference +commons_Configuration::deployments +commons_Deployment::component +commons_Deployment::node +application_ApplicationLayer::components +application_SoftwareComponent::exposedInterfaces +application_SoftwareComponent::consumedInterfaces +application_SaaS::exposedInterfaces +infrastructure_InfrastructureLayer::nodes +infrastructure_InfrastructureLayer::generators +infrastructure_InfrastructureLayer::storages +infrastructure_InfrastructureLayer::faas +infrastructure_InfrastructureLayer::credentials +infrastructure_InfrastructureLayer::groups +infrastructure_InfrastructureLayer::securityGroups +infrastructure_InfrastructureLayer::networks +infrastructure_ComputingNode::ifaces +infrastructure_ComputingNode::location +infrastructure_ComputingNode::credentials +infrastructure_ComputingNode::group +infrastructure_VirtualMachine::generatedFrom +infrastructure_Container::generatedFrom +infrastructure_Container::hosts +infrastructure_VMImage::generatedVMs +infrastructure_ContainerImage::generatedContainers +infrastructure_AutoScalingGroup::machineDefinition +infrastructure_AutoScalingGroup::deploymentNetwork +infrastructure_AutoScalingGroup::securityGroup +infrastructure_Storage::ifaces +infrastructure_FunctionAsAService::ifaces +infrastructure_Network::connectedIfaces +infrastructure_Network::igws +infrastructure_Network::subnets +infrastructure_Subnet::connectedTo +infrastructure_NetworkInterface::belongsTo +infrastructure_NetworkInterface::associated +infrastructure_ComputingGroup::groupedNodes +infrastructure_SecurityGroup::rules +infrastructure_SecurityGroup::ifaces +infrastructure_SwarmRole::nodes +infrastructure_Swarm::roles +concrete_ConcreteInfrastructure::providers +concrete_RuntimeProvider::vms +concrete_RuntimeProvider::vmImages +concrete_RuntimeProvider::containerImages +concrete_RuntimeProvider::networks +concrete_RuntimeProvider::storages +concrete_RuntimeProvider::faas +concrete_RuntimeProvider::group +concrete_VirtualMachine::maps +concrete_VMImage::maps +concrete_ContainerImage::maps +concrete_Network::maps +concrete_Storage::maps +concrete_FunctionAsAService::maps +concrete_ComputingGroup::maps + +Classes +------- + +commons_DOMLElement +commons_Property +commons_IProperty +commons_SProperty +commons_FProperty +commons_BProperty +commons_Configuration +commons_Deployment +application_ApplicationLayer +application_ApplicationComponent +application_SoftwareComponent +application_SaaS +application_SoftwareInterface +application_DBMS +application_SaaSDBMS +infrastructure_InfrastructureLayer +infrastructure_InfrastructureElement +infrastructure_ComputingNode +infrastructure_PhysicalComputingNode +infrastructure_VirtualMachine +infrastructure_Location +infrastructure_Container +infrastructure_ComputingNodeGenerator +infrastructure_VMImage +infrastructure_ContainerImage +infrastructure_AutoScalingGroup +infrastructure_Storage +infrastructure_FunctionAsAService +infrastructure_Network +infrastructure_Subnet +infrastructure_NetworkInterface +infrastructure_InternetGateway +infrastructure_ComputingGroup +infrastructure_SecurityGroup +infrastructure_Rule +infrastructure_Credentials +infrastructure_KeyPair +infrastructure_UserPass +infrastructure_SwarmRole +infrastructure_Swarm +infrastructure_ExtInfrastructureElement +concrete_ConcreteInfrastructure +concrete_ConcreteElement +concrete_RuntimeProvider +concrete_VirtualMachine +concrete_VMImage +concrete_ContainerImage +concrete_Network +concrete_Storage +concrete_FunctionAsAService +concrete_ComputingGroup \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index ec8ef513ffa8ae204f1b6e2847034e325e90bd0b..dbb3f36d3a996bdf801893b338c2ae04707ab7cb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,7 +3,7 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -DOML Model Checker's documentation +DOML Model Checker Documentation ================================== The DOML Model Checker is a component of the `PIACERE`_ framework @@ -15,7 +15,9 @@ in charge of checking the correctness and consistency of `DOML`_ models. :caption: Contents: installation + tests usage + writing-requirements requirements restapis @@ -28,8 +30,8 @@ in charge of checking the correctness and consistency of `DOML`_ models. * :ref:`search` -This project has received funding from the European Union's Horizon 2020 -research and innovation programme under grant agreement No. 101000162. +*This project has received funding from the European Union's Horizon 2020 +research and innovation programme under grant agreement No. 101000162.* .. _PIACERE: https://www.piacere-project.eu/ diff --git a/docs/installation.rst b/docs/installation.rst index 9f30192cd963cf9ffa789f61aacdfd4ff5c70a56..3f0bcb706003d52e91d709582c034fbeb1b482f5 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -1,35 +1,28 @@ Installation -============ +************ -The DOML Model Checker receives user inputs through its REST APIs. -In this guide we illuestrate saveral ways of setting up the server for these APIs. +The model checker can be run in two configurations, *REST API* and *CLI*. +First, you'll need to install the dependencies to run this tool. -Build and run locally for testing ---------------------------------- +Installing the dependencies +=========================== -This project is packaged with `Poetry`_, which we assume you have already -`installed <https://python-poetry.org/docs/#installation>`_ into your system. - - -Build with:: +This project is packaged with `Poetry`_, so you should install it first. +Once *Poetry* has been installed, install the dependencies with:: + poetry install -then run with:: + +Run locally for testing +----------------------- +Run with:: poetry run python -m mc_openapi -this command serves the APIs through a `Flask`_ instance, +This command serves the APIs through a `Flask`_ instance, which is suitable for testing, but not recommended for production. -You may read the API specification generated by `Swagger-UI`_ by -pointing your browser to http://127.0.0.1:8080/ui/. - - -Then, run tests with:: - - poetry run python -m pytest - Run locally with Uvicorn ------------------------ @@ -61,8 +54,13 @@ The Uvicorn server will be running and listening on port 80 of the container. To use it locally, you may e.g. bind it with port 8080 of ``localhost`` by adding ``-p 127.0.0.1:8080:80/tcp`` to the ``docker run`` command. +REST API Endpoints +================== + +You may read the API specification generated by `Swagger-UI`_ at http://127.0.0.1:8080/ui/. + Building the Documentation --------------------------- +========================== The documentation has been written in `Sphinx`_. diff --git a/docs/requirements.rst b/docs/requirements.rst index 6ea7e25dba686b611fb61c5de902540fecc5210c..0fb3c49c2298a4b3347a18c92c280bfd25f5e1a4 100644 --- a/docs/requirements.rst +++ b/docs/requirements.rst @@ -1,5 +1,5 @@ -Checked Requirements -==================== +Built-in Requirements +===================== The DOML Model Checker verifies DOML models against a collection of requirements devised to highlight the most common mistakes made by users when specifying cloud deployments. @@ -60,3 +60,18 @@ Concrete Infrastructure Elements have a maps Association All elements in the active concretization are mapped to some abstract infrastructure element. Makes sure each concrete infrastructure element is mapped to a node in the Abstract Infrastructure Layer. + +Network Interfaces belong to a Security Group +--------------------------------------------- + + All network interfaces belong to a security group. + +Makes sure all network interfaces have been configured to belong to a security group. +This way, the user will be reminded to configure adequate rules for each network. + +External Services are reached through HTTPS +------------------------------------------- + + All external SaaS can be reached only through a secure connection. + +Makes sure that an HTTPS rule is enforced for a Network Interface of a Software Component that interfaces with a SaaS. \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e279e79d32427f119426d5f3ec50ce026c4daa9 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +furo \ No newline at end of file diff --git a/docs/tests.rst b/docs/tests.rst new file mode 100644 index 0000000000000000000000000000000000000000..fb6c26cf1df92aa2c6084ce220ea1858c46d7b30 --- /dev/null +++ b/docs/tests.rst @@ -0,0 +1,10 @@ +Testing +======= + +To run the tests with *PyTest* you'll need to setup the server:: + + poetry run python -m mc_openapi + +and then run separately:: + + poetry run python -m pytest diff --git a/docs/usage.rst b/docs/usage.rst index 0b9c29f39340dc9a2f19c0f639740bd4c4f8000e..0d0478bd24785447bd89fe271474f2acb7e8ff39 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -1,9 +1,9 @@ -Usage through the PIACERE IDE -============================= +Usage +***** -Invoking the DOML Model Checker from the PIACERE IDE ------------------------------------------------------ +Through the PIACERE IDE +======================= The DOML Model Checker is usually invoked from the PIACERE IDE. It expects a DOML file in XMI format as its input, @@ -48,3 +48,62 @@ and then choose *Piacere* -> *Model Checker Preferences*. Here you may enter the endpoint address and port, which is useful in case you want to run the DOML Model Checker locally, instead of using the official deployment. + +Through the Command Line Interface +================================== + +Another way to use the model checker is through the CLI. +It provides additional options that are not available in the IDE at +the moment, such as support for a separate user requirement file +and synthesis of DOMLX. + +You can run it with:: + + python -m mc_openapi [options] + +To display all the available flags, run:: + + python -m mc_openapi -h + +Options +------- + +Please note that not all flags work with eachother. In most cases, some won't have +any effect in certain CLI flags combinations. + +There are **3 Modes** in which the CLI can run: + +- REST API (**R**) +- Model Checker (**C**) +- Model Synthesis (**S**) + +====== ========================= ========= ================= +Flags Mode Description +--------------------------------- --------- ----------------- +Short Long +====== ========================= ========= ================= +``-h`` ``--help`` C, S, R Print the all the available flags with an explanation +``-v`` ``--verbose`` C, S, R Print a detailed human-readable output of everything going on. Helpful for debugging +``-p`` ``--port`` R The port that will expose the REST API (default: 8080) +``-d`` ``--doml`` C, S The DOMLX file to check with the model checker +``-V`` ``--doml-version`` C, S The DOML version in which the DOMLX file is written in +``-r`` ``--requirements`` C, S A text file containing the user-defined requirements written in :doc:`DOMLR <writing-requirements>`. +``-S`` ``--skip-common-checks`` C Skips :doc:`build-in requirements <requirements>` checks +``-c`` ``--check-consistency`` C Perform additional consistency checks (legacy) +``-t`` ``--threads`` C, R The number of threads used by the model checker (default: 2) +``-s`` ``--synth`` S Synthetize a new DOMLX file from requirements +``-m`` ``--max-tries`` S Max number of tries to solve a model during synthesis (default: 10) +====== ========================= ========= ================= + +*If you do not provide the ``--doml`` option or the ``--synth`` option it will start the web server hosting the REST API!* + +Examples +-------- + +To check a DOMLX file with user-provided custom requirements, you may run:: + + python -m mc_openapi -d ./path/to/myModel.domlx -r ./path/to/myRequirements.domlr -V V2_0 + +To synthetize a new DOMLX file with 4 threads and a maximum of 15 tries, you may run:: + + python -m mc_openapi -d ./path/to/myModel.domlx --synth -m 15 \ No newline at end of file diff --git a/docs/writing-requirements.rst b/docs/writing-requirements.rst new file mode 100644 index 0000000000000000000000000000000000000000..b30ec9408365d27dd0f516257badfe6922cbecd0 --- /dev/null +++ b/docs/writing-requirements.rst @@ -0,0 +1,118 @@ +Writing Requirements +******************** + +A feature of the DOML Model Checker is a Domain Specific Language (DSL) +called **DOMLR** (the R stands for requirements). + +It will be integrated in the DOML in a future release. +For now, it can be provided to the Model Checker through the CLI. + +Getting Started +=============== + +First, create a new file with a ``.domlr`` extension. + +If you use VS Code, there's a `Syntax Highlight`_ extension for it. + +Every user requirement file is a list of requirement:: + + + "All Virtual Machines have a Interface and at least 4 cpu cores" + forall vm ( + vm is class abstract.VirtualMachine + implies + exists iface ( + vm has abstract.ComputingNode.ifaces iface + and + vm has abstract.ComputingNode.cpu_count >= 4 + ) + ) + error: "A vm does lacks an associated interface or has less than 4 CPUs" + +Rules in 1 minute +----------------- + +The language is *case-sensitive* but it's not indentation-based, so you are free to write it as you prefer. + +1. A requirement must **start** with a ``+`` or ``-`` character. + + - ``+`` means that the requirement is in **positive form**: the requirement is satisfied when its logic expression is satisfied. + + - ``-`` means that the requirement is in **negative form**: the requirement is satisfied when its logic expression **is not** satisfied. + + The difference is that in **positive form** you would generally use a *for all* quantifier at the beginning, + which doesn't allow you to know which specific element didn't satisfy the requirement, while in **negative form** + you'll have some variables that are not quantified, meaning that it's usually possible to retrieve the names of the + elements associated to those variables that do not satisfy the requirement. + +2. After the ``+`` or ``-`` there's the **name** of the requirement, which is a string between double quotes ``"..."``. + Single quotes ``'...'`` won't work. + +3. Following the requirement name, there's the **logic expression** which is the core of the requirement. + It is written in `First Order Logic`_, so it will evaluate to either true or false. See the `Syntax`_ for details. + +4. Last, following ``error:``, there is the **error message** that is printed when the requirement is not satisfied. + If you have a free variable, which means a variable that is not quantified, you can print its value by putting it in the + string between curly brackets like this: ``{myVar}``. You'll get a warning if the Model Checker can't assign a value to that variable. + +.. `Syntax`: + +Syntax +====== + +The syntax is the following: + +- Unary operators: ``not`` + - Example: ``not <expression>`` +- Binary operators: ``or``, ``and``, ``implies``, ``iff`` (if and only if, AKA double implication) + - Example: ``<expression> and <expression>`` +- Quantifiers: ``forall``, ``exists`` + - Example: ``forall x, y ( <expression> )`` + - After the quantifier keywork (``forall``, ``exists``) you must specify a list of quantified variables + (separated by a comma ``,`` if there's more than one). + - Between the mandatory pair of parenthesis, you'll be able to use the quantified variables in a logic expression. +- Parenthesis: ``(`` ... ``)`` + - Useful when you have doubts about the precedence of operators, or want to increase legibility in certain situations. +- Elements (variables): + - Begin with a lowercase letter. + - Example: ``virtualMachine`` or ``vm`` +- Values (constants): + - Strings are delimited by double quotes ``"..."`` + - Numbers are integers. + - Booleans are either ``:true`` or ``:false`` + - Example: ``56``, ``"linux"``, ``:true`` +- Relationships: ``<elem> has <relationship> <elem/value>`` + - There are two types of relationships: + - **Associations** are a relationship between two elements (variables). + - **Attributes** are a relationship between an element (variable) and a value (variable or constant). + - Relationships follow this naming structure ``<package>.<class>.<relationship>``. + - Example: + - ``vm has abstract.ComputingNode.ifaces iface`` is an **Association**, as it puts in relationship the element ``vm`` with the element ``iface``. + + - ``vm has abstract.ComputingNode.cpu_count >= 4`` is an **Attribute** Relationship, as it compares a property (``cpu_count``) of the element ``vm`` with a constant number. +- Classes: ``class <class name>`` + - They represent a kind of element in the architecture. + - Classes follow this naming structure ``<package>.<class>`` +- Equality: ``is``, ``is not`` + - Used to set an equality (or inequality) constraint on an element variable. You can use it to assign a class to an element. + - Example: ``vm is class abstract.VirtualMachine`` +- Comparisons: ``>``, ``>=``, ``<``, ``<=``, ``==``, ``!=`` + - You can compare attributes with constants, or attributes with attributes. + - Example: + - ``vm has abstract.ComputingNode.cpu_count >= 4`` compares attribute ``cpu_count`` with a numeric constant. + - ``vm1 has abstract.ComputingNode.cpu_count >= vm2 abstract.ComputingNode.cpu_count`` compares attribute ``cpu_count`` of ``vm1`` with the one of ``vm2``. + + + +Operator Precedence +------------------- + +``exists``/``forall`` > ``not`` > ``or`` > ``and`` > ``implies`` > ``iff`` + +Grammar +======= +See the `grammar.lark`_ file on GitHub, it's written in a EBNF-like form. + + +.. _`Syntax Highlight`: https://marketplace.visualstudio.com/items?itemName=andreafra.piacere-domlr +.. _`First Order Logic`: https://en.wikipedia.org/wiki/First-order_logic +.. _`grammar.lark`: https://github.com/andreafra/piacere-model-checker/blob/main/mc_openapi/doml_mc/dsl_parser/grammar.lark \ No newline at end of file diff --git a/mc_openapi/__init__.py b/mc_openapi/__init__.py index 58d478ab160be0a838dab2d6ce9a15ce6d80b07b..a33997dd1004d8fb312324a652e27fcab292f4eb 100644 --- a/mc_openapi/__init__.py +++ b/mc_openapi/__init__.py @@ -1 +1 @@ -__version__ = '1.2.0' +__version__ = '2.1.0' diff --git a/mc_openapi/__main__.py b/mc_openapi/__main__.py index 4289b5dfd801aafbfdaced9b7877ca948fda7523..3ce069095a1d1f2cecafadd719dcc8868f5c5655 100644 --- a/mc_openapi/__main__.py +++ b/mc_openapi/__main__.py @@ -1,5 +1,198 @@ #!/usr/bin/env python3 +import argparse +import sys + +from doml_synthesis.data import init_data +from doml_synthesis.requirements import builtin_requirements +from doml_synthesis.results import check_synth_results, save_results +from doml_synthesis.solver import solve +from doml_synthesis.types import State from mc_openapi.app_config import app +from mc_openapi.doml_mc import DOMLVersion +from mc_openapi.doml_mc.domlr_parser.exceptions import RequirementException +from mc_openapi.doml_mc.domlr_parser.parser import (DOMLRTransformer, Parser, + SynthesisDOMLRTransformer) +from mc_openapi.doml_mc.imc import RequirementStore +from mc_openapi.doml_mc.intermediate_model.metamodel import MetaModelDocs +from mc_openapi.doml_mc.mc import ModelChecker +from mc_openapi.doml_mc.mc_result import MCResult +from mc_openapi.doml_mc.xmi_parser.doml_model import get_pyecore_model + +parser = argparse.ArgumentParser() + +parser.add_argument("-d", "--doml", dest="doml", help="the DOMLX file to check") +parser.add_argument("-V", "--doml-version", dest="doml_version", help="(optional) the version used by the DOMLX file") +parser.add_argument("-r", "--requirements", dest="requirements", help="the user-specified requirements file to check") +parser.add_argument("-p", "--port", dest="port", type=int, default=8080, help="the port exposing the model checker REST API (default: 8080)") +parser.add_argument("-v", "--verbose", dest="verbose", action='store_true', help="print a detailed human-readable output of everything going on. Helpful for debugging.") +# Model Checker +parser.add_argument("-c", "--check-consistency", dest="consistency", action='store_true', help="check on additional built-in consistency requirements") +parser.add_argument("-S", "--skip-common-checks", dest="skip_common", action='store_true', help="skip check on common built-in requirements") +parser.add_argument("-t", "--threads", dest="threads", type=int, default=2, help="number of threads used by the model checker") +# Synthesis +parser.add_argument("-s", "--synth", dest="synth", action='store_true', help="synthetize a new DOMLX file from requirements") +parser.add_argument("-m", "--max-tries", dest="tries", type=int, default=8, help="max number of iteration while trying to solve the model with unbounded variables") + +args = parser.parse_args() + +# Print only when -v flag is true +def printv(*_args): + if args.verbose: + print(*_args) + +printv("== Verbose: ON ==") + +if not args.doml and not args.synth: + # Start the webserver + app.run(port=args.port) +else: + # Run only it via command line + doml_path = args.doml + reqs_path = args.requirements + + # Try using the user-provided DOML version + doml_ver = None + if args.doml_version is not None: + try: + doml_ver = DOMLVersion[args.doml_version] + except: + # Suggest valid DOML versions + print(f"Unknown DOML version '{args.doml_version}'") + versions = [ ver.name for ver in list(DOMLVersion)] + print(f"Available DOML versions = {versions}") + exit(1) + + with open(doml_path, "rb") as xmif: + # Read DOML file from path + doml_xmi = xmif.read() + + # Config the model checker (setup metamodels and intermediate models) + dmc = ModelChecker(doml_xmi, doml_ver) + doml_ver = dmc.doml_version + + # Store of Requirements and unique string constants + user_req_store = RequirementStore() + user_req_str_consts = [] + + synth_user_reqs = [] + synth_user_reqs_strings = [] + + try: + domlr_parser = Parser(DOMLRTransformer) + if args.synth: + synth_domlr_parser = Parser(SynthesisDOMLRTransformer) + except Exception as e: + print(e, file=sys.stderr) + print("Failed to setup DOMLR Parser") + exit(-1) + + user_reqs = None + + if reqs_path: + with open(reqs_path, "r") as reqsf: + # Read the user requirements written in DSL + user_reqs = reqsf.read() + # Parse them + try: + user_req_store, user_req_str_consts = domlr_parser.parse(user_reqs) + except Exception as e: + print(e, file=sys.stderr) + print("Failed to parse the DOMLR.", file=sys.stderr) + exit(-1) + + if doml_ver == DOMLVersion.V2_2: + model = get_pyecore_model(doml_xmi, doml_ver) + func_reqs = model.functionalRequirements.items + for req in func_reqs: + req_name: str = req.name + req_text: str = req.description + req_text = req_text.replace("```", "") + + doml_req_store, doml_req_str_consts = domlr_parser.parse(req_text) + user_req_store += doml_req_store + user_req_str_consts += doml_req_str_consts + + if args.synth: + synth_doml_req_store, synth_doml_req_str_consts = synth_domlr_parser.parse(req_text, for_synthesis=True) + synth_user_reqs.append(synth_doml_req_store) + synth_user_reqs_strings += synth_doml_req_str_consts + + # Remove possible duplicates + user_req_str_consts = list(set(user_req_str_consts)) + + if not args.synth: + try: + # Check satisfiability + results = dmc.check_requirements( + threads=args.threads, + user_requirements=user_req_store, + user_str_values=user_req_str_consts, + consistency_checks=args.consistency, + skip_common_requirements=args.skip_common + ) + + res, msg = results.summarize() + + if res == MCResult.sat: + print("sat") + else: + print(res.name) + print("\033[91m{}\033[00m".format(msg)) + except RequirementException as e: + print(e.message) + + else: # Synthesis + printv("Running synthesis...") + + + # Required files: + mm = MetaModelDocs[doml_ver] + im = { + k: { + 'id': v.id_, + 'name': v.user_friendly_name, + 'class': v.class_, + 'assocs': v.associations, + 'attrs': v.attributes + } + for k, v in dmc.intermediate_model.items() + } + + if user_reqs: + try: + ext_domlr_reqs, ext_domlr_reqs_strings = synth_domlr_parser.parse(user_reqs, for_synthesis=True) + synth_user_reqs.append(ext_domlr_reqs) + synth_user_reqs_strings += ext_domlr_reqs_strings + except Exception as e: + print(e, file=sys.stderr) + print("Failed to parse the DOMLR.", file=sys.stderr) + exit(-1) + + + # Remove duplicated strings + print(synth_user_reqs_strings) + synth_user_reqs_strings = list(set(synth_user_reqs_strings)) + + state = State() + # Parse MM and IM + state = init_data( + state, + doml=im, + metamodel=mm, + ) + + reqs = synth_user_reqs + if not args.skip_common: + reqs.append(builtin_requirements) -app.run(port=8080) + state = solve( + state, + requirements=reqs, + strings=synth_user_reqs_strings, + max_tries=args.tries + ) + # Update state + state = save_results(state) + # Print output + state = check_synth_results(state) \ No newline at end of file diff --git a/mc_openapi/assets/doml_meta_v2.0.yaml b/mc_openapi/assets/doml_meta_v2.0.yaml index f2b58f9344e22f1c759f37c6fa84a3b125e894ba..08cc7176fbeda1681e86fbc37afa83080423522c 100644 --- a/mc_openapi/assets/doml_meta_v2.0.yaml +++ b/mc_openapi/assets/doml_meta_v2.0.yaml @@ -84,10 +84,10 @@ application: associations: exposedInterfaces: class: application_SoftwareInterface - mutiplicity: "0..*" + multiplicity: "0..*" consumedInterfaces: class: application_SoftwareInterface - mutiplicity: "0..*" + multiplicity: "0..*" SaaS: superclass: application_ApplicationComponent attributes: @@ -97,7 +97,7 @@ application: associations: exposedInterfaces: class: application_SoftwareInterface - mutiplicity: "0..*" + multiplicity: "0..*" SoftwareInterface: superclass: application_ApplicationComponent attributes: diff --git a/mc_openapi/assets/doml_meta_v2.1.1.yaml b/mc_openapi/assets/doml_meta_v2.1.1.yaml new file mode 100644 index 0000000000000000000000000000000000000000..df4d72d197d0de585dc74c85c9c487fc59b4dc98 --- /dev/null +++ b/mc_openapi/assets/doml_meta_v2.1.1.yaml @@ -0,0 +1,541 @@ +commons: + DOMLElement: + attributes: + name: + type: String + multiplicity: "0..1" + description: + type: String + multiplicity: "0..1" + associations: + annotations: + class: commons_Property + multiplicity: "0..*" + Property: + attributes: + key: + type: String + multiplicity: "0..1" + associations: + reference: + class: commons_DOMLElement + multiplicity: "0..1" + IProperty: + superclass: commons_Property + attributes: + value: + type: Integer + multiplicity: "0..1" + SProperty: + superclass: commons_Property + attributes: + value: + type: String + multiplicity: "0..1" + FProperty: + superclass: commons_Property + attributes: + value: + type: String + multiplicity: "0..1" + BProperty: + superclass: commons_Property + attributes: + value: + type: Boolean + multiplicity: "0..1" + Configuration: + superclass: commons_DOMLElement + associations: + deployments: + class: commons_Deployment + multiplicity: "0..*" + Credentials: + abstract: true + superclass: commons_DOMLElement + DeployableElement: + abstract: true + superclass: commons_DOMLElement # It's not present in the ECore, but without it breaks. + Deployment: + associations: + component: + class: commons_DeployableElement + multiplicity: "1" + node: + class: infrastructure_InfrastructureElement + multiplicity: "1" + KeyPair: + superclass: commons_Credentials + attributes: + user: + type: String + multiplicity: "0..1" + keyfile: + type: String + multiplicity: "0..1" + algorithm: + type: String + multiplicity: "0..1" + bits: + type: Integer + multiplicity: "0..1" + UserPass: + superclass: commons_Credentials + attributes: + user: + type: String + multiplicity: "0..1" + password: + type: String + multiplicity: "0..1" + Source: + superclass: commons_DOMLElement + attributes: + engine: + type: String + multiplicity: "0..*" + uri: + type: String + multiplicity: "0..*" + entry: + type: String + multiplicity: "0..*" + backend: + type: String + multiplicity: "0..*" + associations: + credential: + class: commons_Credentials +application: + ApplicationLayer: + superclass: commons_DOMLElement + associations: + components: + class: application_ApplicationComponent + multiplicity: "0..*" + ApplicationComponent: + superclass: commons_DOMLElement + SoftwareComponent: + superclass: application_ApplicationComponent # and commons_DeployableElement, but we can't handle multiple parent classes, can't we? + attributes: + isPersistent: + type: Boolean + multiplicity: "1" + default: false + licenseCost: + type: String + multiplicity: "0..1" + associations: + exposedInterfaces: + class: application_SoftwareInterface + multiplicity: "0..*" + consumedInterfaces: + class: application_SoftwareInterface + multiplicity: "0..*" + src: + class: commons_Source + multiplicity: "0..1" + SaaS: + superclass: application_ApplicationComponent + attributes: + licenseCost: + type: String + multiplicity: "0..1" + associations: + exposedInterfaces: + class: application_SoftwareInterface + multiplicity: "0..*" + SoftwareInterface: + superclass: application_ApplicationComponent + attributes: + endPoint: + type: String + multiplicity: "0..1" + DBMS: + superclass: application_SoftwareComponent + SaaSDBMS: + superclass: application_SaaS + +infrastructure: + InfrastructureLayer: + superclass: commons_DOMLElement + associations: + nodes: + class: infrastructure_ComputingNode + multiplicity: "0..*" + generators: + class: infrastructure_ComputingNodeGenerator + multiplicity: "0..*" + storages: + class: infrastructure_Storage + multiplicity: "0..*" + faas: + class: infrastructure_FunctionAsAService + multiplicity: "0..*" + credentials: + class: commons_Credentials + multiplicity: "0..*" + groups: + class: infrastructure_ComputingGroup + multiplicity: "0..*" + securityGroups: + class: infrastructure_SecurityGroup + multiplicity: "0..*" + networks: + class: infrastructure_Network + multiplicity: "0..*" + rules: + class: infrastructure_MonitoringRule + multiplicity: "0..*" + MonitoringRule: + superclass: commons_DOMLElement + attributes: + condition: + type: String + multiplicity: "1" + strategy: + type: String + multiplicity: "1" + strategyConfigurationString: + type: String + multiplicity: "0..1" + InfrastructureElement: + superclass: commons_DeployableElement + ComputingNode: + superclass: infrastructure_InfrastructureElement + attributes: + architecture: + type: String + multiplicity: "0..1" + os: + type: String + multiplicity: "0..1" + memory_mb: + type: Integer + multiplicity: "0..1" + memory_kb: # Missing in official Ecore, added by parser + type: Integer + multiplicity: "0..1" + storage: + type: String + multiplicity: "0..1" + cpu_count: + type: Integer + multiplicity: "0..1" + cost: + type: Integer # in cents + multiplicity: "0..1" + disabledMonitorings: + type: String + multiplicity: "0..1" + associations: + ifaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + location: + class: infrastructure_Location + multiplicity: "0..1" + credentials: + class: commons_Credentials + multiplicity: "0..1" + group: + class: infrastructure_ComputingGroup + multiplicity: "0..1" + inverse_of: infrastructure_ComputingGroup::groupedNodes + PhysicalComputingNode: + superclass: infrastructure_ComputingNode + VirtualMachine: + superclass: infrastructure_ComputingNode + attributes: + sizeDescription: + type: String + multiplicity: "0..1" + associations: + generatedFrom: + class: infrastructure_VMImage + multiplicity: "0..1" + Location: + superclass: commons_DOMLElement + attributes: + region: + type: String + multiplicity: "0..1" + zone: + type: String + multiplicity: "0..1" + ContainerConfig: + superclass: commons_DOMLElement + attributes: + container_port: + type: Integer + multiplicity: "0..1" + vm_port: + type: Integer + multiplicity: "0..1" + associations: + host: + class: infrastructure_ComputingNode + multiplicity: "0..1" + iface: + class: infrastructure_NetworkInterface + multiplicity: "0..1" + Container: + superclass: infrastructure_ComputingNode + associations: + generatedFrom: + class: infrastructure_ContainerImage + multiplicity: "0..1" + configs: + class: infrastructure_ContainerConfig + multiplicity: "0..*" + ComputingNodeGenerator: + superclass: commons_DOMLElement + attributes: + uri: + type: String + multiplicity: "0..1" + kind: + type: GeneratorKind # enum { SCRIPT, IMAGE } + VMImage: + superclass: infrastructure_ComputingNodeGenerator + associations: + generatedVMs: + class: infrastructure_VirtualMachine + multiplicity: "0..*" + inverse_of: infrastructure_VirtualMachine::generatedFrom + ContainerImage: + superclass: infrastructure_ComputingNodeGenerator + associations: + generatedContainers: + class: infrastructure_Container + multiplicity: "0..*" + inverse_of: infrastructure_Container::generatedFrom + AutoScalingGroup: + superclass: infrastructure_ComputingGroup + attributes: + min: + type: Integer + multiplicity: "0..1" + max: + type: Integer + multiplicity: "0..1" + loadBalancer: + type: String + multiplicity: "0..1" + associations: + machineDefinition: + class: infrastructure_VirtualMachine + multiplicity: "1" + securityGroup: + class: infrastructure_SecurityGroup + multiplicity: "0..1" + Storage: + superclass: infrastructure_InfrastructureElement + attributes: + label: + type: String + multiplicity: "0..1" + size_gb: + type: Integer # in GBs + multiplicity: "0..1" + cost: + type: Integer # in cents + multiplicity: "0..1" + associations: + ifaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + FunctionAsAService: + superclass: infrastructure_InfrastructureElement + attributes: + cost: + type: Integer # in cents + multiplicity: "0..1" + associations: + ifaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + Network: + superclass: commons_DOMLElement + attributes: + protocol: + type: String + multiplicity: "0..1" + addressRange: + type: String + multiplicity: "0..1" + cidr: + type: Integer + multiplicity: "0..1" + associations: + connectedIfaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + inverse_of: infrastructure_NetworkInterface::belongsTo + igws: + class: infrastructure_InternetGateway + multiplicity: "0..*" + subnets: + class: infrastructure_Subnet + multiplicity: "0..*" + Subnet: + superclass: infrastructure_Network + associations: + connectedTo: + class: infrastructure_Network + multiplicity: "0..1" + NetworkInterface: + superclass: infrastructure_InfrastructureElement + attributes: + endPoint: + type: Integer + multiplicity: "0..1" + speed: + type: String + multiplicity: "0..1" + associations: + belongsTo: + class: infrastructure_Network + multiplicity: "0..1" # This should be "1", but it would break InternetGateway + associated: + class: infrastructure_SecurityGroup + multiplicity: "0..1" # TODO: try putting this to 1 and see why it fails + InternetGateway: + superclass: infrastructure_NetworkInterface + ComputingGroup: + superclass: commons_DOMLElement + associations: + groupedNodes: + class: infrastructure_ComputingNode + multiplicity: "0..*" + inverse_of: infrastructure_ComputingNode::group + SecurityGroup: + superclass: commons_DOMLElement + associations: + rules: + class: infrastructure_Rule + multiplicity: "0..*" + ifaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + inverse_of: infrastructure_NetworkInterface::associated + Rule: + superclass: commons_DOMLElement + attributes: + kind: + type: String + multiplicity: "1" + protocol: + type: String + multiplicity: "1" + fromPort: + type: Integer + multiplicity: "1" + toPort: + type: Integer + multiplicity: "1" + cidr: + type: String + multiplicity: "0..*" + SwarmRole: + superclass: commons_DOMLElement + attributes: + kind: + type: String + multiplicity: "1" + associations: + nodes: + class: infrastructure_ComputingNode + multiplicity: "0..*" + Swarm: + superclass: infrastructure_ComputingGroup + associations: + roles: + class: infrastructure_SwarmRole + multiplicity: "0..*" + ExtInfrastructureElement: + superclass: infrastructure_InfrastructureElement + +concrete: + ConcreteInfrastructure: + superclass: commons_DOMLElement + associations: + providers: + class: concrete_RuntimeProvider + multiplicity: "0..*" + ConcreteElement: + superclass: commons_DOMLElement + attributes: + configurationScript: + type: String + multiplicity: "0..1" + preexisting: + multiplicity: "1" + type: Boolean + default: false + RuntimeProvider: + superclass: commons_DOMLElement + associations: + vms: + class: concrete_VirtualMachine + multiplicity: "0..*" + vmImages: + class: concrete_VMImage + multiplicity: "0..*" + containerImages: + class: concrete_ContainerImage + multiplicity: "0..*" + networks: + class: concrete_Network + multiplicity: "0..*" + storages: + class: concrete_Storage + multiplicity: "0..*" + faas: + class: concrete_FunctionAsAService + multiplicity: "0..*" + group: + class: concrete_ComputingGroup + multiplicity: "0..*" + VirtualMachine: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_VirtualMachine + multiplicity: "0..1" + VMImage: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_VMImage + multiplicity: "0..1" + ContainerImage: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_ContainerImage + multiplicity: "0..1" + Network: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_Network + multiplicity: "0..1" + Storage: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_Storage + multiplicity: "0..1" + FunctionAsAService: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_FunctionAsAService + multiplicity: "0..1" + ComputingGroup: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_ComputingGroup + multiplicity: "1" diff --git a/mc_openapi/assets/doml_meta_v2.1.yaml b/mc_openapi/assets/doml_meta_v2.1.yaml index a1c19170cc8f86926f8944678399945e04fbde50..cba1f52489abb62aa049084c03073473715d3b81 100644 --- a/mc_openapi/assets/doml_meta_v2.1.yaml +++ b/mc_openapi/assets/doml_meta_v2.1.yaml @@ -84,10 +84,10 @@ application: associations: exposedInterfaces: class: application_SoftwareInterface - mutiplicity: "0..*" + multiplicity: "0..*" consumedInterfaces: class: application_SoftwareInterface - mutiplicity: "0..*" + multiplicity: "0..*" SaaS: superclass: application_ApplicationComponent attributes: @@ -97,7 +97,7 @@ application: associations: exposedInterfaces: class: application_SoftwareInterface - mutiplicity: "0..*" + multiplicity: "0..*" SoftwareInterface: superclass: application_ApplicationComponent attributes: @@ -212,7 +212,7 @@ infrastructure: class: infrastructure_ComputingNode multiplicity: "0..1" iface: - class: infrastructure_NewtorkInterface + class: infrastructure_NetworkInterface multiplicity: "0..1" Container: superclass: infrastructure_ComputingNode diff --git a/mc_openapi/assets/doml_meta_v2.2.yaml b/mc_openapi/assets/doml_meta_v2.2.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d42e5e06140201f8e6451706edd92db024a1a69f --- /dev/null +++ b/mc_openapi/assets/doml_meta_v2.2.yaml @@ -0,0 +1,532 @@ +commons: + DOMLElement: + attributes: + name: + type: String + multiplicity: "0..1" + description: + type: String + multiplicity: "0..1" + associations: + annotations: + class: commons_Property + multiplicity: "0..*" + Property: + attributes: + key: + type: String + multiplicity: "0..1" + associations: + reference: + class: commons_DOMLElement + multiplicity: "0..1" + IProperty: + superclass: commons_Property + attributes: + value: + type: Integer + multiplicity: "0..1" + SProperty: + superclass: commons_Property + attributes: + value: + type: String + multiplicity: "0..1" + FProperty: + superclass: commons_Property + attributes: + value: + type: String + multiplicity: "0..1" + BProperty: + superclass: commons_Property + attributes: + value: + type: Boolean + multiplicity: "0..1" + Configuration: + superclass: commons_DOMLElement + associations: + deployments: + class: commons_Deployment + multiplicity: "0..*" + Credentials: + abstract: true + superclass: commons_DOMLElement + DeployableElement: + abstract: true + superclass: commons_DOMLElement # It's not present in the ECore, but without it breaks. + Deployment: + associations: + component: + class: commons_DeployableElement + multiplicity: "1" + node: + class: infrastructure_InfrastructureElement + multiplicity: "1" + KeyPair: + superclass: commons_Credentials + attributes: + user: + type: String + multiplicity: "0..1" + keyfile: + type: String + multiplicity: "0..1" + algorithm: + type: String + multiplicity: "0..1" + bits: + type: Integer + multiplicity: "0..1" + UserPass: + superclass: commons_Credentials + attributes: + user: + type: String + multiplicity: "0..1" + password: + type: String + multiplicity: "0..1" + Source: + superclass: commons_DOMLElement + attributes: + entry: + type: String + multiplicity: "0..*" + backend: + type: String + multiplicity: "0..*" +application: + ApplicationLayer: + superclass: commons_DOMLElement + associations: + components: + class: application_ApplicationComponent + multiplicity: "0..*" + ApplicationComponent: + superclass: commons_DOMLElement + SoftwareComponent: + superclass: application_ApplicationComponent # and commons_DeployableElement, but we can't handle multiple parent classes, can't we? + attributes: + isPersistent: + type: Boolean + multiplicity: "1" + default: false + licenseCost: + type: String + multiplicity: "0..1" + associations: + exposedInterfaces: + class: application_SoftwareInterface + multiplicity: "0..*" + consumedInterfaces: + class: application_SoftwareInterface + multiplicity: "0..*" + src: + class: commons_Source + multiplicity: "0..1" + SaaS: + superclass: application_ApplicationComponent + attributes: + licenseCost: + type: String + multiplicity: "0..1" + associations: + exposedInterfaces: + class: application_SoftwareInterface + multiplicity: "0..*" + SoftwareInterface: + superclass: application_ApplicationComponent + attributes: + endPoint: + type: String + multiplicity: "0..1" + DBMS: + superclass: application_SoftwareComponent + SaaSDBMS: + superclass: application_SaaS + +infrastructure: + InfrastructureLayer: + superclass: commons_DOMLElement + associations: + nodes: + class: infrastructure_ComputingNode + multiplicity: "0..*" + generators: + class: infrastructure_ComputingNodeGenerator + multiplicity: "0..*" + storages: + class: infrastructure_Storage + multiplicity: "0..*" + faas: + class: infrastructure_FunctionAsAService + multiplicity: "0..*" + credentials: + class: commons_Credentials + multiplicity: "0..*" + groups: + class: infrastructure_ComputingGroup + multiplicity: "0..*" + securityGroups: + class: infrastructure_SecurityGroup + multiplicity: "0..*" + networks: + class: infrastructure_Network + multiplicity: "0..*" + rules: + class: infrastructure_MonitoringRule + multiplicity: "0..*" + MonitoringRule: + superclass: commons_DOMLElement + attributes: + condition: + type: String + multiplicity: "1" + strategy: + type: String + multiplicity: "1" + strategyConfigurationString: + type: String + multiplicity: "0..1" + InfrastructureElement: + superclass: commons_DeployableElement + ComputingNode: + superclass: infrastructure_InfrastructureElement + attributes: + architecture: + type: String + multiplicity: "0..1" + os: + type: String + multiplicity: "0..1" + memory_mb: + type: Integer + multiplicity: "0..1" + memory_kb: # Missing in official Ecore, added by parser + type: Integer + multiplicity: "0..1" + storage: + type: String + multiplicity: "0..1" + cpu_count: + type: Integer + multiplicity: "0..1" + cost: + type: Integer # in cents + multiplicity: "0..1" + disabledMonitorings: + type: String + multiplicity: "0..1" + associations: + ifaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + location: + class: infrastructure_Location + multiplicity: "0..1" + credentials: + class: commons_Credentials + multiplicity: "0..1" + group: + class: infrastructure_ComputingGroup + multiplicity: "0..1" + inverse_of: infrastructure_ComputingGroup::groupedNodes + PhysicalComputingNode: + superclass: infrastructure_ComputingNode + VirtualMachine: + superclass: infrastructure_ComputingNode + attributes: + sizeDescription: + type: String + multiplicity: "0..1" + associations: + generatedFrom: + class: infrastructure_VMImage + multiplicity: "0..1" + Location: + superclass: commons_DOMLElement + attributes: + region: + type: String + multiplicity: "0..1" + zone: + type: String + multiplicity: "0..1" + ContainerConfig: + superclass: commons_DOMLElement + attributes: + container_port: + type: Integer + multiplicity: "0..1" + vm_port: + type: Integer + multiplicity: "0..1" + associations: + host: + class: infrastructure_ComputingNode + multiplicity: "0..1" + iface: + class: infrastructure_NetworkInterface + multiplicity: "0..1" + Container: + superclass: infrastructure_ComputingNode + associations: + generatedFrom: + class: infrastructure_ContainerImage + multiplicity: "0..1" + configs: + class: infrastructure_ContainerConfig + multiplicity: "0..*" + ComputingNodeGenerator: + superclass: commons_DOMLElement + attributes: + uri: + type: String + multiplicity: "0..1" + kind: + type: GeneratorKind # enum { SCRIPT, IMAGE } + VMImage: + superclass: infrastructure_ComputingNodeGenerator + associations: + generatedVMs: + class: infrastructure_VirtualMachine + multiplicity: "0..*" + inverse_of: infrastructure_VirtualMachine::generatedFrom + ContainerImage: + superclass: infrastructure_ComputingNodeGenerator + associations: + generatedContainers: + class: infrastructure_Container + multiplicity: "0..*" + inverse_of: infrastructure_Container::generatedFrom + AutoScalingGroup: + superclass: infrastructure_ComputingGroup + attributes: + min: + type: Integer + multiplicity: "0..1" + max: + type: Integer + multiplicity: "0..1" + loadBalancer: + type: String + multiplicity: "0..1" + associations: + machineDefinition: + class: infrastructure_VirtualMachine + multiplicity: "1" + securityGroup: + class: infrastructure_SecurityGroup + multiplicity: "0..1" + Storage: + superclass: infrastructure_InfrastructureElement + attributes: + label: + type: String + multiplicity: "0..1" + size_gb: + type: Integer # in GBs + multiplicity: "0..1" + cost: + type: Integer # in cents + multiplicity: "0..1" + associations: + ifaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + FunctionAsAService: + superclass: infrastructure_InfrastructureElement + attributes: + cost: + type: Integer # in cents + multiplicity: "0..1" + associations: + ifaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + Network: + superclass: commons_DOMLElement + attributes: + protocol: + type: String + multiplicity: "0..1" + addressRange: + type: String + multiplicity: "0..1" + cidr: + type: Integer + multiplicity: "0..1" + associations: + connectedIfaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + inverse_of: infrastructure_NetworkInterface::belongsTo + igws: + class: infrastructure_InternetGateway + multiplicity: "0..*" + subnets: + class: infrastructure_Subnet + multiplicity: "0..*" + Subnet: + superclass: infrastructure_Network + associations: + connectedTo: + class: infrastructure_Network + multiplicity: "0..1" + NetworkInterface: + superclass: infrastructure_InfrastructureElement + attributes: + endPoint: + type: Integer + multiplicity: "0..1" + speed: + type: String + multiplicity: "0..1" + associations: + belongsTo: + class: infrastructure_Network + multiplicity: "0..1" # This should be "1", but it would break InternetGateway + associated: + class: infrastructure_SecurityGroup + multiplicity: "0..1" # TODO: try putting this to 1 and see why it fails + InternetGateway: + superclass: infrastructure_NetworkInterface + ComputingGroup: + superclass: commons_DOMLElement + associations: + groupedNodes: + class: infrastructure_ComputingNode + multiplicity: "0..*" + inverse_of: infrastructure_ComputingNode::group + SecurityGroup: + superclass: commons_DOMLElement + associations: + rules: + class: infrastructure_Rule + multiplicity: "0..*" + ifaces: + class: infrastructure_NetworkInterface + multiplicity: "0..*" + inverse_of: infrastructure_NetworkInterface::associated + Rule: + superclass: commons_DOMLElement + attributes: + kind: + type: String + multiplicity: "1" + protocol: + type: String + multiplicity: "1" + fromPort: + type: Integer + multiplicity: "1" + toPort: + type: Integer + multiplicity: "1" + cidr: + type: String + multiplicity: "0..*" + SwarmRole: + superclass: commons_DOMLElement + attributes: + kind: + type: String + multiplicity: "1" + associations: + nodes: + class: infrastructure_ComputingNode + multiplicity: "0..*" + Swarm: + superclass: infrastructure_ComputingGroup + associations: + roles: + class: infrastructure_SwarmRole + multiplicity: "0..*" + ExtInfrastructureElement: + superclass: infrastructure_InfrastructureElement + +concrete: + ConcreteInfrastructure: + superclass: commons_DOMLElement + associations: + providers: + class: concrete_RuntimeProvider + multiplicity: "0..*" + ConcreteElement: + superclass: commons_DOMLElement + attributes: + configurationScript: + type: String + multiplicity: "0..1" + preexisting: + multiplicity: "1" + type: Boolean + default: false + RuntimeProvider: + superclass: commons_DOMLElement + associations: + vms: + class: concrete_VirtualMachine + multiplicity: "0..*" + vmImages: + class: concrete_VMImage + multiplicity: "0..*" + containerImages: + class: concrete_ContainerImage + multiplicity: "0..*" + networks: + class: concrete_Network + multiplicity: "0..*" + storages: + class: concrete_Storage + multiplicity: "0..*" + faas: + class: concrete_FunctionAsAService + multiplicity: "0..*" + group: + class: concrete_ComputingGroup + multiplicity: "0..*" + VirtualMachine: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_VirtualMachine + multiplicity: "0..1" + VMImage: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_VMImage + multiplicity: "0..1" + ContainerImage: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_ContainerImage + multiplicity: "0..1" + Network: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_Network + multiplicity: "0..1" + Storage: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_Storage + multiplicity: "0..1" + FunctionAsAService: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_FunctionAsAService + multiplicity: "0..1" + ComputingGroup: + superclass: concrete_ConcreteElement + associations: + maps: + class: infrastructure_ComputingGroup + multiplicity: "1" diff --git a/mc_openapi/assets/doml_v2.1.1.ecore b/mc_openapi/assets/doml_v2.1.1.ecore new file mode 100644 index 0000000000000000000000000000000000000000..a60a074bc835051b98255dfb978200656e955ef9 --- /dev/null +++ b/mc_openapi/assets/doml_v2.1.1.ecore @@ -0,0 +1,419 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="doml" nsURI="http://www.piacere-project.eu/doml" nsPrefix="doml"> + <eAnnotations source="emf.gen"> + <details key="basePackage" value="eu.piacere.doml"/> + <details key="fileExtensions" value="domlx"/> + <details key="complianceLevel" value="JDK80"/> + </eAnnotations> + <eSubpackages name="commons" nsURI="http://www.piacere-project.eu/doml/commons" + nsPrefix="commons"> + <eClassifiers xsi:type="ecore:EClass" name="DOMLModel" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="version" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" + defaultValueLiteral="2.1.1"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="application" eType="#//application/ApplicationLayer" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="infrastructure" eType="#//infrastructure/InfrastructureLayer" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="concretizations" upperBound="-1" + eType="#//concrete/ConcreteInfrastructure" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="optimization" eType="#//optimization/OptimizationLayer" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="configurations" upperBound="-1" + eType="#//commons/Configuration" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="activeConfiguration" + eType="#//commons/Configuration"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="activeInfrastructure" + eType="#//concrete/ConcreteInfrastructure"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="functionalRequirements" + upperBound="-1" eType="#//commons/Requirement" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Property" abstract="true"> + <eOperations name="getValue" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EJavaObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="reference" eType="#//commons/DOMLElement"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="IProperty" eSuperTypes="#//commons/Property"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SProperty" eSuperTypes="#//commons/Property"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="FProperty" eSuperTypes="#//commons/Property"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="BProperty" eSuperTypes="#//commons/Property"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ExtensionElement" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="metaclassName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DOMLElement" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="annotations" upperBound="-1" + eType="#//commons/Property" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="contributesTo" upperBound="-1" + eType="#//commons/Requirement" eOpposite="#//commons/Requirement/predicatesOn"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Configuration" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="deployments" upperBound="-1" + eType="#//commons/Deployment" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DeployableElement" abstract="true"/> + <eClassifiers xsi:type="ecore:EClass" name="Deployment"> + <eStructuralFeatures xsi:type="ecore:EReference" name="component" lowerBound="1" + eType="#//commons/DeployableElement"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="node" lowerBound="1" + eType="#//infrastructure/InfrastructureElement"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="predicatesOn" upperBound="-1" + eType="#//commons/DOMLElement" eOpposite="#//commons/DOMLElement/contributesTo"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="RangedRequirement" eSuperTypes="#//commons/Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="EnumeratedRequirement" eSuperTypes="#//commons/Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DeploymentRequirement" abstract="true" + eSuperTypes="#//commons/Requirement"/> + <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeTypeRequirement" eSuperTypes="#//commons/DeploymentRequirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="validTypes" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeWithPropertyRequirement" + eSuperTypes="#//commons/DeploymentRequirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DeploymentToSpecificNodeRequirement" + eSuperTypes="#//commons/DeploymentRequirement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="validElements" upperBound="-1" + eType="#//infrastructure/InfrastructureElement"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Credentials" abstract="true" eSuperTypes="#//commons/DOMLElement"/> + <eClassifiers xsi:type="ecore:EClass" name="KeyPair" eSuperTypes="#//commons/Credentials"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="user" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="keyfile" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="algorithm" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="bits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="UserPass" eSuperTypes="#//commons/Credentials"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="username" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="password" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Source" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="engine" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="uri" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="entry" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="backend" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="credential" eType="#//commons/Credentials" + containment="true"/> + </eClassifiers> + </eSubpackages> + <eSubpackages name="application" nsURI="http://www.piacere-project.eu/doml/application" + nsPrefix="app"> + <eClassifiers xsi:type="ecore:EClass" name="ApplicationLayer" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="components" upperBound="-1" + eType="#//application/ApplicationComponent" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ApplicationComponent" abstract="true" + eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/> + <eClassifiers xsi:type="ecore:EClass" name="SoftwareComponent" eSuperTypes="#//application/ApplicationComponent"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="isPersistent" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject" + defaultValueLiteral="false"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1" + eType="#//application/SoftwareInterface" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="consumedInterfaces" upperBound="-1" + eType="#//application/SoftwareInterface"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="src" eType="#//commons/Source" + containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DBMS" eSuperTypes="#//application/SoftwareComponent"/> + <eClassifiers xsi:type="ecore:EClass" name="SaaS" eSuperTypes="#//application/ApplicationComponent"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1" + eType="#//application/SoftwareInterface" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SaaSDBMS" eSuperTypes="#//application/SaaS"/> + <eClassifiers xsi:type="ecore:EClass" name="SoftwareInterface" eSuperTypes="#//application/ApplicationComponent"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ExtApplicationComponent" eSuperTypes="#//application/ApplicationComponent #//commons/ExtensionElement"/> + </eSubpackages> + <eSubpackages name="infrastructure" nsURI="http://www.piacere-project.eu/doml/infrastructure" + nsPrefix="infra"> + <eClassifiers xsi:type="ecore:EClass" name="InfrastructureLayer" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1" + eType="#//infrastructure/ComputingNode" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="generators" upperBound="-1" + eType="#//infrastructure/ComputingNodeGenerator" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1" + eType="#//infrastructure/Storage" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1" + eType="#//infrastructure/FunctionAsAService" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" upperBound="-1" + eType="#//commons/Credentials" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="groups" upperBound="-1" + eType="#//infrastructure/ComputingGroup" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroups" upperBound="-1" + eType="#//infrastructure/SecurityGroup" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1" + eType="#//infrastructure/Network" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1" + eType="#//infrastructure/MonitoringRule" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="MonitoringRule" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="condition" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategy" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategyConfigurationString" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" abstract="true" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="groupedNodes" upperBound="-1" + eType="#//infrastructure/ComputingNode" eOpposite="#//infrastructure/ComputingNode/group"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="AutoScalingGroup" eSuperTypes="#//infrastructure/ComputingGroup"> + <eStructuralFeatures xsi:type="ecore:EReference" name="machineDefinition" lowerBound="1" + eType="#//infrastructure/VirtualMachine" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject" + defaultValueLiteral="1"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject" + defaultValueLiteral="1"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroup" eType="#//infrastructure/SecurityGroup" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="loadBalancer" eType="#//infrastructure/LoadBalancerKind" + defaultValueLiteral="DEFAULT"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="LoadBalancerKind"> + <eLiterals name="DEFAULT"/> + <eLiterals name="INTERNAL" value="1"/> + <eLiterals name="EXTERNAL" value="2"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Rule" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RuleKind"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="fromPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="toPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cidr" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="RuleKind"> + <eLiterals name="EGRESS"/> + <eLiterals name="INGRESS" value="1"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SecurityGroup" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1" + eType="#//infrastructure/Rule" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/associated"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="AvailabilityGroup" eSuperTypes="#//infrastructure/ComputingGroup"/> + <eClassifiers xsi:type="ecore:EClass" name="InfrastructureElement" abstract="true" + eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/> + <eClassifiers xsi:type="ecore:EClass" name="ComputingNode" abstract="true" eSuperTypes="#//infrastructure/InfrastructureElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="architecture" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="os" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="memory_mb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="storage" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cpu_count" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="location" eType="#//infrastructure/Location" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" eType="#//commons/Credentials"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="group" eType="#//infrastructure/ComputingGroup" + eOpposite="#//infrastructure/ComputingGroup/groupedNodes"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="disabledMonitorings" + upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ComputingNodeGenerator" abstract="true" + eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="uri" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/GeneratorKind"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="GeneratorKind"> + <eLiterals name="SCRIPT"/> + <eLiterals name="IMAGE" value="1"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator"> + <eStructuralFeatures xsi:type="ecore:EReference" name="generatedVMs" upperBound="-1" + eType="#//infrastructure/VirtualMachine" eOpposite="#//infrastructure/VirtualMachine/generatedFrom"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator"> + <eStructuralFeatures xsi:type="ecore:EReference" name="generatedContainers" + upperBound="-1" eType="#//infrastructure/Container" eOpposite="#//infrastructure/Container/generatedFrom"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="PhysicalComputingNode" eSuperTypes="#//infrastructure/ComputingNode"/> + <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//infrastructure/ComputingNode"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="sizeDescription" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/VMImage" + eOpposite="#//infrastructure/VMImage/generatedVMs"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Location" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="region" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="zone" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ContainerConfig" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="container_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="vm_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="host" eType="#//infrastructure/ComputingNode"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="iface" eType="#//infrastructure/NetworkInterface"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Container" eSuperTypes="#//infrastructure/ComputingNode"> + <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/ContainerImage" + eOpposite="#//infrastructure/ContainerImage/generatedContainers"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="configs" upperBound="-1" + eType="#//infrastructure/ContainerConfig" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="addressRange" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="connectedIfaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/belongsTo"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="igws" upperBound="-1" + eType="#//infrastructure/InternetGateway" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="subnets" upperBound="-1" + eType="#//infrastructure/Subnet" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Subnet" eSuperTypes="#//infrastructure/Network"> + <eStructuralFeatures xsi:type="ecore:EReference" name="connectedTo" upperBound="-1" + eType="#//infrastructure/Subnet"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="NetworkInterface" eSuperTypes="#//infrastructure/InfrastructureElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="speed" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="belongsTo" eType="#//infrastructure/Network" + eOpposite="#//infrastructure/Network/connectedIfaces"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="associated" eType="#//infrastructure/SecurityGroup" + eOpposite="#//infrastructure/SecurityGroup/ifaces"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="InternetGateway" eSuperTypes="#//infrastructure/NetworkInterface"/> + <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//infrastructure/InfrastructureElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="label" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="size_gb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//infrastructure/InfrastructureElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="RoleKind"> + <eLiterals name="NONE"/> + <eLiterals name="MANAGER" value="1"/> + <eLiterals name="WORKER" value="2"/> + <eLiterals name="MASTER" value="3"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SwarmRole" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RoleKind"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1" + eType="#//infrastructure/ComputingNode" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Swarm" eSuperTypes="#//infrastructure/ComputingGroup"> + <eStructuralFeatures xsi:type="ecore:EReference" name="roles" upperBound="-1" + eType="#//infrastructure/SwarmRole" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ExtInfrastructureElement" eSuperTypes="#//infrastructure/InfrastructureElement #//commons/ExtensionElement"/> + </eSubpackages> + <eSubpackages name="concrete" nsURI="http://www.piacere-project.eu/doml/concrete" + nsPrefix="concrete"> + <eClassifiers xsi:type="ecore:EClass" name="ConcreteInfrastructure" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="providers" upperBound="-1" + eType="#//concrete/RuntimeProvider" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="RuntimeProvider" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="vms" upperBound="-1" + eType="#//concrete/VirtualMachine" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="vmImages" upperBound="-1" + eType="#//concrete/VMImage" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="containerImages" upperBound="-1" + eType="#//concrete/ContainerImage" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1" + eType="#//concrete/Network" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1" + eType="#//concrete/Storage" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1" + eType="#//concrete/FunctionAsAService" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="group" upperBound="-1" + eType="#//concrete/ComputingGroup" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ConcreteElement" abstract="true" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="configurationScript" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="preexisting" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject" + defaultValueLiteral="false"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VirtualMachine"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VMImage"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ContainerImage"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Network"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Storage"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/FunctionAsAService"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ComputingGroup"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ExtConcreteElement" eSuperTypes="#//concrete/ConcreteElement #//commons/ExtensionElement"/> + </eSubpackages> + <eSubpackages name="optimization" nsURI="http://www.piacere-project.eu/doml/optimization" + nsPrefix="optimization"> + <eClassifiers xsi:type="ecore:EClass" name="OptimizationLayer" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="startingHint" eType="#//commons/Configuration"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="solutions" upperBound="-1" + eType="#//optimization/OptimizationSolution" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" upperBound="-1" + eType="#//optimization/OptimizationObjective" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="nonfunctionalRequirements" + upperBound="-1" eType="#//commons/Requirement" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ObjectiveValue"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="availability" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="performance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="OptimizationSolution" eSuperTypes="#//commons/Configuration"> + <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" eType="#//optimization/ObjectiveValue" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="decisions" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="OptimizationObjective" abstract="true" + eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" + defaultValueLiteral="Max"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="CountObjective" eSuperTypes="#//optimization/OptimizationObjective"/> + <eClassifiers xsi:type="ecore:EClass" name="MeasurableObjective" eSuperTypes="#//optimization/OptimizationObjective"/> + <eClassifiers xsi:type="ecore:EClass" name="ExtOptimizationObjective" eSuperTypes="#//optimization/OptimizationObjective #//commons/ExtensionElement"/> + </eSubpackages> +</ecore:EPackage> diff --git a/mc_openapi/assets/doml_v2.2.ecore b/mc_openapi/assets/doml_v2.2.ecore new file mode 100644 index 0000000000000000000000000000000000000000..a294cdef5b4ac189c94d5e7088cfb79db4aaf7ae --- /dev/null +++ b/mc_openapi/assets/doml_v2.2.ecore @@ -0,0 +1,415 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="doml" nsURI="http://www.piacere-project.eu/doml" nsPrefix="doml"> + <eAnnotations source="emf.gen"> + <details key="basePackage" value="eu.piacere.doml"/> + <details key="fileExtensions" value="domlx"/> + <details key="complianceLevel" value="JDK80"/> + </eAnnotations> + <eSubpackages name="commons" nsURI="http://www.piacere-project.eu/doml/commons" + nsPrefix="commons"> + <eClassifiers xsi:type="ecore:EClass" name="DOMLModel" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="version" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" + defaultValueLiteral="2.2"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="application" eType="#//application/ApplicationLayer" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="infrastructure" eType="#//infrastructure/InfrastructureLayer" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="concretizations" upperBound="-1" + eType="#//concrete/ConcreteInfrastructure" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="optimization" eType="#//optimization/OptimizationLayer" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="configurations" upperBound="-1" + eType="#//commons/Configuration" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="activeConfiguration" + eType="#//commons/Configuration"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="activeInfrastructure" + eType="#//concrete/ConcreteInfrastructure"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="functionalRequirements" + upperBound="-1" eType="#//commons/Requirement" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Property" abstract="true"> + <eOperations name="getValue" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EJavaObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="reference" eType="#//commons/DOMLElement"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="IProperty" eSuperTypes="#//commons/Property"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SProperty" eSuperTypes="#//commons/Property"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="FProperty" eSuperTypes="#//commons/Property"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="BProperty" eSuperTypes="#//commons/Property"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ExtensionElement" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="metaclassName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DOMLElement" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="annotations" upperBound="-1" + eType="#//commons/Property" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="contributesTo" upperBound="-1" + eType="#//commons/Requirement" eOpposite="#//commons/Requirement/predicatesOn"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Configuration" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="deployments" upperBound="-1" + eType="#//commons/Deployment" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DeployableElement" abstract="true"/> + <eClassifiers xsi:type="ecore:EClass" name="Deployment"> + <eStructuralFeatures xsi:type="ecore:EReference" name="component" lowerBound="1" + eType="#//commons/DeployableElement"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="node" lowerBound="1" + eType="#//infrastructure/InfrastructureElement"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="predicatesOn" upperBound="-1" + eType="#//commons/DOMLElement" eOpposite="#//commons/DOMLElement/contributesTo"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="RangedRequirement" eSuperTypes="#//commons/Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="EnumeratedRequirement" eSuperTypes="#//commons/Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DeploymentRequirement" abstract="true" + eSuperTypes="#//commons/Requirement"/> + <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeTypeRequirement" eSuperTypes="#//commons/DeploymentRequirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="validTypes" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeWithPropertyRequirement" + eSuperTypes="#//commons/DeploymentRequirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DeploymentToSpecificNodeRequirement" + eSuperTypes="#//commons/DeploymentRequirement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="validElements" upperBound="-1" + eType="#//infrastructure/InfrastructureElement"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Credentials" abstract="true" eSuperTypes="#//commons/DOMLElement"/> + <eClassifiers xsi:type="ecore:EClass" name="KeyPair" eSuperTypes="#//commons/Credentials"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="user" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="keyfile" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="algorithm" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="bits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="UserPass" eSuperTypes="#//commons/Credentials"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="username" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="password" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Source" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="entry" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="backend" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + </eSubpackages> + <eSubpackages name="application" nsURI="http://www.piacere-project.eu/doml/application" + nsPrefix="app"> + <eClassifiers xsi:type="ecore:EClass" name="ApplicationLayer" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="components" upperBound="-1" + eType="#//application/ApplicationComponent" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ApplicationComponent" abstract="true" + eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/> + <eClassifiers xsi:type="ecore:EClass" name="SoftwareComponent" eSuperTypes="#//application/ApplicationComponent"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="isPersistent" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject" + defaultValueLiteral="false"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1" + eType="#//application/SoftwareInterface" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="consumedInterfaces" upperBound="-1" + eType="#//application/SoftwareInterface"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="src" eType="#//commons/Source" + containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="DBMS" eSuperTypes="#//application/SoftwareComponent"/> + <eClassifiers xsi:type="ecore:EClass" name="SaaS" eSuperTypes="#//application/ApplicationComponent"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1" + eType="#//application/SoftwareInterface" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SaaSDBMS" eSuperTypes="#//application/SaaS"/> + <eClassifiers xsi:type="ecore:EClass" name="SoftwareInterface" eSuperTypes="#//application/ApplicationComponent"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ExtApplicationComponent" eSuperTypes="#//application/ApplicationComponent #//commons/ExtensionElement"/> + </eSubpackages> + <eSubpackages name="infrastructure" nsURI="http://www.piacere-project.eu/doml/infrastructure" + nsPrefix="infra"> + <eClassifiers xsi:type="ecore:EClass" name="InfrastructureLayer" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1" + eType="#//infrastructure/ComputingNode" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="generators" upperBound="-1" + eType="#//infrastructure/ComputingNodeGenerator" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1" + eType="#//infrastructure/Storage" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1" + eType="#//infrastructure/FunctionAsAService" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" upperBound="-1" + eType="#//commons/Credentials" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="groups" upperBound="-1" + eType="#//infrastructure/ComputingGroup" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroups" upperBound="-1" + eType="#//infrastructure/SecurityGroup" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1" + eType="#//infrastructure/Network" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1" + eType="#//infrastructure/MonitoringRule" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="MonitoringRule" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="condition" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategy" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategyConfigurationString" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" abstract="true" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="groupedNodes" upperBound="-1" + eType="#//infrastructure/ComputingNode" eOpposite="#//infrastructure/ComputingNode/group"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="AutoScalingGroup" eSuperTypes="#//infrastructure/ComputingGroup"> + <eStructuralFeatures xsi:type="ecore:EReference" name="machineDefinition" lowerBound="1" + eType="#//infrastructure/VirtualMachine" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject" + defaultValueLiteral="1"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject" + defaultValueLiteral="1"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroup" eType="#//infrastructure/SecurityGroup" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="loadBalancer" eType="#//infrastructure/LoadBalancerKind" + defaultValueLiteral="DEFAULT"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="LoadBalancerKind"> + <eLiterals name="DEFAULT"/> + <eLiterals name="INTERNAL" value="1"/> + <eLiterals name="EXTERNAL" value="2"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Rule" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RuleKind"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="fromPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="toPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cidr" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="RuleKind"> + <eLiterals name="EGRESS"/> + <eLiterals name="INGRESS" value="1"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SecurityGroup" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1" + eType="#//infrastructure/Rule" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/associated"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="AvailabilityGroup" eSuperTypes="#//infrastructure/ComputingGroup"/> + <eClassifiers xsi:type="ecore:EClass" name="InfrastructureElement" abstract="true" + eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/> + <eClassifiers xsi:type="ecore:EClass" name="ComputingNode" abstract="true" eSuperTypes="#//infrastructure/InfrastructureElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="architecture" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="os" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="memory_mb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="storage" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cpu_count" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="location" eType="#//infrastructure/Location" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" eType="#//commons/Credentials"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="group" eType="#//infrastructure/ComputingGroup" + eOpposite="#//infrastructure/ComputingGroup/groupedNodes"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="disabledMonitorings" + upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ComputingNodeGenerator" abstract="true" + eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="uri" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/GeneratorKind"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="GeneratorKind"> + <eLiterals name="SCRIPT"/> + <eLiterals name="IMAGE" value="1"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator"> + <eStructuralFeatures xsi:type="ecore:EReference" name="generatedVMs" upperBound="-1" + eType="#//infrastructure/VirtualMachine" eOpposite="#//infrastructure/VirtualMachine/generatedFrom"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator"> + <eStructuralFeatures xsi:type="ecore:EReference" name="generatedContainers" + upperBound="-1" eType="#//infrastructure/Container" eOpposite="#//infrastructure/Container/generatedFrom"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="PhysicalComputingNode" eSuperTypes="#//infrastructure/ComputingNode"/> + <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//infrastructure/ComputingNode"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="sizeDescription" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/VMImage" + eOpposite="#//infrastructure/VMImage/generatedVMs"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Location" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="region" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="zone" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ContainerConfig" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="container_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="vm_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="host" eType="#//infrastructure/ComputingNode"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="iface" eType="#//infrastructure/NetworkInterface"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Container" eSuperTypes="#//infrastructure/ComputingNode"> + <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/ContainerImage" + eOpposite="#//infrastructure/ContainerImage/generatedContainers"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="configs" upperBound="-1" + eType="#//infrastructure/ContainerConfig" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="addressRange" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="connectedIfaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/belongsTo"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="igws" upperBound="-1" + eType="#//infrastructure/InternetGateway" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="subnets" upperBound="-1" + eType="#//infrastructure/Subnet" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Subnet" eSuperTypes="#//infrastructure/Network"> + <eStructuralFeatures xsi:type="ecore:EReference" name="connectedTo" upperBound="-1" + eType="#//infrastructure/Subnet"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="NetworkInterface" eSuperTypes="#//infrastructure/InfrastructureElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="speed" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="belongsTo" eType="#//infrastructure/Network" + eOpposite="#//infrastructure/Network/connectedIfaces"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="associated" eType="#//infrastructure/SecurityGroup" + eOpposite="#//infrastructure/SecurityGroup/ifaces"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="InternetGateway" eSuperTypes="#//infrastructure/NetworkInterface"/> + <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//infrastructure/InfrastructureElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="label" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="size_gb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//infrastructure/InfrastructureElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1" + eType="#//infrastructure/NetworkInterface" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="RoleKind"> + <eLiterals name="NONE"/> + <eLiterals name="MANAGER" value="1"/> + <eLiterals name="WORKER" value="2"/> + <eLiterals name="MASTER" value="3"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SwarmRole" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RoleKind"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1" + eType="#//infrastructure/ComputingNode" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Swarm" eSuperTypes="#//infrastructure/ComputingGroup"> + <eStructuralFeatures xsi:type="ecore:EReference" name="roles" upperBound="-1" + eType="#//infrastructure/SwarmRole" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ExtInfrastructureElement" eSuperTypes="#//infrastructure/InfrastructureElement #//commons/ExtensionElement"/> + </eSubpackages> + <eSubpackages name="concrete" nsURI="http://www.piacere-project.eu/doml/concrete" + nsPrefix="concrete"> + <eClassifiers xsi:type="ecore:EClass" name="ConcreteInfrastructure" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="providers" upperBound="-1" + eType="#//concrete/RuntimeProvider" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="RuntimeProvider" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="vms" upperBound="-1" + eType="#//concrete/VirtualMachine" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="vmImages" upperBound="-1" + eType="#//concrete/VMImage" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="containerImages" upperBound="-1" + eType="#//concrete/ContainerImage" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1" + eType="#//concrete/Network" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1" + eType="#//concrete/Storage" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1" + eType="#//concrete/FunctionAsAService" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="group" upperBound="-1" + eType="#//concrete/ComputingGroup" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ConcreteElement" abstract="true" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="configurationScript" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="preexisting" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject" + defaultValueLiteral="false"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VirtualMachine"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VMImage"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ContainerImage"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Network"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Storage"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/FunctionAsAService"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" eSuperTypes="#//concrete/ConcreteElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ComputingGroup"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ExtConcreteElement" eSuperTypes="#//concrete/ConcreteElement #//commons/ExtensionElement"/> + </eSubpackages> + <eSubpackages name="optimization" nsURI="http://www.piacere-project.eu/doml/optimization" + nsPrefix="optimization"> + <eClassifiers xsi:type="ecore:EClass" name="OptimizationLayer" eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="startingHint" eType="#//commons/Configuration"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="solutions" upperBound="-1" + eType="#//optimization/OptimizationSolution" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" upperBound="-1" + eType="#//optimization/OptimizationObjective" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="nonfunctionalRequirements" + upperBound="-1" eType="#//commons/Requirement" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ObjectiveValue"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="availability" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="performance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="OptimizationSolution" eSuperTypes="#//commons/Configuration"> + <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" eType="#//optimization/ObjectiveValue" + containment="true"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="decisions" upperBound="-1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="OptimizationObjective" abstract="true" + eSuperTypes="#//commons/DOMLElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" + defaultValueLiteral="Max"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="CountObjective" eSuperTypes="#//optimization/OptimizationObjective"/> + <eClassifiers xsi:type="ecore:EClass" name="MeasurableObjective" eSuperTypes="#//optimization/OptimizationObjective"/> + <eClassifiers xsi:type="ecore:EClass" name="ExtOptimizationObjective" eSuperTypes="#//optimization/OptimizationObjective #//commons/ExtensionElement"/> + </eSubpackages> +</ecore:EPackage> diff --git a/mc_openapi/doml_mc/common_reqs.py b/mc_openapi/doml_mc/common_reqs.py index cc12e7e79b3f1e828e50c1a5ae33812d7e4d2814..d64a0bdaed3298d9d2bff4a7c159a339ec2ad82f 100644 --- a/mc_openapi/doml_mc/common_reqs.py +++ b/mc_openapi/doml_mc/common_reqs.py @@ -1,15 +1,11 @@ +from re import M from typing import Optional -from z3 import ( - Const, Consts, ExprRef, - Exists, And, Or, Not, - Solver, ModelRef -) +from z3 import And, Const, Consts, Exists, ExprRef, ModelRef, Not, Or, Solver -from .imc import ( - SMTEncoding, SMTSorts, Requirement, RequirementStore -) -from .intermediate_model import IntermediateModel, DOMLVersion +from .error_desc_helper import get_user_friendly_name +from .imc import Requirement, RequirementStore, SMTEncoding, SMTSorts +from .intermediate_model import DOMLVersion, IntermediateModel def get_consts(smtsorts: SMTSorts, consts: list[str]) -> list[ExprRef]: @@ -30,7 +26,7 @@ def vm_iface(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: ) ) - +# All software packages can see the interfaces they need through a common network. def software_package_iface_net(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: asc_consumer, asc_exposer, siface, net, net_iface, cnode, cdeployment, enode, edeployment, vm = get_consts( smtsorts, @@ -153,6 +149,7 @@ def software_package_iface_net_v2_1(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ) +# There are no duplicated interfaces. def iface_uniq(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: endPointAttr = smtenc.attributes["infrastructure_NetworkInterface::endPoint"] ni1, ni2 = get_consts(smtsorts, ["ni1", "ni2"]) @@ -163,7 +160,7 @@ def iface_uniq(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: ni1 != ni2, ) - +# All software components have been deployed to some node. def all_SoftwareComponents_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: sc, deployment, ielem = get_consts(smtsorts, ["sc", "deployment", "ielem"]) return And( @@ -179,7 +176,7 @@ def all_SoftwareComponents_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ) ) - +# All abstract infrastructure elements are mapped to an element in the active concretization. def all_infrastructure_elements_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: def checkOneClass(ielem, concr, provider, celem, ielemClass, providerAssoc, celemAssoc): return And( @@ -227,7 +224,7 @@ def all_infrastructure_elements_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts ) ) - +# All elements in the active concretization are mapped to some abstract infrastructure element. def all_concrete_map_something(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: def checkOneClass(ielem, provider, celem, providerAssoc, celemAssoc): return And( @@ -283,87 +280,150 @@ def all_concrete_map_something(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprR ) ) +# def sw_components_have_source_code_property(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: +# sw_comp, prop = get_consts(smtsorts, ["sw_comp prop"]) -# Error Descriptions +# big_x = smtsorts.attr_data_sort.str(smtenc.str_symbols["source_code"]) -def get_user_friendly_name( - intermediate_model: IntermediateModel, - model: ModelRef, - const: ExprRef -) -> Optional[str]: - z3_elem = model[const] - if z3_elem is not None: - im_elem = intermediate_model.get(str(z3_elem)) - if im_elem is not None: - return im_elem.user_friendly_name - return None +# return And( +# smtenc.element_class_fun(sw_comp) == smtenc.classes["application_SoftwareComponent"], +# Not( +# Exists([prop], And( +# smtenc.element_class_fun(prop) == smtenc.classes["commons_SProperty"], +# smtenc.attribute_rel(prop, smtenc.attributes["commons_Property::key"], big_x), +# smtenc.association_rel(sw_comp, smtenc.associations["commons_DOMLElement::annotations"], prop) +# )) +# ) +# ) +def security_group_must_have_iface(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: + sg, iface = get_consts(smtsorts, ["sg iface"]) + return And( + smtenc.element_class_fun(sg) == smtenc.classes["infrastructure_SecurityGroup"], + Not(Exists([iface], + smtenc.association_rel(iface, smtenc.associations["infrastructure_NetworkInterface::associated"], sg) + )) + ) + +# TODO: Check if HTTP should be disabled too +def external_services_must_have_https(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: + saas, sw_iface, sw_comp, deployment, ielem, net_iface, sec_group, rule = get_consts(smtsorts, + ["saas, sw_iface, sw_comp, deployment, ielem, net_iface, sec_group, rule"]) + return And( + smtenc.element_class_fun(saas) == smtenc.classes["application_SaaS"], + smtenc.element_class_fun(sec_group) == smtenc.classes["infrastructure_SecurityGroup"], + Not(Exists([sw_iface, sw_comp, deployment, ielem, net_iface, rule], + And( + smtenc.association_rel(saas, smtenc.associations["application_SaaS::exposedInterfaces"], sw_iface), + smtenc.association_rel(sw_comp, smtenc.associations["application_SoftwareComponent::consumedInterfaces"], sw_iface), + smtenc.association_rel(deployment, smtenc.associations["commons_Deployment::component"], sw_comp), + smtenc.association_rel(deployment, smtenc.associations["commons_Deployment::node"], ielem), + smtenc.association_rel(ielem, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface), + smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::associated"], sec_group), + smtenc.association_rel(sec_group, smtenc.associations["infrastructure_SecurityGroup::rules"], rule), + smtenc.attribute_rel(rule, smtenc.attributes["infrastructure_Rule::fromPort"], smtsorts.attr_data_sort.int(443)), + smtenc.attribute_rel(rule, smtenc.attributes["infrastructure_Rule::toPort"], smtsorts.attr_data_sort.int(443)), + smtenc.attribute_rel(rule, smtenc.attributes["infrastructure_Rule::kind"], smtsorts.attr_data_sort.str(smtenc.str_symbols["INGRESS"])) + ) + )) + ) + +# Error Descriptions def ed_vm_iface(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str: - vm = Const("vm", smtsorts.element_sort) - vm_name = get_user_friendly_name(intermediate_model, solver.model(), vm) - if vm_name: - return f"Virtual machine {vm_name} is connected to no network interface." - else: + try: + vm = Const("vm", smtsorts.element_sort) + vm_name = get_user_friendly_name(intermediate_model, solver.model(), vm) + if vm_name: + return f"Virtual machine {vm_name} is connected to no network interface." + except: return "A virtual machine is connected to no network interface." def ed_software_package_iface_net(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str: - asc_consumer, asc_exposer, siface = get_consts( - smtsorts, - ["asc_consumer", "asc_exposer", "siface"] - ) - model = solver.model() - asc_consumer_name = get_user_friendly_name(intermediate_model, model, asc_consumer) - asc_exposer_name = get_user_friendly_name(intermediate_model, model, asc_exposer) - siface_name = get_user_friendly_name(intermediate_model, model, siface) - if asc_consumer_name and asc_exposer_name and siface_name: - return ( - f"Software components '{asc_consumer_name}' and '{asc_exposer_name}' " - f"are supposed to communicate through interface '{siface_name}', " - "but they are deployed to nodes that cannot communicate through a common network." + try: + asc_consumer, asc_exposer, siface = get_consts( + smtsorts, + ["asc_consumer", "asc_exposer", "siface"] ) - else: + model = solver.model() + asc_consumer_name = get_user_friendly_name(intermediate_model, model, asc_consumer) + asc_exposer_name = get_user_friendly_name(intermediate_model, model, asc_exposer) + siface_name = get_user_friendly_name(intermediate_model, model, siface) + if asc_consumer_name and asc_exposer_name and siface_name: + return ( + f"Software components '{asc_consumer_name}' and '{asc_exposer_name}' " + f"are supposed to communicate through interface '{siface_name}', " + "but they are deployed to nodes that cannot communicate through a common network." + ) + except: return "A software package is deployed on a node that has no access to an interface it consumes." def ed_iface_uniq(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str: - ni1, ni2 = get_consts(smtsorts, ["ni1", "ni2"]) - model = solver.model() - ni1_name = get_user_friendly_name(intermediate_model, model, ni1) - ni2_name = get_user_friendly_name(intermediate_model, model, ni2) - if ni1_name and ni2_name: - return f"Network interfaces '{ni1_name}' and '{ni2_name}' share the same IP address." - else: + try: + ni1, ni2 = get_consts(smtsorts, ["ni1", "ni2"]) + model = solver.model() + ni1_name = get_user_friendly_name(intermediate_model, model, ni1) + ni2_name = get_user_friendly_name(intermediate_model, model, ni2) + if ni1_name and ni2_name: + return f"Network interfaces '{ni1_name}' and '{ni2_name}' share the same IP address." + except: return "Two network interfaces share the same IP address." def ed_all_SoftwareComponents_deployed(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str: - sc = Const("sc", smtsorts.element_sort) - sc_name = get_user_friendly_name(intermediate_model, solver.model(), sc) - if sc_name: - return f"Software component '{sc_name}' is not deployed to any abstract infrastructure node." - else: + try: + sc = Const("sc", smtsorts.element_sort) + sc_name = get_user_friendly_name(intermediate_model, solver.model(), sc) + if sc_name: + return f"Software component '{sc_name}' is not deployed to any abstract infrastructure node." + except: return "A software component is not deployed to any abstract infrastructure node." def ed_all_infrastructure_elements_deployed(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str: - ielem = Const("ielem", smtsorts.element_sort) - ielem_name = get_user_friendly_name(intermediate_model, solver.model(), ielem) - if ielem_name: - return f"Abstract infrastructure element '{ielem_name}' has not been mapped to any element in the active concretization." - else: + try: + ielem = Const("ielem", smtsorts.element_sort) + ielem_name = get_user_friendly_name(intermediate_model, solver.model(), ielem) + if ielem_name: + return f"Abstract infrastructure element '{ielem_name}' has not been mapped to any element in the active concretization." + except: return "An abstract infrastructure element has not been mapped to any element in the active concretization." def ed_all_concrete_map_something(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str: - celem = Const("celem", smtsorts.element_sort) - celem_name = get_user_friendly_name(intermediate_model, solver.model(), celem) - if celem_name: - return f"Concrete infrastructure element '{celem_name}' is mapped to no abstract infrastructure element." - else: + try: + celem = Const("celem", smtsorts.element_sort) + celem_name = get_user_friendly_name(intermediate_model, solver.model(), celem) + if celem_name: + return f"Concrete infrastructure element '{celem_name}' is mapped to no abstract infrastructure element." + except: return "A concrete infrastructure element is mapped to no abstract infrastructure element." +def ed_security_group_must_have_iface(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str: + try: + sg = Const("sg", smtsorts.element_sort) + sg_name = get_user_friendly_name(intermediate_model, solver.model(), sg) + if sg_name: + return f"Security group '{sg_name}' is not associated with any network interface." + except: + return "A network interface doesn't belong to any security group, or a security group is not associated with any network interface." + +def ed_external_services_must_have_https(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str: + try: + saas = Const("saas", smtsorts.element_sort) + saas_name = get_user_friendly_name(intermediate_model, solver.model(), saas) + + sec_group = Const("sec_group", smtsorts.element_sort) + sec_group_name = get_user_friendly_name(intermediate_model, solver.model(), sec_group) + + if saas_name: + return f"A Security Group doesn't have a rule to access external service (SaaS) named '{saas_name}' through HTTPS (port 443)." + if sec_group: + return f"Security Group {sec_group_name} doesn't have a rule to access external service (SaaS) through HTTPS (port 443)." + except: + return "A Security Group doesn't have a rule to access an external service (SaaS) through HTTPS (port 443)." RequirementLists = { DOMLVersion.V1_0: [ @@ -380,7 +440,9 @@ RequirementLists = { (iface_uniq, "iface_uniq", "There are no duplicated interfaces.", ed_iface_uniq), (all_SoftwareComponents_deployed, "all_SoftwareComponents_deployed", "All software components have been deployed to some node.", ed_all_SoftwareComponents_deployed), (all_infrastructure_elements_deployed, "all_infrastructure_elements_deployed", "All abstract infrastructure elements are mapped to an element in the active concretization.", ed_all_infrastructure_elements_deployed), - (all_concrete_map_something, "all_concrete_map_something", "All elements in the active concretization are mapped to some abstract infrastructure element.", ed_all_concrete_map_something) + (all_concrete_map_something, "all_concrete_map_something", "All elements in the active concretization are mapped to some abstract infrastructure element.", ed_all_concrete_map_something), + (security_group_must_have_iface, "security_group_must_have_iface", "All security group should be a associated to a network interface", ed_security_group_must_have_iface), + (external_services_must_have_https, "external_services_must_have_https", "All external SaaS should be accessed through HTTPS.", ed_external_services_must_have_https) ], DOMLVersion.V2_1: [ (vm_iface, "vm_iface", "All virtual machines must be connected to at least one network interface.", ed_vm_iface), @@ -390,7 +452,15 @@ RequirementLists = { (all_infrastructure_elements_deployed, "all_infrastructure_elements_deployed", "All abstract infrastructure elements are mapped to an element in the active concretization.", ed_all_infrastructure_elements_deployed), (all_concrete_map_something, "all_concrete_map_something", "All elements in the active concretization are mapped to some abstract infrastructure element.", ed_all_concrete_map_something) ], + DOMLVersion.V2_2: [ + (vm_iface, "vm_iface", "All virtual machines must be connected to at least one network interface.", ed_vm_iface), + (software_package_iface_net_v2_1, "software_package_iface_net", "All software packages can see the interfaces they need through a common network.", ed_software_package_iface_net), + (iface_uniq, "iface_uniq", "There are no duplicated interfaces.", ed_iface_uniq), + (all_SoftwareComponents_deployed, "all_SoftwareComponents_deployed", "All software components have been deployed to some node.", ed_all_SoftwareComponents_deployed), + (all_infrastructure_elements_deployed, "all_infrastructure_elements_deployed", "All abstract infrastructure elements are mapped to an element in the active concretization.", ed_all_infrastructure_elements_deployed), + (all_concrete_map_something, "all_concrete_map_something", "All elements in the active concretization are mapped to some abstract infrastructure element.", ed_all_concrete_map_something) + ], } -CommonRequirements = {ver: RequirementStore([Requirement(*rt) for rt in reqs]) for ver, reqs in RequirementLists.items()} +CommonRequirements = {ver: RequirementStore([Requirement(*rt, flipped=True) for rt in reqs]) for ver, reqs in RequirementLists.items()} diff --git a/mc_openapi/doml_mc/consistency_reqs.py b/mc_openapi/doml_mc/consistency_reqs.py index 3b2bcdcf7afe02b7a8c056d74b6430a8b0c78e8d..a562c2ff08cf41a137a4228e1b654419c15c61de 100644 --- a/mc_openapi/doml_mc/consistency_reqs.py +++ b/mc_openapi/doml_mc/consistency_reqs.py @@ -8,7 +8,7 @@ from .intermediate_model.metamodel import get_subclasses_dict from .imc import ( SMTEncoding, SMTSorts, Requirement, RequirementStore ) -from .z3encoding.utils import Iff +from .utils import Iff def subclass_cond(smtenc: SMTEncoding, subclasses: set[str], elem: ExprRef) -> ExprRef: @@ -41,8 +41,8 @@ def get_attribute_type_reqs(mm: MetaModel) -> RequirementStore: tgt_type_cond = smtsorts.attr_data_sort.is_ss(attr_val) # type: ignore else: # mm_attr.type == "GeneratorKind" tgt_type_cond = Or( - attr_val == smtsorts.attr_data_sort.ss(smtenc.str_symbols["IMAGE"]), # type: ignore - attr_val == smtsorts.attr_data_sort.ss(smtenc.str_symbols["SCRIPT"]), # type: ignore + attr_val == smtsorts.attr_data_sort.str(smtenc.str_symbols["IMAGE"]), # type: ignore + attr_val == smtsorts.attr_data_sort.str(smtenc.str_symbols["SCRIPT"]), # type: ignore ) return And( smtenc.attribute_rel(elem, smtenc.attributes[f"{cname}::{mm_attr.name}"], attr_val), @@ -58,6 +58,7 @@ def get_attribute_type_reqs(mm: MetaModel) -> RequirementStore: f"attribute_st_types {cname}::{mm_attr.name}", f"Attribute {mm_attr.name} from class {cname} must have type {mm_attr.type}.", lambda _s, _m, _i: f"Attribute {mm_attr.name} from class {cname} has a type different from {mm_attr.type}.", + flipped=True ) ) return RequirementStore(reqs) @@ -100,6 +101,7 @@ def get_attribute_multiplicity_reqs(mm: MetaModel) -> RequirementStore: f"attribute_mult_lb {cname}::{mm_attr.name}", f"Attribute {mm_attr.name} from class {cname} must have at least one value.", lambda _s, _m, _i: f"Mandatory attribute {mm_attr.name} from class {cname} has no value.", + flipped=True ) ) if ub == "1": @@ -109,6 +111,7 @@ def get_attribute_multiplicity_reqs(mm: MetaModel) -> RequirementStore: f"attribute_mult_ub {cname}::{mm_attr.name}", f"Attribute {mm_attr.name} from class {cname} must have at most one value.", lambda _s, _m, _i: f"Attribute {mm_attr.name} from class {cname} has more than one value.", + flipped=True ) ) return RequirementStore(reqs) @@ -141,6 +144,7 @@ def get_association_type_reqs(mm: MetaModel) -> RequirementStore: f"association_st_classes {cname}::{mm_assoc.name}", f"Association {mm_assoc.name} from class {cname} must target class {mm_assoc.class_}.", lambda _s, _m, _i: f"Association {mm_assoc.name} from class {cname} has a class different from {mm_assoc.class_}.", + flipped=True ) ) return RequirementStore(reqs) @@ -180,6 +184,7 @@ def get_association_multiplicity_reqs(mm: MetaModel) -> RequirementStore: f"association_mult_lb {cname}::{mm_assoc.name}", f"Association {mm_assoc.name} from class {cname} must have at least one target.", lambda _s, _m, _i: f"Mandatory association {mm_assoc.name} is missing from an element of class {cname}.", + flipped=True ) ) if ub == "1": @@ -189,6 +194,7 @@ def get_association_multiplicity_reqs(mm: MetaModel) -> RequirementStore: f"association_mult_ub {cname}::{mm_assoc.name}", f"Association {mm_assoc.name} from class {cname} must have at most one target.", lambda _s, _m, _i: f"Association {mm_assoc.name} has more than one target in an element of class {cname}.", + flipped=True ) ) return RequirementStore(reqs) @@ -213,6 +219,7 @@ def get_inverse_association_reqs(inv_assoc: list[tuple[str, str]]) -> Requiremen f"association_inverse {an1} {an2}", f"Association {an1} must be the inverse of {an2}.", lambda _s, _m, _i: f"Association {an1} is not the inverse of {an2}.", + flipped=True ) ) return RequirementStore(reqs) @@ -247,8 +254,8 @@ def assert_attribute_rel_constraints( tgt_type_cond = smtsorts.attr_data_sort.is_ss(ad) # type: ignore else: # mm_attr.type == "GeneratorKind" tgt_type_cond = Or( - ad == smtsorts.attr_data_sort.ss(smtenc.str_symbols["IMAGE"]), # type: ignore - ad == smtsorts.attr_data_sort.ss(smtenc.str_symbols["SCRIPT"]), # type: ignore + ad == smtsorts.attr_data_sort.str(smtenc.str_symbols["IMAGE"]), # type: ignore + ad == smtsorts.attr_data_sort.str(smtenc.str_symbols["SCRIPT"]), # type: ignore ) assn = ForAll( [es, ad], diff --git a/mc_openapi/doml_mc/domlr_parser/__init__.py b/mc_openapi/doml_mc/domlr_parser/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/mc_openapi/doml_mc/domlr_parser/exceptions.py b/mc_openapi/doml_mc/domlr_parser/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..a37ed1f8d1f9c41ebe72a6d86359e16aa18eef0d --- /dev/null +++ b/mc_openapi/doml_mc/domlr_parser/exceptions.py @@ -0,0 +1,20 @@ +class RequirementException(Exception): + message: str + def __repr__(self) -> str: + return self.message + +class RequirementMissingKeyException(RequirementException): + def __init__(self, key_type: str, key: str, close_matches: list[str], *args: object) -> None: + super().__init__(*args) + fix_syntax = lambda x: x.replace("_", ".", 1).replace("::", "->") + key = fix_syntax(key) + close_matches = list(map(fix_syntax, close_matches)) + self.message = f"Error: no {key_type} found named '{key}'.\n" + if close_matches: + self.message += "Perhaps you meant...\n" + self.message += "".join([f"- '{match}'\n" for match in close_matches]) + +class RequirementBadSyntaxException(RequirementException): + def __init__(self, line: int, col: int, message: str, *args: object) -> None: + super().__init__(*args) + self.message = f"Syntax Error at Ln {line}, Col {col}:\n{message}" diff --git a/mc_openapi/doml_mc/domlr_parser/exceptions.yaml b/mc_openapi/doml_mc/domlr_parser/exceptions.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f04cf3429d4ab3fcd5c414ac9d8661a63c4a8454 --- /dev/null +++ b/mc_openapi/doml_mc/domlr_parser/exceptions.yaml @@ -0,0 +1,43 @@ +TOKENS: + FLIP_EXPR: | + a declaration of a requirement. + To declare a requirement use: + • '+' to declare a requirement + • '-' to declare a requirement in negation form, which means + that if it's satisfied, then the DOML does not respect the + requirements. + + ESCAPED_STRING: a string. Strings are enclosed by double quotes '"'. + BOOL: a boolean value. It can be 'true' or 'false'. + NUMBER: a number. It must be an integer. + VALUE: a value constant. Values must start with an uppercase letter. + CONST: a logic variable. Variables must start with a lowercase letter. + + IS: | + a statement such as: + • 'is', 'is not' followed by a class or a variable + • 'has' followed by an relationship name and then a variable or value + + NOT: a 'not' before an expression or a quantifier. + OR: a logical connective such as 'or' between expressions. + AND: a logical connective such as 'and' between expressions. + IFF: a logical connective such as 'iff' between expressions. + IMPLIES: a logical connective such as 'implies' between expressions. + + COMMA: a ',' separating bounded variables after an 'exists'/'forall' + + LPAR: a '(' after which an expression begins. + RPAR: a ')' closing a previous '('. + + RELATIONSHIP: | + a valid relationship name. + Relationships consists of 'package.class->relationship', with no spaces around '.' and '->'. + + + EXISTS: a 'exists' quantifier. + FORALL: a 'forall' quantifier. + + CLASS_PREFIX: a 'class' followed by a class name + ERR_DESC_SYMBOL: a 'error:' to separate the logic expression from the error message. +HINTS: + DOT: If you're trying to use a class, did you put 'class' before the class name? \ No newline at end of file diff --git a/mc_openapi/doml_mc/domlr_parser/grammar.lark b/mc_openapi/doml_mc/domlr_parser/grammar.lark new file mode 100644 index 0000000000000000000000000000000000000000..1e7709a7978063f96999cf99cd7fbe020bfae8a0 --- /dev/null +++ b/mc_openapi/doml_mc/domlr_parser/grammar.lark @@ -0,0 +1,72 @@ +requirements : requirement (requirement)* + +requirement : FLIP_EXPR req_name expression "error:" error_desc + +req_name : ESCAPED_STRING +error_desc : ESCAPED_STRING + +?expression : iff_expr + +?iff_expr : (implies_expr "iff")? implies_expr + +?implies_expr : (and_expr "implies")? and_expr + +?and_expr : (or_expr "and")* or_expr + +?or_expr : (not_expr "or")* not_expr + +?not_expr : "not" not_expr -> negation + | quantification + +?quantification : "exists" bound_consts "(" expression ")" -> exists + | "forall" bound_consts "(" expression ")" -> forall + | "(" expression ")" + | property + +?property : CONST "has" RELATIONSHIP CONST -> rel_assoc_expr + | CONST "has" RELATIONSHIP COMPARISON_OP value -> rel_attr_value_expr + | CONST "has" RELATIONSHIP COMPARISON_OP CONST RELATIONSHIP -> rel_attr_elem_expr + | const_or_class "is" const_or_class -> equality + | const_or_class "is not" const_or_class -> inequality + + +bound_consts : [CONST ("," CONST)*] + +const_or_class : "class" CLASS + | CONST + +value : ESCAPED_STRING + | NUMBER + | BOOL + +FLIP_EXPR : "+" + | "-" + +COMPARISON_OP : ">" | ">=" + | "<" | "<=" + | "==" | "!=" + +BOOL : ":true" + | ":false" + +// regex: /[a-zA-Z]+_[a-zA-Z]+::[a-zA-Z]+/ +RELATIONSHIP: /[^\W\d_]+\.[^\W\d_]+\.([^\W\d]|_)+/ + +CLASS: /[^\W\d_]+\.[^\W\d_]+/ + +// Const must start with lowercase letter +CONST: (LCASE_LETTER) ("_"|LETTER|DIGIT)* + +// Comment: python/sh style +COMMENT: /#[^\n]*/ + +%import common.ESCAPED_STRING +%import common.NEWLINE +%import common.LETTER +%import common.DIGIT +%import common.NUMBER +%import common.LCASE_LETTER +%import common.UCASE_LETTER +%import common.WS +%ignore WS +%ignore COMMENT diff --git a/mc_openapi/doml_mc/domlr_parser/parser.ipynb b/mc_openapi/doml_mc/domlr_parser/parser.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..2343825b84444eadb1b9a0902abed80dd57f1a64 --- /dev/null +++ b/mc_openapi/doml_mc/domlr_parser/parser.ipynb @@ -0,0 +1,350 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Parser Prototype" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from lark import Lark\n", + "\n", + "with open(\"grammar.lark\") as grammar_file:\n", + " grammar = grammar_file.read()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# vm, iface = get_consts(smtsorts, [\"vm\", \"iface\"])\n", + "# return And(\n", + "# smtenc.element_class_fun(vm) == smtenc.classes[\"abstract_VirtualMachine\"],\n", + "# Not(\n", + "# Exists(\n", + "# [iface],\n", + "# ENCODINGS.association_rel(vm, smtenc.associations[\"abstract_ComputingNode::ifaces\"], iface)\n", + "# )\n", + "# )\n", + "# )\n", + "\n", + "expr_to_parse = r\"\"\"\n", + "+ \"example requirement to test\"\n", + " # Expr to parse\n", + " not vm is class abstract.VirtualMachine\n", + " and\n", + " vm is not class abstract.Storage\n", + " iff\n", + " not exists iface, apple (\n", + " (vm has abstract.ComputingNode.ifaces iface)\n", + " or\n", + " (vm has abstract.ComputingNode.os Os1)\n", + " and\n", + " (vm has abstract.ComputingNode.memory_mb 1024)\n", + " and\n", + " (vm has abstract.ComputingNode.architecture \"linux\")\n", + " and\n", + " (vm has application.SoftwareComponent.isPersistent !True)\n", + " )\n", + " ---\n", + " \"Virtual Machine {vm} has no iface\"\n", + "\n", + "+ \"example requirement to test\"\n", + " # Expr to parse\n", + " not vm is class abstract.VirtualMachine\n", + " and\n", + " vm is not class abstract.Storage\n", + " iff\n", + " not exists iface, apple (\n", + " (vm has abstract.ComputingNode.ifaces iface)\n", + " or\n", + " (vm has abstract.ComputingNode.os Os1)\n", + " and\n", + " (\n", + " vm has abstract.ComputingNode.memory_mb Mem\n", + " and\n", + " Mem > 256\n", + " )\n", + " )\n", + " ---\n", + " \"Virtual Machine {vm} has no iface\"\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "requirements\n", + " requirement\n", + " +\n", + " req_name\t\"example requirement to test\"\n", + " iff_expr\n", + " and_expr\n", + " negation\n", + " equality\n", + " const_or_class\tvm\n", + " const_or_class\tabstract.VirtualMachine\n", + " inequality\n", + " const_or_class\tvm\n", + " const_or_class\tabstract.Storage\n", + " negation\n", + " exists\n", + " bound_consts\n", + " iface\n", + " apple\n", + " and_expr\n", + " or_expr\n", + " relationship_expr\n", + " vm\n", + " abstract.ComputingNode.ifaces\n", + " iface\n", + " relationship_expr\n", + " vm\n", + " abstract.ComputingNode.os\n", + " value\tOs1\n", + " relationship_expr\n", + " vm\n", + " abstract.ComputingNode.memory_mb\n", + " value\t1024\n", + " relationship_expr\n", + " vm\n", + " abstract.ComputingNode.architecture\n", + " value\t\"linux\"\n", + " relationship_expr\n", + " vm\n", + " application.SoftwareComponent.isPersistent\n", + " value\t!True\n", + " ---\n", + " error_desc\t\"Virtual Machine {vm} has no iface\"\n", + " requirement\n", + " +\n", + " req_name\t\"example requirement to test\"\n", + " iff_expr\n", + " and_expr\n", + " negation\n", + " equality\n", + " const_or_class\tvm\n", + " const_or_class\tabstract.VirtualMachine\n", + " inequality\n", + " const_or_class\tvm\n", + " const_or_class\tabstract.Storage\n", + " negation\n", + " exists\n", + " bound_consts\n", + " iface\n", + " apple\n", + " and_expr\n", + " or_expr\n", + " relationship_expr\n", + " vm\n", + " abstract.ComputingNode.ifaces\n", + " iface\n", + " relationship_expr\n", + " vm\n", + " abstract.ComputingNode.os\n", + " value\tOs1\n", + " and_expr\n", + " relationship_expr\n", + " vm\n", + " abstract.ComputingNode.memory_mb\n", + " value\tMem\n", + " comparison\n", + " value\tMem\n", + " >\n", + " value\t256\n", + " ---\n", + " error_desc\t\"Virtual Machine {vm} has no iface\"\n", + "\n" + ] + } + ], + "source": [ + "parser = Lark(grammar, start=\"requirements\")\n", + "tree = parser.parse(expr_to_parse)\n", + "\n", + "print(tree.pretty())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need the `ModelChecker` to import `SMTEncodings` and `SMTSorts` in order to create our Z3 constants programmatically.\n", + "\n", + "Now the model checker should expose the *intermediate model checker* which should provide us with those two collections." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from mc_openapi.doml_mc import ModelChecker, DOMLVersion\n", + "from mc_openapi.doml_mc.imc import IntermediateModelChecker\n", + "\n", + "# Import DOMLX as bytes\n", + "doml_document_path = \"../../../tests/doml/faas.domlx\"\n", + "with open(doml_document_path, \"rb\") as xmif:\n", + " doml_xmi = xmif.read()\n", + "\n", + "model_checker = ModelChecker(doml_xmi, DOMLVersion.V2_0)\n", + "\n", + "intermediate_model_checker = IntermediateModelChecker(\n", + " model_checker.metamodel,\n", + " model_checker.inv_assoc,\n", + " model_checker.intermediate_model\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The parser will now produce a Z3 expression to evaluate." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[Requirement(assert_callable=<function DSLTransformer.iff_expr.<locals>.<lambda> at 0x7fe654129900>,\n", + " assert_name='example_requirement_to_test',\n", + " description='example requirement to test',\n", + " error_description=<function DSLTransformer.requirement.<locals>.<lambda> at 0x7fe6541295a0>,\n", + " flipped=False),\n", + " Requirement(assert_callable=<function DSLTransformer.iff_expr.<locals>.<lambda> at 0x7fe65412ad40>,\n", + " assert_name='example_requirement_to_test',\n", + " description='example requirement to test',\n", + " error_description=<function DSLTransformer.requirement.<locals>.<lambda> at 0x7fe65412aef0>,\n", + " flipped=False)]\n" + ] + } + ], + "source": [ + "from pprint import pprint\n", + "from z3 import Not, And, Or, Xor, Implies, Exists, ForAll\n", + "\n", + "from mc_openapi.doml_mc.dsl_parser.parser import Parser\n", + "\n", + "parser = Parser(grammar)\n", + "\n", + "reqs_store, user_value_strings = parser.parse(expr_to_parse)\n", + "\n", + "pprint(reqs_store.get_all_requirements())" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "intermediate_model_checker.instantiate_solver(user_value_strings)\n", + "ENCODINGS = intermediate_model_checker.smt_encoding\n", + "SORTS = intermediate_model_checker.smt_sorts\n", + "\n", + "assert ENCODINGS and SORTS" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "And(Not(elem_class(vm) == infrastructure_VirtualMachine),\n", + " elem_class(vm) != infrastructure_Storage) ==\n", + "Not(Exists([iface, apple],\n", + " And(Or(association(vm,\n", + " infrastructure_ComputingNode::ifaces,\n", + " iface),\n", + " attribute(vm,\n", + " infrastructure_ComputingNode::os,\n", + " Os1)),\n", + " attribute(vm,\n", + " infrastructure_ComputingNode::memory_mb,\n", + " int(1024)),\n", + " attribute(vm,\n", + " infrastructure_ComputingNode::architecture,\n", + " str(ss_50__linux_)),\n", + " attribute(vm,\n", + " application_SoftwareComponent::isPersistent,\n", + " bool(True)))))\n", + "And(Not(elem_class(vm) == infrastructure_VirtualMachine),\n", + " elem_class(vm) != infrastructure_Storage) ==\n", + "Not(Exists([iface, apple],\n", + " And(Or(association(vm,\n", + " infrastructure_ComputingNode::ifaces,\n", + " iface),\n", + " attribute(vm,\n", + " infrastructure_ComputingNode::os,\n", + " Os1)),\n", + " And(attribute(vm,\n", + " infrastructure_ComputingNode::memory_mb,\n", + " Mem),\n", + " get_int(Mem) > get_int(int(256))))))\n" + ] + } + ], + "source": [ + "for req in reqs_store.get_all_requirements():\n", + " print(req.assert_callable(ENCODINGS, SORTS))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.7 ('.venv': poetry)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.7" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/mc_openapi/doml_mc/domlr_parser/parser.py b/mc_openapi/doml_mc/domlr_parser/parser.py new file mode 100644 index 0000000000000000000000000000000000000000..c2f751a5470835ba679b479a2fc6f81efa6a3492 --- /dev/null +++ b/mc_openapi/doml_mc/domlr_parser/parser.py @@ -0,0 +1,615 @@ +import os +import re +from typing import Callable + +import yaml +from lark import Lark, Transformer, UnexpectedCharacters, UnexpectedEOF +from mc_openapi.doml_mc.domlr_parser.exceptions import RequirementBadSyntaxException +from mc_openapi.doml_mc.domlr_parser.utils import (RefHandler, StringValuesCache, SynthesisRefHandler, + VarStore) +from mc_openapi.doml_mc.error_desc_helper import get_user_friendly_name +from mc_openapi.doml_mc.imc import (Requirement, RequirementStore, SMTEncoding, + SMTSorts) +from mc_openapi.doml_mc.intermediate_model import IntermediateModel +from z3 import And, Exists, ExprRef, ForAll, Implies, Not, Or, Solver, Xor, simplify +from doml_synthesis import State + +class ParserData: + def __init__(self) -> None: + # TODO: Replace with files api? + grammar_path = os.path.join(os.path.dirname(__file__), "grammar.lark") + exceptions_path = os.path.join(os.path.dirname(__file__), "exceptions.yaml") + with open(grammar_path, "r") as grammar: + self.grammar = grammar.read() + with open(exceptions_path, "r") as exceptions: + self.exceptions = yaml.safe_load(exceptions) + +PARSER_DATA = ParserData() + +class Parser: + def __init__(self, transformer, grammar: str = PARSER_DATA.grammar): + self.parser = Lark(grammar, start="requirements", parser="lalr") + self.transformer = transformer + + def parse(self, input: str, for_synthesis: bool = False): + """Parse the input string containing the DOMLR requirements and + returns a tuple with: + - RequirementStore with the parsed requirements inside + - A list of strings to be added to the string constant EnumSort + """ + try: + self.tree = self.parser.parse(input) + + const_store = VarStore() + user_values_cache = StringValuesCache() + + transformer = self.transformer(const_store, user_values_cache) + + if not for_synthesis: + return ( + RequirementStore(transformer.transform(self.tree)), + user_values_cache.get_list() + ) + else: + reqs = transformer.transform(self.tree) + + # This function has to return state or it will break the + # synthesis solver + def user_reqs(state: State): + for (req, id, negated) in reqs: + state.solver.assert_and_track( + req(state) if not negated else Not(req(state)), f'Requirement {id}') + return state + + return user_reqs, user_values_cache.get_list() + + except UnexpectedEOF as e: + msg = "Unexpected End of File:\n" + msg += "Did you forget the `error:` message at the end of a requirement?" + raise Exception(msg) + + except UnexpectedCharacters as e: + msg = _get_error_desc_for_unexpected_characters(e, input) + raise RequirementBadSyntaxException(e.line, e.column, msg) + + + +class DOMLRTransformer(Transformer): + # These callbacks will be called when a rule with the same name + # is matched. It starts from the leaves. + def __init__(self, + const_store: VarStore, + user_values_cache: StringValuesCache, + visit_tokens: bool = True + ) -> None: + super().__init__(visit_tokens) + self.const_store = const_store + self.user_values_cache = user_values_cache + + def __default__(self, data, children, meta): + return children + + # start + def requirements(self, args) -> list[Requirement]: + return args + + def requirement(self, args) -> Requirement: + flip_expr: bool = args[0].value == "-" + name: str = args[1] + expr: Callable[[SMTEncoding, SMTSorts], ExprRef] = args[2] + errd: Callable[[Solver, SMTSorts, IntermediateModel, int], str] = args[3] + index = self.const_store.get_index_and_push() + return Requirement( + expr, + name.lower().replace(" ", "_"), + name, + lambda solver, sorts, model: errd( + solver, sorts, model, + index, + name + ), + flipped=flip_expr + ) + + def req_name(self, args) -> str: + return str(args[0].value.replace('"', '')) + + # Requirement requirement expression + + def bound_consts(self, args): + const_names = list(map(lambda arg: arg.value, args)) + for name in const_names: + self.const_store.use(name) + self.const_store.quantify(name) + return lambda _, sorts: RefHandler.get_consts(const_names, sorts) + + def negation(self, args): + return lambda enc, sorts: Not(args[0](enc, sorts)) + + def iff_expr(self, args): + return lambda enc, sorts: args[0](enc, sorts) == args[1](enc, sorts) + + def implies_expr(self, args): + return lambda enc, sorts: Implies(args[0](enc, sorts), args[1](enc, sorts)) + + def and_expr(self, args): + return lambda enc, sorts: And([arg(enc, sorts) for arg in args]) + + def or_expr(self, args): + return lambda enc, sorts: Or([arg(enc, sorts) for arg in args]) + + def exists(self, args): + return lambda enc, sorts: Exists(args[0](enc, sorts), args[1](enc, sorts)) + + def forall(self, args): + return lambda enc, sorts: ForAll(args[0](enc, sorts), args[1](enc, sorts)) + + def rel_assoc_expr(self, args): + """An ASSOCIATION relationship""" + rel_name = args[1].value + self.const_store.use(args[0].value) + self.const_store.use(args[2].value) + + def _gen_rel_elem_expr(enc: SMTEncoding, sorts: SMTSorts): + rel, rel_type = RefHandler.get_relationship(enc, rel_name) + + assert rel_type == RefHandler.ASSOCIATION + + return RefHandler.get_association_rel( + enc, + RefHandler.get_const(args[0].value, sorts), + rel, + RefHandler.get_const(args[2].value, sorts) + ) + return _gen_rel_elem_expr + + def rel_attr_value_expr(self, args): + """An ATTRIBUTE relationship with a rhs that is a value""" + + rel_name = args[1].value + def _gen_rel_attr_value_expr(enc: SMTEncoding, sorts: SMTSorts): + elem = RefHandler.get_const(args[0].value, sorts) + rel, rel_type = RefHandler.get_relationship(enc, rel_name) + assert rel_type == RefHandler.ATTRIBUTE + + rhs_value, rhs_value_type = args[3] + rhs_value = rhs_value(enc, sorts) + op = args[2].value + + if rhs_value_type == RefHandler.INTEGER: + + lhs_value = RefHandler.get_value("x", sorts) + + return And( + RefHandler.get_attribute_rel(enc, + elem, + rel, + lhs_value + ), + self.compare_int(sorts, op, lhs_value, rhs_value) + ) + elif rhs_value_type == RefHandler.STRING or rhs_value_type == RefHandler.BOOLEAN: + expr = RefHandler.get_attribute_rel(enc, + elem, + rel, + rhs_value + ) + if op == "==": + return expr + elif op == "!=": + return Not(expr) + else: + raise f'Invalid compare operator "{op}". It must be "==" or "!=".' + + + return _gen_rel_attr_value_expr + + def rel_attr_elem_expr(self, args): + """An ATTRIBUTE relationship with a rhs that is another element""" + + rel1_name = args[1].value + rel2_name = args[4].value + op = args[2].value + + def _gen_rel_attr_elem_expr(enc: SMTEncoding, sorts: SMTSorts): + elem1 = RefHandler.get_const(args[0].value, sorts) + elem2 = RefHandler.get_const(args[3].value, sorts) + rel1, rel1_type = RefHandler.get_relationship(enc, rel1_name) + rel2, rel2_type = RefHandler.get_relationship(enc, rel2_name) + + assert rel1_type == RefHandler.ATTRIBUTE + assert rel2_type == RefHandler.ATTRIBUTE + + rhs_value = RefHandler.get_value("x", sorts) + + expr = And( + RefHandler.get_attribute_rel(enc, + elem1, + rel1, + rhs_value + ), + RefHandler.get_attribute_rel(enc, + elem2, + rel2, + rhs_value + ) + ) + if op == "==": + return expr + elif op == "!=": + return Not(expr) + else: + rhs1_value = RefHandler.get_value("rhs1", sorts) + rhs2_value = RefHandler.get_value("rhs2", sorts) + expr = And( + RefHandler.get_attribute_rel(enc, + elem1, + rel1, + rhs1_value + ), + RefHandler.get_attribute_rel(enc, + elem2, + rel2, + rhs2_value + ), + self.compare_int(sorts, op, rhs1_value, rhs2_value) + ) + print( + "Warning: Comparing attributes of two elements with {op} is experimental!\n", + "Assumption: the attribute is an Integer." + ) + return expr + + return _gen_rel_attr_elem_expr + + def _get_equality_sides(self, arg1, arg2): + # We track use of const in const_or_class + if arg1.type == "CONST" and arg2.type == "CONST": + return ( + lambda _, sorts: RefHandler.get_const(arg1.value, sorts), + lambda _, sorts: RefHandler.get_const(arg2.value, sorts) + ) + + if arg1.type == "CLASS": + arg1_ret = lambda enc, _: RefHandler.get_class(enc, arg1.value) + else: + arg1_ret = lambda enc, sorts: RefHandler.get_element_class(enc, RefHandler.get_const(arg1.value, sorts)) + + if arg2.type == "CLASS": + arg2_ret = lambda enc, _: RefHandler.get_class(enc, arg2.value) + else: + arg2_ret = lambda enc, sorts: RefHandler.get_element_class(enc, RefHandler.get_const(arg2.value, sorts)) + + return (arg1_ret, arg2_ret) + + def equality(self, args): + a, b = self._get_equality_sides(args[0], args[1]) + return lambda enc, sorts: a(enc, sorts) == b(enc, sorts) + + def inequality(self, args): + a, b = self._get_equality_sides(args[0], args[1]) + return lambda enc, sorts: a(enc, sorts) != b(enc, sorts) + + def const_or_class(self, args): + if args[0].type == "CONST": + self.const_store.use(args[0].value) + return args[0] + + def compare_int(self, sorts: SMTSorts, op: str, a, b): + # To extract the `int` contained in the attr_data_sort, + # we need to call its `get_int` method on the `DatatypeRef` + get_int = sorts.attr_data_sort.get_int + + a = get_int(a) + b = get_int(b) + + if op == ">": + return a > b + if op == ">=": + return a >= b + if op == "<": + return a < b + if op == "<=": + return a <= b + if op == "==": + return a == b + if op == "!=": + return a != b + raise f"Invalid Compare Operator Symbol: {op}" + + + def value(self, args): + type = args[0].type + value = args[0].value + + if type == "ESCAPED_STRING": + value = value.replace('"', '') + self.user_values_cache.add(value) + return lambda enc, sorts: RefHandler.get_str(value, enc, sorts), RefHandler.STRING + elif type == "NUMBER": + return lambda _, sorts: RefHandler.get_int(value, sorts), RefHandler.INTEGER + elif type == "BOOL": + return lambda _, sorts: RefHandler.get_bool(value, sorts), RefHandler.BOOLEAN + # elif type == "VALUE": + # return lambda _, sorts: RefHandler.get_value(value, sorts), RefHandler.VALUE_REF + + def error_desc(self, args): + def err_callback( + solver: Solver, + sorts: SMTSorts, + intermediate_model: IntermediateModel, + index: int, + requirement_desc: str + ) -> str: + msg: str = f"[Requirement \"{requirement_desc}\"]" + msg += "\n\t" + args[0].value.replace('"', '') + # Get list of free variables + consts_name = self.const_store.get_free_vars(index) + consts = RefHandler.get_consts(consts_name, sorts) + notes = "" + try: + model = solver.model() + for const in consts: + name = get_user_friendly_name(intermediate_model, model, const) + msg = msg.replace("{" + str(const) + "}", f"'{name}'") + except: + notes += "\n\t- model not found: it's not possible to show which element is causing the issue" + + # tell the user which variables are not free + unused_free_vars = re.findall(r"{[^{}]*}", msg) + if unused_free_vars: + notes += "\n\t- The following variables are not free and should be removed from the error description:" + notes += "\n\t" + " ".join(unused_free_vars) + + return msg + ("\n\n\tNOTES:" + notes if notes else "") + return err_callback + +class SynthesisDOMLRTransformer(Transformer): + # These callbacks will be called when a rule with the same name + # is matched. It starts from the leaves. + def __init__(self, + const_store: VarStore, + user_values_cache: StringValuesCache, + visit_tokens: bool = True + ) -> None: + super().__init__(visit_tokens) + self.const_store = const_store + self.user_values_cache = user_values_cache + + def __default__(self, data, children, meta): + return children + + # start + def requirements(self, args) -> list[tuple]: + return args + + def requirement(self, args) -> tuple: + flip_expr: bool = args[0].value == "-" + name: str = args[1] + expr: Callable[[State], ExprRef] = args[2] + return ( + expr, + name.lower().replace(" ", "_"), # id + flip_expr + ) + + def req_name(self, args) -> str: + return str(args[0].value.replace('"', '')) + + # Requirement requirement expression + + def bound_consts(self, args): + const_names = list(map(lambda arg: arg.value, args)) + for name in const_names: + self.const_store.use(name) + self.const_store.quantify(name) + return lambda state: SynthesisRefHandler.get_consts(const_names, state) + + def negation(self, args): + return lambda state: Not(args[0](state)) + + def iff_expr(self, args): + return lambda state: args[0](state) == args[1](state) + + def implies_expr(self, args): + return lambda state: Implies(args[0](state), args[1](state)) + + def and_expr(self, args): + return lambda state: And([arg(state) for arg in args]) + + def or_expr(self, args): + return lambda state: Or([arg(state) for arg in args]) + + def exists(self, args): + return lambda state: Exists(args[0](state), args[1](state)) + + def forall(self, args): + return lambda state: ForAll(args[0](state), args[1](state)) + + def rel_assoc_expr(self, args): + """An ASSOCIATION relationship""" + rel_name = args[1].value + self.const_store.use(args[0].value) + self.const_store.use(args[2].value) + + def _gen_rel_elem_expr(state: State): + rel = SynthesisRefHandler.get_assoc(state, rel_name) + + return state.rels.AssocRel( + SynthesisRefHandler.get_const(args[0].value, state), + rel.ref, + SynthesisRefHandler.get_const(args[2].value, state) + ) + return _gen_rel_elem_expr + + def rel_attr_value_expr(self, args): + """An ATTRIBUTE relationship with a rhs that is a value + + CONST "has" RELATIONSHIP COMPARISON_OP value + 0 1 2 3 + """ + + rel_name = args[1].value + def _gen_rel_attr_value_expr(state: State): + elem = SynthesisRefHandler.get_const(args[0].value, state) + rel = SynthesisRefHandler.get_attr(state, rel_name) + + rhs_value, rhs_value_type = args[3] + rhs_value = rhs_value(state) + op = args[2].value + + if rhs_value_type == SynthesisRefHandler.INTEGER and rel.type == 'Integer': + lhs_value = state.rels.int.AttrValueRel(elem, rel.ref) + return And( + self.compare(op, lhs_value, rhs_value), + state.rels.int.AttrSynthRel(elem, rel.ref) + ) + elif op != "==" and op != "!=": + raise "You can only use == and != to compare Strings and Booleans!" + elif rhs_value_type == SynthesisRefHandler.STRING: + lhs_value = state.rels.str.AttrValueRel(elem, rel.ref) + + return And( + lhs_value == rhs_value if op == "==" else lhs_value != rhs_value, + state.rels.str.AttrSynthRel(elem, rel.ref) + ) + elif rhs_value_type == SynthesisRefHandler.BOOLEAN: + lhs_value = state.rels.bool.AttrValueRel(elem, rel.ref) + return And( + lhs_value == rhs_value if op == "==" else lhs_value != rhs_value, + state.rels.bool.AttrSynthRel(elem, rel.ref) + ) + else: + raise f'Invalid value {rhs_value} during parsing for synthesis.' + + + return _gen_rel_attr_value_expr + + def rel_attr_elem_expr(self, args): + """An ATTRIBUTE relationship with a rhs that is another element + CONST "has" RELATIONSHIP COMPARISON_OP CONST RELATIONSHIP + 0 1 2 3 4 + """ + + rel1_name = args[1].value + rel2_name = args[4].value + op = args[2].value + + def _gen_rel_attr_elem_expr(state: State): + elem1 = SynthesisRefHandler.get_const(args[0].value, state) + elem2 = SynthesisRefHandler.get_const(args[3].value, state) + rel1 = SynthesisRefHandler.get_attr(state, rel1_name) + rel2 = SynthesisRefHandler.get_attr(state, rel2_name) + + if rel1.type == rel2.type == 'Integer': + return And( + state.rels.int.AttrSynthRel(elem1, rel1.ref), + state.rels.int.AttrSynthRel(elem2, rel2.ref), + self.compare( + op, + state.rels.int.AttrValueRel(elem1, rel1.ref), + state.rels.int.AttrValueRel(elem2, rel2.ref) + ) + ) + if rel1.type == rel2.type == 'Boolean': + return And( + state.rels.bool.AttrSynthRel(elem1, rel1.ref), + state.rels.bool.AttrSynthRel(elem2, rel2.ref), + self.compare( + op, + state.rels.bool.AttrValueRel(elem1, rel1.ref), + state.rels.bool.AttrValueRel(elem2, rel2.ref) + ) + ) + if rel1.type == rel2.type == 'String': + return And( + state.rels.str.AttrSynthRel(elem1, rel1.ref), + state.rels.str.AttrSynthRel(elem2, rel2.ref), + self.compare( + op, + state.rels.str.AttrValueRel(elem1, rel1.ref), + state.rels.str.AttrValueRel(elem2, rel2.ref) + ) + ) + raise f'Attribute relationships {rel1_name} ({rel1.type}) and {rel2_name} ({rel2.type}) have mismatch type.' + + return _gen_rel_attr_elem_expr + + def _get_equality_sides(self, arg1, arg2): + # We track use of const in const_or_class + if arg1.type == "CONST" and arg2.type == "CONST": + return ( + lambda state: SynthesisRefHandler.get_const(arg1.value, state), + lambda state: SynthesisRefHandler.get_const(arg2.value, state) + ) + + if arg1.type == "CLASS": + arg1_ret = lambda state: SynthesisRefHandler.get_class(state, arg1.value) + else: + arg1_ret = lambda state: SynthesisRefHandler.get_element_class(state, SynthesisRefHandler.get_const(arg1.value, state)) + + if arg2.type == "CLASS": + arg2_ret = lambda state: SynthesisRefHandler.get_class(state, arg2.value) + else: + arg2_ret = lambda state: SynthesisRefHandler.get_element_class(state, SynthesisRefHandler.get_const(arg2.value, state)) + + return (arg1_ret, arg2_ret) + + def equality(self, args): + a, b = self._get_equality_sides(args[0], args[1]) + return lambda state: a(state) == b(state) + + def inequality(self, args): + a, b = self._get_equality_sides(args[0], args[1]) + return lambda state: a(state) != b(state) + + def const_or_class(self, args): + if args[0].type == "CONST": + self.const_store.use(args[0].value) + return args[0] + + def compare(self, op: str, a, b): + + if op == ">": + return a > b + if op == ">=": + return a >= b + if op == "<": + return a < b + if op == "<=": + return a <= b + if op == "==": + return a == b + if op == "!=": + return a != b + raise f"Invalid Compare Operator Symbol: {op}" + + + def value(self, args): + type = args[0].type + value = args[0].value + + if type == "ESCAPED_STRING": + value = value.replace('"', '') + self.user_values_cache.add(value) + return lambda state: SynthesisRefHandler.get_str(value, state), SynthesisRefHandler.STRING + elif type == "NUMBER": + return lambda _: value, SynthesisRefHandler.INTEGER + elif type == "BOOL": + return lambda _: SynthesisRefHandler.get_bool(value), SynthesisRefHandler.BOOLEAN + +def _get_error_desc_for_unexpected_characters(e: UnexpectedCharacters, input: str): + # Error description + msg = "Syntax Error:\n\n" + msg += e.get_context(input) + msg += "Expected one of the following:\n" + for val in e.allowed: + val = PARSER_DATA.exceptions["TOKENS"].get(val, "") + msg += (f"• {val}\n") + # Suggestion that might be useful + if e.char == ".": + msg += "HINTS:\n" + msg += PARSER_DATA.exceptions["HINTS"]["DOT"] + # Print line highlighting the error + + return msg \ No newline at end of file diff --git a/mc_openapi/doml_mc/domlr_parser/utils.py b/mc_openapi/doml_mc/domlr_parser/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..b52a2ae01a01ce7472fb18276a0f4fb0b0c6ab57 --- /dev/null +++ b/mc_openapi/doml_mc/domlr_parser/utils.py @@ -0,0 +1,166 @@ +from difflib import get_close_matches + +from mc_openapi.doml_mc.domlr_parser.exceptions import \ + RequirementMissingKeyException +from mc_openapi.doml_mc.imc import SMTEncoding, SMTSorts +from z3 import Const, DatatypeRef, ExprRef, FuncDeclRef, SortRef, Ints, And +from doml_synthesis import State, AssocRel, AttrRel + +class StringValuesCache: + def __init__(self) -> None: + self.values: set[str] = set() + + def add(self, value: str): + self.values.add(value) + + def get_list(self): + return list(self.values) + +class VarStore: + """This class provides a way to instance a Z3 variable only the first time + it's called, and subsequent uses of that variable simply retrieve it + from the store. + """ + + def __init__(self): + self.expressions: list[dict[str, bool]] = [] + self.curr_vars: dict[str, bool] = dict() + self.curr_index: int = 0 + + def use(self, name: str): + self.curr_vars[name] = self.curr_vars.get(name, False) + + def quantify(self, name: str): + self.curr_vars[name] = True + + def get_index_and_push(self): + self.expressions.append(self.curr_vars) + self.curr_vars = dict() + + self.curr_index += 1 + return self.curr_index - 1 + + def get_free_vars(self, index: int) -> list[ExprRef]: + vars = self.expressions[index] + if not vars: + return [] + free_vars = [key for key, val in vars.items() if not val] + return free_vars + + +class RefHandler: + """A utility class that provides simplified ways to create Z3 Refs. + """ + + def get_consts(names: list[str], sorts: SMTSorts): + return [Const(name, sorts.element_sort) for name in names] + + def get_const(name: str, sorts: SMTSorts): + return Const(name, sorts.element_sort) + + def get_value(name: str, sorts: SMTSorts): + return Const(name, sorts.attr_data_sort) + + def get_int(value: str, sorts: SMTSorts): + return sorts.attr_data_sort.int(int(value)) + + def get_bool(value: str, sorts: SMTSorts): + return sorts.attr_data_sort.bool(value == "!True") + + def get_str(value: str, enc: SMTEncoding, sorts: SMTSorts): + return sorts.attr_data_sort.str(enc.str_symbols[value]) + + def get_element_class(enc: SMTEncoding, const: ExprRef) -> FuncDeclRef: + return enc.element_class_fun(const) + + def get_class(enc: SMTEncoding, class_name: str) -> DatatypeRef: + class_name = _convert_rel_str(class_name) + _class = enc.classes.get(class_name, None) + if _class is not None: + return _class + else: + close_matches = get_close_matches(class_name, enc.classes.keys()) + raise RequirementMissingKeyException("class", class_name, close_matches) + + ASSOCIATION = 0 + ATTRIBUTE = 1 + + INTEGER = 2 + BOOLEAN = 3 + STRING = 4 + + def get_relationship(enc: SMTEncoding, rel_name: str) -> tuple[DatatypeRef, int]: + rel_name = _convert_rel_str(rel_name) + rel = enc.associations.get(rel_name, None) + if rel is not None: + return rel, RefHandler.ASSOCIATION + else: + rel = enc.attributes.get(rel_name, None) + if rel is not None: + return rel, RefHandler.ATTRIBUTE + else: + close_matches = get_close_matches(rel_name, list(enc.associations.keys()) + list(enc.attributes.keys())) + raise RequirementMissingKeyException("relationship", rel_name, close_matches) + + def get_association_rel(enc: SMTEncoding, a: ExprRef, rel: DatatypeRef, b: ExprRef) -> DatatypeRef: + return enc.association_rel(a, rel, b) + + def get_attribute_rel(enc: SMTEncoding, a: ExprRef, rel: DatatypeRef, b: ExprRef) -> DatatypeRef: + return enc.attribute_rel(a, rel, b) + +class SynthesisRefHandler: + """A utility class that provides simplified ways to create Z3 Refs. + To be used when parsing requirements for synthesis + """ + + INTEGER = 2 + BOOLEAN = 3 + STRING = 4 + + def get_consts(names: list[str], state: State): + return [Const(name, state.sorts.Elem) for name in names] + + def get_const(name: str, state: State): + return Const(name, state.sorts.Elem) + + def get_bool(value: str): + return value == "!True" + + def get_str(value: str, state: State): + return state.data.Strings[value] + + def get_element_class(state: State, const: ExprRef) -> FuncDeclRef: + return state.rels.ElemClass(const) + + def get_class(state: State, class_name: str) -> DatatypeRef: + class_name = _convert_rel_str(class_name) + _class = state.data.Classes.get(class_name, None) + if _class is not None: + return _class.ref + else: + close_matches = get_close_matches(class_name, state.data.Classes.keys()) + raise RequirementMissingKeyException("class", class_name, close_matches) + + def get_assoc(state: State, rel_name: str) -> AssocRel: + rel_name = _convert_rel_str(rel_name) + rel = state.data.Assocs.get(rel_name, None) + if rel is not None: + return rel + else: + raise f"Association {rel_name} not present in the metamodel!" + + def get_attr(state: State, rel_name: str) -> AttrRel: + rel_name = _convert_rel_str(rel_name) + rel = state.data.Attrs.get(rel_name, None) + if rel is not None: + return rel + else: + raise f"Attribute {rel_name} not present in the metamodel!" + +def _convert_rel_str(rel: str) -> str: + tokens = rel.replace("abstract", "infrastructure").split(".") + if len(tokens) == 2: + return tokens[0] + "_" + tokens[1] + if len(tokens) == 3: + return tokens[0] + "_" + tokens[1] + "::" + tokens[2] + raise f"Bad relationship name: {rel}" diff --git a/mc_openapi/doml_mc/error_desc_helper.py b/mc_openapi/doml_mc/error_desc_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..abf13dd44346a26b4469b2840480ea8f603affa7 --- /dev/null +++ b/mc_openapi/doml_mc/error_desc_helper.py @@ -0,0 +1,15 @@ +from z3 import ExprRef, ModelRef +from typing import Optional +from mc_openapi.doml_mc.intermediate_model import IntermediateModel + +def get_user_friendly_name( + intermediate_model: IntermediateModel, + model: ModelRef, + const: ExprRef +) -> Optional[str]: + z3_elem = model[const] + if z3_elem is not None: + im_elem = intermediate_model.get(str(z3_elem)) + if im_elem is not None: + return im_elem.user_friendly_name + return None diff --git a/mc_openapi/doml_mc/imc.py b/mc_openapi/doml_mc/imc.py index fb3ca02f46f7b0099d07fc62d5fea19709ef8bc0..09f4d6a40d6e85d80dc21787b391766d6cc49ef0 100644 --- a/mc_openapi/doml_mc/imc.py +++ b/mc_openapi/doml_mc/imc.py @@ -1,26 +1,21 @@ from collections.abc import Callable from dataclasses import dataclass -from z3 import ( - Context, FuncDeclRef, Solver, ExprRef, SortRef, DatatypeSortRef, sat -) +from z3 import (Context, DatatypeSortRef, ExprRef, FuncDeclRef, Solver, + SortRef, sat) from .intermediate_model.doml_element import IntermediateModel -from .z3encoding.im_encoding import ( - assert_im_associations_q, assert_im_attributes, - def_elem_class_f_and_assert_classes, - mk_elem_sort_dict, mk_stringsym_sort_dict -) -from .z3encoding.metamodel_encoding import ( - def_association_rel, - def_attribute_rel, - mk_association_sort_dict, - mk_attribute_sort_dict, mk_class_sort_dict -) -from .z3encoding.types import Refs -from .z3encoding.utils import mk_adata_sort from .mc_result import MCResult, MCResults - +from .z3encoding.im_encoding import (assert_im_associations, + assert_im_attributes, + def_elem_class_f_and_assert_classes, mk_attr_data_sort, + mk_elem_sort_dict, mk_stringsym_sort_dict) +from .z3encoding.metamodel_encoding import (def_association_rel, + def_attribute_rel, + mk_association_sort_dict, + mk_attribute_sort_dict, + mk_class_sort_dict) +from .z3encoding.types import Refs @dataclass class SMTEncoding: @@ -50,10 +45,10 @@ class Requirement: assert_name: str description: str error_description: Callable[[Solver, SMTSorts, IntermediateModel], str] - + flipped: bool = False class RequirementStore: - def __init__(self, requirements: list[Requirement]): + def __init__(self, requirements: list[Requirement] = []): self.requirements = requirements pass @@ -72,75 +67,80 @@ class RequirementStore: class IntermediateModelChecker: def __init__(self, metamodel, inv_assoc, intermediate_model: IntermediateModel): - def instantiate_solver(): - self.z3Context = Context() - self.solver = Solver(ctx=self.z3Context) - - class_sort, class_ = mk_class_sort_dict(self.metamodel, self.z3Context) - assoc_sort, assoc = mk_association_sort_dict(self.metamodel, self.z3Context) - attr_sort, attr = mk_attribute_sort_dict(self.metamodel, self.z3Context) - elem_sort, elem = mk_elem_sort_dict(self.intermediate_model, self.z3Context) - ss_sort, ss = mk_stringsym_sort_dict(self.intermediate_model, self.metamodel, self.z3Context) - AData = mk_adata_sort(ss_sort, self.z3Context) - elem_class_f = def_elem_class_f_and_assert_classes( - self.intermediate_model, - self.solver, - elem_sort, - elem, - class_sort, - class_ - ) - attr_rel = def_attribute_rel( - attr_sort, - elem_sort, - AData - ) - assert_im_attributes( - attr_rel, - self.solver, - self.intermediate_model, - self.metamodel, - elem, - attr_sort, - attr, - AData, - ss - ) - assoc_rel = def_association_rel( - assoc_sort, - elem_sort - ) - assert_im_associations_q( - assoc_rel, - self.solver, - {k: v for k, v in self.intermediate_model.items()}, - elem, - assoc_sort, - assoc, - ) - self.smt_encoding = SMTEncoding( - class_, - assoc, - attr, - elem, - ss, - elem_class_f, - attr_rel, - assoc_rel - ) - self.smt_sorts = SMTSorts( - class_sort, - assoc_sort, - attr_sort, - elem_sort, - ss_sort, - AData - ) - self.metamodel = metamodel self.inv_assoc = inv_assoc self.intermediate_model = intermediate_model - instantiate_solver() + self.instantiate_solver() + + def instantiate_solver(self, user_string_values=[]): + self.z3Context = Context() + self.solver = Solver(ctx=self.z3Context) + + class_sort, class_ = mk_class_sort_dict(self.metamodel, self.z3Context) + assoc_sort, assoc = mk_association_sort_dict(self.metamodel, self.z3Context) + attr_sort, attr = mk_attribute_sort_dict(self.metamodel, self.z3Context) + elem_sort, elem = mk_elem_sort_dict(self.intermediate_model, self.z3Context) + str_sort, str = mk_stringsym_sort_dict( + self.intermediate_model, + self.metamodel, + self.z3Context, + user_string_values + ) + attr_data_sort = mk_attr_data_sort(str_sort, self.z3Context) + elem_class_f = def_elem_class_f_and_assert_classes( + self.intermediate_model, + self.solver, + elem_sort, + elem, + class_sort, + class_ + ) + attr_rel = def_attribute_rel( + attr_sort, + elem_sort, + attr_data_sort + ) + assert_im_attributes( + attr_rel, + self.solver, + self.intermediate_model, + self.metamodel, + elem, + attr_sort, + attr, + attr_data_sort, + str + ) + assoc_rel = def_association_rel( + assoc_sort, + elem_sort + ) + assert_im_associations( + assoc_rel, + self.solver, + {k: v for k, v in self.intermediate_model.items()}, + elem, + assoc_sort, + assoc, + ) + self.smt_encoding = SMTEncoding( + class_, + assoc, + attr, + elem, + str, + elem_class_f, + attr_rel, + assoc_rel + ) + self.smt_sorts = SMTSorts( + class_sort, + assoc_sort, + attr_sort, + elem_sort, + str_sort, + attr_data_sort + ) def check_requirements(self, reqs: RequirementStore, timeout: int = 0) -> MCResults: self.solver.set(timeout=(timeout * 1000)) @@ -154,9 +154,10 @@ class IntermediateModelChecker: ) res = self.solver.check() results.append(( - MCResult.from_z3result(res, flipped=True), + MCResult.from_z3result(res, flipped=req.flipped), req.error_description(self.solver, self.smt_sorts, self.intermediate_model) - if res == sat else "" + # if res == sat else "" # not needed since we're try/catching model() errors + # in each requirement now )) self.solver.pop() diff --git a/mc_openapi/doml_mc/intermediate_model/metamodel.py b/mc_openapi/doml_mc/intermediate_model/metamodel.py index 4b4fe8b052a021b7c854dfbdd10eef61146b310b..a10a505687e64ce3ede5de1bd5a10501f464e7d3 100644 --- a/mc_openapi/doml_mc/intermediate_model/metamodel.py +++ b/mc_openapi/doml_mc/intermediate_model/metamodel.py @@ -1,19 +1,19 @@ +import importlib.resources as ilres from dataclasses import dataclass -from typing import cast, Literal, Optional, Union from enum import Enum +from typing import Literal, Optional, Union, cast -import importlib.resources as ilres -import yaml import networkx as nx +import yaml from ... import assets -from .._utils import merge_dicts - +from ..utils import merge_dicts class DOMLVersion(Enum): V1_0 = "v1.0" V2_0 = "v2.0" V2_1 = "v2.1" + V2_2 = "v2.2" Multiplicity = tuple[Literal["0", "1"], Literal["1", "*"]] @@ -53,6 +53,7 @@ class DOMLAssociation: MetaModel = dict[str, DOMLClass] InverseAssociation = list[tuple[str, str]] +MetaModelDocs: dict[DOMLVersion, dict] = {} MetaModels: dict[DOMLVersion, MetaModel] = {} InverseAssociations: dict[DOMLVersion, InverseAssociation] = {} @@ -152,9 +153,12 @@ def parse_inverse_associations(doc: dict) -> list[tuple[str, str]]: def init_metamodels(): - global MetaModels, InverseAssociations + global MetaModelDocs, MetaModels, InverseAssociations for ver in DOMLVersion: - mmdoc = yaml.load(ilres.read_text(assets, f"doml_meta_{ver.value}.yaml"), yaml.Loader) + source = ilres.files(assets).joinpath(f"doml_meta_{ver.value}.yaml") + + mmdoc = yaml.load(source.read_text() , yaml.Loader) + MetaModelDocs[ver] = mmdoc MetaModels[ver] = parse_metamodel(mmdoc) InverseAssociations[ver] = parse_inverse_associations(mmdoc) @@ -208,6 +212,7 @@ def _find_attribute_class( if aname in c.attributes: return c elif c.superclass is None: + print(c) raise AttributeNotFound( f"Attribute {aname} not found in subclasses of {cname}." ) diff --git a/mc_openapi/doml_mc/mc.py b/mc_openapi/doml_mc/mc.py index 5e5b721cce98883cb5406648532386c0d130f494..48be8aa743af9e25070475d397e9c55790012432 100644 --- a/mc_openapi/doml_mc/mc.py +++ b/mc_openapi/doml_mc/mc.py @@ -1,23 +1,19 @@ -from typing import Optional -from joblib import parallel_backend, Parallel, delayed from multiprocessing import TimeoutError +from typing import Optional + +from joblib import Parallel, delayed, parallel_backend -from .intermediate_model.metamodel import ( - DOMLVersion, - MetaModels, - InverseAssociations -) -from .xmi_parser.doml_model import parse_doml_model -from .mc_result import MCResult, MCResults -from .imc import RequirementStore, IntermediateModelChecker from .common_reqs import CommonRequirements -from .consistency_reqs import ( - get_attribute_type_reqs, - get_attribute_multiplicity_reqs, - get_association_type_reqs, - get_association_multiplicity_reqs, - get_inverse_association_reqs -) +from .consistency_reqs import (get_association_multiplicity_reqs, + get_association_type_reqs, + get_attribute_multiplicity_reqs, + get_attribute_type_reqs, + get_inverse_association_reqs) +from .imc import IntermediateModelChecker, RequirementStore +from .intermediate_model.metamodel import (DOMLVersion, InverseAssociations, + MetaModels) +from .mc_result import MCResult, MCResults +from .xmi_parser.doml_model import parse_doml_model class ModelChecker: @@ -26,9 +22,21 @@ class ModelChecker: self.metamodel = MetaModels[self.doml_version] self.inv_assoc = InverseAssociations[self.doml_version] - def check_common_requirements(self, threads: int = 1, consistency_checks: bool = False, timeout: Optional[int] = None) -> MCResults: + def check_requirements( + self, + threads: int = 1, + user_requirements: Optional[RequirementStore] = None, + user_str_values: list[str] = [], + skip_common_requirements: bool = False, + consistency_checks: bool = False, + timeout: Optional[int] = None + ) -> MCResults: assert self.metamodel and self.inv_assoc - req_store = CommonRequirements[self.doml_version] + req_store = RequirementStore([]) + + if not skip_common_requirements: + req_store += CommonRequirements[self.doml_version] + if consistency_checks: req_store = req_store \ + get_attribute_type_reqs(self.metamodel) \ @@ -36,31 +44,38 @@ class ModelChecker: + get_association_type_reqs(self.metamodel) \ + get_association_multiplicity_reqs(self.metamodel) \ + get_inverse_association_reqs(self.inv_assoc) + + if user_requirements: + req_store += user_requirements def worker(rfrom: int, rto: int): imc = IntermediateModelChecker(self.metamodel, self.inv_assoc, self.intermediate_model) rs = RequirementStore(req_store.get_all_requirements()[rfrom:rto]) + imc.instantiate_solver(user_str_values) return imc.check_requirements(rs) - if threads <= 1: - imc = IntermediateModelChecker(self.metamodel, self.inv_assoc, self.intermediate_model) - reqs = imc.check_requirements(req_store, timeout=(0 if timeout is None else timeout)) - return reqs - else: - def split_reqs(n_reqs: int, n_split: int): - slice_size = n_reqs // n_split - rto = 0 - while rto < n_reqs: - rfrom = rto - rto = min(rfrom + slice_size, n_reqs) - yield rfrom, rto + def split_reqs(n_reqs: int, n_split: int): + slice_size = max(n_reqs // n_split, 1) + + rto = 0 + while rto < n_reqs: + rfrom = rto + rto = min(rfrom + slice_size, n_reqs) + yield rfrom, rto + + + + try: + with parallel_backend('loky', n_jobs=threads): + results = Parallel(timeout=timeout)(delayed(worker)(rfrom, rto) for rfrom, rto in split_reqs(len(req_store), threads)) + + # Uncomment for ease of debug + # results =[ worker(0, len(req_store) )] + + ret = MCResults([]) + for res in results: + ret.add_results(res) - try: - with parallel_backend('loky', n_jobs=threads): - results = Parallel(timeout=timeout)(delayed(worker)(rfrom, rto) for rfrom, rto in split_reqs(len(req_store), threads)) - ret = MCResults([]) - for res in results: - ret.add_results(res) - return ret - except TimeoutError: - return MCResults([(MCResult.dontknow, "")]) + return ret + except TimeoutError: + return MCResults([(MCResult.dontknow, "")]) diff --git a/mc_openapi/doml_mc/mc_result.py b/mc_openapi/doml_mc/mc_result.py index 78309c1d17958bdd972ce802ec46ac494ea30d5f..ae785f4f9f4563f65b4162116f408daca5228197 100644 --- a/mc_openapi/doml_mc/mc_result.py +++ b/mc_openapi/doml_mc/mc_result.py @@ -9,6 +9,10 @@ class MCResult(Enum): @staticmethod def from_z3result(z3res: CheckSatResult, flipped: bool = False) -> "MCResult": + """Returns an Enum which is either sat, unsat or dontknow. + If flipped is true, then the sat and unsat are swapped: it's useful when + we are evaluating an expression in negative form. + """ if flipped: if z3res == sat: return MCResult.unsat @@ -25,7 +29,7 @@ class MCResult(Enum): class MCResults: - dontknow_msg = "Timed out: unable to check some requirements." + DONTKNOW_MSG = "Timed out: unable to check some requirements." def __init__(self, results: list[tuple[MCResult, str]]): self.results = results @@ -35,12 +39,12 @@ class MCResults: some_dontknow = any(res == MCResult.dontknow for res, _ in self.results) if some_unsat: - err_msg = " ".join(msg for res, msg in self.results if res == MCResult.unsat) + err_msg = "\n\n".join([msg for res, msg in self.results if res == MCResult.unsat]) if some_dontknow: - err_msg = err_msg + MCResults.dontknow_msg + err_msg = err_msg + MCResults.DONTKNOW_MSG return MCResult.unsat, err_msg elif some_dontknow: - return MCResult.dontknow, MCResults.dontknow_msg + return MCResult.dontknow, MCResults.DONTKNOW_MSG else: return MCResult.sat, "All requirements satisfied." diff --git a/mc_openapi/doml_mc/synthesis_old/__init__.py b/mc_openapi/doml_mc/synthesis_old/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5aa44e830cce8f8953cf82a58943221cf9cbb247 --- /dev/null +++ b/mc_openapi/doml_mc/synthesis_old/__init__.py @@ -0,0 +1,3 @@ +import warnings +warnings.warn("the synthesis module is deprecated", DeprecationWarning, + stacklevel=2) \ No newline at end of file diff --git a/mc_openapi/doml_mc/synthesis_old/positive_common_reqs.domlr b/mc_openapi/doml_mc/synthesis_old/positive_common_reqs.domlr new file mode 100644 index 0000000000000000000000000000000000000000..b792c5c82e8493e6727b1802431a1cc981af1bee --- /dev/null +++ b/mc_openapi/doml_mc/synthesis_old/positive_common_reqs.domlr @@ -0,0 +1,85 @@ ++ "All VMs have iface" + forall vm ( + vm is class abstract.VirtualMachine + implies + exists iface ( + vm has abstract.ComputingNode.ifaces iface + ) + ) + --- + "X" + ++ "Concretization of Software Interfaces" + forall asc_consumer, asc_exposer, siface ( + ( + asc_consumer has application.SoftwareComponent.exposedInterfaces siface + and + asc_exposer has application.SoftwareComponent.consumedInterfaces siface + ) + implies + exists cdeployment, cnode, edeployment, enode, net ( + cdeployment has commons.Deployment.component asc_consumer + and + cdeployment has commons.Deployment.node cnode + and + exists vm, net_iface ( + ( + # asc_consumer is deployed on a component with an interface in network n + node has abstract.ComputingNode.ifaces net_iface + and + net_iface has abstract.NetworkInterface.belongsTo net + ) + or + ( + # asc_consumer is deployed on a component with an interface in network n + cnode has abstract.Container.hosts vm + and + vm has abstract.ComputingNode.ifaces net_iface + and + net_iface has abstract.NetworkInterface.belongsTo net + ) + or + ( + # asc_consumer is deployed on a VM in an AutoScalingGroup with an interface in network n + cnode has abstract.AutoScalingGroup.machineDefinition vm + and + vm has abstract.ComputingNode.ifaces net_iface + and + net_iface has abstract.NetworkInterface.belongsTo net + ) + ) + ) + and + edeployment has commons.Deployment.component asc_exposer + and + edeployment has commons.Deployment.node enode + and + exists vm, net_iface ( + ( + # asc_exposer is deployed on a component with an interface in network n + enode has abstract.ComputingNode.ifaces net_iface + and + net_iface has abstract.NetworkInterface.belongsTo net + ) + or + ( + # asc_exposer is deployed on a container hosted on a VM with an interface in network n + enode has abstract.Container.hosts vm + and + vm has abstract.ComputingNode.ifaces net_iface + and + net_iface has abstract.NetworkInterface.belongsTo net + ) + or + ( + # asc_exposer is deployed on a VM in an AutoScalingGroup with an interface in network n + enode has abstract.AutoScalingGroup.machineDefinition vm + and + vm has abstract.ComputingNode.ifaces net_iface + and + net_iface has abstract.NetworkInterface.belongsTo net + ) + ) + ) + --- + "YY" \ No newline at end of file diff --git a/mc_openapi/doml_mc/synthesis_old/synthesis.py b/mc_openapi/doml_mc/synthesis_old/synthesis.py new file mode 100644 index 0000000000000000000000000000000000000000..ade0858b84ba6ac2144773f2477aeca7c8d2a6f1 --- /dev/null +++ b/mc_openapi/doml_mc/synthesis_old/synthesis.py @@ -0,0 +1,354 @@ + + +from dataclasses import dataclass +from itertools import product +from typing import Tuple + +from z3 import (DatatypeRef, DatatypeSortRef, Not, FuncDeclRef, Model, Solver, sat, + unsat) +from mc_openapi.doml_mc.imc import Requirement, SMTEncoding, SMTSorts +from mc_openapi.doml_mc.intermediate_model.doml_element import IntermediateModel + +from mc_openapi.doml_mc.intermediate_model.metamodel import (DOMLVersion, MetaModel, + parse_metamodel) +from mc_openapi.doml_mc.xmi_parser.doml_model import parse_doml_model +from mc_openapi.doml_mc.z3encoding.im_encoding import ( + assert_im_associations, assert_im_attributes, + def_elem_class_f_and_assert_classes, mk_attr_data_sort, mk_elem_sort_dict, + mk_stringsym_sort_dict) +from mc_openapi.doml_mc.z3encoding.metamodel_encoding import ( + def_association_rel, def_attribute_rel, mk_association_sort_dict, + mk_attribute_sort_dict, mk_class_sort_dict) +from mc_openapi.doml_mc.z3encoding.types import Refs + +# Types +Elem = Value = Tuple[str, DatatypeRef] +AssocAndElems = Tuple[Elem, DatatypeRef, Elem] +AttrAndValues = Tuple[Elem, DatatypeRef, Value] + +@dataclass +class Context: + solver: Solver + class_sort: DatatypeSortRef + class_refs: Refs + assoc_sort: DatatypeSortRef + assoc_refs: Refs + attr_sort: DatatypeSortRef + attr_refs: Refs + str_sort: DatatypeSortRef + str_refs: Refs + elem_sort: DatatypeSortRef + elem_refs: Refs + + attr_data_sort: DatatypeSortRef + + elem_class_fn: FuncDeclRef + attr_rel: FuncDeclRef + assoc_rel: FuncDeclRef + + unbound_elems: list[str] + unbound_values: Refs + +class Synthesis: + def __init__(self, + metamodel: MetaModel, + intermediate_model: IntermediateModel, + verbose: bool = False + ) -> None: + """ + Initialize the data required to synthetize a new DOML according to provided requirements. + + :param metamodel_input_file: The result of parsing the YAML metamodel file + :param domlx_input_file: A XMI DOML file read as bytes containing the model to run through the tests. + :param doml_version: The DOML version as an Enum. + """ + self.mm = metamodel + self.im = intermediate_model + self.verbose = verbose + + def _init_context( + self, + ub_elem_n : int = 0, + ub_vals_n : int = 0, + reqs : list[Requirement] = [], + user_req_strings : list[str] = [] + ) -> Context: + """Builds a Context object containing all the relationships sorts and refs. + """ + solver = Solver() + + class_sort, class_refs = mk_class_sort_dict(self.mm, solver.ctx) + assoc_sort, assoc_refs = mk_association_sort_dict(self.mm, solver.ctx) + attr_sort, attr_refs = mk_attribute_sort_dict(self.mm, solver.ctx) + str_sort, str_refs = mk_stringsym_sort_dict(self.im, self.mm, solver.ctx, user_req_strings) + attr_data_sort = mk_attr_data_sort(str_sort, solver.ctx) + + unbound_elems = [f"unbound_elem_{i}" for i in range(ub_elem_n)] + + # Takes a list of strings and creates an Enum out of 'em + elem_sort, elem_refs = mk_elem_sort_dict(self.im, solver.ctx, unbound_elems) + + unbound_values_names = [f"unbound_val_{i}" for i in range(ub_vals_n)] + unbound_values = { + name : attr_data_sort.placeholder for name in unbound_values_names + } + # Examples of values that can go in unbound_values: + # ctx["attr_data_sort"].int(42), # ok + # ctx["attr_data_sort"].bool(True), # ok + # ctx["attr_data_sort"].str("x"), # cant do: it accept a ctx["str"][<str_key>] as input + # Const("x", ctx["attr_data_sort"]) # cant do: it is a symbolic value that cannot be converted to a BoolRef expression + + elem_class_fn = def_elem_class_f_and_assert_classes( + self.im, + solver, + elem_sort, + elem_refs, + class_sort, + class_refs + ) + + # attr_rel :: (elem_sort, attr_sort, attr_data_sort) -> BoolRef + attr_rel = def_attribute_rel( + attr_sort, + elem_sort, + attr_data_sort + ) + + assert_im_attributes( + attr_rel, + solver, + self.im, + self.mm, + elem_refs, + attr_sort, + attr_refs, + attr_data_sort, + str_refs + ) + + # assoc_rel :: (elem_sort, assoc_sort, elem_sort) -> BoolRef + assoc_rel = def_association_rel( + assoc_sort, + elem_sort + ) + + assert_im_associations( + assoc_rel, + solver, + {k: v for k, v in self.im.items() if k not in unbound_elems}, + elem_refs, + assoc_sort, + assoc_refs, + ) + + context = Context( + solver, + class_sort, class_refs, + assoc_sort, assoc_refs, + attr_sort, attr_refs, + str_sort, str_refs, + elem_sort, elem_refs, + attr_data_sort, + elem_class_fn, + attr_rel, + assoc_rel, + unbound_elems, + unbound_values + ) + + + encodings = SMTEncoding( + class_refs, + assoc_refs, + attr_refs, + elem_refs, + str_refs, + elem_class_fn, + attr_rel, + assoc_rel + ) + sorts = SMTSorts( + class_sort, + assoc_sort, + attr_sort, + elem_sort, + str_sort, + attr_data_sort + ) + + # Add requirements + # TODO: Investigate whether it's possible or a good idea + # to handle each requirement individually, like in imc.py + for req in reqs: + req_fn = req.assert_callable(encodings, sorts) + req_name = req.assert_name + solver.assert_and_track(req_fn, req_name) + + return context + + def check(self, + ub_elems_n: int = 0, + ub_vals_n: int = 0, + reqs: list = [], + curr_try: int = 0, + max_tries: int = 10, + user_req_strings: list[str] = [] + ) -> Context: + if curr_try > max_tries: + raise RuntimeError("Max tries exceeded.") + + ctx = self._init_context(ub_elems_n, ub_vals_n, reqs, user_req_strings) + + res = ctx.solver.check() + + if res == sat: + if self.verbose: + print(f"<Sat>\tub_elems_n={ub_elems_n}, ubvals_n={ub_vals_n}") + return ctx + elif res == unsat: + if self.verbose: + print(f"<Unsat>\tub_elems_n={ub_elems_n}, ubvals_n={ub_vals_n}") + + # TODO: Choose which goes first in a smart way? + if ub_elems_n > ub_vals_n: + new_ub_vals_n = ub_vals_n * 2 if ub_vals_n >= 1 else 1 + return self.check(ub_elems_n, new_ub_vals_n, reqs, curr_try + 1, max_tries) + elif ub_elems_n <= ub_vals_n: + new_ub_elems_n = ub_elems_n * 2 if ub_elems_n >= 1 else 1 + return self.check(new_ub_elems_n, ub_vals_n, reqs, curr_try + 1, max_tries) + else: # res == dontknow + raise RuntimeError("It took too long to decide satifiability.") + + def get_ub_elems_and_assoc(self, ctx: Context, model: Model) -> list[AssocAndElems]: + """Returns the associations between unbound elements.""" + return [ ((elem_1_k, elem_1_v), a, (elem_2_k, elem_2_v)) + for (elem_1_k, elem_1_v), a, (elem_2_k, elem_2_v) in product(ctx.elem_refs.items(), ctx.assoc_refs.values(), ctx.elem_refs.items()) + if (elem_1_k in ctx.unbound_elems or elem_2_k in ctx.unbound_elems) and model.eval(ctx.assoc_rel(elem_1_v, a, elem_2_v)) + ] + + def get_ub_vals_and_attr(self, ctx: Context, model: Model) -> list[AttrAndValues]: + """Returns the attribute relationships between elements and attribute data/values.""" + return [ ((elem_k, elem_v), a, (ubval_k, ubval_v)) + for (elem_k, elem_v), a, (ubval_k, ubval_v) in product(ctx.elem_refs.items(), ctx.attr_refs.values(), ctx.unbound_values.items()) + if model.eval(ctx.attr_rel(elem_v, a, ubval_v)) + ] + + def pretty_ub_elems_assoc(self, assoc_elems: list[AssocAndElems]) -> str: + """Returns a string containg a human-readable name of the elements and their association. + """ + (elem_1_k, _), a, (elem_2_k, _) = assoc_elems + elem_1 = self.im.get(elem_1_k) + if elem_1: + elem_1_name = f"{elem_1.class_} ({elem_1.user_friendly_name})" if elem_1_k[0:4] == "elem" else f"<'{elem_1_k}' not found>" + else: + elem_1_name = elem_1_k + + elem_2 = self.im.get(elem_2_k) + if elem_2: + elem_2_name = f"{elem_2.class_} ({elem_2.user_friendly_name})" if elem_2_k[0:4] == "elem" else f"<'{elem_2_k}' not found>" + else: + elem_2_name = elem_2_k + + assoc_name = str(a) + + return f"{elem_1_name:<50s} {assoc_name:<60s} {elem_2_name:<30s}" + + def pretty_ub_vals_attr(self, attr_and_val: list[AttrAndValues]) -> str: + """Returns a string containg a human-readable name of the element, the value and the + attribute relationship. + """ + (elem_k, _), a, (ubval_k, _) = attr_and_val + + elem_1 = self.im.get(elem_k) + if elem_1: + elem_1_name = f"{elem_1.class_} ({elem_1.user_friendly_name})" if elem_k[0:4] == "elem" else f"<'{elem_k}' not found>" + else: + elem_1_name = elem_k + + attr_name = str(a) + + val_name = str(ubval_k) + + return f"{elem_1_name:<50s} {attr_name:<60s} {val_name:<30s}" + + def thin_ub_elems_and_assoc(self, ctx: Context, ub_elems_and_assoc: list[AssocAndElems]): + if not ub_elems_and_assoc: + return [] + + (_, elem_1_v), a, (_, elem_2_v) = assoc = ub_elems_and_assoc[0] + assoc_rel = ctx.assoc_rel(elem_1_v, a, elem_2_v) + + # Add negated constraint + ctx.solver.push() + + if self.verbose: + print(f"\tAdd constraint Not({self.pretty_ub_elems_assoc(assoc)})") + ctx.solver.add(Not(assoc_rel)) + + res = ctx.solver.check() + + if res == sat: + if self.verbose: + print("SAT:\tAdding one more constraint and trying again") + # Get new ub_elems_and_assoc + model = ctx.solver.model() + thinned_ub_elems_and_assoc = self.get_ub_elems_and_assoc(ctx, model) + + # Print table showing the diff + from difflib import context_diff + uvar_as_text = lambda input: [self.pretty_ub_elems_assoc(assoc) for assoc in input] + if self.verbose: + print("\n".join([a for a in context_diff(uvar_as_text(ub_elems_and_assoc), uvar_as_text(thinned_ub_elems_and_assoc), lineterm="", fromfile='Before', tofile="After")])) + + # Iterate + return self.thin_ub_elems_and_assoc(ctx, thinned_ub_elems_and_assoc) + else: + if self.verbose: + print("UNSAT\tLast constraint was the association we are looking for!") + ctx.solver.pop() + + if ub_elems_and_assoc[1:]: + if self.verbose: + print("\tIterating over") + print("\t\t" + "\n\t\t".join([self.pretty_ub_elems_assoc(assoc) for assoc in ub_elems_and_assoc[1:]])) + return [*set([assoc] + self.thin_ub_elems_and_assoc(ctx, ub_elems_and_assoc[1:]))] + + def thin_ub_vals_and_attr(self, ctx: Context, ub_vals_and_attr: list[AttrAndValues]): + if not ub_vals_and_attr: + return [] + + (_, elem_v), a, (_, attr_v) = attr = ub_vals_and_attr[0] + attr_rel = ctx["attr_rel"](elem_v, a, attr_v) + + # Add negated constraint + ctx.solver.push() + if self.verbose: + print(f"\tAdd constraint Not({self.pretty_ubvals_attrs(attr)})") + ctx.solver.add(Not(attr_rel)) + + res = ctx.solver.check() + + if res == sat: + print("SAT:\tAdding one more constraint and trying again") + # Get new ub_elems_and_assoc + model = ctx.solver.model() + thinned_ub_vals_and_attr = self.get_ubvals_and_attr(ctx, model) + + # Print table showing the diff + from difflib import context_diff + uvar_as_text = lambda input: [self.pretty_ubvals_attrs(attr) for attr in input] + if self.verbose: + print("\n".join([a for a in context_diff(uvar_as_text(ub_vals_and_attr), uvar_as_text(thinned_ub_vals_and_attr), lineterm="", fromfile='Before', tofile="After")])) + + # Iterate + return self.thin_ub_vals_and_attr(ctx, thinned_ub_vals_and_attr) + else: + if self.verbose: + print("UNSAT\tLast constraint was the attribute we are looking for!") + ctx.solver.pop() + + if ub_vals_and_attr[1:]: + if self.verbose: + print("\tIterating over") + print("\t\t" + "\n\t\t".join([self.pretty_ubvals_attrs(attr) for attr in ub_vals_and_attr[1:]])) + return [*set([attr] + self.thin_ub_vals_and_attr(ctx, ub_vals_and_attr[1:]))] diff --git a/mc_openapi/doml_mc/synthesis_old/synthesis_common_reqs.py b/mc_openapi/doml_mc/synthesis_old/synthesis_common_reqs.py new file mode 100644 index 0000000000000000000000000000000000000000..1607a9cb59d30a867f91af2a5e4f7a08b3e5e50b --- /dev/null +++ b/mc_openapi/doml_mc/synthesis_old/synthesis_common_reqs.py @@ -0,0 +1,194 @@ +from z3 import ( + Consts, ExprRef, + ForAll, Exists, Implies, And, Or +) + +from mc_openapi.doml_mc.imc import ( + SMTEncoding, SMTSorts, Requirement, RequirementStore +) + + + + +def get_consts(smtsorts: SMTSorts, consts: list[str]) -> list[ExprRef]: + return Consts(" ".join(consts), smtsorts.element_sort) + + +def vm_iface(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: + vm, iface = get_consts(smtsorts, ["vm", "iface"]) + return ForAll( + [vm], + Implies( + smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"], + Exists( + [iface], + And( + smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface) + ) + ) + ) + ) + + +def software_package_iface_net(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: + asc_consumer, asc_exposer, siface, net, net_iface, cnode, cdeployment, enode, edeployment, vm, dc = get_consts( + smtsorts, + ["asc_consumer", "asc_exposer", "siface", "net", "net_iface", "cnode", "cdeployment", "enode", "edeployment", "vm", "dc"] + ) + return ForAll( + [asc_consumer, asc_exposer, siface], + Implies( + And( + smtenc.association_rel(asc_consumer, smtenc.associations["application_SoftwareComponent::exposedInterfaces"], siface), + smtenc.association_rel(asc_exposer, smtenc.associations["application_SoftwareComponent::consumedInterfaces"], siface), + ), + Exists( + [cdeployment, cnode, edeployment, enode, net], + And( + smtenc.association_rel(cdeployment, smtenc.associations["commons_Deployment::component"], asc_consumer), + smtenc.association_rel(cdeployment, smtenc.associations["commons_Deployment::node"], cnode), + Exists( + [vm, net_iface], + Or( + And( # asc_consumer is deployed on a component with an interface in network n + smtenc.association_rel(cnode, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface), + smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net), + ), + And( # asc_consumer is deployed on a component with an interface in network n + smtenc.association_rel(cnode, smtenc.associations["infrastructure_Container::hosts"], vm), + smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface), + smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net), + ), + And( # asc_consumer is deployed on a VM in an AutoScalingGroup with an interface in network n + smtenc.association_rel(cnode, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], vm), + smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface), + smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net), + ), + ) + ), + smtenc.association_rel(edeployment, smtenc.associations["commons_Deployment::component"], asc_exposer), + smtenc.association_rel(edeployment, smtenc.associations["commons_Deployment::node"], enode), + Exists( + [vm, net_iface], + Or( + And( # asc_exposer is deployed on a component with an interface in network n + smtenc.association_rel(enode, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface), + smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net), + ), + And( # asc_exposer is deployed on a container hosted on a VM with an interface in network n + smtenc.association_rel(enode, smtenc.associations["infrastructure_Container::hosts"], vm), + smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface), + smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net), + ), + And( # asc_exposer is deployed on a VM in an AutoScalingGroup with an interface in network n + smtenc.association_rel(enode, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], vm), + smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface), + smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net), + ), + ) + ) + ) + ) + ) + ) + + +def iface_uniq(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: + def any_iface(elem, iface): + ifaces_assocs = [ + "infrastructure_ComputingNode::ifaces", + "infrastructure_Storage::ifaces", + "infrastructure_FunctionAsAService::ifaces" + ] + return Or(*(smtenc.association_rel(elem, smtenc.associations[assoc_name], iface) for assoc_name in ifaces_assocs)) + + e1, e2, ni = get_consts(smtsorts, ["e1", "e2", "i"]) + return ForAll( + [e1, e2, ni], + Implies( + And(any_iface(e1, ni), any_iface(e2, ni)), + e1 == e2 + ) + ) + + +def all_SoftwareComponents_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: + sc, deployment, ielem = get_consts(smtsorts, ["sc", "deployment", "ielem"]) + return ForAll( + [sc], + Implies( + smtenc.element_class_fun(sc) == smtenc.classes["application_SoftwareComponent"], + Exists( + [deployment, ielem], + And( + smtenc.association_rel(deployment, smtenc.associations["commons_Deployment::component"], sc), + smtenc.association_rel(deployment, smtenc.associations["commons_Deployment::node"], ielem), + ) + ) + ) + ) + + +def all_infrastructure_elements_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef: + def checkOneClass(ielem, concr, provider, celem, ielemClass, providerAssoc, celemAssoc): + return Implies( + smtenc.element_class_fun(ielem) == smtenc.classes[ielemClass], + Exists( + [provider, celem], + And( + smtenc.association_rel(concr, smtenc.associations["concrete_ConcreteInfrastructure::providers"], provider), + smtenc.association_rel(provider, smtenc.associations[providerAssoc], celem), + smtenc.association_rel(celem, smtenc.associations[celemAssoc], ielem) + ) + ) + ) + + ielem, concr, provider, celem = get_consts(smtsorts, ["ielem", "concr", "provider", "celem"]) + return Exists( + [concr], + And( + smtenc.element_class_fun(concr) == smtenc.classes["concrete_ConcreteInfrastructure"], + ForAll( + [ielem], + And( + checkOneClass( + ielem, concr, provider, celem, + "infrastructure_VirtualMachine", + "concrete_RuntimeProvider::vms", + "concrete_VirtualMachine::maps" + ), + checkOneClass( + ielem, concr, provider, celem, + "infrastructure_Network", + "concrete_RuntimeProvider::networks", + "concrete_Network::maps" + ), + checkOneClass( + ielem, concr, provider, celem, + "infrastructure_Storage", + "concrete_RuntimeProvider::storages", + "concrete_Storage::maps" + ), + checkOneClass( + ielem, concr, provider, celem, + "infrastructure_FunctionAsAService", + "concrete_RuntimeProvider::faas", + "concrete_FunctionAsAService::maps" + ), + ) + ) + ) + ) + + +synthesis_default_req_store = RequirementStore( + [ + Requirement(*rt) for rt in [ + (vm_iface, "vm_iface", "All virtual machines must be connected to at least one network interface.", "A virtual machine is connected to no network interface."), + (software_package_iface_net, "software_package_iface_net", "All software packages can see the interfaces they need through a common network.", "A software package is deployed on a node that has no access to an interface it consumes."), + (iface_uniq, "iface_uniq", "There are no duplicated interfaces.", "There is a duplicated interface."), + (all_SoftwareComponents_deployed, "all_SoftwareComponents_deployed", "All software components have been deployed to some node.", "A software component has not been deployed to any node."), + (all_infrastructure_elements_deployed, "all_infrastructure_elements_deployed", "All abstract infrastructure elements are mapped to an element in the active concretization.", "An abstract infrastructure element has not been mapped to any element in the active concretization."), + ] + ] +) \ No newline at end of file diff --git a/mc_openapi/doml_mc/synthesis_old/xmi_gen.py b/mc_openapi/doml_mc/synthesis_old/xmi_gen.py new file mode 100644 index 0000000000000000000000000000000000000000..14766b5b9be74da698d7c1ceebdd75e2b909c813 --- /dev/null +++ b/mc_openapi/doml_mc/synthesis_old/xmi_gen.py @@ -0,0 +1,89 @@ +import re +from itertools import product + +from pyecore.ecore import EClass, EObject + +from mc_openapi.doml_mc.intermediate_model.doml_element import \ + IntermediateModel +from mc_openapi.doml_mc.intermediate_model.metamodel import DOMLVersion +from mc_openapi.doml_mc.synthesis_old.synthesis import AssocAndElems +from mc_openapi.doml_mc.xmi_parser.doml_model import get_rset + +import secrets +import base64 + +def _gen_random_suffix_hash(len: int = 6): + return base64.urlsafe_b64encode(secrets.token_bytes(len)).decode() + +def _convert_camelcase_to_snakecase(input: str): + return re.sub(r'(?<!^)(?=[A-Z])', '_', input).lower() + +def generate_xmi(root: EObject, new_assocs: list[AssocAndElems], im: IntermediateModel, doml_ver: DOMLVersion = DOMLVersion.V2_0): + + def find_eclass(eclass_package: str, eclass_name: str): + """`eclass_package` is like `infrastructure` + `eclass_name` is like `VirtualMachine` + """ + pkgs = [pkg for pkg + in list(get_rset(doml_ver).metamodel_registry.values()) + if pkg.name == eclass_package + ] + # `metamodel_registry` is a dict consisting of: + # - ecore + # - doml + # |- commons + # |- application + # |- infrastructure + # |- concrete + # |- optimization + return pkgs[0].getEClassifier(eclass_name) + + def find_elem(elem_name: str): + ret = [] + for elem in root.eAllContents(): + try: + if elem.name == elem_name: + ret.append(elem) + except: + pass + return ret[0] + + print(find_eclass("infrastructure", "NetworkInterface")) + + for ((e1_k, e1_v), assoc, (e2_k, e2_v)) in new_assocs: + if "unbound" not in e1_k: + # it's an existing element + e1 = im[e1_k] + e1_class = re.search("^.*_(.+?)$", e1.class_).group(1) + e1_name = e1.attributes["commons_DOMLElement::name"][0] + print(e1_class, e1_name) + # TODO: Should I handle the case where the first element is an unbound one? + + e1_instance = find_elem(e1_name) + + # Regex to split <package>_<class>::<name> + assoc_re = re.search("^(.+?)_(.+?)::(.+?)$", str(assoc)) + assoc_package = assoc_re.group(1) + assoc_class = assoc_re.group(2) + assoc_name = assoc_re.group(3) + print(assoc_package, assoc_class, assoc_name) + + if "unbound" not in e2_k: + # it's an existing element + e2 = im[e2_k] + e2_class = re.search("^.*_(.+?)$", e2.class_).group(1) + e2_name = e2.attributes["commons_DOMLElement::name"][0] + print(e2_class, e2_name) + # TODO: Add relationship between the two? + else: + e1_container = getattr(e1_instance, assoc_name) + e2_instance_type = e1_container.feature.eType + e2_instance_name = ( + _convert_camelcase_to_snakecase(e1_container.feature.eType.name) + + "_" + + _gen_random_suffix_hash()) + e2_instance = e2_instance_type(name=e2_instance_name) + e1_container.append(e2_instance) + + + return root \ No newline at end of file diff --git a/mc_openapi/doml_mc/_utils.py b/mc_openapi/doml_mc/utils.py similarity index 86% rename from mc_openapi/doml_mc/_utils.py rename to mc_openapi/doml_mc/utils.py index 458c453bc55b6d4975d1cb4c61bd836f206177f6..ac0a3c7e1688c4ec5ece0f1a9c8b6968754b8a10 100644 --- a/mc_openapi/doml_mc/_utils.py +++ b/mc_openapi/doml_mc/utils.py @@ -1,10 +1,11 @@ from typing import TypeVar from collections.abc import Iterable - _K = TypeVar("_K") _V = TypeVar("_V") - def merge_dicts(it: Iterable[dict[_K, _V]]) -> dict[_K, _V]: return dict(kv for d in it for kv in d.items()) + +def Iff(a, b): + return a == b diff --git a/mc_openapi/bytes_uri.py b/mc_openapi/doml_mc/xmi_parser/bytes_uri.py similarity index 100% rename from mc_openapi/bytes_uri.py rename to mc_openapi/doml_mc/xmi_parser/bytes_uri.py diff --git a/mc_openapi/doml_mc/xmi_parser/doml_model.py b/mc_openapi/doml_mc/xmi_parser/doml_model.py index 6310d4ff5d4cc7782f72436179821d2b2eaf373f..0659bf67af5beadee8fe0fda9bb4cefc3cfeef1b 100644 --- a/mc_openapi/doml_mc/xmi_parser/doml_model.py +++ b/mc_openapi/doml_mc/xmi_parser/doml_model.py @@ -1,30 +1,34 @@ -from typing import Optional, Tuple import copy import importlib.resources as ilres -from lxml import etree +from typing import Optional, Tuple -from mc_openapi import assets -from mc_openapi.bytes_uri import BytesURI +from lxml import etree from pyecore.ecore import EObject from pyecore.resources import ResourceSet -from ..intermediate_model.doml_element import IntermediateModel, reciprocate_inverse_associations -from ..intermediate_model.metamodel import DOMLVersion, MetaModels, InverseAssociations +from mc_openapi import assets + +from ..intermediate_model.doml_element import ( + IntermediateModel, reciprocate_inverse_associations) +from ..intermediate_model.metamodel import (DOMLVersion, InverseAssociations, + MetaModels) +from .bytes_uri import BytesURI from .ecore import ELayerParser from .special_parsers import SpecialParsers - doml_rsets = {} def init_doml_rsets(): # noqa: E302 global doml_rsets for ver in DOMLVersion: rset = ResourceSet() + source = ilres.files(assets).joinpath(f"doml_{ver.value}.ecore") resource = rset.get_resource(BytesURI( - "doml", bytes=ilres.read_binary(assets, f"doml_{ver.value}.ecore") + "doml", bytes=source.read_bytes() )) doml_metamodel = resource.contents[0] rset.metamodel_registry[doml_metamodel.nsURI] = doml_metamodel + # .ecore file is loaded in the rset as a metamodel for subp in doml_metamodel.eSubpackages: rset.metamodel_registry[subp.nsURI] = subp @@ -56,16 +60,38 @@ def infer_domlx_version(raw_model: bytes) -> DOMLVersion: else: raise RuntimeError(f"Supplied with DOMLX model of unsupported version {v_str}") else: - return DOMLVersion.V2_0 # Should be DOMLVersion.V1_0, but we use V2_0 because the 2.0 IDE doesn't fill it + return DOMLVersion.V2_0 # Should be DOMLVersion.V1_0, but we use V2_0 because the 2.1 IDE doesn't fill it else: - raise RuntimeError("Supplied with malformed DOMLX model.") + raise RuntimeError(f"Supplied with malformed DOMLX model or unsupported DOML version.\nIn use version is: {DOMLVersion.V2_0}") def parse_doml_model(raw_model: bytes, doml_version: Optional[DOMLVersion]) -> Tuple[IntermediateModel, DOMLVersion]: + # if doml_version is None: + # doml_version = infer_domlx_version(raw_model) + + # Try every DOML version until one works! if doml_version is None: - doml_version = infer_domlx_version(raw_model) - model = parse_xmi_model(raw_model, doml_version) + doml_versions = [x for x in DOMLVersion] + print(doml_versions) + + def get_model(raw_model, doml_version): + try: + dv = doml_versions.pop(0) + doml_version = dv + return parse_xmi_model(raw_model, dv), dv + except Exception as e: + print(f"Couldn't parse with DOML {dv.value}. Trying another version...") + if len(doml_versions) == 0: + raise e + else: + return get_model(raw_model, doml_version) + + model, doml_version = get_model(raw_model, doml_version) + else: # if user specifies DOML version, respect that choice! + model = parse_xmi_model(raw_model, doml_version) + + print(f"Using DOML {doml_version.value}") elp = ELayerParser(MetaModels[doml_version], SpecialParsers[doml_version]) if model.application: @@ -84,3 +110,23 @@ def parse_doml_model(raw_model: bytes, doml_version: Optional[DOMLVersion]) -> T reciprocate_inverse_associations(im, InverseAssociations[doml_version]) return im, doml_version + +def get_pyecore_model(raw_model: bytes, doml_version: Optional[DOMLVersion]) -> EObject: + if doml_version is None: + doml_version = infer_domlx_version(raw_model) + # TODO: See if its better replaced by the get_model() in parse_doml_version() + return parse_xmi_model(raw_model, doml_version) + +from typing import Optional + +def serialize_pyecore_model(root: EObject, doml_version: DOMLVersion = DOMLVersion.V2_0, path: Optional[str] = None): + from pyecore.resources import URI + + # Get rset with metamodel + rset = get_rset(doml_version) + # Create the resource where we'll save the updated model/DOMLX + res = rset.create_resource(URI("./output.domlx")) + # Append updated EObject + res.append(root) + # Serialize to file + res.save() diff --git a/mc_openapi/doml_mc/xmi_parser/special_parsers.py b/mc_openapi/doml_mc/xmi_parser/special_parsers.py index 4427aae18fb61baa51875aa87bf55376cca11382..2b700e9256ccbfddac29dcc3023b266a40eb93e7 100644 --- a/mc_openapi/doml_mc/xmi_parser/special_parsers.py +++ b/mc_openapi/doml_mc/xmi_parser/special_parsers.py @@ -60,6 +60,12 @@ def init_special_parsers(): ("infrastructure_ComputingNode", "memory_mb"): parse_memory_mb, ("commons_FProperty", "value"): parse_fproperty, }, + DOMLVersion.V2_2: { + ("infrastructure_Network", "addressRange"): parse_cidr, + ("infrastructure_NetworkInterface", "endPoint"): parse_iface_address, + ("infrastructure_ComputingNode", "memory_mb"): parse_memory_mb, + ("commons_FProperty", "value"): parse_fproperty, + }, } for ver in DOMLVersion: SpecialParsers[ver] = SpecialParser(MetaModels[ver], attribute_parsers[ver]) diff --git a/mc_openapi/doml_mc/z3encoding/im_encoding.py b/mc_openapi/doml_mc/z3encoding/im_encoding.py index 31948d9eb04de6e6300ab5ccac03a59c53b35968..533ca401735a8368d913977c4994def3c2437577 100644 --- a/mc_openapi/doml_mc/z3encoding/im_encoding.py +++ b/mc_openapi/doml_mc/z3encoding/im_encoding.py @@ -1,31 +1,16 @@ -from typing import Union from itertools import product +from typing import Union + +from z3 import (And, BoolSort, Const, Context, Datatype, DatatypeRef, + DatatypeSortRef, ForAll, FuncDeclRef, Function, IntSort, Not, + Or, Solver, EnumSort) -from z3 import ( - And, - Const, - Context, - DatatypeRef, - DatatypeSortRef, - ForAll, - FuncDeclRef, - Function, - Not, - Or, - Solver, -) +from mc_openapi.doml_mc.z3encoding.metamodel_encoding import mk_enum_sort_dict from ..intermediate_model import IntermediateModel, MetaModel from ..intermediate_model.metamodel import get_mangled_attribute_defaults - from .types import Refs, SortAndRefs -from .utils import ( - assert_relation_tuples, - Iff, - mk_enum_sort_dict, - mk_stringsym_sort_from_strings, -) - +from ..utils import Iff def mk_elem_sort_dict( im: IntermediateModel, @@ -61,41 +46,42 @@ def assert_im_attributes( solver: Solver, im: IntermediateModel, mm: MetaModel, - elem: Refs, - attr_sort: DatatypeSortRef, - attr: Refs, - AData: DatatypeSortRef, - ss: Refs, + elems: Refs, + attr_sort: DatatypeSortRef, # Relationship sort + attrs: Refs, # Relationship data + attr_data_sort: DatatypeSortRef, # Value sort + strings: Refs, + allow_placeholders: bool = False ) -> None: """ ### Effects This procedure is effectful on `solver`. """ - def encode_adata(v: Union[str, int, bool]) -> DatatypeRef: + def encode_attr_data(v: Union[str, int, bool]) -> DatatypeRef: if type(v) is str: - return AData.ss(ss[v]) # type: ignore + return attr_data_sort.str(strings[v]) # type: ignore elif type(v) is int: - return AData.int(v) # type: ignore + return attr_data_sort.int(v) # type: ignore else: # type(v) is bool - return AData.bool(v) # type: ignore + return attr_data_sort.bool(v) # type: ignore a = Const("a", attr_sort) - d = Const("d", AData) + d = Const("d", attr_data_sort) for esn, im_es in im.items(): - mangled_attrs = get_mangled_attribute_defaults(mm, im_es.class_) | im_es.attributes - if mangled_attrs: + attr_data = get_mangled_attribute_defaults(mm, im_es.class_) | im_es.attributes + if attr_data: assn = ForAll( [a, d], Iff( - attr_rel(elem[esn], a, d), + attr_rel(elems[esn], a, d), Or( *( And( - a == attr[aname], - d == encode_adata(avalue), + a == attrs[aname], + d == encode_attr_data(avalue) ) - for aname, avalues in mangled_attrs.items() + for aname, avalues in attr_data.items() for avalue in avalues ) ), @@ -104,43 +90,14 @@ def assert_im_attributes( else: assn = ForAll( [a, d], - Not(attr_rel(elem[esn], a, d)) + Not(attr_rel(elems[esn], a, d)) ) solver.assert_and_track(assn, f"attribute_values {esn}") - def assert_im_associations( assoc_rel: FuncDeclRef, solver: Solver, - im: IntermediateModel, - mm: MetaModel, - elem: Refs, - assoc: Refs, -) -> None: - """ - ### Effects - This procedure is effectful on `solver`. - """ - elem_names = set(im.keys()) - assoc_mangled_names = { - f"{cname}::{aname}" - for cname, c in mm.items() - for aname in c.associations - } - rel_tpls = [ - [esn, amn, etn] - for esn, amn, etn in product( - elem_names, assoc_mangled_names, elem_names - ) - if etn in im[esn].associations.get(amn, set()) - ] - assert_relation_tuples(assoc_rel, solver, rel_tpls, elem, assoc, elem) - - -def assert_im_associations_q( - assoc_rel: FuncDeclRef, - solver: Solver, - im: IntermediateModel, + im: IntermediateModel, # Contains only bounded elements elem: Refs, assoc_sort: DatatypeSortRef, assoc: Refs, @@ -150,29 +107,30 @@ def assert_im_associations_q( This procedure is effectful on `solver`. """ - a = Const("a", assoc_sort) - for (esn, im_es), etn in product(im.items(), im): + assoc_ref = Const("a", assoc_sort) + for (elem_1_k, elem_1_v), elem_2_k in product(im.items(), im): assn = ForAll( - [a], + [assoc_ref], Iff( - assoc_rel(elem[esn], a, elem[etn]), + assoc_rel(elem[elem_1_k], assoc_ref, elem[elem_2_k]), Or( *( - a == assoc[amn] - for amn, etns in im_es.associations.items() - if etn in etns + assoc_ref == assoc[elem_1_assoc_k] + for elem_1_assoc_k, elem_1_assoc_elems_k in elem_1_v.associations.items() + if elem_2_k in elem_1_assoc_elems_k ), solver.ctx ), ), ) - solver.assert_and_track(assn, f"associations {esn} {etn}") + solver.assert_and_track(assn, f"associations {elem_1_k} {elem_2_k}") def mk_stringsym_sort_dict( im: IntermediateModel, mm: MetaModel, - z3ctx: Context + z3ctx: Context, + additional_strings: list[str] = [] ) -> SortAndRefs: strings = ( { @@ -191,5 +149,36 @@ def mk_stringsym_sort_dict( if isinstance(v, str) } | {"SCRIPT", "IMAGE"} # GeneratorKind values + | {"INGRESS", "EGRESS"} # TODO: Check if this fix is required + # It solves a KeyError when MC is run on openstack_template.domlx + | { + v + for v in additional_strings + } ) return mk_stringsym_sort_from_strings(list(strings), z3ctx=z3ctx) + +def mk_attr_data_sort( + str_sort: DatatypeSortRef, + z3ctx: Context +) -> DatatypeSortRef: + attr_data = Datatype("AttributeData", ctx=z3ctx) + attr_data.declare("placeholder") + attr_data.declare("int", ("get_int", IntSort(ctx=z3ctx))) + attr_data.declare("bool", ("get_bool", BoolSort(ctx=z3ctx))) + attr_data.declare("str", ("get_str", str_sort)) # str_sort is the one returned by the function above + return attr_data.create() + +def mk_stringsym_sort_from_strings( + strings: list[str], + z3ctx: Context +) -> SortAndRefs: + str_list = [f"str_{i}_{symbolize(s)}" for i, s in enumerate(strings)] + string_sort, str_refs_dict = mk_enum_sort_dict("string", str_list, z3ctx=z3ctx) + string_sort_dict = { + s: str_refs_dict[str] for s, str in zip(strings, str_list) + } + return string_sort, string_sort_dict + +def symbolize(s: str) -> str: + return "".join([c.lower() if c.isalnum() else "_" for c in s[:16]]) diff --git a/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py b/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py index 22c48484de3709b6526aa77c44d80da3aea07700..97af7a3b7860a171b652c6d724428cc035b651ae 100644 --- a/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py +++ b/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py @@ -4,12 +4,11 @@ from z3 import ( DatatypeSortRef, FuncDeclRef, Function, + EnumSort ) from ..intermediate_model import MetaModel from .types import SortAndRefs -from .utils import mk_enum_sort_dict - def mk_class_sort_dict(mm: MetaModel, z3ctx: Context) -> SortAndRefs: return mk_enum_sort_dict("Class", list(mm), z3ctx) @@ -38,13 +37,18 @@ def mk_association_sort_dict( ] return mk_enum_sort_dict("Association", assocs, z3ctx) +def mk_enum_sort_dict(name: str, values: list[str], z3ctx: Context) -> SortAndRefs: + """Makes a Z3 sort and a dict indexing sort values by their name""" + + sort, datatype_refs = EnumSort(name, values, ctx=z3ctx) + return sort, dict(zip(values, datatype_refs)) def def_attribute_rel( attr_sort: DatatypeSortRef, elem_sort: DatatypeSortRef, - AData: DatatypeSortRef + attr_data_sort: DatatypeSortRef ) -> FuncDeclRef: - return Function("attribute", elem_sort, attr_sort, AData, BoolSort(ctx=elem_sort.ctx)) + return Function("attribute", elem_sort, attr_sort, attr_data_sort, BoolSort(ctx=elem_sort.ctx)) def def_association_rel( diff --git a/mc_openapi/doml_mc/z3encoding/utils.py b/mc_openapi/doml_mc/z3encoding/utils.py deleted file mode 100644 index 04730494fc3687311d439f9bc06f1f73e16a9fc2..0000000000000000000000000000000000000000 --- a/mc_openapi/doml_mc/z3encoding/utils.py +++ /dev/null @@ -1,150 +0,0 @@ -from typing import cast -from collections.abc import Sequence -from itertools import product - -from z3 import ( - BoolSort, - BoolVal, - Context, - Datatype, - DatatypeSortRef, - ExprRef, - EnumSort, - FuncDeclRef, - IntSort, - Solver, -) - -from .types import Refs, SortAndRefs - - -def mk_enum_sort_dict(name: str, values: list[str], z3ctx: Context) -> SortAndRefs: - """Makes a Z3 sort and a dict indexing sort values by their name""" - - sort, dtrefs = EnumSort(name, values, ctx=z3ctx) - return sort, dict(zip(values, dtrefs)) - - -def assert_relation_tuples( - rel: FuncDeclRef, - solver: Solver, - rel_tpls: list[list[str]], - *sig_dicts: Refs, -) -> None: - """ - ### Parameters - - `rel` is a Z3 function with return type Bool representing a relation; - - `solver` is the Z3 solver on which to assert; - - `rel_tpls` is a list of lists of names of symbols which are related in - `rel`; - - `sig_dicts` are the domains of `rel`. - - ### Effects - This procedure is effectful on `solver`. - """ - - # Length of tuples must me homogeneous and equal to the number of given - # domains. - if lengths := [len(tpl) for tpl in rel_tpls]: - assert min(lengths) == max(lengths) - assert lengths[0] == len(sig_dicts) - - sym_tpls = [ - cast( - list[ExprRef], - [dom[sym_name] for sym_name, dom in zip(doms_tpl, sig_dicts)], - ) - + [BoolVal(doms_tpl in rel_tpls, ctx=solver.ctx)] - for doms_tpl in map(list, product(*sig_dicts)) - ] - - assert_function_tuples_raw(rel, solver, sym_tpls) - - -def assert_function_tuples( - f: FuncDeclRef, - solver: Solver, - f_tpls: list[list[str]], - *sig_dicts: Refs, -) -> None: - """ - ### Parameters - - `f` is a Z3 function; - - `solver` is the Z3 solver on which to assert; - - `f_tpls` is a list of tuples of Z3 symbols. The first elements in each - tuple are the inputs of `f`, and the last element is its output; - - `sig_dicts` are the domains of `f`, the last one being its codomain. - - ### Effects - This procedure is effectful on `solver`. - """ - - # Length of tuples must me homogeneous and equal to the number of given - # domains. - if lengths := [len(tpl) for tpl in f_tpls]: - assert min(lengths) == max(lengths) - assert lengths[0] == len(sig_dicts) - - sym_tpls = [ - [dom[sym_name] for sym_name, dom in zip(f_tpl, sig_dicts)] - for f_tpl in f_tpls - ] - - assert_function_tuples_raw(f, solver, sym_tpls) - - -def assert_function_tuples_raw( - f: FuncDeclRef, - solver: Solver, - f_tpls: Sequence[Sequence[ExprRef]], -) -> None: - """ - ### Parameters - - `f` is a Z3 function; - - `solver` is the Z3 solver on which to assert; - - `f_tpls` is a list of tuples of Z3 references or otherwise accepted - values. The first elements in each tuple are the inputs of `f`, and the - last element is its output; - - ### Effects - This procedure is effectful on `solver`. - """ - # Length of tuples must me homogeneous. - if lengths := [len(tpl) for tpl in f_tpls]: - assert min(lengths) == max(lengths) - - for *xs, y in f_tpls: - solver.assert_and_track( - f(*xs) == y, - f"{f.name()} " + " ".join(str(x) for x in xs) + f" {y}", - ) - - -def mk_stringsym_sort_from_strings( - strings: list[str], - z3ctx: Context -) -> SortAndRefs: - def symbolize(s: str) -> str: - return "".join([c.lower() if c.isalnum() else "_" for c in s[:16]]) - - ss_list = [f"ss_{i}_{symbolize(s)}" for i, s in enumerate(strings)] - stringsym_sort, ss_refs_dict = mk_enum_sort_dict("StringSym", ss_list, z3ctx=z3ctx) - stringsym_sort_dict = { - s: ss_refs_dict[ss] for s, ss in zip(strings, ss_list) - } - return stringsym_sort, stringsym_sort_dict - - -def mk_adata_sort( - ss_sort: DatatypeSortRef, - z3ctx: Context -) -> DatatypeSortRef: - AData = Datatype("AttributeData", ctx=z3ctx) - AData.declare("int", ("get_int", IntSort(ctx=z3ctx))) - AData.declare("bool", ("get_bool", BoolSort(ctx=z3ctx))) - AData.declare("ss", ("get_ss", ss_sort)) - return AData.create() - - -def Iff(a, b): - return a == b diff --git a/mc_openapi/handlers.py b/mc_openapi/handlers.py index 9c84b9b0ce668eef3d75feab2f0b55d24d152878..99b3d8521ad36bf1ccef906f9b1d960a2f2c4d7f 100644 --- a/mc_openapi/handlers.py +++ b/mc_openapi/handlers.py @@ -1,4 +1,9 @@ import datetime +from mc_openapi.doml_mc.domlr_parser.parser import DOMLRTransformer, Parser +from mc_openapi.doml_mc.imc import RequirementStore + +from mc_openapi.doml_mc.intermediate_model.metamodel import DOMLVersion +from mc_openapi.doml_mc.xmi_parser.doml_model import get_pyecore_model from .doml_mc import ModelChecker, MCResult @@ -6,14 +11,37 @@ def make_error(user_msg, debug_msg=None): result = {"message": user_msg, "timestamp": datetime.datetime.now()} if debug_msg is not None: result["debug_message"] = debug_msg + print(f"ERROR [{datetime.datetime.now()}]: {debug_msg}") return result -def post(body, requirement=None): +def post(body): doml_xmi = body try: + dmc = ModelChecker(doml_xmi) - results = dmc.check_common_requirements(threads=2, consistency_checks=False, timeout=50) + + user_req_store = None + user_req_str_consts = [] + + # Add support for Requirements in DOML + if dmc.doml_version == DOMLVersion.V2_2: + domlr_parser = Parser(DOMLRTransformer) + model = get_pyecore_model(doml_xmi, DOMLVersion.V2_2) + func_reqs = model.functionalRequirements.items + + user_req_store = RequirementStore() + + for req in func_reqs: + req_name: str = req.name + req_text: str = req.description + req_text = req_text.replace("```", "") + doml_req_store, doml_req_str_consts = domlr_parser.parse(req_text) + user_req_store += doml_req_store + user_req_str_consts += doml_req_str_consts + + + results = dmc.check_requirements(threads=2, user_requirements=user_req_store, user_str_values=user_req_str_consts, consistency_checks=False, timeout=50) res, msg = results.summarize() if res == MCResult.sat: @@ -22,5 +50,6 @@ def post(body, requirement=None): return {"result": res.name, "description": msg} + # TODO: Make noteworthy exceptions to at least tell the user what is wrong except Exception as e: return make_error("The supplied DOMLX model is malformed or its DOML version is unsupported.", debug_msg=str(e)), 400 diff --git a/mc_openapi/notebooks/dict_reference.ipynb b/mc_openapi/notebooks/dict_reference.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..7307d91f12c97fa324e54f9ef42888f49b86d824 --- /dev/null +++ b/mc_openapi/notebooks/dict_reference.ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "from pprint import pprint\n", + "\n", + "from mc_openapi.doml_mc import ModelChecker, DOMLVersion\n", + "\n", + "doml_document_path = \"../../tests/doml/v2.0/nginx-openstack_v2.0.domlx\"\n", + "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0_wrong_vm_iface.domlx\"\n", + "# doml_document_path = \"../../tests/doml/faas.domlx\"\n", + "with open(doml_document_path, \"rb\") as xmif:\n", + " doc = xmif.read()\n", + "\n", + "model_checker = ModelChecker(doc, DOMLVersion.V2_0)\n", + "meta_model = model_checker.metamodel\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "f-string: unmatched '(' (2134446349.py, line 2)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn [13], line 2\u001b[0;36m\u001b[0m\n\u001b[0;31m f\"{cname.replace(\"_\", \".\")}.{aname}\"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m f-string: unmatched '('\n" + ] + } + ], + "source": [ + "atts = [\n", + " f\"{cname}::{aname}\"\n", + " for cname, c in meta_model.items()\n", + " for aname in c.attributes\n", + "]\n", + "\n", + "pprint(atts)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['commons_DOMLElement.annotations',\n", + " 'commons_Property.reference',\n", + " 'commons_Configuration.deployments',\n", + " 'commons_Deployment.component',\n", + " 'commons_Deployment.node',\n", + " 'application_ApplicationLayer.components',\n", + " 'application_SoftwareComponent.exposedInterfaces',\n", + " 'application_SoftwareComponent.consumedInterfaces',\n", + " 'application_SaaS.exposedInterfaces',\n", + " 'infrastructure_InfrastructureLayer.nodes',\n", + " 'infrastructure_InfrastructureLayer.generators',\n", + " 'infrastructure_InfrastructureLayer.storages',\n", + " 'infrastructure_InfrastructureLayer.faas',\n", + " 'infrastructure_InfrastructureLayer.credentials',\n", + " 'infrastructure_InfrastructureLayer.groups',\n", + " 'infrastructure_InfrastructureLayer.securityGroups',\n", + " 'infrastructure_InfrastructureLayer.networks',\n", + " 'infrastructure_ComputingNode.ifaces',\n", + " 'infrastructure_ComputingNode.location',\n", + " 'infrastructure_ComputingNode.credentials',\n", + " 'infrastructure_ComputingNode.group',\n", + " 'infrastructure_VirtualMachine.generatedFrom',\n", + " 'infrastructure_Container.generatedFrom',\n", + " 'infrastructure_Container.hosts',\n", + " 'infrastructure_VMImage.generatedVMs',\n", + " 'infrastructure_ContainerImage.generatedContainers',\n", + " 'infrastructure_AutoScalingGroup.machineDefinition',\n", + " 'infrastructure_AutoScalingGroup.deploymentNetwork',\n", + " 'infrastructure_AutoScalingGroup.securityGroup',\n", + " 'infrastructure_Storage.ifaces',\n", + " 'infrastructure_FunctionAsAService.ifaces',\n", + " 'infrastructure_Network.connectedIfaces',\n", + " 'infrastructure_Network.igws',\n", + " 'infrastructure_Network.subnets',\n", + " 'infrastructure_Subnet.connectedTo',\n", + " 'infrastructure_NetworkInterface.belongsTo',\n", + " 'infrastructure_NetworkInterface.associated',\n", + " 'infrastructure_ComputingGroup.groupedNodes',\n", + " 'infrastructure_SecurityGroup.rules',\n", + " 'infrastructure_SecurityGroup.ifaces',\n", + " 'infrastructure_SwarmRole.nodes',\n", + " 'infrastructure_Swarm.roles',\n", + " 'concrete_ConcreteInfrastructure.providers',\n", + " 'concrete_RuntimeProvider.vms',\n", + " 'concrete_RuntimeProvider.vmImages',\n", + " 'concrete_RuntimeProvider.containerImages',\n", + " 'concrete_RuntimeProvider.networks',\n", + " 'concrete_RuntimeProvider.storages',\n", + " 'concrete_RuntimeProvider.faas',\n", + " 'concrete_RuntimeProvider.group',\n", + " 'concrete_VirtualMachine.maps',\n", + " 'concrete_VMImage.maps',\n", + " 'concrete_ContainerImage.maps',\n", + " 'concrete_Network.maps',\n", + " 'concrete_Storage.maps',\n", + " 'concrete_FunctionAsAService.maps',\n", + " 'concrete_ComputingGroup.maps']\n" + ] + } + ], + "source": [ + "assocs = [\n", + " f\"{cname}::{aname}\"\n", + " for cname, c in meta_model.items()\n", + " for aname in c.associations\n", + "]\n", + "\n", + "pprint(assocs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'mm' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn [10], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m strings \u001b[39m=\u001b[39m [v\n\u001b[0;32m----> 2\u001b[0m \u001b[39mfor\u001b[39;00m c \u001b[39min\u001b[39;00m mm\u001b[39m.\u001b[39mvalues()\n\u001b[1;32m 3\u001b[0m \u001b[39mfor\u001b[39;00m a \u001b[39min\u001b[39;00m c\u001b[39m.\u001b[39mattributes\u001b[39m.\u001b[39mvalues()\n\u001b[1;32m 4\u001b[0m \u001b[39mif\u001b[39;00m a\u001b[39m.\u001b[39mdefault \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[39mfor\u001b[39;00m v \u001b[39min\u001b[39;00m a\u001b[39m.\u001b[39mdefault\n\u001b[1;32m 6\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39misinstance\u001b[39m(v, \u001b[39mstr\u001b[39m)]\n\u001b[1;32m 8\u001b[0m pprint(strings)\n", + "\u001b[0;31mNameError\u001b[0m: name 'mm' is not defined" + ] + } + ], + "source": [ + "strings = [v\n", + " for c in mm.values()\n", + " for a in c.attributes.values()\n", + " if a.default is not None\n", + " for v in a.default\n", + " if isinstance(v, str)]\n", + "\n", + "pprint(strings)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['commons_DOMLElement',\n", + " 'commons_Property',\n", + " 'commons_IProperty',\n", + " 'commons_SProperty',\n", + " 'commons_FProperty',\n", + " 'commons_BProperty',\n", + " 'commons_Configuration',\n", + " 'commons_Deployment',\n", + " 'application_ApplicationLayer',\n", + " 'application_ApplicationComponent',\n", + " 'application_SoftwareComponent',\n", + " 'application_SaaS',\n", + " 'application_SoftwareInterface',\n", + " 'application_DBMS',\n", + " 'application_SaaSDBMS',\n", + " 'infrastructure_InfrastructureLayer',\n", + " 'infrastructure_InfrastructureElement',\n", + " 'infrastructure_ComputingNode',\n", + " 'infrastructure_PhysicalComputingNode',\n", + " 'infrastructure_VirtualMachine',\n", + " 'infrastructure_Location',\n", + " 'infrastructure_Container',\n", + " 'infrastructure_ComputingNodeGenerator',\n", + " 'infrastructure_VMImage',\n", + " 'infrastructure_ContainerImage',\n", + " 'infrastructure_AutoScalingGroup',\n", + " 'infrastructure_Storage',\n", + " 'infrastructure_FunctionAsAService',\n", + " 'infrastructure_Network',\n", + " 'infrastructure_Subnet',\n", + " 'infrastructure_NetworkInterface',\n", + " 'infrastructure_InternetGateway',\n", + " 'infrastructure_ComputingGroup',\n", + " 'infrastructure_SecurityGroup',\n", + " 'infrastructure_Rule',\n", + " 'infrastructure_Credentials',\n", + " 'infrastructure_KeyPair',\n", + " 'infrastructure_UserPass',\n", + " 'infrastructure_SwarmRole',\n", + " 'infrastructure_Swarm',\n", + " 'infrastructure_ExtInfrastructureElement',\n", + " 'concrete_ConcreteInfrastructure',\n", + " 'concrete_ConcreteElement',\n", + " 'concrete_RuntimeProvider',\n", + " 'concrete_VirtualMachine',\n", + " 'concrete_VMImage',\n", + " 'concrete_ContainerImage',\n", + " 'concrete_Network',\n", + " 'concrete_Storage',\n", + " 'concrete_FunctionAsAService',\n", + " 'concrete_ComputingGroup']\n" + ] + } + ], + "source": [ + "keys = list(meta_model.keys())\n", + "\n", + "pprint(keys)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.11.0 ('.venv': poetry)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/mc_openapi/doml_mc/example_faas.ipynb b/mc_openapi/notebooks/example_faas.ipynb similarity index 98% rename from mc_openapi/doml_mc/example_faas.ipynb rename to mc_openapi/notebooks/example_faas.ipynb index 642003e845d962002106eaf3b16ba442ca60c5d3..b377059a68a10a6b6c3adbaeb424bfd59e37f9f8 100644 --- a/mc_openapi/doml_mc/example_faas.ipynb +++ b/mc_openapi/notebooks/example_faas.ipynb @@ -108,8 +108,8 @@ "assoc_sort, assoc = mk_association_sort_dict(mm, solver.ctx)\n", "attr_sort, attr = mk_attribute_sort_dict(mm, solver.ctx)\n", "elem_sort, elem = mk_elem_sort_dict(im, solver.ctx, unbound_elems)\n", - "ss_sort, ss = mk_stringsym_sort_dict(im, mm, solver.ctx)\n", - "AData = mk_adata_sort(ss_sort, solver.ctx)\n", + "str_sort, str = mk_stringsym_sort_dict(im, mm, solver.ctx)\n", + "AData = mk_adata_sort(str_sort, solver.ctx)\n", "elem_class_f = def_elem_class_f_and_assert_classes(\n", " im,\n", " solver,\n", @@ -132,7 +132,7 @@ " attr_sort,\n", " attr,\n", " AData,\n", - " ss\n", + " str\n", ")\n", "assoc_rel = def_association_rel(\n", " assoc_sort,\n", @@ -205,7 +205,7 @@ "print(\"Number of attributes (IM):\", n_attrs_im)\n", "n_assocs_im = sum(len(a) for e in im.values() for a in e.associations.values())\n", "print(\"Number of associations (IM):\", n_assocs_im)\n", - "print(\"Number of string symbols:\", len(ss))\n", + "print(\"Number of string symbols:\", len(str))\n", "print(\"Number of IM attribute assertions:\", n_elems)\n", "print(\"Number of IM association assertions:\", n_elems ** 2)" ] @@ -340,13 +340,13 @@ " Implies(\n", " And(\n", " elem_class_f(softwareComponent) == class_[\"application_SoftwareComponent\"],\n", - " # attr_rel(softwareComponent, attr[\"commons_DOMLElement::name\"], AData.ss(ss[\"web\"]))\n", + " # attr_rel(softwareComponent, attr[\"commons_DOMLElement::name\"], ADatastr(str[\"web\"]))\n", " ),\n", " Exists(\n", " [prop],\n", " And(\n", " elem_class_f(prop) == class_[\"commons_SProperty\"],\n", - " attr_rel(prop, attr[\"commons_Property::key\"], AData.ss(ss[\"source_code\"])),\n", + " attr_rel(prop, attr[\"commons_Property::key\"], ADatastr(str[\"source_code\"])),\n", " assoc_rel(softwareComponent, assoc[\"commons_DOMLElement::annotations\"], prop)\n", " )\n", " )\n", @@ -476,7 +476,7 @@ "assn = ForAll(\n", " [web],\n", " Implies(\n", - " attr_rel(web, attr[\"commons_DOMLElement::name\"], AData.ss(ss[\"web\"])),\n", + " attr_rel(web, attr[\"commons_DOMLElement::name\"], ADatastr(str[\"web\"])),\n", " Exists( # web is deployed on a container hosting a VM with an interface in network n\n", " [deployment, ielem1, ielem2, iface, rule],\n", " And(\n", @@ -488,7 +488,7 @@ " assoc_rel(sg, assoc[\"infrastructure_SecurityGroup::rules\"], rule),\n", " attr_rel(rule, attr[\"infrastructure_Rule::fromPort\"], AData.int(443)),\n", " attr_rel(rule, attr[\"infrastructure_Rule::toPort\"], AData.int(443)),\n", - " attr_rel(rule, attr[\"infrastructure_Rule::kind\"], AData.ss(ss[\"INGRESS\"]))\n", + " attr_rel(rule, attr[\"infrastructure_Rule::kind\"], ADatastr(str[\"INGRESS\"]))\n", " ),\n", " )\n", " )\n", diff --git a/mc_openapi/doml_mc/example_nginx.ipynb b/mc_openapi/notebooks/example_nginx.ipynb similarity index 97% rename from mc_openapi/doml_mc/example_nginx.ipynb rename to mc_openapi/notebooks/example_nginx.ipynb index 48fbd363bc85a58249393c5575ba6d2abcb05899..5d6213826f7166dc742f389feb62068f5d34c11d 100644 --- a/mc_openapi/doml_mc/example_nginx.ipynb +++ b/mc_openapi/notebooks/example_nginx.ipynb @@ -128,8 +128,8 @@ "assoc_sort, assoc = mk_association_sort_dict(mm, solver.ctx)\n", "attr_sort, attr = mk_attribute_sort_dict(mm, solver.ctx)\n", "elem_sort, elem = mk_elem_sort_dict(im, solver.ctx, unbound_elems)\n", - "ss_sort, ss = mk_stringsym_sort_dict(im, mm, solver.ctx)\n", - "AData = mk_adata_sort(ss_sort, solver.ctx)\n", + "str_sort, str = mk_stringsym_sort_dict(im, mm, solver.ctx)\n", + "AData = mk_adata_sort(str_sort, solver.ctx)\n", "elem_class_f = def_elem_class_f_and_assert_classes(\n", " im,\n", " solver,\n", @@ -152,7 +152,7 @@ " attr_sort,\n", " attr,\n", " AData,\n", - " ss\n", + " str\n", ")\n", "assoc_rel = def_association_rel(\n", " assoc_sort,\n", @@ -225,7 +225,7 @@ "print(\"Number of attributes (IM):\", n_attrs_im)\n", "n_assocs_im = sum(len(a) for e in im.values() for a in e.associations.values())\n", "print(\"Number of associations (IM):\", n_assocs_im)\n", - "print(\"Number of string symbols:\", len(ss))\n", + "print(\"Number of string symbols:\", len(str))\n", "print(\"Number of IM attribute assertions:\", n_elems)\n", "print(\"Number of IM association assertions:\", n_elems ** 2)" ] @@ -324,13 +324,13 @@ " Implies(\n", " And(\n", " elem_class_f(softwareComponent) == class_[\"application_SoftwareComponent\"],\n", - " attr_rel(softwareComponent, attr[\"commons_DOMLElement::name\"], AData.ss(ss[\"nginx\"]))\n", + " attr_rel(softwareComponent, attr[\"commons_DOMLElement::name\"], ADatastr(str[\"nginx\"]))\n", " ),\n", " Exists(\n", " [prop],\n", " And(\n", " elem_class_f(prop) == class_[\"commons_SProperty\"],\n", - " attr_rel(prop, attr[\"commons_Property::key\"], AData.ss(ss[\"source_code\"])),\n", + " attr_rel(prop, attr[\"commons_Property::key\"], ADatastr(str[\"source_code\"])),\n", " assoc_rel(softwareComponent, assoc[\"commons_DOMLElement::annotations\"], prop)\n", " )\n", " )\n", diff --git a/mc_openapi/notebooks/find_missing_requirement.ipynb b/mc_openapi/notebooks/find_missing_requirement.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..8229d3b7ffdee975f835a143300012e2767a126c --- /dev/null +++ b/mc_openapi/notebooks/find_missing_requirement.ipynb @@ -0,0 +1,500 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Finding Missing Requirements\n", + "\n", + "In this notebook, I try to put together an iterative way to:\n", + "1. Add *unbound variables* until the requirement is satisfied\n", + "2. Get the *relationships* of the unbound variables\n", + "3. Filter these relationships by adding one at a time as a negated constraint\n", + " and check again the model.\n", + "4. When we find the one that makes the model unsat, it means we've found the right one.\n", + "\n", + "#### Goals\n", + "- Make the search of finding the correct relationship as fast as possible:\n", + " usually relationships are quite a lot, and we need to iterate them at least a\n", + " couple of times. We can add progressively only the relationships that remain\n", + " after each pass, always one at a time and checking the model again." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "from mc_openapi.doml_mc.intermediate_model.metamodel import parse_metamodel, parse_inverse_associations\n", + "from mc_openapi.doml_mc.xmi_parser.doml_model import parse_doml_model\n", + "from mc_openapi.doml_mc.xmi_parser.doml_model import parse_xmi_model\n", + "from mc_openapi.doml_mc import DOMLVersion\n", + "from z3 import Solver, Model, DatatypeSortRef, FuncDeclRef, Consts, Const, ForAll, Exists, Implies, And, Or, Not, Bools, sat, unsat\n", + "import yaml\n", + "\n", + "from mc_openapi.doml_mc.z3encoding.metamodel_encoding import (\n", + " def_association_rel,\n", + " def_attribute_rel,\n", + " mk_association_sort_dict,\n", + " mk_attribute_sort_dict,\n", + " mk_class_sort_dict\n", + ")\n", + "from mc_openapi.doml_mc.z3encoding.im_encoding import (\n", + " assert_im_associations,\n", + " assert_im_attributes,\n", + " def_elem_class_f_and_assert_classes,\n", + " mk_elem_sort_dict,\n", + " mk_stringsym_sort_dict,\n", + " mk_attr_data_sort\n", + ")\n", + "from mc_openapi.doml_mc.z3encoding.types import Refs\n", + "\n", + "from itertools import product\n", + "from operator import itemgetter" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"../assets/doml_meta_v2.0.yaml\") as mmf:\n", + " mmdoc = yaml.load(mmf, yaml.Loader)\n", + "mm = parse_metamodel(mmdoc)\n", + "inv_assoc = parse_inverse_associations(mmdoc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**You can change here the input DOML file**" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0.domlx\"\n", + "doml_document_path = \"../../tests/doml/v2.0/nginx-openstack_v2.0_wrong_vm_iface.domlx\"\n", + "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0_wrong_iface_uniq.domlx\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "with open(doml_document_path, \"rb\") as xmif:\n", + " doc = xmif.read()\n", + "\n", + "im, _ = parse_doml_model(doc, DOMLVersion.V2_0)\n", + "doml_xmi = parse_xmi_model(doc, DOMLVersion.V2_0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need to initialize each time the Solver context before iterating,\n", + "since an unbound variable is an element, and elements are an EnumSort,\n", + "and EnumSorts cannot be modified and depend on the solver context.\n", + "\n", + "The following code is stuff that is already present in the `IntermediateModelChecker`." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Dict\n", + "\n", + "Context = Dict" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "def initialize_solver(\n", + " unbound_elems_quantity: int = 0,\n", + " requirements: list = []\n", + ") -> Context:\n", + " ctx = dict()\n", + " \n", + " ctx[\"solver\"] = Solver()\n", + "\n", + " ctx[\"class_sort\"], ctx[\"class_\"] = mk_class_sort_dict(mm, ctx[\"solver\"].ctx)\n", + " ctx[\"assoc_sort\"], ctx[\"assoc\"] = mk_association_sort_dict(mm, ctx[\"solver\"].ctx)\n", + " ctx[\"attr_sort\"], ctx[\"attr\"] = mk_attribute_sort_dict(mm, ctx[\"solver\"].ctx)\n", + " ctx[\"str_sort\"], ctx[\"str\"] = mk_stringsym_sort_dict(im, mm, ctx[\"solver\"].ctx)\n", + " ctx[\"attr_data_sort\"] = mk_attr_data_sort(ctx[\"str_sort\"], ctx[\"solver\"].ctx)\n", + "\n", + " ctx[\"unbound_elems\"] = [f\"unbound{i}\" for i in range(unbound_elems_quantity)]\n", + " ctx[\"elem_sort\"], ctx[\"elem\"] = mk_elem_sort_dict(im, ctx[\"solver\"].ctx, ctx[\"unbound_elems\"])\n", + "\n", + " ctx[\"elem_class_f\"] = def_elem_class_f_and_assert_classes(\n", + " im,\n", + " ctx[\"solver\"],\n", + " ctx[\"elem_sort\"],\n", + " ctx[\"elem\"],\n", + " ctx[\"class_sort\"],\n", + " ctx[\"class_\"]\n", + " )\n", + " # attr_rel :: (elem_sort, attr_sort, attr_data_sort) -> BoolRef\n", + " ctx[\"attr_rel\"] = def_attribute_rel(\n", + " ctx[\"attr_sort\"],\n", + " ctx[\"elem_sort\"],\n", + " ctx[\"attr_data_sort\"]\n", + " )\n", + " assert_im_attributes(\n", + " ctx[\"attr_rel\"],\n", + " ctx[\"solver\"],\n", + " im,\n", + " mm,\n", + " ctx[\"elem\"],\n", + " ctx[\"attr_sort\"],\n", + " ctx[\"attr\"],\n", + " ctx[\"attr_data_sort\"],\n", + " ctx[\"str\"]\n", + " )\n", + "\n", + " # assoc_rel :: (elem_sort, assoc_sort, elem_sort) -> BoolRef\n", + " ctx[\"assoc_rel\"] = def_association_rel(\n", + " ctx[\"assoc_sort\"],\n", + " ctx[\"elem_sort\"]\n", + " )\n", + " assert_im_associations(\n", + " ctx[\"assoc_rel\"],\n", + " ctx[\"solver\"],\n", + " {k: v for k, v in im.items() if k not in ctx[\"unbound_elems\"]},\n", + " ctx[\"elem\"],\n", + " ctx[\"assoc_sort\"],\n", + " ctx[\"assoc\"],\n", + " )\n", + "\n", + " # Add requirements\n", + " for req in requirements:\n", + " req(ctx)\n", + "\n", + " return ctx" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "def req_every_vm_has_iface(ctx: Context): \n", + " vm, iface = Consts(\"vm iface\", ctx[\"elem_sort\"])\n", + " vmIfaceAssertion = ForAll(\n", + " [vm],\n", + " Implies(\n", + " ctx[\"elem_class_f\"](vm) == ctx[\"class_\"][\"infrastructure_VirtualMachine\"],\n", + " Exists(\n", + " [iface],\n", + " And(\n", + " ctx[\"assoc_rel\"](vm, ctx[\"assoc\"][\"infrastructure_ComputingNode::ifaces\"], iface)\n", + " )\n", + " )\n", + " )\n", + " )\n", + " ctx[\"solver\"].assert_and_track(vmIfaceAssertion, \"vm_iface\")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "def req_every_iface_has_a_secgroup(ctx):\n", + " sg, iface = Consts(\"sg iface\", ctx[\"elem_sort\"])\n", + " vmIfaceSecGroupAssertion = ForAll(\n", + " [sg],\n", + " Implies(\n", + " ctx[\"elem_class_f\"](sg) == ctx[\"class_\"][\"infrastructure_SecurityGroup\"],\n", + " Exists([iface], \n", + " ctx[\"assoc_rel\"](iface, ctx[\"assoc\"][\"infrastructure_NetworkInterface::associated\"], sg)\n", + " )\n", + " )\n", + " )\n", + " ctx[\"solver\"].assert_and_track(vmIfaceSecGroupAssertion, \"vm_secgroup\")" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "# There are no duplicated interfaces.\n", + "def req_iface_uniq(ctx):\n", + " endPointAttr = ctx[\"attr\"][\"infrastructure_NetworkInterface::endPoint\"]\n", + " ni1, ni2 = Consts(\"ni1, ni2\", ctx[\"elem_sort\"])\n", + " value = Const(\"value\", ctx[\"attr_data_sort\"])\n", + " uniqueIfaceAssertion = And(\n", + " ctx[\"attr_rel\"](ni1, endPointAttr, value),\n", + " ctx[\"attr_rel\"](ni2, endPointAttr, value),\n", + " ni1 != ni2,\n", + " )\n", + " ctx[\"solver\"].assert_and_track(uniqueIfaceAssertion, \"unique_iface\")" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "def check_with_ubvars(ubvars_n: int = 0, requirements: list = []) -> Context:\n", + " ctx = initialize_solver(ubvars_n, requirements)\n", + " solver = ctx[\"solver\"]\n", + "\n", + " res = solver.check()\n", + "\n", + " if res == sat:\n", + " print(f\"Sat with {ubvars_n} unbounded variables\")\n", + " return ctx\n", + " elif res == unsat:\n", + " # print(f\"ubvars={ubvars_n}; UNSAT_CORE:\")\n", + " # print(solver.unsat_core())\n", + " print(f\"Increasing unbound vars to {ubvars_n + 1}\")\n", + " return check_with_ubvars(ubvars_n + 1, requirements=requirements)\n", + " else:\n", + " raise RuntimeError(\"It took too long to decide.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "REQUIREMENTS = [\n", + " req_every_vm_has_iface,\n", + " req_every_iface_has_a_secgroup,\n", + " req_iface_uniq\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Increasing unbound vars to 1\n", + "Increasing unbound vars to 2\n", + "Sat with 2 unbounded variables\n" + ] + } + ], + "source": [ + "solved_ctx = check_with_ubvars(requirements=REQUIREMENTS)\n", + "solved_model = solved_ctx[\"solver\"].model()" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "def get_ubvars_and_assoc(ctx: Context, model: Model):\n", + " elem, assoc, assoc_rel, unbound_elems = itemgetter(\"elem\", \"assoc\", \"assoc_rel\", \"unbound_elems\")(ctx)\n", + "\n", + " return [ ((e1n, e1), a, (e2n, e2)) \n", + " for (e1n, e1), a, (e2n, e2) in product(elem.items(), assoc.values(), elem.items()) \n", + " if (e1n in unbound_elems or e2n in unbound_elems) and model.eval(assoc_rel(e1, a, e2))\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "def pretty_ubvar_assoc(assoc):\n", + " (e1n, e1), a, (e2n, e2) = assoc\n", + " tokens = str(str(e1) + \" \" + str(a) + \" \" + str(e2)).split()\n", + " ret_str = \"\"\n", + " for token in tokens:\n", + " if token[0:4] == \"elem\":\n", + " value = im.get(token)\n", + " ret_str += f\"{value.class_} ({value.user_friendly_name})\" if value else f\"<'{token}' not found>\"\n", + " else:\n", + " ret_str += token\n", + " ret_str += \" \"\n", + " return ret_str.strip()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see, there are many associations that involve the unbound variable `unbound0`.\n", + "We can see that between them, there is the one we really want:\n", + "\n", + "`infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound0`\n", + "\n", + "We now need to filter out all the others, by taking one of these lines at a time, and adding it as a negated constraint.\n", + "\n", + "NOTE: It appears that the list is not deterministic. Sometimes at the end there are associations that start from `unbound0`, sometimes there is none. " + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "ubvars_and_assoc = get_ubvars_and_assoc(solved_ctx, solved_model)\n", + "# print(\"\\n\".join([pretty_ubvar_assoc(assoc) for assoc in ubvars_and_assoc]))" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-----------------------------------------\n", + "\tAdd constraint Not(infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound0)\n" + ] + }, + { + "ename": "Z3Exception", + "evalue": "True, False or Z3 Boolean expression expected. Received [__neg_{e1_name}_{str(a)}_{e2_name}] of type <class 'list'>", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mZ3Exception\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn [52], line 44\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m\"\u001b[39m\u001b[39m\\t\u001b[39;00m\u001b[39m\\t\u001b[39;00m\u001b[39m\"\u001b[39m \u001b[39m+\u001b[39m \u001b[39m\"\u001b[39m\u001b[39m\\n\u001b[39;00m\u001b[39m\\t\u001b[39;00m\u001b[39m\\t\u001b[39;00m\u001b[39m\"\u001b[39m\u001b[39m.\u001b[39mjoin([pretty_ubvar_assoc(assoc) \u001b[39mfor\u001b[39;00m assoc \u001b[39min\u001b[39;00m ubvars_and_assoc[\u001b[39m1\u001b[39m:]]))\n\u001b[1;32m 41\u001b[0m \u001b[39mreturn\u001b[39;00m [\u001b[39m*\u001b[39m\u001b[39mset\u001b[39m([assoc] \u001b[39m+\u001b[39m thin_ubvars_and_assoc(ctx, ubvars_and_assoc[\u001b[39m1\u001b[39m:]))]\n\u001b[0;32m---> 44\u001b[0m assoc_to_implement \u001b[39m=\u001b[39m thin_ubvars_and_assoc(solved_ctx, ubvars_and_assoc)\n", + "Cell \u001b[0;32mIn [52], line 18\u001b[0m, in \u001b[0;36mthin_ubvars_and_assoc\u001b[0;34m(ctx, ubvars_and_assoc)\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[39m# ctx[\"solver\"].assert_and_track(Not(assoc_rel), f\"__neg_{e1_name}_{str(a)}_{e2_name}\")\u001b[39;00m\n\u001b[1;32m 17\u001b[0m x \u001b[39m=\u001b[39m Bools(\u001b[39m\"\u001b[39m\u001b[39m__neg_\u001b[39m\u001b[39m{e1_name}\u001b[39;00m\u001b[39m_\u001b[39m\u001b[39m{\u001b[39m\u001b[39mstr(a)}_\u001b[39m\u001b[39m{e2_name}\u001b[39;00m\u001b[39m\"\u001b[39m)\n\u001b[0;32m---> 18\u001b[0m ctx[\u001b[39m\"\u001b[39m\u001b[39msolver\u001b[39m\u001b[39m\"\u001b[39m]\u001b[39m.\u001b[39madd(Implies(x, Not(assoc_rel)))\n\u001b[1;32m 20\u001b[0m res \u001b[39m=\u001b[39m ctx[\u001b[39m\"\u001b[39m\u001b[39msolver\u001b[39m\u001b[39m\"\u001b[39m]\u001b[39m.\u001b[39mcheck()\n\u001b[1;32m 21\u001b[0m \u001b[39mif\u001b[39;00m res \u001b[39m==\u001b[39m sat:\n", + "File \u001b[0;32m~/Projects/piacere-model-checker/.venv/lib/python3.10/site-packages/z3/z3.py:1785\u001b[0m, in \u001b[0;36mImplies\u001b[0;34m(a, b, ctx)\u001b[0m\n\u001b[1;32m 1783\u001b[0m ctx \u001b[39m=\u001b[39m _get_ctx(_ctx_from_ast_arg_list([a, b], ctx))\n\u001b[1;32m 1784\u001b[0m s \u001b[39m=\u001b[39m BoolSort(ctx)\n\u001b[0;32m-> 1785\u001b[0m a \u001b[39m=\u001b[39m s\u001b[39m.\u001b[39;49mcast(a)\n\u001b[1;32m 1786\u001b[0m b \u001b[39m=\u001b[39m s\u001b[39m.\u001b[39mcast(b)\n\u001b[1;32m 1787\u001b[0m \u001b[39mreturn\u001b[39;00m BoolRef(Z3_mk_implies(ctx\u001b[39m.\u001b[39mref(), a\u001b[39m.\u001b[39mas_ast(), b\u001b[39m.\u001b[39mas_ast()), ctx)\n", + "File \u001b[0;32m~/Projects/piacere-model-checker/.venv/lib/python3.10/site-packages/z3/z3.py:1528\u001b[0m, in \u001b[0;36mBoolSortRef.cast\u001b[0;34m(self, val)\u001b[0m\n\u001b[1;32m 1526\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m is_expr(val):\n\u001b[1;32m 1527\u001b[0m msg \u001b[39m=\u001b[39m \u001b[39m\"\u001b[39m\u001b[39mTrue, False or Z3 Boolean expression expected. Received \u001b[39m\u001b[39m%s\u001b[39;00m\u001b[39m of type \u001b[39m\u001b[39m%s\u001b[39;00m\u001b[39m\"\u001b[39m\n\u001b[0;32m-> 1528\u001b[0m _z3_assert(is_expr(val), msg \u001b[39m%\u001b[39;49m (val, \u001b[39mtype\u001b[39;49m(val)))\n\u001b[1;32m 1529\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39meq(val\u001b[39m.\u001b[39msort()):\n\u001b[1;32m 1530\u001b[0m _z3_assert(\u001b[39mself\u001b[39m\u001b[39m.\u001b[39meq(val\u001b[39m.\u001b[39msort()), \u001b[39m\"\u001b[39m\u001b[39mValue cannot be converted into a Z3 Boolean value\u001b[39m\u001b[39m\"\u001b[39m)\n", + "File \u001b[0;32m~/Projects/piacere-model-checker/.venv/lib/python3.10/site-packages/z3/z3.py:107\u001b[0m, in \u001b[0;36m_z3_assert\u001b[0;34m(cond, msg)\u001b[0m\n\u001b[1;32m 105\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m_z3_assert\u001b[39m(cond, msg):\n\u001b[1;32m 106\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m cond:\n\u001b[0;32m--> 107\u001b[0m \u001b[39mraise\u001b[39;00m Z3Exception(msg)\n", + "\u001b[0;31mZ3Exception\u001b[0m: True, False or Z3 Boolean expression expected. Received [__neg_{e1_name}_{str(a)}_{e2_name}] of type <class 'list'>" + ] + } + ], + "source": [ + "def thin_ubvars_and_assoc(ctx: Context, ubvars_and_assoc: list):\n", + " \"\"\"Returns a tuple where the first item is\n", + " \"\"\"\n", + " if not ubvars_and_assoc:\n", + " return []\n", + "\n", + "\n", + " (e1_name, e1), a, (e2_name, e2) = assoc = ubvars_and_assoc[0]\n", + " assoc_rel = ctx[\"assoc_rel\"](e1, a, e2)\n", + " \n", + " print(\"-----------------------------------------\")\n", + "\n", + " # Add negated constraint\n", + " print(f\"\\tAdd constraint Not({pretty_ubvar_assoc(ubvars_and_assoc[0])})\")\n", + " ctx[\"solver\"].push()\n", + " # ctx[\"solver\"].assert_and_track(Not(assoc_rel), f\"__neg_{e1_name}_{str(a)}_{e2_name}\")\n", + " ctx[\"solver\"].add(Not(assoc_rel))\n", + " \n", + " res = ctx[\"solver\"].check()\n", + " if res == sat:\n", + " print(\"SAT:\\tAdding one more constraint and trying again\")\n", + " # Get new ubvars_and_assoc\n", + " model = ctx[\"solver\"].model()\n", + " thinned_ubvars_and_assoc = get_ubvars_and_assoc(ctx, model)\n", + " \n", + " # Print table showing the diff\n", + " from difflib import context_diff\n", + " uvar_as_text = lambda input: [pretty_ubvar_assoc(assoc) for assoc in input]\n", + " print(\"\\n\".join([a for a in context_diff(uvar_as_text(ubvars_and_assoc), uvar_as_text(thinned_ubvars_and_assoc), lineterm=\"\", fromfile='Before', tofile=\"After\")]))\n", + "\n", + " # Iterate\n", + " return thin_ubvars_and_assoc(ctx, thinned_ubvars_and_assoc)\n", + " else:\n", + " print(\"UNSAT\\tLast constraint was the association we are looking for!\")\n", + " ctx[\"solver\"].pop()\n", + " \n", + " if ubvars_and_assoc[1:]:\n", + " print(\"\\tIterating over\")\n", + " print(\"\\t\\t\" + \"\\n\\t\\t\".join([pretty_ubvar_assoc(assoc) for assoc in ubvars_and_assoc[1:]]))\n", + " return [*set([assoc] + thin_ubvars_and_assoc(ctx, ubvars_and_assoc[1:]))]\n", + "\n", + "\n", + "assoc_to_implement = thin_ubvars_and_assoc(solved_ctx, ubvars_and_assoc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound1\n", + "unbound1 infrastructure_NetworkInterface::associated infrastructure_SecurityGroup (sg)\n" + ] + } + ], + "source": [ + "print(\"\\n\".join([pretty_ubvar_assoc(assoc) for assoc in assoc_to_implement]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From here, we should then add this in the Intermediate Model, and then in the ECore (?) to generate the DOML file somehow.\n", + "\n", + "We can then provide the new file, or a diff to be patched onto the original?" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.7 ('.venv': poetry)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/mc_openapi/notebooks/find_missing_requirement_with_attrs.ipynb b/mc_openapi/notebooks/find_missing_requirement_with_attrs.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..a30bc463263626ab2c0341274b13f75b22d171ef --- /dev/null +++ b/mc_openapi/notebooks/find_missing_requirement_with_attrs.ipynb @@ -0,0 +1,773 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Finding Missing Requirements (with Attributes)\n", + "\n", + "In this notebook, I try to put together an iterative way to:\n", + "1. Add *unbound variables* until the requirement is satisfied\n", + "2. Get the *relationships* of the unbound variables\n", + "3. Filter these relationships by adding one at a time as a negated constraint\n", + " and check again the model.\n", + "4. When we find the one that makes the model unsat, it means we've found the right one.\n", + "\n", + "#### Goals\n", + "- Make the search of finding the correct relationship as fast as possible:\n", + " usually relationships are quite a lot, and we need to iterate them at least a\n", + " couple of times. We can add progressively only the relationships that remain\n", + " after each pass, always one at a time and checking the model again." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "from itertools import product\n", + "from operator import itemgetter\n", + "\n", + "import yaml\n", + "from z3 import (And, Const, Consts, DatatypeSortRef, Exists, ForAll,\n", + " FuncDeclRef, Implies, Model, Not, Or, Solver, sat, unsat)\n", + "\n", + "from mc_openapi.doml_mc import DOMLVersion\n", + "from mc_openapi.doml_mc.intermediate_model.metamodel import (\n", + " parse_inverse_associations, parse_metamodel)\n", + "from mc_openapi.doml_mc.xmi_parser.doml_model import (parse_doml_model,\n", + " parse_xmi_model)\n", + "from mc_openapi.doml_mc.z3encoding.im_encoding import (\n", + " assert_im_associations, assert_im_attributes,\n", + " def_elem_class_f_and_assert_classes, mk_attr_data_sort, mk_elem_sort_dict,\n", + " mk_stringsym_sort_dict)\n", + "from mc_openapi.doml_mc.z3encoding.metamodel_encoding import (\n", + " def_association_rel, def_attribute_rel, mk_association_sort_dict,\n", + " mk_attribute_sort_dict, mk_class_sort_dict)\n", + "from mc_openapi.doml_mc.z3encoding.types import Refs" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"../assets/doml_meta_v2.0.yaml\") as mmf:\n", + " mmdoc = yaml.load(mmf, yaml.Loader)\n", + "mm = parse_metamodel(mmdoc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**You can change here the input DOML file**" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0.domlx\"\n", + "# doml_document_path = \"../../tests/doml/v2.0/nginx-openstack_v2.0_wrong_vm_iface.domlx\"\n", + "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0_wrong_iface_uniq.domlx\"\n", + "# doml_document_path = \"../../tests/doml/saas_no_https_rule.domlx\"\n", + "# doml_document_path = \"../../tests/doml/saas_https_no_attrs.domlx\"\n", + "doml_document_path = \"../../tests/doml/openstack_template.domlx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "with open(doml_document_path, \"rb\") as xmif:\n", + " doc = xmif.read()\n", + "\n", + "im, _ = parse_doml_model(doc, DOMLVersion.V2_0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need to initialize each time the Solver context before iterating,\n", + "since an unbound variable is an element, and elements are an EnumSort,\n", + "and EnumSorts cannot be modified and depend on the solver context.\n", + "\n", + "The following code is stuff that is already present in the `IntermediateModelChecker`." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Dict\n", + "\n", + "Context = Dict" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "from mc_openapi.doml_mc.intermediate_model.metamodel import get_mangled_attribute_defaults\n", + "\n", + "\n", + "def initialize_solver(\n", + " unbound_elems_quantity: int = 0,\n", + " unbound_values_quantity: int = 0,\n", + " requirements: list = []\n", + ") -> Context:\n", + " ctx = dict()\n", + " \n", + " ctx[\"solver\"] = Solver()\n", + "\n", + " ctx[\"class_sort\"], ctx[\"class_\"] = mk_class_sort_dict(mm, ctx[\"solver\"].ctx)\n", + " ctx[\"assoc_sort\"], ctx[\"assoc\"] = mk_association_sort_dict(mm, ctx[\"solver\"].ctx)\n", + " ctx[\"attr_sort\"], ctx[\"attr\"] = mk_attribute_sort_dict(mm, ctx[\"solver\"].ctx)\n", + " ctx[\"str_sort\"], ctx[\"str\"] = mk_stringsym_sort_dict(im, mm, ctx[\"solver\"].ctx)\n", + " ctx[\"attr_data_sort\"] = mk_attr_data_sort(ctx[\"str_sort\"], ctx[\"solver\"].ctx)\n", + "\n", + " ctx[\"unbound_elems\"] = [f\"unbound_elem_{i}\" for i in range(unbound_elems_quantity)]\n", + "\n", + " # Takes a list of strings and creates an Enum out of 'em\n", + " ctx[\"elem_sort\"], ctx[\"elem\"] = mk_elem_sort_dict(im, ctx[\"solver\"].ctx, ctx[\"unbound_elems\"])\n", + "\n", + " ub_val_names = [f\"unbound_val_{i}\" for i in range(unbound_values_quantity)]\n", + " ctx[\"unbound_values\"] = {\n", + " name : ctx[\"attr_data_sort\"].placeholder for name in ub_val_names\n", + " }\n", + " # Examples of values that can go in unbound_values:\n", + " # ctx[\"attr_data_sort\"].int(42), # ok\n", + " # ctx[\"attr_data_sort\"].bool(True), # ok\n", + " # ctx[\"attr_data_sort\"].str(\"x\"), # cant do: it accept a ctx[\"str\"][<str_key>] as input\n", + " # Const(\"x\", ctx[\"attr_data_sort\"]) # cant do: it is a symbolic value that cannot be converted to a BoolRef expression\n", + "\n", + " ctx[\"elem_class_f\"] = def_elem_class_f_and_assert_classes(\n", + " im,\n", + " ctx[\"solver\"],\n", + " ctx[\"elem_sort\"],\n", + " ctx[\"elem\"],\n", + " ctx[\"class_sort\"],\n", + " ctx[\"class_\"]\n", + " )\n", + " \n", + " # attr_rel :: (elem_sort, attr_sort, attr_data_sort) -> BoolRef\n", + " ctx[\"attr_rel\"] = def_attribute_rel(\n", + " ctx[\"attr_sort\"],\n", + " ctx[\"elem_sort\"],\n", + " ctx[\"attr_data_sort\"]\n", + " )\n", + "\n", + " assert_im_attributes(\n", + " ctx[\"attr_rel\"],\n", + " ctx[\"solver\"],\n", + " im,\n", + " mm,\n", + " ctx[\"elem\"],\n", + " ctx[\"attr_sort\"],\n", + " ctx[\"attr\"],\n", + " ctx[\"attr_data_sort\"],\n", + " ctx[\"str\"]\n", + " )\n", + "\n", + " # assoc_rel :: (elem_sort, assoc_sort, elem_sort) -> BoolRef\n", + " ctx[\"assoc_rel\"] = def_association_rel(\n", + " ctx[\"assoc_sort\"],\n", + " ctx[\"elem_sort\"]\n", + " )\n", + " \n", + " assert_im_associations(\n", + " ctx[\"assoc_rel\"],\n", + " ctx[\"solver\"],\n", + " {k: v for k, v in im.items() if k not in ctx[\"unbound_elems\"]},\n", + " ctx[\"elem\"],\n", + " ctx[\"assoc_sort\"],\n", + " ctx[\"assoc\"],\n", + " )\n", + "\n", + " # Add requirements\n", + " for req in requirements:\n", + " req(ctx)\n", + "\n", + " return ctx" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "def req_every_vm_has_iface(ctx: Context): \n", + " vm, iface = Consts(\"vm iface\", ctx[\"elem_sort\"])\n", + " vmIfaceAssertion = ForAll(\n", + " [vm],\n", + " Implies(\n", + " ctx[\"elem_class_f\"](vm) == ctx[\"class_\"][\"infrastructure_VirtualMachine\"],\n", + " Exists(\n", + " [iface],\n", + " And(\n", + " ctx[\"assoc_rel\"](vm, ctx[\"assoc\"][\"infrastructure_ComputingNode::ifaces\"], iface)\n", + " )\n", + " )\n", + " )\n", + " )\n", + " ctx[\"solver\"].assert_and_track(vmIfaceAssertion, \"vm_iface\")" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "def req_every_vm_has_cpucount(ctx: Context): \n", + " vm = Const(\"vm\", ctx[\"elem_sort\"])\n", + " CpuCount = Const(\"cpucount\", ctx[\"attr_data_sort\"])\n", + " vmIfaceAssertion = ForAll(\n", + " [vm],\n", + " Implies(\n", + " ctx[\"elem_class_f\"](vm) == ctx[\"class_\"][\"infrastructure_VirtualMachine\"],\n", + " Exists(\n", + " [CpuCount],\n", + " And(\n", + " ctx[\"attr_rel\"](vm, ctx[\"attr\"][\"infrastructure_ComputingNode::cpu_count\"], CpuCount)\n", + " )\n", + " )\n", + " )\n", + " )\n", + " ctx[\"solver\"].assert_and_track(vmIfaceAssertion, \"vm_cpucount\")" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "def req_every_iface_has_a_secgroup(ctx):\n", + " sg, iface = Consts(\"sg iface\", ctx[\"elem_sort\"])\n", + " vmIfaceSecGroupAssertion = ForAll(\n", + " [sg],\n", + " Implies(\n", + " ctx[\"elem_class_f\"](sg) == ctx[\"class_\"][\"infrastructure_SecurityGroup\"],\n", + " Exists([iface], \n", + " ctx[\"assoc_rel\"](iface, ctx[\"assoc\"][\"infrastructure_NetworkInterface::associated\"], sg)\n", + " )\n", + " )\n", + " )\n", + " ctx[\"solver\"].assert_and_track(vmIfaceSecGroupAssertion, \"vm_secgroup\")" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "def req_iface_uniq(ctx):\n", + " endPointAttr = ctx[\"attr\"][\"infrastructure_NetworkInterface::endPoint\"]\n", + " ni1, ni2 = Consts(\"ni1 ni2\", ctx[\"elem_sort\"])\n", + " value = Const(\"value\", ctx[\"attr_data_sort\"])\n", + " uniqueIfaceAssertion = And(\n", + " ctx[\"attr_rel\"](ni1, endPointAttr, value),\n", + " ctx[\"attr_rel\"](ni2, endPointAttr, value),\n", + " ni1 != ni2,\n", + " )\n", + " ctx[\"solver\"].assert_and_track(uniqueIfaceAssertion, \"unique_iface\")" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "def req_external_services_must_have_https(ctx):\n", + " saas, sw_iface, sw_comp, deployment, ielem, net_iface, sec_group, rule = Consts(\"saas, sw_iface, sw_comp, deployment, ielem, net_iface, sec_group, rule\", ctx[\"elem_sort\"])\n", + " assertion = ForAll(\n", + " [saas, sec_group, sw_iface, sw_comp, deployment, ielem, net_iface],\n", + " Implies(\n", + " And(\n", + " ctx[\"elem_class_f\"](saas) == ctx[\"class_\"][\"application_SaaS\"],\n", + " ctx[\"elem_class_f\"](sec_group) == ctx[\"class_\"][\"infrastructure_SecurityGroup\"],\n", + " ctx[\"assoc_rel\"](saas, ctx[\"assoc\"][\"application_SaaS::exposedInterfaces\"], sw_iface),\n", + " ctx[\"assoc_rel\"](sw_comp, ctx[\"assoc\"][\"application_SoftwareComponent::consumedInterfaces\"], sw_iface),\n", + " ctx[\"assoc_rel\"](deployment, ctx[\"assoc\"][\"commons_Deployment::component\"], sw_comp),\n", + " ctx[\"assoc_rel\"](deployment, ctx[\"assoc\"][\"commons_Deployment::node\"], ielem),\n", + " ctx[\"assoc_rel\"](ielem, ctx[\"assoc\"][\"infrastructure_ComputingNode::ifaces\"], net_iface),\n", + " ctx[\"assoc_rel\"](net_iface, ctx[\"assoc\"][\"infrastructure_NetworkInterface::associated\"], sec_group),\n", + " ctx[\"assoc_rel\"](sec_group, ctx[\"assoc\"][\"infrastructure_SecurityGroup::rules\"], rule),\n", + " ),\n", + " Exists([rule],\n", + " And(\n", + " # Every node that contacts an external service should belong to a security group implementing HTTPS\n", + " ctx[\"attr_rel\"](rule, ctx[\"attr\"][\"infrastructure_Rule::fromPort\"], ctx[\"attr_data_sort\"].int(443)),\n", + " ctx[\"attr_rel\"](rule, ctx[\"attr\"][\"infrastructure_Rule::toPort\"], ctx[\"attr_data_sort\"].int(443)),\n", + " ctx[\"attr_rel\"](rule, ctx[\"attr\"][\"infrastructure_Rule::kind\"], ctx[\"attr_data_sort\"].str(ctx[\"str\"][\"INGRESS\"]))\n", + " )\n", + " )\n", + " )\n", + " )\n", + " ctx[\"solver\"].assert_and_track(assertion, \"ext_service_https\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### REMEMBER TO ADD REQUIREMENTS TO THE LIST!" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "REQUIREMENTS = [\n", + " req_every_vm_has_iface,\n", + " # req_every_vm_has_cpucount\n", + " # req_every_iface_has_a_secgroup,\n", + " # req_iface_uniq,\n", + " # req_external_services_must_have_https\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "def check_iteratively(ubelems_n: int = 0, ubvals_n: int = 0, requirements: list = [], curr_try: int = 0, max_tries: int = 10) -> Context:\n", + " if curr_try > max_tries:\n", + " raise RuntimeError(\"Max tries exceeded.\")\n", + "\n", + " ctx = initialize_solver(ubelems_n, ubvals_n, requirements)\n", + " solver = ctx[\"solver\"]\n", + "\n", + " res = solver.check()\n", + "\n", + " if res == sat:\n", + " print(\"\\033[92m\" + f\"<Sat>\\tubelems_n={ubelems_n}, ubvals_n={ubvals_n}\" + \"\\033[0m\")\n", + " return ctx\n", + " elif res == unsat:\n", + " print(\"\\033[91m\" + f\"<Unsat>\\tubelems_n={ubelems_n}, ubvals_n={ubvals_n}\" + \"\\033[0m\")\n", + " if ubelems_n > ubvals_n:\n", + " new_ubvals_n = ubvals_n * 2 if ubvals_n >= 1 else 1\n", + " return check_iteratively(ubelems_n, new_ubvals_n, requirements, curr_try + 1, max_tries)\n", + " # TODO: Choose which goes first\n", + " elif ubelems_n <= ubvals_n:\n", + " new_ubelems_n = ubelems_n * 2 if ubelems_n >= 1 else 1\n", + " return check_iteratively(new_ubelems_n, ubvals_n, requirements, curr_try + 1, max_tries)\n", + " else: # res == dontknow\n", + " raise RuntimeError(\"It took too long to decide.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[91m<Unsat>\tubelems_n=0, ubvals_n=0\u001b[0m\n", + "\u001b[92m<Sat>\tubelems_n=1, ubvals_n=0\u001b[0m\n" + ] + } + ], + "source": [ + "solved_ctx = check_iteratively(0, 0, requirements=REQUIREMENTS)\n", + "\n", + "solved_model = solved_ctx[\"solver\"].model()" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "def get_ubelems_and_assoc(ctx: Context, model: Model):\n", + " elem, assoc, assoc_rel, unbound_elems = itemgetter(\"elem\", \"assoc\", \"assoc_rel\", \"unbound_elems\")(ctx)\n", + "\n", + " return [ ((e1n, e1), a, (e2n, e2)) \n", + " for (e1n, e1), a, (e2n, e2) in product(elem.items(), assoc.values(), elem.items()) \n", + " if (e1n in unbound_elems or e2n in unbound_elems) and model.eval(assoc_rel(e1, a, e2))\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [], + "source": [ + "def get_ubvals_and_attr(ctx: Context, model: Model):\n", + " elem, attr, attr_rel, unbound_values = itemgetter(\"elem\", \"attr\", \"attr_rel\", \"unbound_values\")(ctx)\n", + "\n", + " return [ ((elem_k, elem_v), a, (ubval_k, ubval_v))\n", + " for (elem_k, elem_v), a, (ubval_k, ubval_v) in product(elem.items(), attr.values(), unbound_values.items())\n", + " if model.eval(attr_rel(elem_v, a, ubval_v))\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "# Utility code to print the names of associations and attributes in a human-readable way\n", + "def pretty_ubelems_assoc(assoc):\n", + " (elem_1_k, elem_1_v), a, (elem_2_k, elem_2_v) = assoc\n", + " elem_1 = im.get(elem_1_k)\n", + " if elem_1:\n", + " elem_1_name = f\"{elem_1.class_} ({elem_1.user_friendly_name})\" if elem_1_k[0:4] == \"elem\" else f\"<'{elem_1_k}' not found>\"\n", + " else:\n", + " elem_1_name = elem_1_k\n", + " \n", + " elem_2 = im.get(elem_2_k)\n", + " if elem_2:\n", + " elem_2_name = f\"{elem_2.class_} ({elem_2.user_friendly_name})\" if elem_2_k[0:4] == \"elem\" else f\"<'{elem_2_k}' not found>\"\n", + " else:\n", + " elem_2_name = elem_2_k\n", + " \n", + " assoc_name = str(a)\n", + "\n", + " return f\"{elem_1_name:<50s} {assoc_name:<60s} {elem_2_name:<30s}\"\n", + "\n", + "def pretty_ubvals_attrs(attrs):\n", + " (elem_k, elem_v), a, (ubval_k, ubval_v) = attrs\n", + "\n", + " elem_1 = im.get(elem_k)\n", + " if elem_1:\n", + " elem_1_name = f\"{elem_1.class_} ({elem_1.user_friendly_name})\" if elem_k[0:4] == \"elem\" else f\"<'{elem_k}' not found>\"\n", + " else:\n", + " elem_1_name = elem_k\n", + "\n", + " attr_name = str(a)\n", + "\n", + " val_name = str(ubval_k)\n", + "\n", + " return f\"{elem_1_name:<50s} {attr_name:<60s} {val_name:<30s}\"" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "infrastructure_VirtualMachine (vm1) commons_Property::reference unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) application_SoftwareComponent::exposedInterfaces unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) application_SoftwareComponent::consumedInterfaces unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) application_SaaS::exposedInterfaces unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::generators unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::storages unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::faas unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::credentials unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::groups unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::securityGroups unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::networks unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::location unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::credentials unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::group unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_VirtualMachine::generatedFrom unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_Container::generatedFrom unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_Container::hosts unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_VMImage::generatedVMs unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_ContainerImage::generatedContainers unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_AutoScalingGroup::machineDefinition unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_AutoScalingGroup::deploymentNetwork unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_AutoScalingGroup::securityGroup unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_Storage::ifaces unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_FunctionAsAService::ifaces unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_Network::connectedIfaces unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_Network::igws unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_Network::subnets unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_Subnet::connectedTo unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_NetworkInterface::belongsTo unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_NetworkInterface::associated unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_ComputingGroup::groupedNodes unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_SecurityGroup::rules unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_SecurityGroup::ifaces unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_SwarmRole::nodes unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) infrastructure_Swarm::roles unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::vmImages unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::containerImages unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::networks unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::storages unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::faas unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::group unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_VMImage::maps unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_ContainerImage::maps unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_Network::maps unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_Storage::maps unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_FunctionAsAService::maps unbound_elem_0 \n", + "infrastructure_VirtualMachine (vm1) concrete_ComputingGroup::maps unbound_elem_0 \n", + "------------------------------------------------------------------------------------------------------------------------\n", + "\n" + ] + } + ], + "source": [ + "ubelems_and_assoc = get_ubelems_and_assoc(solved_ctx, solved_model)\n", + "print(\"\\n\".join([pretty_ubelems_assoc(assoc) for assoc in ubelems_and_assoc]))\n", + "\n", + "print(\"-\" * 120)\n", + "\n", + "ubvals_and_attr = get_ubvals_and_attr(solved_ctx, solved_model)\n", + "print(\"\\n\".join([pretty_ubvals_attrs(attr) for attr in ubvals_and_attr]))" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\tAdd constraint Not(infrastructure_VirtualMachine (vm1) commons_Property::reference unbound_elem_0 )\n", + "SAT:\tAdding one more constraint and trying again\n", + "*** Before\n", + "--- After\n", + "***************\n", + "*** 1,48 ****\n", + "- infrastructure_VirtualMachine (vm1) commons_Property::reference unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) application_SoftwareComponent::exposedInterfaces unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) application_SoftwareComponent::consumedInterfaces unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) application_SaaS::exposedInterfaces unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::generators unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::storages unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::faas unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::credentials unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::groups unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::securityGroups unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_InfrastructureLayer::networks unbound_elem_0 \n", + " infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::location unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::credentials unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::group unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_VirtualMachine::generatedFrom unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_Container::generatedFrom unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_Container::hosts unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_VMImage::generatedVMs unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_ContainerImage::generatedContainers unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_AutoScalingGroup::machineDefinition unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_AutoScalingGroup::deploymentNetwork unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_AutoScalingGroup::securityGroup unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_Storage::ifaces unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_FunctionAsAService::ifaces unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_Network::connectedIfaces unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_Network::igws unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_Network::subnets unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_Subnet::connectedTo unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_NetworkInterface::belongsTo unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_NetworkInterface::associated unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_ComputingGroup::groupedNodes unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_SecurityGroup::rules unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_SecurityGroup::ifaces unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_SwarmRole::nodes unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) infrastructure_Swarm::roles unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::vmImages unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::containerImages unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::networks unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::storages unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::faas unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_RuntimeProvider::group unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_VMImage::maps unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_ContainerImage::maps unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_Network::maps unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_Storage::maps unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_FunctionAsAService::maps unbound_elem_0 \n", + "- infrastructure_VirtualMachine (vm1) concrete_ComputingGroup::maps unbound_elem_0 \n", + "--- 1 ----\n", + "\tAdd constraint Not(infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound_elem_0 )\n", + "UNSAT\tLast constraint was the association we are looking for!\n" + ] + } + ], + "source": [ + "def thin_ubelems_and_assoc(ctx: Context, ubelems_and_assoc: list):\n", + " if not ubelems_and_assoc:\n", + " return []\n", + "\n", + " (_, elem_1_v), a, (_, elem_2_v) = assoc = ubelems_and_assoc[0]\n", + " assoc_rel = ctx[\"assoc_rel\"](elem_1_v, a, elem_2_v)\n", + "\n", + " # Add negated constraint\n", + " ctx[\"solver\"].push()\n", + " print(f\"\\tAdd constraint Not({pretty_ubelems_assoc(assoc)})\")\n", + " ctx[\"solver\"].add(Not(assoc_rel))\n", + " \n", + " res = ctx[\"solver\"].check()\n", + " \n", + " if res == sat:\n", + " print(\"SAT:\\tAdding one more constraint and trying again\")\n", + " # Get new ubelems_and_assoc\n", + " model = ctx[\"solver\"].model()\n", + " thinned_ubelems_and_assoc = get_ubelems_and_assoc(ctx, model)\n", + " \n", + " # Print table showing the diff\n", + " from difflib import context_diff\n", + " uvar_as_text = lambda input: [pretty_ubelems_assoc(assoc) for assoc in input]\n", + " print(\"\\n\".join([a for a in context_diff(uvar_as_text(ubelems_and_assoc), uvar_as_text(thinned_ubelems_and_assoc), lineterm=\"\", fromfile='Before', tofile=\"After\")]))\n", + "\n", + " # Iterate\n", + " return thin_ubelems_and_assoc(ctx, thinned_ubelems_and_assoc)\n", + " else:\n", + " print(\"UNSAT\\tLast constraint was the association we are looking for!\")\n", + " ctx[\"solver\"].pop()\n", + " \n", + " if ubelems_and_assoc[1:]:\n", + " print(\"\\tIterating over\")\n", + " print(\"\\t\\t\" + \"\\n\\t\\t\".join([pretty_ubelems_assoc(assoc) for assoc in ubelems_and_assoc[1:]]))\n", + " return [*set([assoc] + thin_ubelems_and_assoc(ctx, ubelems_and_assoc[1:]))]\n", + "\n", + "\n", + "assoc_to_implement = thin_ubelems_and_assoc(solved_ctx, ubelems_and_assoc)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound_elem_0 \n" + ] + } + ], + "source": [ + "print(\"\\n\".join([pretty_ubelems_assoc(assoc) for assoc in assoc_to_implement]))" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "def thin_ubvals_and_attr(ctx: Context, ubvals_and_attr: list):\n", + " if not ubvals_and_attr:\n", + " return []\n", + "\n", + " (_, elem_v), a, (_, attr_v) = attr = ubvals_and_attr[0]\n", + " attr_rel = ctx[\"attr_rel\"](elem_v, a, attr_v)\n", + "\n", + " # Add negated constraint\n", + " ctx[\"solver\"].push()\n", + " print(f\"\\tAdd constraint Not({pretty_ubvals_attrs(attr)})\")\n", + " ctx[\"solver\"].add(Not(attr_rel))\n", + " \n", + " res = ctx[\"solver\"].check()\n", + " \n", + " if res == sat:\n", + " print(\"SAT:\\tAdding one more constraint and trying again\")\n", + " # Get new ubelems_and_assoc\n", + " model = ctx[\"solver\"].model()\n", + " thinned_ubvals_and_attr = get_ubvals_and_attr(ctx, model)\n", + " \n", + " # Print table showing the diff\n", + " from difflib import context_diff\n", + " uvar_as_text = lambda input: [pretty_ubvals_attrs(attr) for attr in input]\n", + " print(\"\\n\".join([a for a in context_diff(uvar_as_text(ubelems_and_assoc), uvar_as_text(thinned_ubvals_and_attr), lineterm=\"\", fromfile='Before', tofile=\"After\")]))\n", + "\n", + " # Iterate\n", + " return thin_ubvals_and_attr(ctx, thinned_ubvals_and_attr)\n", + " else:\n", + " print(\"UNSAT\\tLast constraint was the attribute we are looking for!\")\n", + " ctx[\"solver\"].pop()\n", + " \n", + " if ubvals_and_attr[1:]:\n", + " print(\"\\tIterating over\")\n", + " print(\"\\t\\t\" + \"\\n\\t\\t\".join([pretty_ubvals_attrs(attr) for attr in ubvals_and_attr[1:]]))\n", + " return [*set([attr] + thin_ubvals_and_attr(ctx, ubvals_and_attr[1:]))]\n", + "\n", + "\n", + "attrs_to_implement = thin_ubvals_and_attr(solved_ctx, ubvals_and_attr)" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "print(\"\\n\".join([pretty_ubvals_attrs(attr) for attr in attrs_to_implement]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From here, we should then add this in the Intermediate Model, and then in the ECore (?) to generate the DOML file somehow.\n", + "\n", + "We can then provide the new file, or a diff to be patched onto the original?" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.7 ('.venv': poetry)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/mc_openapi/doml_mc/test.ipynb b/mc_openapi/notebooks/test.ipynb similarity index 83% rename from mc_openapi/doml_mc/test.ipynb rename to mc_openapi/notebooks/test.ipynb index 9d72011c35730dd45f39f1b5d4d1f587a59d67ae..c94c86e4f20176442a329ef00ad45ef6d54d6de9 100644 --- a/mc_openapi/doml_mc/test.ipynb +++ b/mc_openapi/notebooks/test.ipynb @@ -23,14 +23,14 @@ "metadata": {}, "outputs": [], "source": [ - "r = dmc.check_common_requirements(2, False, 50)\n", + "r = dmc.check_requirements(2, False, 50)\n", "r.summarize()" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3.10.4 ('mc-openapi-dl7Bx6Lh-py3.10')", + "display_name": "Python 3.11.0 ('.venv': poetry)", "language": "python", "name": "python3" }, @@ -44,12 +44,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.11.0" }, "orig_nbformat": 4, "vscode": { "interpreter": { - "hash": "ad63ed7e22c54016fdab5faefd8d83d59c3e39bc25e97a3e7b72bed4daaf83ed" + "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16" } } }, diff --git a/mc_openapi/openapi/model_checker.yaml b/mc_openapi/openapi/model_checker.yaml index b1875dd5fcab22615fd7d6bb63595aa38d96ae98..66638bbff3283e435c25af47ddd47e8e61e2eaf3 100644 --- a/mc_openapi/openapi/model_checker.yaml +++ b/mc_openapi/openapi/model_checker.yaml @@ -17,13 +17,6 @@ paths: schema: type: string required: true - parameters: - - in: query - name: requirement - required: false - schema: - type: string - description: Requirement to be verified (optional) responses: "200": content: diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index df5701280e4a00cbf20b8932a05d504f3fbb239c..0000000000000000000000000000000000000000 --- a/poetry.lock +++ /dev/null @@ -1,2020 +0,0 @@ -[[package]] -name = "alabaster" -version = "0.7.12" -description = "A configurable sidebar-enabled Sphinx theme" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "anyio" -version = "3.6.1" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" - -[package.extras] -doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] -trio = ["trio (>=0.16)"] - -[[package]] -name = "appnope" -version = "0.1.3" -description = "Disable App Nap on macOS >= 10.9" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "asttokens" -version = "2.0.8" -description = "Annotate AST trees with source code positions" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -six = "*" - -[package.extras] -test = ["astroid (<=2.5.3)", "pytest"] - -[[package]] -name = "attrs" -version = "22.1.0" -description = "Classes Without Boilerplate" -category = "main" -optional = false -python-versions = ">=3.5" - -[package.extras] -dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] -docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] - -[[package]] -name = "Babel" -version = "2.10.3" -description = "Internationalization utilities" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pytz = ">=2015.7" - -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "certifi" -version = "2022.9.24" -description = "Python package for providing Mozilla's CA Bundle." -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "cffi" -version = "1.15.1" -description = "Foreign Function Interface for Python calling C code." -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -pycparser = "*" - -[[package]] -name = "charset-normalizer" -version = "2.1.1" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" -optional = false -python-versions = ">=3.6.0" - -[package.extras] -unicode_backport = ["unicodedata2"] - -[[package]] -name = "click" -version = "8.1.3" -description = "Composable command line interface toolkit" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "clickclick" -version = "20.10.2" -description = "Click utility functions" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -click = ">=4.0" -PyYAML = ">=3.11" - -[[package]] -name = "colorama" -version = "0.4.5" -description = "Cross-platform colored terminal text." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "colorful" -version = "0.5.4" -description = "Terminal string styling done right, in Python." -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "connexion" -version = "2.14.1" -description = "Connexion - API first applications with OpenAPI/Swagger and Flask" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -clickclick = ">=1.2,<21" -flask = ">=1.0.4,<3" -inflection = ">=0.3.1,<0.6" -itsdangerous = ">=0.24" -jsonschema = ">=2.5.1,<5" -packaging = ">=20" -PyYAML = ">=5.1,<7" -requests = ">=2.9.1,<3" -swagger-ui-bundle = {version = ">=0.0.2,<0.1", optional = true, markers = "extra == \"swagger-ui\""} -werkzeug = ">=1.0,<3" - -[package.extras] -aiohttp = ["MarkupSafe (>=0.23)", "aiohttp (>=2.3.10,<4)", "aiohttp-jinja2 (>=0.14.0,<2)"] -docs = ["sphinx-autoapi (==1.8.1)"] -flask = ["flask (>=1.0.4,<3)", "itsdangerous (>=0.24)"] -swagger-ui = ["swagger-ui-bundle (>=0.0.2,<0.1)"] -tests = ["MarkupSafe (>=0.23)", "aiohttp (>=2.3.10,<4)", "aiohttp-jinja2 (>=0.14.0,<2)", "aiohttp-remotes", "decorator (>=5,<6)", "flask (>=1.0.4,<3)", "itsdangerous (>=0.24)", "pytest (>=6,<7)", "pytest-aiohttp", "pytest-cov (>=2,<3)", "swagger-ui-bundle (>=0.0.2,<0.1)", "testfixtures (>=6,<7)"] - -[[package]] -name = "debugpy" -version = "1.6.3" -description = "An implementation of the Debug Adapter Protocol for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "decorator" -version = "5.1.1" -description = "Decorators for Humans" -category = "dev" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "docutils" -version = "0.17.1" -description = "Docutils -- Python Documentation Utilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "entrypoints" -version = "0.4" -description = "Discover and load entry points from installed packages." -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "executing" -version = "1.1.0" -description = "Get the currently executing AST node of a frame, and other information" -category = "dev" -optional = false -python-versions = "*" - -[package.extras] -tests = ["asttokens", "littleutils", "pytest", "rich"] - -[[package]] -name = "Flask" -version = "2.2.2" -description = "A simple framework for building complex web applications." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -click = ">=8.0" -importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""} -itsdangerous = ">=2.0" -Jinja2 = ">=3.0" -Werkzeug = ">=2.2.2" - -[package.extras] -async = ["asgiref (>=3.2)"] -dotenv = ["python-dotenv"] - -[[package]] -name = "future-fstrings" -version = "1.2.0" -description = "A backport of fstrings to python<3.6" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.extras] -rewrite = ["tokenize-rt (>=3)"] - -[[package]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "httptools" -version = "0.5.0" -description = "A collection of framework independent HTTP protocol utils." -category = "main" -optional = false -python-versions = ">=3.5.0" - -[package.extras] -test = ["Cython (>=0.29.24,<0.30.0)"] - -[[package]] -name = "idna" -version = "3.4" -description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "imagesize" -version = "1.4.1" -description = "Getting image size from png/jpeg/jpeg2000/gif file" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "importlib-metadata" -version = "5.0.0" -description = "Read metadata from Python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] - -[[package]] -name = "inflection" -version = "0.5.1" -description = "A port of Ruby on Rails inflector to Python" -category = "main" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "ipykernel" -version = "6.16.0" -description = "IPython Kernel for Jupyter" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -appnope = {version = "*", markers = "platform_system == \"Darwin\""} -debugpy = ">=1.0" -ipython = ">=7.23.1" -jupyter-client = ">=6.1.12" -matplotlib-inline = ">=0.1" -nest-asyncio = "*" -packaging = "*" -psutil = "*" -pyzmq = ">=17" -tornado = ">=6.1" -traitlets = ">=5.1.0" - -[package.extras] -test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=6.0)", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "ipython" -version = "8.5.0" -description = "IPython: Productive Interactive Computing" -category = "dev" -optional = false -python-versions = ">=3.8" - -[package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -decorator = "*" -jedi = ">=0.16" -matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" -prompt-toolkit = ">3.0.1,<3.1.0" -pygments = ">=2.4.0" -stack-data = "*" -traitlets = ">=5" - -[package.extras] -all = ["Sphinx (>=1.3)", "black", "curio", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "testpath", "trio"] -black = ["black"] -doc = ["Sphinx (>=1.3)"] -kernel = ["ipykernel"] -nbconvert = ["nbconvert"] -nbformat = ["nbformat"] -notebook = ["ipywidgets", "notebook"] -parallel = ["ipyparallel"] -qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test_extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] - -[[package]] -name = "itsdangerous" -version = "2.1.2" -description = "Safely pass data to untrusted environments and back." -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "jedi" -version = "0.18.1" -description = "An autocompletion tool for Python that can be used for text editors." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -parso = ">=0.8.0,<0.9.0" - -[package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"] - -[[package]] -name = "Jinja2" -version = "3.1.2" -description = "A very fast and expressive template engine." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "joblib" -version = "1.2.0" -description = "Lightweight pipelining with Python functions" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "jsonschema" -version = "4.16.0" -description = "An implementation of JSON Schema validation for Python" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -attrs = ">=17.4.0" -pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" - -[package.extras] -format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] - -[[package]] -name = "jupyter-client" -version = "7.3.5" -description = "Jupyter protocol implementation and client libraries" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -entrypoints = "*" -jupyter-core = ">=4.9.2" -nest-asyncio = ">=1.5.4" -python-dateutil = ">=2.8.2" -pyzmq = ">=23.0" -tornado = ">=6.2" -traitlets = "*" - -[package.extras] -doc = ["ipykernel", "myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] -test = ["codecov", "coverage", "ipykernel (>=6.5)", "ipython", "mypy", "pre-commit", "pytest", "pytest-asyncio (>=0.18)", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "jupyter-core" -version = "4.11.1" -description = "Jupyter core package. A base package on which Jupyter projects rely." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} -traitlets = "*" - -[package.extras] -test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "lxml" -version = "4.9.1" -description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" - -[package.extras] -cssselect = ["cssselect (>=0.7)"] -html5 = ["html5lib"] -htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=0.29.7)"] - -[[package]] -name = "MarkupSafe" -version = "2.1.1" -description = "Safely add untrusted strings to HTML/XML markup." -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "matplotlib-inline" -version = "0.1.6" -description = "Inline Matplotlib backend for Jupyter" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -traitlets = "*" - -[[package]] -name = "nest-asyncio" -version = "1.5.6" -description = "Patch asyncio to allow nested event loops" -category = "dev" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "networkx" -version = "2.8.7" -description = "Python package for creating and manipulating graphs and networks" -category = "main" -optional = false -python-versions = ">=3.8" - -[package.extras] -default = ["matplotlib (>=3.4)", "numpy (>=1.19)", "pandas (>=1.3)", "scipy (>=1.8)"] -developer = ["mypy (>=0.981)", "pre-commit (>=2.20)"] -doc = ["nb2plots (>=0.6)", "numpydoc (>=1.4)", "pillow (>=9.1)", "pydata-sphinx-theme (>=0.9)", "sphinx (>=5)", "sphinx-gallery (>=0.10)", "texext (>=0.6.6)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.9)", "sympy (>=1.10)"] -test = ["codecov (>=2.1)", "pytest (>=7.1)", "pytest-cov (>=3.0)"] - -[[package]] -name = "ordered-set" -version = "4.1.0" -description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -dev = ["black", "mypy", "pytest"] - -[[package]] -name = "packaging" -version = "21.3" -description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - -[[package]] -name = "parso" -version = "0.8.3" -description = "A Python Parser" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] - -[[package]] -name = "pexpect" -version = "4.8.0" -description = "Pexpect allows easy control of interactive console applications." -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "prettyprinter" -version = "0.18.0" -description = "Syntax-highlighting, declarative and composable pretty printer for Python 3.5+" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -colorful = ">=0.4.0" -Pygments = ">=2.2.0" - -[[package]] -name = "prompt-toolkit" -version = "3.0.31" -description = "Library for building powerful interactive command lines in Python" -category = "dev" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -wcwidth = "*" - -[[package]] -name = "psutil" -version = "5.9.2" -description = "Cross-platform lib for process and system monitoring in Python." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "pure-eval" -version = "0.2.2" -description = "Safely evaluate AST nodes without side effects" -category = "dev" -optional = false -python-versions = "*" - -[package.extras] -tests = ["pytest"] - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "pycparser" -version = "2.21" -description = "C parser in Python" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "pyecore" -version = "0.12.2" -description = "A Python(ic) Implementation of the Eclipse Modeling Framework (EMF/Ecore)" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -future-fstrings = "*" -lxml = "*" -ordered-set = ">=4.0.1" -restrictedpython = ">=4.0b6" - -[[package]] -name = "Pygments" -version = "2.13.0" -description = "Pygments is a syntax highlighting package written in Python." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -plugins = ["importlib-metadata"] - -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" -optional = false -python-versions = ">=3.6.8" - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - -[[package]] -name = "pyrsistent" -version = "0.18.1" -description = "Persistent/Functional/Immutable data structures" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "pytest" -version = "7.1.3" -description = "pytest: simple powerful testing with Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "python-dotenv" -version = "0.21.0" -description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -cli = ["click (>=5.0)"] - -[[package]] -name = "pytz" -version = "2022.4" -description = "World timezone definitions, modern and historical" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "pywin32" -version = "304" -description = "Python for Window Extensions" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "PyYAML" -version = "6.0" -description = "YAML parser and emitter for Python" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "pyzmq" -version = "24.0.1" -description = "Python bindings for 0MQ" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -cffi = {version = "*", markers = "implementation_name == \"pypy\""} -py = {version = "*", markers = "implementation_name == \"pypy\""} - -[[package]] -name = "requests" -version = "2.28.1" -description = "Python HTTP for Humans." -category = "main" -optional = false -python-versions = ">=3.7, <4" - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<3" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "RestrictedPython" -version = "5.0" -description = "RestrictedPython is a defined subset of the Python language which allows to provide a program input into a trusted environment." -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -setuptools = "*" - -[package.extras] -test = ["pytest", "pytest-mock"] - -[[package]] -name = "setuptools" -version = "65.4.1" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "sniffio" -version = "1.3.0" -description = "Sniff out which async library your code is running under" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "Sphinx" -version = "5.2.3" -description = "Python documentation generator" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -alabaster = ">=0.7,<0.8" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.14,<0.20" -imagesize = ">=1.3" -importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.12" -requests = ">=2.5.0" -snowballstemmer = ">=2.0" -sphinxcontrib-applehelp = "*" -sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = ">=2.0.0" -sphinxcontrib-jsmath = "*" -sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" - -[package.extras] -docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"] -test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"] - -[[package]] -name = "sphinx-rtd-theme" -version = "1.0.0" -description = "Read the Docs theme for Sphinx" -category = "dev" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" - -[package.dependencies] -docutils = "<0.18" -sphinx = ">=1.6" - -[package.extras] -dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client"] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "1.0.2" -description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "1.0.2" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.0.0" -description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["html5lib", "pytest"] - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -description = "A sphinx extension which renders display math in HTML via JavaScript" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -test = ["flake8", "mypy", "pytest"] - -[[package]] -name = "sphinxcontrib-qthelp" -version = "1.0.3" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "1.1.5" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "stack-data" -version = "0.5.1" -description = "Extract data from python stack frames and tracebacks for informative displays" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -asttokens = "*" -executing = "*" -pure-eval = "*" - -[package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] - -[[package]] -name = "swagger-ui-bundle" -version = "0.0.9" -description = "swagger_ui_bundle - swagger-ui files in a pip package" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -Jinja2 = ">=2.0" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "tornado" -version = "6.2" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -category = "dev" -optional = false -python-versions = ">= 3.7" - -[[package]] -name = "traitlets" -version = "5.4.0" -description = "" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -test = ["pre-commit", "pytest"] - -[[package]] -name = "urllib3" -version = "1.26.12" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "uvicorn" -version = "0.18.3" -description = "The lightning-fast ASGI server." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} -h11 = ">=0.8" -httptools = {version = ">=0.4.0", optional = true, markers = "extra == \"standard\""} -python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} -watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -websockets = {version = ">=10.0", optional = true, markers = "extra == \"standard\""} - -[package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] - -[[package]] -name = "uvloop" -version = "0.17.0" -description = "Fast implementation of asyncio event loop on top of libuv" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -dev = ["Cython (>=0.29.32,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"] - -[[package]] -name = "watchfiles" -version = "0.17.0" -description = "Simple, modern and high performance file watching and code reload in python." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -anyio = ">=3.0.0,<4" - -[[package]] -name = "wcwidth" -version = "0.2.5" -description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "websockets" -version = "10.3" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "Werkzeug" -version = "2.2.2" -description = "The comprehensive WSGI web application library." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -MarkupSafe = ">=2.1.1" - -[package.extras] -watchdog = ["watchdog"] - -[[package]] -name = "z3-solver" -version = "4.11.2.0" -description = "an efficient SMT solver library" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "zipp" -version = "3.8.1" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] -testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[metadata] -lock-version = "1.1" -python-versions = "^3.9" -content-hash = "a9d927113aa49367234cc4d09abee6d3743b94f59a0f47c6d1b707abd47c246e" - -[metadata.files] -alabaster = [ - {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, - {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, -] -anyio = [ - {file = "anyio-3.6.1-py3-none-any.whl", hash = "sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be"}, - {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"}, -] -appnope = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, -] -asttokens = [ - {file = "asttokens-2.0.8-py2.py3-none-any.whl", hash = "sha256:e3305297c744ae53ffa032c45dc347286165e4ffce6875dc662b205db0623d86"}, - {file = "asttokens-2.0.8.tar.gz", hash = "sha256:c61e16246ecfb2cde2958406b4c8ebc043c9e6d73aaa83c941673b35e5d3a76b"}, -] -attrs = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, -] -Babel = [ - {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"}, - {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, -] -backcall = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] -certifi = [ - {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, - {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, -] -cffi = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, -] -charset-normalizer = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -clickclick = [ - {file = "clickclick-20.10.2-py2.py3-none-any.whl", hash = "sha256:c8f33e6d9ec83f68416dd2136a7950125bd256ec39ccc9a85c6e280a16be2bb5"}, - {file = "clickclick-20.10.2.tar.gz", hash = "sha256:4efb13e62353e34c5eef7ed6582c4920b418d7dedc86d819e22ee089ba01802c"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -colorful = [ - {file = "colorful-0.5.4-py2.py3-none-any.whl", hash = "sha256:8d264b52a39aae4c0ba3e2a46afbaec81b0559a99be0d2cfe2aba4cf94531348"}, - {file = "colorful-0.5.4.tar.gz", hash = "sha256:86848ad4e2eda60cd2519d8698945d22f6f6551e23e95f3f14dfbb60997807ea"}, -] -connexion = [ - {file = "connexion-2.14.1-py2.py3-none-any.whl", hash = "sha256:f343717241b4c4802a694c38fee66fb1693c897fe4ea5a957fa9b3b07caf6394"}, - {file = "connexion-2.14.1.tar.gz", hash = "sha256:99aa5781e70a7b94f8ffae8cf89f309d49cdb811bbd65a8e2f2546f3b19a01e6"}, -] -debugpy = [ - {file = "debugpy-1.6.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:c4b2bd5c245eeb49824bf7e539f95fb17f9a756186e51c3e513e32999d8846f3"}, - {file = "debugpy-1.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b8deaeb779699350deeed835322730a3efec170b88927debc9ba07a1a38e2585"}, - {file = "debugpy-1.6.3-cp310-cp310-win32.whl", hash = "sha256:fc233a0160f3b117b20216f1169e7211b83235e3cd6749bcdd8dbb72177030c7"}, - {file = "debugpy-1.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:dda8652520eae3945833e061cbe2993ad94a0b545aebd62e4e6b80ee616c76b2"}, - {file = "debugpy-1.6.3-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5c814596a170a0a58fa6fad74947e30bfd7e192a5d2d7bd6a12156c2899e13a"}, - {file = "debugpy-1.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c4cd6f37e3c168080d61d698390dfe2cd9e74ebf80b448069822a15dadcda57d"}, - {file = "debugpy-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:3c9f985944a30cfc9ae4306ac6a27b9c31dba72ca943214dad4a0ab3840f6161"}, - {file = "debugpy-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:5ad571a36cec137ae6ed951d0ff75b5e092e9af6683da084753231150cbc5b25"}, - {file = "debugpy-1.6.3-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:adcfea5ea06d55d505375995e150c06445e2b20cd12885bcae566148c076636b"}, - {file = "debugpy-1.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:daadab4403427abd090eccb38d8901afd8b393e01fd243048fab3f1d7132abb4"}, - {file = "debugpy-1.6.3-cp38-cp38-win32.whl", hash = "sha256:6efc30325b68e451118b795eff6fe8488253ca3958251d5158106d9c87581bc6"}, - {file = "debugpy-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:86d784b72c5411c833af1cd45b83d80c252b77c3bfdb43db17c441d772f4c734"}, - {file = "debugpy-1.6.3-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4e255982552b0edfe3a6264438dbd62d404baa6556a81a88f9420d3ed79b06ae"}, - {file = "debugpy-1.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cca23cb6161ac89698d629d892520327dd1be9321c0960e610bbcb807232b45d"}, - {file = "debugpy-1.6.3-cp39-cp39-win32.whl", hash = "sha256:7c302095a81be0d5c19f6529b600bac971440db3e226dce85347cc27e6a61908"}, - {file = "debugpy-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:34d2cdd3a7c87302ba5322b86e79c32c2115be396f3f09ca13306d8a04fe0f16"}, - {file = "debugpy-1.6.3-py2.py3-none-any.whl", hash = "sha256:84c39940a0cac410bf6aa4db00ba174f973eef521fbe9dd058e26bcabad89c4f"}, - {file = "debugpy-1.6.3.zip", hash = "sha256:e8922090514a890eec99cfb991bab872dd2e353ebb793164d5f01c362b9a40bf"}, -] -decorator = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] -docutils = [ - {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, - {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, -] -entrypoints = [ - {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"}, - {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"}, -] -executing = [ - {file = "executing-1.1.0-py2.py3-none-any.whl", hash = "sha256:4a6d96ba89eb3dcc11483471061b42b9006d8c9f81c584dd04246944cd022530"}, - {file = "executing-1.1.0.tar.gz", hash = "sha256:2c2c07d1ec4b2d8f9676b25170f1d8445c0ee2eb78901afb075a4b8d83608c6a"}, -] -Flask = [ - {file = "Flask-2.2.2-py3-none-any.whl", hash = "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"}, - {file = "Flask-2.2.2.tar.gz", hash = "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b"}, -] -future-fstrings = [ - {file = "future_fstrings-1.2.0-py2.py3-none-any.whl", hash = "sha256:90e49598b553d8746c4dc7d9442e0359d038c3039d802c91c0a55505da318c63"}, - {file = "future_fstrings-1.2.0.tar.gz", hash = "sha256:6cf41cbe97c398ab5a81168ce0dbb8ad95862d3caf23c21e4430627b90844089"}, -] -h11 = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] -httptools = [ - {file = "httptools-0.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f470c79061599a126d74385623ff4744c4e0f4a0997a353a44923c0b561ee51"}, - {file = "httptools-0.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e90491a4d77d0cb82e0e7a9cb35d86284c677402e4ce7ba6b448ccc7325c5421"}, - {file = "httptools-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d2357f791b12d86faced7b5736dea9ef4f5ecdc6c3f253e445ee82da579449"}, - {file = "httptools-0.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f90cd6fd97c9a1b7fe9215e60c3bd97336742a0857f00a4cb31547bc22560c2"}, - {file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5230a99e724a1bdbbf236a1b58d6e8504b912b0552721c7c6b8570925ee0ccde"}, - {file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a47a34f6015dd52c9eb629c0f5a8a5193e47bf2a12d9a3194d231eaf1bc451a"}, - {file = "httptools-0.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:24bb4bb8ac3882f90aa95403a1cb48465de877e2d5298ad6ddcfdebec060787d"}, - {file = "httptools-0.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e67d4f8734f8054d2c4858570cc4b233bf753f56e85217de4dfb2495904cf02e"}, - {file = "httptools-0.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e5eefc58d20e4c2da82c78d91b2906f1a947ef42bd668db05f4ab4201a99f49"}, - {file = "httptools-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0297822cea9f90a38df29f48e40b42ac3d48a28637368f3ec6d15eebefd182f9"}, - {file = "httptools-0.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:557be7fbf2bfa4a2ec65192c254e151684545ebab45eca5d50477d562c40f986"}, - {file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:54465401dbbec9a6a42cf737627fb0f014d50dc7365a6b6cd57753f151a86ff0"}, - {file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4d9ebac23d2de960726ce45f49d70eb5466725c0087a078866043dad115f850f"}, - {file = "httptools-0.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:e8a34e4c0ab7b1ca17b8763613783e2458e77938092c18ac919420ab8655c8c1"}, - {file = "httptools-0.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f659d7a48401158c59933904040085c200b4be631cb5f23a7d561fbae593ec1f"}, - {file = "httptools-0.5.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1616b3ba965cd68e6f759eeb5d34fbf596a79e84215eeceebf34ba3f61fdc7"}, - {file = "httptools-0.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3625a55886257755cb15194efbf209584754e31d336e09e2ffe0685a76cb4b60"}, - {file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:72ad589ba5e4a87e1d404cc1cb1b5780bfcb16e2aec957b88ce15fe879cc08ca"}, - {file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:850fec36c48df5a790aa735417dca8ce7d4b48d59b3ebd6f83e88a8125cde324"}, - {file = "httptools-0.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f222e1e9d3f13b68ff8a835574eda02e67277d51631d69d7cf7f8e07df678c86"}, - {file = "httptools-0.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3cb8acf8f951363b617a8420768a9f249099b92e703c052f9a51b66342eea89b"}, - {file = "httptools-0.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550059885dc9c19a072ca6d6735739d879be3b5959ec218ba3e013fd2255a11b"}, - {file = "httptools-0.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a04fe458a4597aa559b79c7f48fe3dceabef0f69f562daf5c5e926b153817281"}, - {file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d0c1044bce274ec6711f0770fd2d5544fe392591d204c68328e60a46f88843b"}, - {file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c6eeefd4435055a8ebb6c5cc36111b8591c192c56a95b45fe2af22d9881eee25"}, - {file = "httptools-0.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b65be160adcd9de7a7e6413a4966665756e263f0d5ddeffde277ffeee0576a5"}, - {file = "httptools-0.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fe9c766a0c35b7e3d6b6939393c8dfdd5da3ac5dec7f971ec9134f284c6c36d6"}, - {file = "httptools-0.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:85b392aba273566c3d5596a0a490978c085b79700814fb22bfd537d381dd230c"}, - {file = "httptools-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5e3088f4ed33947e16fd865b8200f9cfae1144f41b64a8cf19b599508e096bc"}, - {file = "httptools-0.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c2a56b6aad7cc8f5551d8e04ff5a319d203f9d870398b94702300de50190f63"}, - {file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b571b281a19762adb3f48a7731f6842f920fa71108aff9be49888320ac3e24d"}, - {file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa47ffcf70ba6f7848349b8a6f9b481ee0f7637931d91a9860a1838bfc586901"}, - {file = "httptools-0.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:bede7ee075e54b9a5bde695b4fc8f569f30185891796b2e4e09e2226801d09bd"}, - {file = "httptools-0.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:64eba6f168803a7469866a9c9b5263a7463fa8b7a25b35e547492aa7322036b6"}, - {file = "httptools-0.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b098e4bb1174096a93f48f6193e7d9aa7071506a5877da09a783509ca5fff42"}, - {file = "httptools-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9423a2de923820c7e82e18980b937893f4aa8251c43684fa1772e341f6e06887"}, - {file = "httptools-0.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1b7becf7d9d3ccdbb2f038f665c0f4857e08e1d8481cbcc1a86a0afcfb62b2"}, - {file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:50d4613025f15f4b11f1c54bbed4761c0020f7f921b95143ad6d58c151198142"}, - {file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ffce9d81c825ac1deaa13bc9694c0562e2840a48ba21cfc9f3b4c922c16f372"}, - {file = "httptools-0.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:1af91b3650ce518d226466f30bbba5b6376dbd3ddb1b2be8b0658c6799dd450b"}, - {file = "httptools-0.5.0.tar.gz", hash = "sha256:295874861c173f9101960bba332429bb77ed4dcd8cdf5cee9922eb00e4f6bc09"}, -] -idna = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] -imagesize = [ - {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, - {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, -] -importlib-metadata = [ - {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, - {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, -] -inflection = [ - {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, - {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -ipykernel = [ - {file = "ipykernel-6.16.0-py3-none-any.whl", hash = "sha256:d3d95241cd4dd302fea9d5747b00509b58997356d1f6333c9a074c3eccb78cb3"}, - {file = "ipykernel-6.16.0.tar.gz", hash = "sha256:7fe42c0d58435e971dc15fd42189f20d66bf35f3056bda4f6554271bc1fa3d0d"}, -] -ipython = [ - {file = "ipython-8.5.0-py3-none-any.whl", hash = "sha256:6f090e29ab8ef8643e521763a4f1f39dc3914db643122b1e9d3328ff2e43ada2"}, - {file = "ipython-8.5.0.tar.gz", hash = "sha256:097bdf5cd87576fd066179c9f7f208004f7a6864ee1b20f37d346c0bcb099f84"}, -] -itsdangerous = [ - {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, - {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, -] -jedi = [ - {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, - {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, -] -Jinja2 = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, -] -joblib = [ - {file = "joblib-1.2.0-py3-none-any.whl", hash = "sha256:091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385"}, - {file = "joblib-1.2.0.tar.gz", hash = "sha256:e1cee4a79e4af22881164f218d4311f60074197fb707e082e803b61f6d137018"}, -] -jsonschema = [ - {file = "jsonschema-4.16.0-py3-none-any.whl", hash = "sha256:9e74b8f9738d6a946d70705dc692b74b5429cd0960d58e79ffecfc43b2221eb9"}, - {file = "jsonschema-4.16.0.tar.gz", hash = "sha256:165059f076eff6971bae5b742fc029a7b4ef3f9bcf04c14e4776a7605de14b23"}, -] -jupyter-client = [ - {file = "jupyter_client-7.3.5-py3-none-any.whl", hash = "sha256:b33222bdc9dd1714228bd286af006533a0abe2bbc093e8f3d29dc0b91bdc2be4"}, - {file = "jupyter_client-7.3.5.tar.gz", hash = "sha256:3c58466a1b8d55dba0bf3ce0834e4f5b7760baf98d1d73db0add6f19de9ecd1d"}, -] -jupyter-core = [ - {file = "jupyter_core-4.11.1-py3-none-any.whl", hash = "sha256:715e22bb6cc7db3718fddfac1f69f1c7e899ca00e42bdfd4bf3705452b9fd84a"}, - {file = "jupyter_core-4.11.1.tar.gz", hash = "sha256:2e5f244d44894c4154d06aeae3419dd7f1b0ef4494dc5584929b398c61cfd314"}, -] -lxml = [ - {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"}, - {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"}, - {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"}, - {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"}, - {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"}, - {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"}, - {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"}, - {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"}, - {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"}, - {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"}, - {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"}, - {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"}, - {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"}, - {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"}, - {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"}, - {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"}, - {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"}, - {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"}, - {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"}, - {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"}, - {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, -] -MarkupSafe = [ - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, - {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, -] -matplotlib-inline = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, -] -nest-asyncio = [ - {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"}, - {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, -] -networkx = [ - {file = "networkx-2.8.7-py3-none-any.whl", hash = "sha256:15cdf7f7c157637107ea690cabbc488018f8256fa28242aed0fb24c93c03a06d"}, - {file = "networkx-2.8.7.tar.gz", hash = "sha256:815383fd52ece0a7024b5fd8408cc13a389ea350cd912178b82eed8b96f82cd3"}, -] -ordered-set = [ - {file = "ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8"}, - {file = "ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -parso = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, -] -pexpect = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, -] -pickleshare = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -prettyprinter = [ - {file = "prettyprinter-0.18.0-py2.py3-none-any.whl", hash = "sha256:358a58f276cb312e3ca29d7a7f244c91e4e0bda7848249d30e4f36d2eb58b67c"}, - {file = "prettyprinter-0.18.0.tar.gz", hash = "sha256:9fe5da7ec53510881dd35d7a5c677ba45f34cfe6a8e78d1abd20652cf82139a8"}, -] -prompt-toolkit = [ - {file = "prompt_toolkit-3.0.31-py3-none-any.whl", hash = "sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d"}, - {file = "prompt_toolkit-3.0.31.tar.gz", hash = "sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148"}, -] -psutil = [ - {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:8f024fbb26c8daf5d70287bb3edfafa22283c255287cf523c5d81721e8e5d82c"}, - {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b2f248ffc346f4f4f0d747ee1947963613216b06688be0be2e393986fe20dbbb"}, - {file = "psutil-5.9.2-cp27-cp27m-win32.whl", hash = "sha256:b1928b9bf478d31fdffdb57101d18f9b70ed4e9b0e41af751851813547b2a9ab"}, - {file = "psutil-5.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:404f4816c16a2fcc4eaa36d7eb49a66df2d083e829d3e39ee8759a411dbc9ecf"}, - {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:94e621c6a4ddb2573d4d30cba074f6d1aa0186645917df42c811c473dd22b339"}, - {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:256098b4f6ffea6441eb54ab3eb64db9ecef18f6a80d7ba91549195d55420f84"}, - {file = "psutil-5.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:614337922702e9be37a39954d67fdb9e855981624d8011a9927b8f2d3c9625d9"}, - {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec06dc6c934fb53df10c1672e299145ce609ff0611b569e75a88f313634969"}, - {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3ac2c0375ef498e74b9b4ec56df3c88be43fe56cac465627572dbfb21c4be34"}, - {file = "psutil-5.9.2-cp310-cp310-win32.whl", hash = "sha256:e4c4a7636ffc47b7141864f1c5e7d649f42c54e49da2dd3cceb1c5f5d29bfc85"}, - {file = "psutil-5.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:f4cb67215c10d4657e320037109939b1c1d2fd70ca3d76301992f89fe2edb1f1"}, - {file = "psutil-5.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dc9bda7d5ced744622f157cc8d8bdd51735dafcecff807e928ff26bdb0ff097d"}, - {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75291912b945a7351d45df682f9644540d564d62115d4a20d45fa17dc2d48f8"}, - {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4018d5f9b6651f9896c7a7c2c9f4652e4eea53f10751c4e7d08a9093ab587ec"}, - {file = "psutil-5.9.2-cp36-cp36m-win32.whl", hash = "sha256:f40ba362fefc11d6bea4403f070078d60053ed422255bd838cd86a40674364c9"}, - {file = "psutil-5.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9770c1d25aee91417eba7869139d629d6328a9422ce1cdd112bd56377ca98444"}, - {file = "psutil-5.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42638876b7f5ef43cef8dcf640d3401b27a51ee3fa137cb2aa2e72e188414c32"}, - {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91aa0dac0c64688667b4285fa29354acfb3e834e1fd98b535b9986c883c2ce1d"}, - {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fb54941aac044a61db9d8eb56fc5bee207db3bc58645d657249030e15ba3727"}, - {file = "psutil-5.9.2-cp37-cp37m-win32.whl", hash = "sha256:7cbb795dcd8ed8fd238bc9e9f64ab188f3f4096d2e811b5a82da53d164b84c3f"}, - {file = "psutil-5.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5d39e3a2d5c40efa977c9a8dd4f679763c43c6c255b1340a56489955dbca767c"}, - {file = "psutil-5.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd331866628d18223a4265371fd255774affd86244fc307ef66eaf00de0633d5"}, - {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b315febaebae813326296872fdb4be92ad3ce10d1d742a6b0c49fb619481ed0b"}, - {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7929a516125f62399d6e8e026129c8835f6c5a3aab88c3fff1a05ee8feb840d"}, - {file = "psutil-5.9.2-cp38-cp38-win32.whl", hash = "sha256:561dec454853846d1dd0247b44c2e66a0a0c490f937086930ec4b8f83bf44f06"}, - {file = "psutil-5.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:67b33f27fc0427483b61563a16c90d9f3b547eeb7af0ef1b9fe024cdc9b3a6ea"}, - {file = "psutil-5.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3591616fa07b15050b2f87e1cdefd06a554382e72866fcc0ab2be9d116486c8"}, - {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b29f581b5edab1f133563272a6011925401804d52d603c5c606936b49c8b97"}, - {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4642fd93785a29353d6917a23e2ac6177308ef5e8be5cc17008d885cb9f70f12"}, - {file = "psutil-5.9.2-cp39-cp39-win32.whl", hash = "sha256:ed29ea0b9a372c5188cdb2ad39f937900a10fb5478dc077283bf86eeac678ef1"}, - {file = "psutil-5.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:68b35cbff92d1f7103d8f1db77c977e72f49fcefae3d3d2b91c76b0e7aef48b8"}, - {file = "psutil-5.9.2.tar.gz", hash = "sha256:feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c"}, -] -ptyprocess = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] -pure-eval = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -pycparser = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, -] -pyecore = [ - {file = "pyecore-0.12.2-py3-none-any.whl", hash = "sha256:8ebbefea2fcb97602ddb9eb859ae15d7c0900231128da92e10b7f9a9e1a29b76"}, - {file = "pyecore-0.12.2.tar.gz", hash = "sha256:4fb417df37fc5433da37f3d42724f7c4cc36cbbe63988f3e43ad7653e0808387"}, -] -Pygments = [ - {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, - {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, -] -pyparsing = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] -pyrsistent = [ - {file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"}, - {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"}, - {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"}, - {file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"}, - {file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"}, - {file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"}, - {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"}, - {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"}, - {file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"}, - {file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"}, - {file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"}, - {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"}, - {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"}, - {file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"}, - {file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"}, - {file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"}, -] -pytest = [ - {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, - {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] -python-dotenv = [ - {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"}, - {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"}, -] -pytz = [ - {file = "pytz-2022.4-py2.py3-none-any.whl", hash = "sha256:2c0784747071402c6e99f0bafdb7da0fa22645f06554c7ae06bf6358897e9c91"}, - {file = "pytz-2022.4.tar.gz", hash = "sha256:48ce799d83b6f8aab2020e369b627446696619e79645419610b9facd909b3174"}, -] -pywin32 = [ - {file = "pywin32-304-cp310-cp310-win32.whl", hash = "sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3"}, - {file = "pywin32-304-cp310-cp310-win_amd64.whl", hash = "sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48"}, - {file = "pywin32-304-cp310-cp310-win_arm64.whl", hash = "sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f"}, - {file = "pywin32-304-cp311-cp311-win32.whl", hash = "sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269"}, - {file = "pywin32-304-cp311-cp311-win_amd64.whl", hash = "sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4"}, - {file = "pywin32-304-cp311-cp311-win_arm64.whl", hash = "sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43"}, - {file = "pywin32-304-cp36-cp36m-win32.whl", hash = "sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1"}, - {file = "pywin32-304-cp36-cp36m-win_amd64.whl", hash = "sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988"}, - {file = "pywin32-304-cp37-cp37m-win32.whl", hash = "sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"}, - {file = "pywin32-304-cp37-cp37m-win_amd64.whl", hash = "sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df"}, - {file = "pywin32-304-cp38-cp38-win32.whl", hash = "sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96"}, - {file = "pywin32-304-cp38-cp38-win_amd64.whl", hash = "sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e"}, - {file = "pywin32-304-cp39-cp39-win32.whl", hash = "sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc"}, - {file = "pywin32-304-cp39-cp39-win_amd64.whl", hash = "sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9"}, -] -PyYAML = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] -pyzmq = [ - {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:28b119ba97129d3001673a697b7cce47fe6de1f7255d104c2f01108a5179a066"}, - {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bcbebd369493d68162cddb74a9c1fcebd139dfbb7ddb23d8f8e43e6c87bac3a6"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae61446166983c663cee42c852ed63899e43e484abf080089f771df4b9d272ef"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f7ac99b15270db8d53f28c3c7b968612993a90a5cf359da354efe96f5372b4"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca7c3956b03b7663fac4d150f5e6d4f6f38b2462c1e9afd83bcf7019f17913"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8c78bfe20d4c890cb5580a3b9290f700c570e167d4cdcc55feec07030297a5e3"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48f721f070726cd2a6e44f3c33f8ee4b24188e4b816e6dd8ba542c8c3bb5b246"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afe1f3bc486d0ce40abb0a0c9adb39aed3bbac36ebdc596487b0cceba55c21c1"}, - {file = "pyzmq-24.0.1-cp310-cp310-win32.whl", hash = "sha256:3e6192dbcefaaa52ed81be88525a54a445f4b4fe2fffcae7fe40ebb58bd06bfd"}, - {file = "pyzmq-24.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:86de64468cad9c6d269f32a6390e210ca5ada568c7a55de8e681ca3b897bb340"}, - {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:838812c65ed5f7c2bd11f7b098d2e5d01685a3f6d1f82849423b570bae698c00"}, - {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfb992dbcd88d8254471760879d48fb20836d91baa90f181c957122f9592b3dc"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7abddb2bd5489d30ffeb4b93a428130886c171b4d355ccd226e83254fcb6b9ef"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94010bd61bc168c103a5b3b0f56ed3b616688192db7cd5b1d626e49f28ff51b3"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8242543c522d84d033fe79be04cb559b80d7eb98ad81b137ff7e0a9020f00ace"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ccb94342d13e3bf3ffa6e62f95b5e3f0bc6bfa94558cb37f4b3d09d6feb536ff"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6640f83df0ae4ae1104d4c62b77e9ef39be85ebe53f636388707d532bee2b7b8"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a180dbd5ea5d47c2d3b716d5c19cc3fb162d1c8db93b21a1295d69585bfddac1"}, - {file = "pyzmq-24.0.1-cp311-cp311-win32.whl", hash = "sha256:624321120f7e60336be8ec74a172ae7fba5c3ed5bf787cc85f7e9986c9e0ebc2"}, - {file = "pyzmq-24.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1724117bae69e091309ffb8255412c4651d3f6355560d9af312d547f6c5bc8b8"}, - {file = "pyzmq-24.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:15975747462ec49fdc863af906bab87c43b2491403ab37a6d88410635786b0f4"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b947e264f0e77d30dcbccbb00f49f900b204b922eb0c3a9f0afd61aaa1cedc3d"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ec91f1bad66f3ee8c6deb65fa1fe418e8ad803efedd69c35f3b5502f43bd1dc"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db03704b3506455d86ec72c3358a779e9b1d07b61220dfb43702b7b668edcd0d"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e7e66b4e403c2836ac74f26c4b65d8ac0ca1eef41dfcac2d013b7482befaad83"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7a23ccc1083c260fa9685c93e3b170baba45aeed4b524deb3f426b0c40c11639"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fa0ae3275ef706c0309556061185dd0e4c4cd3b7d6f67ae617e4e677c7a41e2e"}, - {file = "pyzmq-24.0.1-cp36-cp36m-win32.whl", hash = "sha256:f01de4ec083daebf210531e2cca3bdb1608dbbbe00a9723e261d92087a1f6ebc"}, - {file = "pyzmq-24.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:de4217b9eb8b541cf2b7fde4401ce9d9a411cc0af85d410f9d6f4333f43640be"}, - {file = "pyzmq-24.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:78068e8678ca023594e4a0ab558905c1033b2d3e806a0ad9e3094e231e115a33"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77c2713faf25a953c69cf0f723d1b7dd83827b0834e6c41e3fb3bbc6765914a1"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bb4af15f305056e95ca1bd086239b9ebc6ad55e9f49076d27d80027f72752f6"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0f14cffd32e9c4c73da66db97853a6aeceaac34acdc0fae9e5bbc9370281864c"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0108358dab8c6b27ff6b985c2af4b12665c1bc659648284153ee501000f5c107"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d66689e840e75221b0b290b0befa86f059fb35e1ee6443bce51516d4d61b6b99"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae08ac90aa8fa14caafc7a6251bd218bf6dac518b7bff09caaa5e781119ba3f2"}, - {file = "pyzmq-24.0.1-cp37-cp37m-win32.whl", hash = "sha256:8421aa8c9b45ea608c205db9e1c0c855c7e54d0e9c2c2f337ce024f6843cab3b"}, - {file = "pyzmq-24.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54d8b9c5e288362ec8595c1d98666d36f2070fd0c2f76e2b3c60fbad9bd76227"}, - {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:acbd0a6d61cc954b9f535daaa9ec26b0a60a0d4353c5f7c1438ebc88a359a47e"}, - {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:47b11a729d61a47df56346283a4a800fa379ae6a85870d5a2e1e4956c828eedc"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abe6eb10122f0d746a0d510c2039ae8edb27bc9af29f6d1b05a66cc2401353ff"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:07bec1a1b22dacf718f2c0e71b49600bb6a31a88f06527dfd0b5aababe3fa3f7"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d945a85b70da97ae86113faf9f1b9294efe66bd4a5d6f82f2676d567338b66"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7928bb7580736ffac5baf814097be342ba08d3cfdfb48e52773ec959572287"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b946da90dc2799bcafa682692c1d2139b2a96ec3c24fa9fc6f5b0da782675330"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c8840f064b1fb377cffd3efeaad2b190c14d4c8da02316dae07571252d20b31f"}, - {file = "pyzmq-24.0.1-cp38-cp38-win32.whl", hash = "sha256:4854f9edc5208f63f0841c0c667260ae8d6846cfa233c479e29fdc85d42ebd58"}, - {file = "pyzmq-24.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:42d4f97b9795a7aafa152a36fe2ad44549b83a743fd3e77011136def512e6c2a"}, - {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:52afb0ac962963fff30cf1be775bc51ae083ef4c1e354266ab20e5382057dd62"}, - {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bad8210ad4df68c44ff3685cca3cda448ee46e20d13edcff8909eba6ec01ca4"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dabf1a05318d95b1537fd61d9330ef4313ea1216eea128a17615038859da3b3b"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5bd3d7dfd9cd058eb68d9a905dec854f86649f64d4ddf21f3ec289341386c44b"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8012bce6836d3f20a6c9599f81dfa945f433dab4dbd0c4917a6fb1f998ab33d"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c31805d2c8ade9b11feca4674eee2b9cce1fec3e8ddb7bbdd961a09dc76a80ea"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3104f4b084ad5d9c0cb87445cc8cfd96bba710bef4a66c2674910127044df209"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:df0841f94928f8af9c7a1f0aaaffba1fb74607af023a152f59379c01c53aee58"}, - {file = "pyzmq-24.0.1-cp39-cp39-win32.whl", hash = "sha256:a435ef8a3bd95c8a2d316d6e0ff70d0db524f6037411652803e118871d703333"}, - {file = "pyzmq-24.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2032d9cb994ce3b4cba2b8dfae08c7e25bc14ba484c770d4d3be33c27de8c45b"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bb5635c851eef3a7a54becde6da99485eecf7d068bd885ac8e6d173c4ecd68b0"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:83ea1a398f192957cb986d9206ce229efe0ee75e3c6635baff53ddf39bd718d5"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:941fab0073f0a54dc33d1a0460cb04e0d85893cb0c5e1476c785000f8b359409"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8f482c44ccb5884bf3f638f29bea0f8dc68c97e38b2061769c4cb697f6140d"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:613010b5d17906c4367609e6f52e9a2595e35d5cc27d36ff3f1b6fa6e954d944"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:65c94410b5a8355cfcf12fd600a313efee46ce96a09e911ea92cf2acf6708804"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:20e7eeb1166087db636c06cae04a1ef59298627f56fb17da10528ab52a14c87f"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2712aee7b3834ace51738c15d9ee152cc5a98dc7d57dd93300461b792ab7b43"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7c280185c4da99e0cc06c63bdf91f5b0b71deb70d8717f0ab870a43e376db8"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:858375573c9225cc8e5b49bfac846a77b696b8d5e815711b8d4ba3141e6e8879"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:80093b595921eed1a2cead546a683b9e2ae7f4a4592bb2ab22f70d30174f003a"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f3f3154fde2b1ff3aa7b4f9326347ebc89c8ef425ca1db8f665175e6d3bd42f"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb756147314430bee5d10919b8493c0ccb109ddb7f5dfd2fcd7441266a25b75"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e706bac34e9f50779cb8c39f10b53a4d15aebb97235643d3112ac20bd577b4"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:687700f8371643916a1d2c61f3fdaa630407dd205c38afff936545d7b7466066"}, - {file = "pyzmq-24.0.1.tar.gz", hash = "sha256:216f5d7dbb67166759e59b0479bca82b8acf9bed6015b526b8eb10143fb08e77"}, -] -requests = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, -] -RestrictedPython = [ - {file = "RestrictedPython-5.0-py2.py3-none-any.whl", hash = "sha256:9bd69505147b0ff8c68f4ff5a275975a3ab66fc43cbf3b61a195650ed767cd4e"}, - {file = "RestrictedPython-5.0.tar.gz", hash = "sha256:a080569bffdf53371ae3e754ab1732f43054b1bab904fc100f74ba68ac731abc"}, -] -setuptools = [ - {file = "setuptools-65.4.1-py3-none-any.whl", hash = "sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012"}, - {file = "setuptools-65.4.1.tar.gz", hash = "sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -sniffio = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, -] -snowballstemmer = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, -] -Sphinx = [ - {file = "Sphinx-5.2.3.tar.gz", hash = "sha256:5b10cb1022dac8c035f75767799c39217a05fc0fe2d6fe5597560d38e44f0363"}, - {file = "sphinx-5.2.3-py3-none-any.whl", hash = "sha256:7abf6fabd7b58d0727b7317d5e2650ef68765bbe0ccb63c8795fa8683477eaa2"}, -] -sphinx-rtd-theme = [ - {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, - {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"}, -] -sphinxcontrib-applehelp = [ - {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, - {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, -] -sphinxcontrib-devhelp = [ - {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, - {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, -] -sphinxcontrib-htmlhelp = [ - {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, - {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, -] -sphinxcontrib-jsmath = [ - {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, - {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, -] -sphinxcontrib-qthelp = [ - {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, - {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, -] -sphinxcontrib-serializinghtml = [ - {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, - {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, -] -stack-data = [ - {file = "stack_data-0.5.1-py3-none-any.whl", hash = "sha256:5120731a18ba4c82cefcf84a945f6f3e62319ef413bfc210e32aca3a69310ba2"}, - {file = "stack_data-0.5.1.tar.gz", hash = "sha256:95eb784942e861a3d80efd549ff9af6cf847d88343a12eb681d7157cfcb6e32b"}, -] -swagger-ui-bundle = [ - {file = "swagger_ui_bundle-0.0.9-py3-none-any.whl", hash = "sha256:cea116ed81147c345001027325c1ddc9ca78c1ee7319935c3c75d3669279d575"}, - {file = "swagger_ui_bundle-0.0.9.tar.gz", hash = "sha256:b462aa1460261796ab78fd4663961a7f6f347ce01760f1303bbbdf630f11f516"}, -] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] -tornado = [ - {file = "tornado-6.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72"}, - {file = "tornado-6.2-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca"}, - {file = "tornado-6.2-cp37-abi3-win32.whl", hash = "sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23"}, - {file = "tornado-6.2-cp37-abi3-win_amd64.whl", hash = "sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"}, - {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"}, -] -traitlets = [ - {file = "traitlets-5.4.0-py3-none-any.whl", hash = "sha256:93663cc8236093d48150e2af5e2ed30fc7904a11a6195e21bab0408af4e6d6c8"}, - {file = "traitlets-5.4.0.tar.gz", hash = "sha256:3f2c4e435e271592fe4390f1746ea56836e3a080f84e7833f0f801d9613fec39"}, -] -urllib3 = [ - {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, - {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, -] -uvicorn = [ - {file = "uvicorn-0.18.3-py3-none-any.whl", hash = "sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af"}, - {file = "uvicorn-0.18.3.tar.gz", hash = "sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b"}, -] -uvloop = [ - {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718"}, - {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c"}, - {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d"}, - {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff3d00b70ce95adce264462c930fbaecb29718ba6563db354608f37e49e09024"}, - {file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a5abddb3558d3f0a78949c750644a67be31e47936042d4f6c888dd6f3c95f4aa"}, - {file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8efcadc5a0003d3a6e887ccc1fb44dec25594f117a94e3127954c05cf144d811"}, - {file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3378eb62c63bf336ae2070599e49089005771cc651c8769aaad72d1bd9385a7c"}, - {file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6aafa5a78b9e62493539456f8b646f85abc7093dd997f4976bb105537cf2635e"}, - {file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c686a47d57ca910a2572fddfe9912819880b8765e2f01dc0dd12a9bf8573e539"}, - {file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:864e1197139d651a76c81757db5eb199db8866e13acb0dfe96e6fc5d1cf45fc4"}, - {file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2a6149e1defac0faf505406259561bc14b034cdf1d4711a3ddcdfbaa8d825a05"}, - {file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6708f30db9117f115eadc4f125c2a10c1a50d711461699a0cbfaa45b9a78e376"}, - {file = "uvloop-0.17.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:23609ca361a7fc587031429fa25ad2ed7242941adec948f9d10c045bfecab06b"}, - {file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2deae0b0fb00a6af41fe60a675cec079615b01d68beb4cc7b722424406b126a8"}, - {file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45cea33b208971e87a31c17622e4b440cac231766ec11e5d22c76fab3bf9df62"}, - {file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9b09e0f0ac29eee0451d71798878eae5a4e6a91aa275e114037b27f7db72702d"}, - {file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dbbaf9da2ee98ee2531e0c780455f2841e4675ff580ecf93fe5c48fe733b5667"}, - {file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a4aee22ece20958888eedbad20e4dbb03c37533e010fb824161b4f05e641f738"}, - {file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:307958f9fc5c8bb01fad752d1345168c0abc5d62c1b72a4a8c6c06f042b45b20"}, - {file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ebeeec6a6641d0adb2ea71dcfb76017602ee2bfd8213e3fcc18d8f699c5104f"}, - {file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1436c8673c1563422213ac6907789ecb2b070f5939b9cbff9ef7113f2b531595"}, - {file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8887d675a64cfc59f4ecd34382e5b4f0ef4ae1da37ed665adba0c2badf0d6578"}, - {file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3db8de10ed684995a7f34a001f15b374c230f7655ae840964d51496e2f8a8474"}, - {file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d37dccc7ae63e61f7b96ee2e19c40f153ba6ce730d8ba4d3b4e9738c1dccc1b"}, - {file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cbbe908fda687e39afd6ea2a2f14c2c3e43f2ca88e3a11964b297822358d0e6c"}, - {file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d97672dc709fa4447ab83276f344a165075fd9f366a97b712bdd3fee05efae8"}, - {file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1e507c9ee39c61bfddd79714e4f85900656db1aec4d40c6de55648e85c2799c"}, - {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c092a2c1e736086d59ac8e41f9c98f26bbf9b9222a76f21af9dfe949b99b2eb9"}, - {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded"}, - {file = "uvloop-0.17.0.tar.gz", hash = "sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1"}, -] -watchfiles = [ - {file = "watchfiles-0.17.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:c7e1ffbd03cbcb46d1b7833e10e7d6b678ab083b4e4b80db06cfff5baca3c93f"}, - {file = "watchfiles-0.17.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:539bcdb55a487126776c9d8c011094214d1df3f9a2321a6c0b1583197309405a"}, - {file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:00e5f307a58752ec1478eeb738863544bde21cc7a2728bd1c216060406bde9c1"}, - {file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:92675f379a9d5adbc6a52179f3e39aa56944c6eecb80384608fff2ed2619103a"}, - {file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dd1e3181ad5d83ca35e9147c72e24f39437fcdf570c9cdc532016399fb62957"}, - {file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:204950f1d6083539af5c8b7d4f5f8039c3ce36fa692da12d9743448f3199cb15"}, - {file = "watchfiles-0.17.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:4056398d8f6d4972fe0918707b59d4cb84470c91d3c37f0e11e5a66c2a598760"}, - {file = "watchfiles-0.17.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ffff3418dc753a2aed2d00200a4daeaac295c40458f8012836a65555f288be8b"}, - {file = "watchfiles-0.17.0-cp37-abi3-win32.whl", hash = "sha256:b5c334cd3bc88aa4a8a1e08ec9f702b63c947211275defdc2dd79dc037fcb500"}, - {file = "watchfiles-0.17.0-cp37-abi3-win_amd64.whl", hash = "sha256:53a2faeb121bc51bb6b960984f46901227e2e2475acc5a8d4c905a600436752d"}, - {file = "watchfiles-0.17.0-cp37-abi3-win_arm64.whl", hash = "sha256:58dc3140dcf02a8aa76464a77a093016f10e89306fec21a4814922a64f3e8b9f"}, - {file = "watchfiles-0.17.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:adcf15ecc2182ea9d2358c1a8c2b53203c3909484918776929b7bbe205522c0e"}, - {file = "watchfiles-0.17.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:afd35a1bd3b9e68efe384ae7538481ae725597feb66f56f4bd23ecdbda726da0"}, - {file = "watchfiles-0.17.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad2bdcae4c0f07ca6c090f5a2c30188cc6edba011b45e7c96eb1896648092367"}, - {file = "watchfiles-0.17.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:a53cb6c06e5c1f216c792fbb432ce315239d432cb8b68d508547100939ec0399"}, - {file = "watchfiles-0.17.0-pp39-pypy39_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6a3d6c699f3ce238dfa90bcef501f331a69b0d9b076f14459ed8eab26ba2f4cf"}, - {file = "watchfiles-0.17.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f4271af86569bdbf131dd5c7c121c45d0ed194f3c88b88326e48a3b6a2db12"}, - {file = "watchfiles-0.17.0.tar.gz", hash = "sha256:ae7c57ef920589a40270d5ef3216d693f4e6f8864d8fc8b6cb7885ca98ad2a61"}, -] -wcwidth = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, -] -websockets = [ - {file = "websockets-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978"}, - {file = "websockets-10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500"}, - {file = "websockets-10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b"}, - {file = "websockets-10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c"}, - {file = "websockets-10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8"}, - {file = "websockets-10.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677"}, - {file = "websockets-10.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e"}, - {file = "websockets-10.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f"}, - {file = "websockets-10.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47"}, - {file = "websockets-10.3-cp310-cp310-win32.whl", hash = "sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae"}, - {file = "websockets-10.3-cp310-cp310-win_amd64.whl", hash = "sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079"}, - {file = "websockets-10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916"}, - {file = "websockets-10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb"}, - {file = "websockets-10.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79"}, - {file = "websockets-10.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d"}, - {file = "websockets-10.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98"}, - {file = "websockets-10.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e"}, - {file = "websockets-10.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6"}, - {file = "websockets-10.3-cp37-cp37m-win32.whl", hash = "sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1"}, - {file = "websockets-10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4"}, - {file = "websockets-10.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36"}, - {file = "websockets-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69"}, - {file = "websockets-10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd"}, - {file = "websockets-10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2"}, - {file = "websockets-10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c"}, - {file = "websockets-10.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e"}, - {file = "websockets-10.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991"}, - {file = "websockets-10.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442"}, - {file = "websockets-10.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76"}, - {file = "websockets-10.3-cp38-cp38-win32.whl", hash = "sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559"}, - {file = "websockets-10.3-cp38-cp38-win_amd64.whl", hash = "sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d"}, - {file = "websockets-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094"}, - {file = "websockets-10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667"}, - {file = "websockets-10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731"}, - {file = "websockets-10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9"}, - {file = "websockets-10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680"}, - {file = "websockets-10.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247"}, - {file = "websockets-10.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af"}, - {file = "websockets-10.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3"}, - {file = "websockets-10.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8"}, - {file = "websockets-10.3-cp39-cp39-win32.whl", hash = "sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582"}, - {file = "websockets-10.3-cp39-cp39-win_amd64.whl", hash = "sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02"}, - {file = "websockets-10.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7"}, - {file = "websockets-10.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f"}, - {file = "websockets-10.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4"}, - {file = "websockets-10.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755"}, - {file = "websockets-10.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55"}, - {file = "websockets-10.3.tar.gz", hash = "sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4"}, -] -Werkzeug = [ - {file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"}, - {file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"}, -] -z3-solver = [ - {file = "z3-solver-4.11.2.0.tar.gz", hash = "sha256:c7c7f10350db19eec831f9a45833268022c786e9ac0fbd9b2330956b377b9c39"}, - {file = "z3_solver-4.11.2.0-py2.py3-none-macosx_10_16_x86_64.whl", hash = "sha256:90b34ffbd42ee9465ca047bfb99775c1000f6548f2b98bdeb7d52397347aa197"}, - {file = "z3_solver-4.11.2.0-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:2cb81dcc220292dfcff6b5937f5faebeba4d0db7d2cc690f43e6f619bda40c47"}, - {file = "z3_solver-4.11.2.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:9b5a11370df7ac27394fc660c812b2c9aac26f21fadf11e2c51a19cb707c1795"}, - {file = "z3_solver-4.11.2.0-py2.py3-none-win32.whl", hash = "sha256:e4d3302c4046d65d0c8b5601d9b085f219b0fa78e312d08a5b24c86bb1629d05"}, - {file = "z3_solver-4.11.2.0-py2.py3-none-win_amd64.whl", hash = "sha256:f763c6ad22a8455df46efa3755a75d5af5d40535a1e5ec5171c199cfda663e90"}, -] -zipp = [ - {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"}, - {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"}, -] diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 5555494edb4086027825211b318f958a3f79fc49..0000000000000000000000000000000000000000 --- a/pyproject.toml +++ /dev/null @@ -1,28 +0,0 @@ -[tool.poetry] -name = "mc_openapi" -version = "1.2.0" -description = "OpenAPI interface for the PIACERE DOML model checker." -authors = ["Michele Chiari <michele.chiari@polimi.it>", "Michele De Pascalis <michele.de.pascalis.1024@gmail.com>"] -license = "Apache-2.0" - -[tool.poetry.dependencies] -python = "^3.9" -connexion = {extras = ["swagger-ui"], version = "^2.14"} -pyecore = "^0.12.2" -z3-solver = "^4.9" -PyYAML = "^6.0" -networkx = "^2.8" -joblib = "^1.1" -uvicorn = {extras = ["standard"], version = "^0.18"} - -[tool.poetry.dev-dependencies] -pytest = "^7.0" -requests = "^2.28" -ipykernel = "^6.15" -prettyprinter = "^0.18" -Sphinx = "^5.0" -sphinx-rtd-theme = "^1.0" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt index 33608f3d47393b4ec11aa1a1b6fea42cd1812fd1..b5475e5c8b9a4ef6d17a7ee2173db6e95a7ffa72 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,42 +1,54 @@ -anyio==3.6.1 ; python_version >= "3.9" and python_version < "4.0" -attrs==22.1.0 ; python_version >= "3.9" and python_version < "4.0" -certifi==2022.9.24 ; python_version >= "3.9" and python_version < "4" -charset-normalizer==2.1.1 ; python_version >= "3.9" and python_version < "4" -click==8.1.3 ; python_version >= "3.9" and python_version < "4.0" -clickclick==20.10.2 ; python_version >= "3.9" and python_version < "4.0" -colorama==0.4.5 ; sys_platform == "win32" and python_version >= "3.9" and python_version < "4.0" or python_version >= "3.9" and python_version < "4.0" and platform_system == "Windows" -connexion[swagger-ui]==2.14.1 ; python_version >= "3.9" and python_version < "4.0" -flask==2.2.2 ; python_version >= "3.9" and python_version < "4.0" -future-fstrings==1.2.0 ; python_version >= "3.9" and python_version < "4.0" -h11==0.14.0 ; python_version >= "3.9" and python_version < "4.0" -httptools==0.5.0 ; python_version >= "3.9" and python_version < "4.0" -idna==3.4 ; python_version >= "3.9" and python_version < "4" -importlib-metadata==5.0.0 ; python_version >= "3.9" and python_version < "3.10" -inflection==0.5.1 ; python_version >= "3.9" and python_version < "4.0" -itsdangerous==2.1.2 ; python_version >= "3.9" and python_version < "4.0" -jinja2==3.1.2 ; python_version >= "3.9" and python_version < "4.0" -joblib==1.2.0 ; python_version >= "3.9" and python_version < "4.0" -jsonschema==4.16.0 ; python_version >= "3.9" and python_version < "4.0" -lxml==4.9.1 ; python_version >= "3.9" and python_version < "4.0" -markupsafe==2.1.1 ; python_version >= "3.9" and python_version < "4.0" -networkx==2.8.7 ; python_version >= "3.9" and python_version < "4.0" -ordered-set==4.1.0 ; python_version >= "3.9" and python_version < "4.0" -packaging==21.3 ; python_version >= "3.9" and python_version < "4.0" -pyecore==0.12.2 ; python_version >= "3.9" and python_version < "4.0" -pyparsing==3.0.9 ; python_version >= "3.9" and python_version < "4.0" -pyrsistent==0.18.1 ; python_version >= "3.9" and python_version < "4.0" -python-dotenv==0.21.0 ; python_version >= "3.9" and python_version < "4.0" -pyyaml==6.0 ; python_version >= "3.9" and python_version < "4.0" -requests==2.28.1 ; python_version >= "3.9" and python_version < "4" -restrictedpython==5.0 ; python_version >= "3.9" and python_version < "4.0" -setuptools==65.4.1 ; python_version >= "3.9" and python_version < "4.0" -sniffio==1.3.0 ; python_version >= "3.9" and python_version < "4.0" -swagger-ui-bundle==0.0.9 ; python_version >= "3.9" and python_version < "4.0" -urllib3==1.26.12 ; python_version >= "3.9" and python_version < "4" -uvicorn[standard]==0.18.3 ; python_version >= "3.9" and python_version < "4.0" -uvloop==0.17.0 ; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" and python_version >= "3.9" and python_version < "4.0" -watchfiles==0.17.0 ; python_version >= "3.9" and python_version < "4.0" -websockets==10.3 ; python_version >= "3.9" and python_version < "4.0" -werkzeug==2.2.2 ; python_version >= "3.9" and python_version < "4.0" -z3-solver==4.11.2.0 ; python_version >= "3.9" and python_version < "4.0" -zipp==3.8.1 ; python_version >= "3.9" and python_version < "3.10" +alabaster==0.7.13 +attrs==22.2.0 +Babel==2.11.0 +beautifulsoup4==4.11.1 +certifi==2022.12.7 +charset-normalizer==3.0.1 +click==8.1.3 +clickclick==20.10.2 +connexion==2.14.2 +docutils==0.19 +Flask==2.2.2 +furo==2022.12.7 +future-fstrings==1.2.0 +h11==0.14.0 +idna==3.4 +imagesize==1.4.1 +inflection==0.5.1 +iniconfig==2.0.0 +itsdangerous==2.1.2 +Jinja2==3.1.2 +joblib==1.2.0 +jsonschema==4.17.3 +lark==1.1.5 +lxml==4.9.2 +MarkupSafe==2.1.2 +networkx==3.0 +ordered-set==4.1.0 +packaging==23.0 +piacere-doml-synthesis==2023.1.3 +pluggy==1.0.0 +pyecore==0.13.0 +Pygments==2.14.0 +pyrsistent==0.19.3 +pytest==7.2.1 +pytz==2022.7.1 +PyYAML==6.0 +requests==2.28.2 +RestrictedPython==6.0 +snowballstemmer==2.2.0 +soupsieve==2.3.2.post1 +Sphinx==6.1.3 +sphinx-basic-ng==1.0.0b1 +sphinxcontrib-applehelp==1.0.4 +sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-htmlhelp==2.0.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-serializinghtml==1.1.5 +swagger-ui-bundle==0.0.9 +termcolor==2.2.0 +urllib3==1.26.14 +uvicorn==0.20.0 +Werkzeug==2.2.2 +z3-solver==4.11.2.0 diff --git a/tests/doml/v2.0/nginx-openstack_v2.0_valid_mem_req.domlx b/tests/doml/v2.0/nginx-openstack_v2.0_valid_mem_req.domlx new file mode 100644 index 0000000000000000000000000000000000000000..79ba8b959d36aa642f1b3515e830e80af943e4aa --- /dev/null +++ b/tests/doml/v2.0/nginx-openstack_v2.0_valid_mem_req.domlx @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_openstack" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="app"> + <components xsi:type="app:SoftwareComponent" name="nginx"> + <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/> + </components> + </application> + <infrastructure name="infra"> + <generators xsi:type="infra:VMImage" name="v_img" generatedVMs="//@infrastructure/@groups.0/@machineDefinition"/> + <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/> + <groups xsi:type="infra:AutoScalingGroup" name="ag" deploymentNetwork="//@infrastructure/@networks.0"> + <machineDefinition name="vm1" os="ubuntu-20.04.3" memory_mb="512.0" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0"> + <ifaces name="i1" endPoint="16.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </machineDefinition> + </groups> + <securityGroups name="sg" ifaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="net1" protocol="tcp/ip" addressRange="16.0.0.0/24" connectedIfaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"/> + </infrastructure> + <concretizations name="con_infra"> + <providers name="openstack"> + <vms name="concrete_vm" maps="//@infrastructure/@groups.0/@machineDefinition"> + <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/> + <annotations xsi:type="commons:SProperty" key="vm_flavor" value="small"/> + <annotations xsi:type="commons:SProperty" key="vm_key_name" value="user1"/> + </vms> + <vmImages name="concrete_vm_image" maps="//@infrastructure/@generators.0"> + <annotations xsi:type="commons:SProperty" key="name" value="ubuntu-20.04.3"/> + </vmImages> + <networks name="concrete_net" maps="//@infrastructure/@networks.0"> + <annotations xsi:type="commons:SProperty" key="name" value="ostack2"/> + </networks> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost <= 200" property="cost" max="200.0"/> + <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider"> + <values>AMAZ</values> + </nonfunctionalRequirements> + </optimization> + <configurations name="config"> + <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.0/nginx-openstack_v2.0_wrong_nginx_source_code.domlx b/tests/doml/v2.0/nginx-openstack_v2.0_wrong_nginx_source_code.domlx new file mode 100644 index 0000000000000000000000000000000000000000..455b90f55300e3a4d61b4c5d726a1224fa9d81dc --- /dev/null +++ b/tests/doml/v2.0/nginx-openstack_v2.0_wrong_nginx_source_code.domlx @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_openstack" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="app"> + <components xsi:type="app:SoftwareComponent" name="nginx"/> + </application> + <infrastructure name="infra"> + <generators xsi:type="infra:VMImage" name="v_img" generatedVMs="//@infrastructure/@groups.0/@machineDefinition"/> + <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/> + <groups xsi:type="infra:AutoScalingGroup" name="ag" deploymentNetwork="//@infrastructure/@networks.0"> + <machineDefinition name="vm1" os="ubuntu-20.04.3" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0"> + <ifaces name="i1" endPoint="16.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </machineDefinition> + </groups> + <securityGroups name="sg" ifaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="net1" protocol="tcp/ip" addressRange="16.0.0.0/24" connectedIfaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"/> + </infrastructure> + <concretizations name="con_infra"> + <providers name="openstack"> + <vms name="concrete_vm" maps="//@infrastructure/@groups.0/@machineDefinition"> + <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/> + <annotations xsi:type="commons:SProperty" key="vm_flavor" value="small"/> + <annotations xsi:type="commons:SProperty" key="vm_key_name" value="user1"/> + </vms> + <vmImages name="concrete_vm_image" maps="//@infrastructure/@generators.0"> + <annotations xsi:type="commons:SProperty" key="name" value="ubuntu-20.04.3"/> + </vmImages> + <networks name="concrete_net" maps="//@infrastructure/@networks.0"> + <annotations xsi:type="commons:SProperty" key="name" value="ostack2"/> + </networks> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost <= 200" property="cost" max="200.0"/> + <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider"> + <values>AMAZ</values> + </nonfunctionalRequirements> + </optimization> + <configurations name="config"> + <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.0/openstack_template.domlx b/tests/doml/v2.0/openstack_template.domlx new file mode 100644 index 0000000000000000000000000000000000000000..514308a5a88e83ed0173b8af5b5d698bc00744ff --- /dev/null +++ b/tests/doml/v2.0/openstack_template.domlx @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_openstack" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="app"> + <components xsi:type="app:SoftwareComponent" name="nginx"> + <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/> + </components> + </application> + <infrastructure name="infra"> + <nodes xsi:type="infra:VirtualMachine" name="vm1" os="ubuntu-20.04.3"/> + </infrastructure> + <concretizations name="con_infra"> + <providers name="openstack"> + <vms name="concrete_vm" maps="//@infrastructure/@nodes.0"> + <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/> + <annotations xsi:type="commons:SProperty" key="vm_flavor" value="small"/> + <annotations xsi:type="commons:SProperty" key="vm_key_name" value="user1"/> + </vms> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + </optimization> + <configurations name="config"> + <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.0/saas.domlx b/tests/doml/v2.0/saas.domlx new file mode 100644 index 0000000000000000000000000000000000000000..bdfa1f32b00544dc4215557ea74c98884e61e693 --- /dev/null +++ b/tests/doml/v2.0/saas.domlx @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="iot_simple_app"> + <components xsi:type="app:DBMS" name="oracle"> + <exposedInterfaces name="sql_interface"/> + </components> + <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0"> + <exposedInterfaces name="sensor_info"/> + </components> + <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/> + <components xsi:type="app:SaaS" name="external_meteo"> + <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/> + </components> + </application> + <infrastructure name="infra"> + <nodes xsi:type="infra:VirtualMachine" name="vm1"> + <ifaces name="i1" endPoint="10.0.0.2" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:VirtualMachine" name="vm2"> + <ifaces name="i1" endPoint="10.0.0.3" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1"> + <ifaces name="i1" endPoint="10.0.0.4" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2"> + <ifaces name="i1" endPoint="10.0.0.5" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/> + <securityGroups name="sg1" ifaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="net1" protocol="tcp/ip" addressRange="10.0.0.0/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"/> + </infrastructure> + <concretizations name="con_infra1"> + <providers name="aws"> + <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0"> + <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/> + </vms> + <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/> + <networks name="concrete_net1" maps="//@infrastructure/@networks.0"/> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost <= 200" property="cost" max="200.0"/> + <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider"> + <values>AMAZ</values> + </nonfunctionalRequirements> + </optimization> + <configurations name="config1"> + <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/> + <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.0/saas_https_no_attrs.domlx b/tests/doml/v2.0/saas_https_no_attrs.domlx new file mode 100644 index 0000000000000000000000000000000000000000..38cf851c241d1de8d8d970c58117e7e5c9f026e3 --- /dev/null +++ b/tests/doml/v2.0/saas_https_no_attrs.domlx @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="iot_simple_app"> + <components xsi:type="app:DBMS" name="oracle"> + <exposedInterfaces name="sql_interface"/> + </components> + <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0"> + <exposedInterfaces name="sensor_info"/> + </components> + <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/> + <components xsi:type="app:SaaS" name="external_meteo"> + <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/> + </components> + </application> + <infrastructure name="infra"> + <nodes xsi:type="infra:VirtualMachine" name="vm1"> + <ifaces name="i1" endPoint="10.0.0.2" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:VirtualMachine" name="vm2"> + <ifaces name="i1" endPoint="10.0.0.3" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1"> + <ifaces name="i1" endPoint="10.0.0.4" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2"> + <ifaces name="i1" endPoint="10.0.0.5" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/> + <securityGroups name="sg1" ifaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="https" kind="INGRESS"/> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="net1" protocol="tcp/ip" addressRange="10.0.0.0/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"/> + </infrastructure> + <concretizations name="con_infra1"> + <providers name="aws"> + <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0"> + <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/> + </vms> + <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/> + <networks name="concrete_net1" maps="//@infrastructure/@networks.0"/> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost <= 200" property="cost" max="200.0"/> + <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider"> + <values>AMAZ</values> + </nonfunctionalRequirements> + </optimization> + <configurations name="config1"> + <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/> + <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.0/saas_no_https_rule.domlx b/tests/doml/v2.0/saas_no_https_rule.domlx new file mode 100644 index 0000000000000000000000000000000000000000..8d824c6679283729984ceec8bc4ff0c4a313729f --- /dev/null +++ b/tests/doml/v2.0/saas_no_https_rule.domlx @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="iot_simple_app"> + <components xsi:type="app:DBMS" name="oracle"> + <exposedInterfaces name="sql_interface"/> + </components> + <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0"> + <exposedInterfaces name="sensor_info"/> + </components> + <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/> + <components xsi:type="app:SaaS" name="external_meteo"> + <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/> + </components> + </application> + <infrastructure name="infra"> + <nodes xsi:type="infra:VirtualMachine" name="vm1"> + <ifaces name="i1" endPoint="10.0.0.2" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:VirtualMachine" name="vm2"> + <ifaces name="i1" endPoint="10.0.0.3" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1"> + <ifaces name="i1" endPoint="10.0.0.4" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2"> + <ifaces name="i1" endPoint="10.0.0.5" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/> + <securityGroups name="sg1" ifaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="net1" protocol="tcp/ip" addressRange="10.0.0.0/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"/> + </infrastructure> + <concretizations name="con_infra1"> + <providers name="aws"> + <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0"> + <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/> + </vms> + <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/> + <networks name="concrete_net1" maps="//@infrastructure/@networks.0"/> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost <= 200" property="cost" max="200.0"/> + <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider"> + <values>AMAZ</values> + </nonfunctionalRequirements> + </optimization> + <configurations name="config1"> + <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/> + <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.0/saas_wrong_no_iface_sg.domlx b/tests/doml/v2.0/saas_wrong_no_iface_sg.domlx new file mode 100644 index 0000000000000000000000000000000000000000..be6aaffdf2eda69c3eef4d1ebbf936ae2b5afdbe --- /dev/null +++ b/tests/doml/v2.0/saas_wrong_no_iface_sg.domlx @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="iot_simple_app"> + <components xsi:type="app:DBMS" name="oracle"> + <exposedInterfaces name="sql_interface"/> + </components> + <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0"> + <exposedInterfaces name="sensor_info"/> + </components> + <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/> + <components xsi:type="app:SaaS" name="external_meteo"> + <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/> + </components> + </application> + <infrastructure name="infra"> + <nodes xsi:type="infra:VirtualMachine" name="vm1"> + <ifaces name="i1" endPoint="10.0.0.2" belongsTo="//@infrastructure/@networks.0"/> + </nodes> + <nodes xsi:type="infra:VirtualMachine" name="vm2"> + <ifaces name="i1" endPoint="10.0.0.3" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1"> + <ifaces name="i1" endPoint="10.0.0.4" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2"> + <ifaces name="i1" endPoint="10.0.0.5" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + </nodes> + <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/> + <securityGroups name="sg1" ifaces="//@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="net1" protocol="tcp/ip" addressRange="10.0.0.0/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"/> + </infrastructure> + <concretizations name="con_infra1"> + <providers name="aws"> + <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0"> + <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/> + </vms> + <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/> + <networks name="concrete_net1" maps="//@infrastructure/@networks.0"/> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost <= 200" property="cost" max="200.0"/> + <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider"> + <values>AMAZ</values> + </nonfunctionalRequirements> + </optimization> + <configurations name="config1"> + <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/> + <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.2/.project b/tests/doml/v2.2/.project new file mode 100644 index 0000000000000000000000000000000000000000..96bcdb7a1076c114a39e5046f8f7d8a1b7c96daa --- /dev/null +++ b/tests/doml/v2.2/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>domlTests</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.xtext.ui.shared.xtextBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.xtext.ui.shared.xtextNature</nature> + </natures> +</projectDescription> diff --git a/tests/doml/v2.2/faas.doml b/tests/doml/v2.2/faas.doml new file mode 100644 index 0000000000000000000000000000000000000000..9345cc7d776cafd80d1a0af2553202e6f8ea112d --- /dev/null +++ b/tests/doml/v2.2/faas.doml @@ -0,0 +1,177 @@ +doml faas_app + +application ImageResizeApp { + + software_component image_resize { + provides { + handle_image + } + consumes { + storage_interface, + bucket_in, + bucket_out + } + properties { + source_code = "path/lambda/function/image_resize.py"; + } + } + + saas s1 { + provides { + storage_interface + bucket_in + } + } + + saas s2 { + provides { + storage_interface + bucket_out + } + } + + software_component notification { + consumes { + handle_image, + bucket_in + } + } + + software_component web { + consumes { + storage_interface, + bucket_out + } + properties { + source_code = "path/web_app"; + } + } +} + +infrastructure infra { + vm vm1 { + iface i1 { + address "10.0.0.1" + belongs_to vpc + security sg + } + credentials ssh_key + loc { + region "eu-central-1" + } + } + + vm_image v_img { + generates vm1 + image "ami-xxxxxxxxxxxxxxxxx" + } + + container c { + host vm1 + } + + cont_image c_img { + generates c + image "web-app:0.1.0" + } + + faas f { } + + sto st1 { } + + sto st2 { } + + net vpc { + cidr "/24" + protocol "tcp/ip" + subnet vpc_subnet { + cidr "/24" + protocol "tcp/ip" + } + } + + security_group sg { + egress icmp { + from_port -1 + to_port -1 + protocol "icmp" + cidr ["0.0.0.0/0"] + } + ingress http { + from_port 80 + to_port 80 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ingress https { + from_port 443 + to_port 443 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ingress ssh { + from_port 22 + to_port 22 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ifaces i1 + } + + key_pair ssh_key { + user "ec2-user" + keyfile "/tmp/ssh_key_file" + algorithm "RSA" + bits 4096 + } +} + +deployment config1 { + image_resize -> f, + web -> c, + s1 -> st1, + s2 -> st2 +} + +active deployment config1 + +concretizations { + concrete_infrastructure con_infra { + provider aws { + vm concrete_vm { + properties { + instance_type = "t2.micro"; + ssh_key_name = "demo-key"; + ec2_role_name = "demo-ec2-role"; + } + maps vm1 + } + faas concrete_f { + properties { + lambda_role_name = "DemoLambdaRole"; + lambda_runtime = "python3.8"; + lambda_handler = "image_resize.lambda_handler"; + lambda_timeout = 5; + lambda_memory = 128; + } + maps f + } + storage s3_bucket_in { + properties { + bucket_name = "bucket_in"; + } + maps st1 + } + storage s3_bucket_out { + properties { + bucket_name = "bucket_out"; + } + maps st2 + } + net concrete_net { + maps vpc + } + } + } + active con_infra +} \ No newline at end of file diff --git a/tests/doml/v2.2/faas.domlx b/tests/doml/v2.2/faas.domlx new file mode 100644 index 0000000000000000000000000000000000000000..dc83d7135253786f5e7d1fbb9180c0ab1da9e2ca --- /dev/null +++ b/tests/doml/v2.2/faas.domlx @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" name="faas_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="ImageResizeApp"> + <components xsi:type="app:SoftwareComponent" name="image_resize" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0 //@application/@components.1/@exposedInterfaces.1 //@application/@components.2/@exposedInterfaces.1"> + <annotations xsi:type="commons:SProperty" key="source_code" value="path/lambda/function/image_resize.py"/> + <exposedInterfaces name="handle_image"/> + </components> + <components xsi:type="app:SaaS" name="s1"> + <exposedInterfaces name="storage_interface"/> + <exposedInterfaces name="bucket_in"/> + </components> + <components xsi:type="app:SaaS" name="s2"> + <exposedInterfaces name="storage_interface"/> + <exposedInterfaces name="bucket_out"/> + </components> + <components xsi:type="app:SoftwareComponent" name="notification" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.1/@exposedInterfaces.1"/> + <components xsi:type="app:SoftwareComponent" name="web" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0 //@application/@components.2/@exposedInterfaces.1"> + <annotations xsi:type="commons:SProperty" key="source_code" value="path/web_app"/> + </components> + </application> + <infrastructure name="infra"> + <nodes xsi:type="infra:VirtualMachine" name="vm1" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0"> + <ifaces name="i1" endPoint="10.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + <location region="eu-central-1"/> + </nodes> + <nodes xsi:type="infra:Container" name="c" generatedFrom="//@infrastructure/@generators.1"> + <configs host="//@infrastructure/@nodes.0"/> + </nodes> + <generators xsi:type="infra:VMImage" name="v_img" uri="ami-xxxxxxxxxxxxxxxxx" kind="IMAGE" generatedVMs="//@infrastructure/@nodes.0"/> + <generators xsi:type="infra:ContainerImage" name="c_img" uri="web-app:0.1.0" kind="IMAGE" generatedContainers="//@infrastructure/@nodes.1"/> + <storages name="st1"/> + <storages name="st2"/> + <faas name="f"/> + <credentials xsi:type="commons:KeyPair" name="ssh_key" user="ec2-user" keyfile="/tmp/ssh_key_file" algorithm="RSA" bits="4096"/> + <securityGroups name="sg" ifaces="//@infrastructure/@nodes.0/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="vpc" protocol="tcp/ip" addressRange="/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0"> + <subnets name="vpc_subnet" protocol="tcp/ip" addressRange="/24"/> + </networks> + </infrastructure> + <concretizations name="con_infra"> + <providers name="aws"> + <vms name="concrete_vm" maps="//@infrastructure/@nodes.0"> + <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/> + <annotations xsi:type="commons:SProperty" key="ssh_key_name" value="demo-key"/> + <annotations xsi:type="commons:SProperty" key="ec2_role_name" value="demo-ec2-role"/> + </vms> + <networks name="concrete_net" maps="//@infrastructure/@networks.0"/> + <storages name="s3_bucket_in" maps="//@infrastructure/@storages.0"> + <annotations xsi:type="commons:SProperty" key="bucket_name" value="bucket_in"/> + </storages> + <storages name="s3_bucket_out" maps="//@infrastructure/@storages.1"> + <annotations xsi:type="commons:SProperty" key="bucket_name" value="bucket_out"/> + </storages> + <faas name="concrete_f" maps="//@infrastructure/@faas.0"> + <annotations xsi:type="commons:SProperty" key="lambda_role_name" value="DemoLambdaRole"/> + <annotations xsi:type="commons:SProperty" key="lambda_runtime" value="python3.8"/> + <annotations xsi:type="commons:SProperty" key="lambda_handler" value="image_resize.lambda_handler"/> + <annotations xsi:type="commons:IProperty" key="lambda_timeout" value="5"/> + <annotations xsi:type="commons:IProperty" key="lambda_memory" value="128"/> + </faas> + </providers> + </concretizations> + <configurations name="config1"> + <deployments component="//@application/@components.0" node="//@infrastructure/@faas.0"/> + <deployments component="//@application/@components.4" node="//@infrastructure/@nodes.1"/> + <deployments component="//@application/@components.1" node="//@infrastructure/@storages.0"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@storages.1"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.2/iot_simple_app.doml b/tests/doml/v2.2/iot_simple_app.doml new file mode 100644 index 0000000000000000000000000000000000000000..4dca09ac6ec52afa070731e6942535354b8eb5b4 --- /dev/null +++ b/tests/doml/v2.2/iot_simple_app.doml @@ -0,0 +1,52 @@ +doml iot_simple_app + +application iot_simple_app { + dbms oracle { + provides { sql_interface } + } + + software_component web_server { + provides { sensor_info } + consumes { sql_interface, get_weather } + } + + software_component iot_provider { + consumes { sensor_info } + } + + saas external_meteo { + provides { get_weather @ "https://api.mymeteo.com/get" } + } +} + +infrastructure infra { + vm vm1 {} + vm vm2 {} + node iot_device1 {} + node iot_device2 {} +} + +deployment config1 { + oracle -> vm1, + web_server -> vm2, + iot_provider -> iot_device1, + iot_provider -> iot_device2 +} + +active deployment config1 + +concretizations { + concrete_infrastructure con_infra1 { + provider aws { + vm concrete_vm1 { + properties { instance_type = "t2.micro"; } + maps vm1 + } + vm concrete_vm2 { + properties {} + maps vm2 + } + } + } + active con_infra1 +} \ No newline at end of file diff --git a/tests/doml/v2.2/iot_simple_app.domlx b/tests/doml/v2.2/iot_simple_app.domlx new file mode 100644 index 0000000000000000000000000000000000000000..d750eee5e1487c0b0097e48b3a92453dc3da95d2 --- /dev/null +++ b/tests/doml/v2.2/iot_simple_app.domlx @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="iot_simple_app"> + <components xsi:type="app:DBMS" name="oracle"> + <exposedInterfaces name="sql_interface"/> + </components> + <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0"> + <exposedInterfaces name="sensor_info"/> + </components> + <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/> + <components xsi:type="app:SaaS" name="external_meteo"> + <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/> + </components> + </application> + <infrastructure name="infra"> + <nodes xsi:type="infra:VirtualMachine" name="vm1"/> + <nodes xsi:type="infra:VirtualMachine" name="vm2"/> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1"/> + <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2"/> + </infrastructure> + <concretizations name="con_infra1"> + <providers name="aws"> + <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0"> + <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/> + </vms> + <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/> + </providers> + </concretizations> + <configurations name="config1"> + <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/> + <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/> + <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.2/nginx-aws-ec2.doml b/tests/doml/v2.2/nginx-aws-ec2.doml new file mode 100644 index 0000000000000000000000000000000000000000..8b1f7635abe55981f613ee869c490d364fd236a0 --- /dev/null +++ b/tests/doml/v2.2/nginx-aws-ec2.doml @@ -0,0 +1,121 @@ +doml nginx_aws_ec2 + +application app { + + software_component nginx { + properties { + source_code="/usr/share/nginx/html/index.html"; + } + } +} + +infrastructure infra { + + vm_image vm_img { + generates vm1 + image "ami-xxxxxxxxxxxxxxxxx" + } + + net vpc { + cidr "/24" + protocol "tcp/ip" + subnet vpc_subnet { + cidr "/24" + protocol "tcp/ip" + } + } + + security_group sg { + egress icmp { + from_port -1 + to_port -1 + protocol "icmp" + cidr ["0.0.0.0/0"] + } + ingress http { + from_port 80 + to_port 80 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ingress https { + from_port 443 + to_port 443 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ingress ssh { + from_port 22 + to_port 22 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ifaces i1 + } + + key_pair ssh_key { + user "ec2-user" + keyfile "/tmp/ssh_key_file" + algorithm "RSA" + bits 4096 + } + + autoscale_group ag { + vm vm1 { + iface i1 { + address "10.0.0.1" + belongs_to vpc + security sg + } + credentials ssh_key + loc { + region "eu-central-1" + } + } + } +} + +deployment conf { + nginx -> vm1 +} + +active deployment conf + +concretizations { + concrete_infrastructure con_infra { + provider aws { + vm ec2_vm { + properties { + vm_name = "nginx-host"; + instance_type = "t2.micro"; + ssh_key_name = "demo-key"; + ec2_role_name = "demo-ec2-role"; + } + maps vm1 + } + + vm_image concrete_vm_image { + maps vm_img + } + + net concrete_net { + properties { + vm_name = "nginx-host"; + } + maps vpc + } + } + } + active con_infra +} + +optimization opt { + objectives { + "cost" => min + "availability" => max + } + nonfunctional_requirements { + req1 "Cost <= 70.0" max 70.0 => "cost"; + req2 "Availability >= 66.5%" min 66.5 => "availability"; + } +} diff --git a/tests/doml/v2.2/nginx-aws-ec2.domlx b/tests/doml/v2.2/nginx-aws-ec2.domlx new file mode 100644 index 0000000000000000000000000000000000000000..14660f0286d3bb24560cccada553c121e06cd4e9 --- /dev/null +++ b/tests/doml/v2.2/nginx-aws-ec2.domlx @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_aws_ec2" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="app"> + <components xsi:type="app:SoftwareComponent" name="nginx"> + <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/> + </components> + </application> + <infrastructure name="infra"> + <generators xsi:type="infra:VMImage" name="vm_img" uri="ami-xxxxxxxxxxxxxxxxx" kind="IMAGE" generatedVMs="//@infrastructure/@groups.0/@machineDefinition"/> + <credentials xsi:type="commons:KeyPair" name="ssh_key" user="ec2-user" keyfile="/tmp/ssh_key_file" algorithm="RSA" bits="4096"/> + <groups xsi:type="infra:AutoScalingGroup" name="ag"> + <machineDefinition name="vm1" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0"> + <ifaces name="i1" endPoint="10.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + <location region="eu-central-1"/> + </machineDefinition> + </groups> + <securityGroups name="sg" ifaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="vpc" protocol="tcp/ip" addressRange="/24" connectedIfaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"> + <subnets name="vpc_subnet" protocol="tcp/ip" addressRange="/24"/> + </networks> + </infrastructure> + <concretizations name="con_infra"> + <providers name="aws"> + <vms name="ec2_vm" maps="//@infrastructure/@groups.0/@machineDefinition"> + <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/> + <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/> + <annotations xsi:type="commons:SProperty" key="ssh_key_name" value="demo-key"/> + <annotations xsi:type="commons:SProperty" key="ec2_role_name" value="demo-ec2-role"/> + </vms> + <vmImages name="concrete_vm_image" maps="//@infrastructure/@generators.0"/> + <networks name="concrete_net" maps="//@infrastructure/@networks.0"> + <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/> + </networks> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + <objectives xsi:type="optimization:MeasurableObjective" kind="max" property="availability"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost <= 70.0" property="cost" max="70.0"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req2" description="Availability >= 66.5%" property="availability" min="66.5"/> + </optimization> + <configurations name="conf"> + <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/> + </configurations> +</commons:DOMLModel> diff --git a/tests/doml/v2.2/nginx_func_req.doml b/tests/doml/v2.2/nginx_func_req.doml new file mode 100644 index 0000000000000000000000000000000000000000..f810a6be84417f7a40da07b084b08c4e5f50db8a --- /dev/null +++ b/tests/doml/v2.2/nginx_func_req.doml @@ -0,0 +1,149 @@ +doml nginx_func_req + +application app { + + software_component nginx { + properties { + source_code="/usr/share/nginx/html/index.html"; + } + } +} + +infrastructure infra { + + vm_image vm_img { + generates vm1 + image "ami-xxxxxxxxxxxxxxxxx" + } + + net vpc { + cidr "/24" + protocol "tcp/ip" + subnet vpc_subnet { + cidr "/24" + protocol "tcp/ip" + } + } + + security_group sg { + egress icmp { + from_port -1 + to_port -1 + protocol "icmp" + cidr ["0.0.0.0/0"] + } + ingress http { + from_port 80 + to_port 80 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ingress https { + from_port 443 + to_port 443 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ingress ssh { + from_port 22 + to_port 22 + protocol "tcp" + cidr ["0.0.0.0/0"] + } + ifaces i1 + } + + key_pair ssh_key { + user "ec2-user" + keyfile "/tmp/ssh_key_file" + algorithm "RSA" + bits 4096 + } + + autoscale_group ag { + vm vm1 { + iface i1 { + address "10.0.0.1" + belongs_to vpc + security sg + } + credentials ssh_key + loc { + region "eu-central-1" + } + } + } +} + +deployment conf { + nginx -> vm1 +} + +active deployment conf + +concretizations { + concrete_infrastructure con_infra { + provider aws { + vm ec2_vm { + properties { + vm_name = "nginx-host"; + instance_type = "t2.micro"; + ssh_key_name = "demo-key"; + ec2_role_name = "demo-ec2-role"; + } + maps vm1 + } + + vm_image concrete_vm_image { + maps vm_img + } + + net concrete_net { + properties { + vm_name = "nginx-host"; + } + maps vpc + } + } + } + active con_infra +} + +optimization opt { + objectives { + "cost" => min + "availability" => max + } + nonfunctional_requirements { + req1 "Cost <= 70.0" max 70.0 => "cost"; + req2 "Availability >= 66.5%" min 66.5 => "availability"; + } +} + +functional_requirements { + req_ext ``` + > "example requirement to test" + # Expr to parse + not ( + vm is class infrastructure.VirtualMachine + and + vm is not class infrastructure.Storage + or + vm is not class infrastructure.Storage + implies + vm is class infrastructure.Storage + ) + iff + not exists iface, apple ( + forall orange ( + vm has association infrastructure.ComputingNode->ifaces iface + or + vm has association infrastructure.ComputingNode->ifaces iface + ) + and + vm has attribute infrastructure.ComputingNode->os Os1 + ) + --- + "Virtual Machine {vm} has no iface" + ```; +} diff --git a/tests/doml/v2.2/nginx_func_req.domlx b/tests/doml/v2.2/nginx_func_req.domlx new file mode 100644 index 0000000000000000000000000000000000000000..f0f4e5af2424f404c8532f60487286bcf46367fb --- /dev/null +++ b/tests/doml/v2.2/nginx_func_req.domlx @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="ASCII"?> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_func_req" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> + <application name="app"> + <components xsi:type="app:SoftwareComponent" name="nginx"> + <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/> + </components> + </application> + <infrastructure name="infra"> + <generators xsi:type="infra:VMImage" name="vm_img" uri="ami-xxxxxxxxxxxxxxxxx" kind="IMAGE" generatedVMs="//@infrastructure/@groups.0/@machineDefinition"/> + <credentials xsi:type="commons:KeyPair" name="ssh_key" user="ec2-user" keyfile="/tmp/ssh_key_file" algorithm="RSA" bits="4096"/> + <groups xsi:type="infra:AutoScalingGroup" name="ag"> + <machineDefinition name="vm1" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0"> + <ifaces name="i1" endPoint="10.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/> + <location region="eu-central-1"/> + </machineDefinition> + </groups> + <securityGroups name="sg" ifaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"> + <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443"> + <cidr>0.0.0.0/0</cidr> + </rules> + <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22"> + <cidr>0.0.0.0/0</cidr> + </rules> + </securityGroups> + <networks name="vpc" protocol="tcp/ip" addressRange="/24" connectedIfaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"> + <subnets name="vpc_subnet" protocol="tcp/ip" addressRange="/24"/> + </networks> + </infrastructure> + <concretizations name="con_infra"> + <providers name="aws"> + <vms name="ec2_vm" maps="//@infrastructure/@groups.0/@machineDefinition"> + <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/> + <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/> + <annotations xsi:type="commons:SProperty" key="ssh_key_name" value="demo-key"/> + <annotations xsi:type="commons:SProperty" key="ec2_role_name" value="demo-ec2-role"/> + </vms> + <vmImages name="concrete_vm_image" maps="//@infrastructure/@generators.0"/> + <networks name="concrete_net" maps="//@infrastructure/@networks.0"> + <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/> + </networks> + </providers> + </concretizations> + <optimization name="opt"> + <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/> + <objectives xsi:type="optimization:MeasurableObjective" kind="max" property="availability"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost <= 70.0" property="cost" max="70.0"/> + <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req2" description="Availability >= 66.5%" property="availability" min="66.5"/> + </optimization> + <configurations name="conf"> + <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/> + </configurations> + <functionalRequirements name="req_ext" description="+ "All Virtual Machines have a Interface and at least 4 CPUs" forall vm (vm is class abstract.VirtualMachine implies exists iface (vm has abstract.ComputingNode.ifaces iface and vm has abstract.ComputingNode.cpu_count >= 4 )) error: "A vm does lacks an associated interface or has less than 4 CPUs""/> +</commons:DOMLModel> diff --git a/tests/domlr/example_multiple_reqs.domlr b/tests/domlr/example_multiple_reqs.domlr new file mode 100644 index 0000000000000000000000000000000000000000..451857494997fd31bd458e29b6c09d8c19021338 --- /dev/null +++ b/tests/domlr/example_multiple_reqs.domlr @@ -0,0 +1,52 @@ +- "VM must have iface" + vm is class infrastructure.VirtualMachine + and + not exists iface ( + vm has infrastructure.ComputingNode.ifaces iface + ) + + error: "VM {vm} must have iface {iface}" + +# + "VM must have iface" +# forall vm ( +# vm is class infrastructure.VirtualMachine +# implies +# exists iface ( +# vm has infrastructure.ComputingNode.ifaces iface +# ) +# ) + +# error: "VM {vm} must have iface {iface}" + ++ "VM must have cpu_count >= 4" + forall vm ( + vm is class infrastructure.VirtualMachine + implies + vm has infrastructure.ComputingNode.cpu_count >= 4 + ) + + error: "VM {vm} must have cpu_count >= 4 {iface}" + ++ "VM must have os == 'rhel8'" + forall vm ( + vm is class infrastructure.VirtualMachine + implies + vm has infrastructure.ComputingNode.os == "rhel8" + ) + + error: "VM {vm} must have os == 'rhel'" + +# OLD SYNTAX: +# - "Iface must be unique" +# ni1 has infrastructure.NetworkInterface.endPoint Value +# and +# ni1 is not ni2 +# and +# ni2 has infrastructure.NetworkInterface.endPoint Value + +- "Iface must be unique" + ni1 has infrastructure.NetworkInterface.endPoint == ni2 infrastructure.NetworkInterface.endPoint + and + ni1 is not ni2 + + error: "Iface {ni1} and {ni2} must have different values" diff --git a/tests/domlr/example_single_req.domlr b/tests/domlr/example_single_req.domlr new file mode 100644 index 0000000000000000000000000000000000000000..a3e87f406f7802d20ad1964591d49b2b7cad0210 --- /dev/null +++ b/tests/domlr/example_single_req.domlr @@ -0,0 +1,18 @@ +# vm, iface = get_consts(smtsorts, ["vm", "iface"]) +# return And( +# smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"], +# Not( +# Exists( +# [iface], +# ENCODINGS.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface) +# ) +# ) +# ) + +- "All VMs have at least one interface 1" + vm is class infrastructure.VirtualMachine + and + not exists iface ( + vm has abstract.ComputingNode.ifaces iface + ) + error: "VM {vm} has no associated interface." diff --git a/tests/domlr/example_single_req_bad_syntax.domlr b/tests/domlr/example_single_req_bad_syntax.domlr new file mode 100644 index 0000000000000000000000000000000000000000..195f5b49205d9368e0245a3d17334cda7a765ef9 --- /dev/null +++ b/tests/domlr/example_single_req_bad_syntax.domlr @@ -0,0 +1,21 @@ +# vm, iface = get_consts(smtsorts, ["vm", "iface"]) +# return And( +# smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"], +# Not( +# Exists( +# [iface], +# ENCODINGS.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface) +# ) +# ) +# ) + ++ "All VMs have at least one interface 1" + vm is class infrastructure.VirtualMachine + and + not exists iface ( + vm has infrastructure.ComputingNode.ifaces iface + and + vm has infrastructure.ComputingNode.ifaces X + ) + --- + "VM {vm} has no associated interface." diff --git a/tests/domlr/example_single_req_qty_comparison.domlr b/tests/domlr/example_single_req_qty_comparison.domlr new file mode 100644 index 0000000000000000000000000000000000000000..9d7029dcc1b145e2d62a8885e81f3fc1aa564de7 --- /dev/null +++ b/tests/domlr/example_single_req_qty_comparison.domlr @@ -0,0 +1,35 @@ +# vm, iface = get_consts(smtsorts, ["vm", "iface"]) +# return And( +# smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"], +# Not( +# Exists( +# [iface], +# ENCODINGS.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface) +# ) +# ) +# ) + +# OLD SYNTAX +# + "All VMs have at least 512 MB of memory" +# forall vm ( +# vm is class infrastructure.VirtualMachine +# implies +# ( +# vm has abstract.ComputingNode.memory_mb Mem +# and +# Mem < 512 +# ) +# ) + +# --- +# "All VMs have at least 256 MB of memory" + ++ "All VMs have at least 512 MB of memory" + forall vm ( + vm is class infrastructure.VirtualMachine + implies + vm has abstract.ComputingNode.memory_mb >= 512 + + ) + + error: "All VMs have at least 256 MB of memory" \ No newline at end of file diff --git a/tests/domlr/example_vm_has_sizedesc_cpu_count.domlr b/tests/domlr/example_vm_has_sizedesc_cpu_count.domlr new file mode 100644 index 0000000000000000000000000000000000000000..c48e812e1f15ed1a38e473fb56baf6e970b38fab --- /dev/null +++ b/tests/domlr/example_vm_has_sizedesc_cpu_count.domlr @@ -0,0 +1,9 @@ ++ "VM has size description and cpu_count >= 4" + forall vm ( + vm is class infrastructure.VirtualMachine + implies + vm has infrastructure.VirtualMachine.sizeDescription == "EXAMPLE" + and + vm has infrastructure.ComputingNode.cpu_count >= 4 + ) + error: "Model is wrong..." \ No newline at end of file diff --git a/tests/test_mc_openapi.py b/tests/test_mc_openapi.py index d96ac8938bb3fff770a35a40b8c5eca5b9c2f7b1..506b33b37590ea0f4f0cbfff748747b41559d4c5 100644 --- a/tests/test_mc_openapi.py +++ b/tests/test_mc_openapi.py @@ -3,11 +3,6 @@ from mc_openapi.doml_mc.common_reqs import CommonRequirements from mc_openapi.doml_mc import DOMLVersion import requests - -def test_version(): - assert __version__ == '1.2.0' - - # V2_0 tests def test_post_nginx_sat_V2_0(): with open("tests/doml/v2.0/nginx-openstack_v2.0.domlx", "r") as f: @@ -74,3 +69,36 @@ def test_post_faas_unsat_V2_1(): assert r.status_code == requests.codes.ok assert payload["result"] is not None assert payload["result"] == "unsat" + +# V2_2 tests +def test_post_nginx_sat_V2_1(): + with open("tests/doml/v2.2/nginx-aws-ec2.domlx", "r") as f: + doml = f.read() + + r = requests.post("http://0.0.0.0:8080/modelcheck", data=doml) + payload = r.json() + assert r.status_code == requests.codes.ok + assert payload["result"] is not None + assert payload["result"] == "sat" + + +def test_post_faas_unsat_V2_2(): + with open("tests/doml/v2.2/faas.domlx", "r") as f: + doml = f.read() + + r = requests.post("http://0.0.0.0:8080/modelcheck", data=doml) + payload = r.json() + assert r.status_code == requests.codes.ok + assert payload["result"] is not None + assert payload["result"] == "unsat" + + +def test_post_nginx_with_func_reqs_unsat_V2_2(): + with open("tests/doml/v2.2/nginx_func_req.domlx", "r") as f: + doml = f.read() + + r = requests.post("http://0.0.0.0:8080/modelcheck", data=doml) + payload = r.json() + assert r.status_code == requests.codes.ok + assert payload["result"] is not None + assert payload["result"] == "unsat" \ No newline at end of file