Skip to content
Snippets Groups Projects
Commit 21971842 authored by Andrea Franchini's avatar Andrea Franchini
Browse files

Proof of Concept of CSP Compatibility Check

parent 7dcbbd95
No related branches found
No related tags found
No related merge requests found
......@@ -29,7 +29,9 @@ parser.add_argument("-v", "--verbose", dest="verbose", action='store_true', help
# 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("-C", "--csp", dest="csp", action='store_true', help="check compatibility with supported CSPs")
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")
......@@ -71,6 +73,13 @@ else:
dmc = ModelChecker(doml_xmi, doml_ver)
doml_ver = dmc.doml_version
# Check CSP Compatibility
if args.csp:
from mc_openapi.doml_mc.csp_compatibility import CSPCompatibilityValidator
cspc = CSPCompatibilityValidator
cspc.check(dmc.intermediate_model, doml_ver)
exit(0)
# Store of Requirements and unique string constants
user_req_store = RequirementStore()
user_req_str_consts = []
......
# CSP Name
aws:
- x86
- x86_64
- ARM64
gcp:
- x86
- ARM
azure:
- x86
- ARM
bad_csp:
- PowerPC
# CSP Name
aws:
- algorithm: "RSA"
bits: "2048"
- algorithm: "ED25519"
azure:
- algorithm: "RSA"
bits: "2048-*"
bad_csp:
- algorithm: "OLD_ALGO"
bits: "*-1024"
\ No newline at end of file
aws:
- us-east-2
- us-east-1
- us-west-1
- us-west-2
- af-south-1
- ap-east-1
- ap-south-2
- ap-southeast-3
- ap-southeast-4
- ap-south-1
- ap-northeast-3
- ap-northeast-2
- ap-southeast-1
- ap-southeast-2
- ap-northeast-1
- ca-central-1
- eu-central-1
- eu-west-1
- eu-west-2
- eu-south-1
- eu-west-3
- eu-south-2
- eu-north-1
- eu-central-2
- me-south-1
- me-central-1
- sa-east-1
- us-gov-east-1
- us-gov-west-1
gcp:
- asia-east1-a
- asia-east1-b
- asia-east1-c
- asia-east2-a
- asia-east2-b
- asia-east2-c
- asia-northeast1-a
- asia-northeast1-b
- asia-northeast1-c
- asia-northeast2-a
- asia-northeast2-b
- asia-northeast2-c
- asia-northeast3-a
- asia-northeast3-b
- asia-northeast3-c
- asia-south1-a
- asia-south1-b
- asia-south1-c
- asia-south2-a
- asia-south2-b
- asia-south2-c
- asia-southeast1-a
- asia-southeast1-b
- asia-southeast1-c
- asia-southeast2-a
- asia-southeast2-b
- asia-southeast2-c
- australia-southeast1-a
- australia-southeast1-b
- australia-southeast1-c
- australia-southeast2-a
- australia-southeast2-b
- australia-southeast2-c
- europe-central2-a
- europe-central2-b
- europe-central2-c
- europe-north1-a
- europe-north1-b
- europe-north1-c
- europe-southwest1-a
- europe-southwest1-b
- europe-southwest1-c
- europe-west1-b
- europe-west1-c
- europe-west1-d
- europe-west2-a
- europe-west2-b
- europe-west2-c
- europe-west3-a
- europe-west3-b
- europe-west3-c
- europe-west4-a
- europe-west4-b
- europe-west4-c
- europe-west6-a
- europe-west6-b
- europe-west6-c
- europe-west8-a
- europe-west8-b
- europe-west8-c
- europe-west9-a
- europe-west9-b
- europe-west9-c
- me-west1-a
- me-west1-b
- me-west1-c
- northamerica-northeast1-a
- northamerica-northeast1-b
- northamerica-northeast1-c
- northamerica-northeast2-a
- northamerica-northeast2-b
- northamerica-northeast2-c
- southamerica-east1-a
- southamerica-east1-b
- southamerica-east1-c
- southamerica-west1-a
- southamerica-west1-b
- southamerica-west1-c
- us-central1-a
- us-central1-b
- us-central1-c
- us-central1-f
- us-east1-b
- us-east1-c
- us-east1-d
- us-east4-a
- us-east4-b
- us-east4-c
- us-east5-a
- us-east5-b
- us-east5-c
- us-south1-a
- us-south1-b
- us-south1-c
- us-west1-a
- us-west1-b
- us-west1-c
- us-west2-a
- us-west2-b
- us-west2-c
- us-west3-a
- us-west3-b
- us-west3-c
- us-west4-a
- us-west4-b
- us-west4-c
azure:
- eastasia
- southeastasia
- centralus
- eastus
- eastus2
- westus
- northcentralus
- southcentralus
- northeurope
- westeurope
- japanwest
- japaneast
- brazilsouth
- australiaeast
- australiasoutheast
- southindia
- centralindia
- westindia
- canadacentral
- canadaeast
- uksouth
- ukwest
- westcentralus
- westus2
- koreacentral
- koreasouth
- francecentral
- francesouth
- australiacentral
- australiacentral2
- uaecentral
- uaenorth
- southafricanorth
- southafricawest
\ No newline at end of file
from .validator import CSPCompatibilityValidator
import importlib.resources as ilres
from ... import assets
import yaml
FILE = lambda filename: ilres.files(assets).joinpath(f"csp/{filename}")
with open(FILE('keypairs.yml')) as kp:
KEYPAIRS = yaml.safe_load(kp)
with open(FILE('architectures.yml')) as kp:
ARCHS = yaml.safe_load(kp)
with open(FILE('regions.yml')) as kp:
REGIONS = yaml.safe_load(kp)
CSPCompatibilityValidator = CSPCompatibilityValidator(
keypairs=KEYPAIRS,
architectures=ARCHS,
regions=REGIONS
)
from mc_openapi.doml_mc.intermediate_model.doml_element import DOMLElement, IntermediateModel
from mc_openapi.doml_mc.intermediate_model.metamodel import DOMLVersion
import re
class CSPCompatibilityValidator:
def __init__(self, keypairs, architectures, regions) -> None:
self.valid_keypairs = keypairs
self.valid_architectures = architectures
self.valid_regions = regions
pass
def check(self, model: IntermediateModel, doml_version: DOMLVersion) -> list[str]:
"""Returns a list of CSP supported by the model"""
if doml_version == DOMLVersion.V2_2:
elems = model.values()
print('=====================================')
print('========= CSP Compatibility =========')
print('=====================================')
# Check KeyPair
keypairs = [kp for kp in elems if kp.class_ == 'commons_KeyPair']
print("\n--- Keypairs ---")
self.check_keypair(keypairs)
# ComputingNode and inheritors
print("\n--- Architectures ---")
compnodes = [cn for cn in elems if re.match(r"infrastructure_(ComputingNode|Container|PhysicalComputingNode|VirtualMachine)", cn.class_)]
self.check_computing_nodes(compnodes)
# Locations
print("\n--- Locations ---")
locations = [lc for lc in elems if lc.class_ == 'infrastructure_Location']
self.check_locations(locations)
else:
raise "Unsupported DOML version (<2.2) for CSP Compatibility check"
def check_keypair(self, keypairs: list[DOMLElement]):
for kp in keypairs:
algorithm = kp.attributes.get('commons_KeyPair::algorithm')
bits = kp.attributes.get('commons_KeyPair::bits')
# For each vendor, check if there's at least one supported configuration
for vendor, vkps in self.valid_keypairs.items():
valid_algorithms = []
valid_bits = []
if algorithm:
valid_algorithms = [vkp.get('algorithm').lower() == algorithm[0].lower() for vkp in vkps]
if bits:
def comp_bits(b, bits):
if b is None:
return True
b = b.split('-')
if len(b) > 1:
lb = b[0]
ub = b[1]
return (int(lb) <= bits if lb != '*' else True) and (bits <= int(ub) if ub != '*' else True)
else:
return b[0] == bits
valid_bits = [comp_bits(vkp.get('bits'), bits[0]) for vkp in vkps]
if not any(valid_algorithms):
print(f"{kp.user_friendly_name} 'algorithm' not compatible with: {vendor}")
if not any(valid_bits):
print(f"{kp.user_friendly_name} 'bits' not compatible with: {vendor}")
def check_computing_nodes(self, elems: list[DOMLElement]):
for el in elems:
arch = el.attributes.get('infrastructure_ComputingNode::architecture')
# os = el.attributes.get('infrastructure_ComputingNode::os')
# cpu_count = el.attributes.get('infrastructure_ComputingNode::cpu_count')
# memory_mb = el.attributes.get('infrastructure_ComputingNode::memory_mb')
if arch:
for vendor, varchs in self.valid_architectures.items():
valid_archs = [arch[0] == varch for varch in varchs]
if not any(valid_archs):
print(f"{el.user_friendly_name} 'architecture' not compatible with: {vendor}")
# OS requires probably a fine-handling of <os>, <flavor/version>
def check_locations(self, locations: list[DOMLElement]):
for loc in locations:
reg = loc.attributes.get('infrastructure_Location::region')
if reg:
for vendor, vregs in self.valid_regions.items():
valid_regs = [reg[0] == vreg for vreg in vregs]
if not any(valid_regs):
print(f"{loc.user_friendly_name or 'A'} 'region' (value: {reg[0]}) not compatible with: {vendor}")
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
}
key_pair ed_key {
user "ec2-user"
keyfile "/tmp/ED25519_key_file"
algorithm "ED25519"
}
autoscale_group ag {
vm vm1 {
arch "x86"
os "RHEL"
cpu_count 128
mem_mb 512000.0
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";
}
}
<?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"/>
<credentials xsi:type="commons:KeyPair" name="ed_key" user="ec2-user" keyfile="/tmp/ED25519_key_file" algorithm="ED25519"/>
<groups xsi:type="infra:AutoScalingGroup" name="ag">
<machineDefinition name="vm1" architecture="x86" os="RHEL" memory_mb="512000.0" cpu_count="128" 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 &lt;= 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>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment