From 1fe1511b5fa61649a8eae0ca0772709f96f28cf3 Mon Sep 17 00:00:00 2001
From: Andrea Franchini <hello@andreafranchini.com>
Date: Thu, 1 Jun 2023 13:15:15 +0200
Subject: [PATCH] Add requirement for issue #22 (VM and OS)

---
 docs/requirements.rst                         |  6 ++
 mc_openapi/__init__.py                        |  2 +-
 .../doml_mc/builtin_requirements/__init__.py  |  4 +-
 .../builtin_requirements/vm_os_required.py    | 72 +++++++++++++++++++
 mc_openapi/doml_mc/common_reqs.py             | 17 ++++-
 5 files changed, 97 insertions(+), 4 deletions(-)
 create mode 100644 mc_openapi/doml_mc/builtin_requirements/vm_os_required.py

diff --git a/docs/requirements.rst b/docs/requirements.rst
index 3e03d6a..913bbc0 100644
--- a/docs/requirements.rst
+++ b/docs/requirements.rst
@@ -95,6 +95,12 @@ ID: ``concrete_asg_no_vm``
 Makes sure a VM present inside an AutoScaleGroup in the Infrastructure Layer is not present
 and mapped in the Concretization layer.
 
+Virtual Machines that host a container need an OS
+-------------------------------------------------
+
+*Available from DOML v2.2+*
+
+Makes sure a VM hosting a container has the OS field present.
 
 .. Deprecated
 
diff --git a/mc_openapi/__init__.py b/mc_openapi/__init__.py
index e59b17b..b8c5494 100644
--- a/mc_openapi/__init__.py
+++ b/mc_openapi/__init__.py
@@ -1 +1 @@
-__version__ = '2.5.0'
+__version__ = '2.5.1'
diff --git a/mc_openapi/doml_mc/builtin_requirements/__init__.py b/mc_openapi/doml_mc/builtin_requirements/__init__.py
index 7406583..edac2d1 100644
--- a/mc_openapi/doml_mc/builtin_requirements/__init__.py
+++ b/mc_openapi/doml_mc/builtin_requirements/__init__.py
@@ -15,6 +15,7 @@ from .all_infrastructure_elements_deployed import ALL_INFRASTRUCTURE_ELEMENTS_DE
 from .all_concrete_maps_something import ALL_CONCRETE_MAP_SOMETHING
 from .security_group_must_have_iface import SECURITY_GROUP_MUST_HAVE_IFACE
 from .concrete_asg_no_vm import CONCRETE_ASG_NO_VM
+from .vm_os_required import VM_OS_REQUIRED
 
 __ALL__ = [
     VM_HAS_IFACE,
@@ -27,5 +28,6 @@ __ALL__ = [
     ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED,
     ALL_CONCRETE_MAP_SOMETHING,
     SECURITY_GROUP_MUST_HAVE_IFACE,
-    CONCRETE_ASG_NO_VM
+    CONCRETE_ASG_NO_VM,
+    VM_OS_REQUIRED
 ]
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/builtin_requirements/vm_os_required.py b/mc_openapi/doml_mc/builtin_requirements/vm_os_required.py
new file mode 100644
index 0000000..2209c88
--- /dev/null
+++ b/mc_openapi/doml_mc/builtin_requirements/vm_os_required.py
@@ -0,0 +1,72 @@
+from z3 import And, Const, Consts, Exists, ExprRef, Not, Or, Solver, Implies
+from mc_openapi.doml_mc.imc import Requirement, SMTEncoding, SMTSorts
+from mc_openapi.doml_mc.intermediate_model import DOMLVersion, IntermediateModel
+from mc_openapi.doml_mc.error_desc_helper import get_user_friendly_name
+
+
+def vm_os_required(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    # cont, contcfg, vm = Consts("cont contcfg vm", smtsorts.element_sort)
+    # os = Const("os", smtsorts.attr_data_sort)
+    # return And(
+    #     smtenc.element_class_fun(cont) == smtenc.classes["infrastructure_Container"],
+    #     Not(
+    #         Exists(
+    #             [contcfg, os],
+    #             And(
+    #                 smtenc.association_rel(
+    #                     cont, smtenc.associations["infrastructure_Container::configs"], contcfg),
+    #                 smtenc.association_rel(
+    #                     contcfg, smtenc.associations["infrastructure_ContainerConfig::host"], vm),
+    #                 smtenc.attribute_rel(
+    #                     vm, smtenc.attributes["infrastructure_ComputingNode::os"], os
+    #                 )
+    #             )
+    #         )
+    #     )
+    # )
+    vm, cont, ccfg = Consts("vm cont ccfg", smtsorts.element_sort)
+    os = Const("os", smtsorts.attr_data_sort)
+    return And(
+        smtenc.element_class_fun(
+            vm) == smtenc.classes["infrastructure_VirtualMachine"],
+        smtenc.element_class_fun(
+            cont) == smtenc.classes["infrastructure_Container"],
+        Not(
+            Exists(
+                [vm, os, ccfg],
+                And(
+                    smtenc.association_rel(
+                        cont, smtenc.associations["infrastructure_Container::configs"], ccfg),
+                    smtenc.association_rel(
+                        ccfg, smtenc.associations["infrastructure_ContainerConfig::host"], vm),
+                    smtenc.attribute_rel(
+                        vm, smtenc.attributes["infrastructure_ComputingNode::os"], os)
+                )
+            )
+        )
+    )
+
+
+def ed_vm_os_required(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
+    try:
+        cont = Const("cont", smtsorts.element_sort)
+        vm = Const("vm", smtsorts.element_sort)
+        cont_name = get_user_friendly_name(
+            intermediate_model, solver.model(), cont)
+        vm_name = get_user_friendly_name(
+            intermediate_model, solver.model(), vm)
+        if cont_name and vm_name:
+            return f"The virtual machine '{vm_name}' hosting container '{cont_name}' needs an OS."
+    except:
+        return "A Virtual machine hosting a container needs an OS."
+    
+
+MSG = "When something is hosted on a virtual machine (e.g.: containers), the VM must have the 'os' specified."
+
+VM_OS_REQUIRED = (
+    vm_os_required, 
+    "vm_os_required",
+    MSG,
+    ed_vm_os_required
+)
+
diff --git a/mc_openapi/doml_mc/common_reqs.py b/mc_openapi/doml_mc/common_reqs.py
index f49cf80..6f989d9 100644
--- a/mc_openapi/doml_mc/common_reqs.py
+++ b/mc_openapi/doml_mc/common_reqs.py
@@ -30,7 +30,8 @@ REQUIREMENTS = {
         ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED,
         ALL_CONCRETE_MAP_SOMETHING,
         SECURITY_GROUP_MUST_HAVE_IFACE,
-        CONCRETE_ASG_NO_VM
+        CONCRETE_ASG_NO_VM,
+        VM_OS_REQUIRED
     ],
     DOMLVersion.V2_3: [
         VM_HAS_IFACE_V2_3,
@@ -40,8 +41,20 @@ REQUIREMENTS = {
         ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED,
         ALL_CONCRETE_MAP_SOMETHING,
         SECURITY_GROUP_MUST_HAVE_IFACE,
-        CONCRETE_ASG_NO_VM
+        CONCRETE_ASG_NO_VM,
+        VM_OS_REQUIRED
     ],
+    DOMLVersion.V3_0: [
+        VM_HAS_IFACE_V2_3,
+        SOFTWARE_PACKAGE_IFACE_NET_V2_3,
+        IFACE_UNIQ,
+        ALL_SOFTWARE_COMPONENTS_DEPLOYED,
+        ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED,
+        ALL_CONCRETE_MAP_SOMETHING,
+        SECURITY_GROUP_MUST_HAVE_IFACE,
+        CONCRETE_ASG_NO_VM,
+        VM_OS_REQUIRED
+    ]
 }
 
 CommonRequirements = {ver: RequirementStore(
-- 
GitLab