Commit 66308f4b authored by Maverick Chardet's avatar Maverick Chardet
Browse files

Added ability to read from and write to non-data provide ports.

Updated Madeus wrapper to the new version with only USE and PROVIDE
ports and no groups.
Madeus example updated.
OldMadeus component, assembly and example kept temporarily (deprecated).
parent b312641e
......@@ -966,3 +966,22 @@ class Component(object, metaclass=ABCMeta):
def get_initial_places(self):
return [self.initial_place]
def get_accessible_places_from(self, origin_places: List[str], behavior_list: List[str]):
from copy import deepcopy
for place in origin_places:
assert(place in self.places)
accessible_places = set(origin_places)
old_accessible_places = set()
while accessible_places != old_accessible_places:
diff_places = accessible_places - old_accessible_places
old_accessible_places = deepcopy(accessible_places)
for place in diff_places:
for transition in self.transitions.values():
if len(transition) == 6:
src_name, dst_name, bhv, _, _, _ = transition
else: # len = 5
src_name, dst_name, bhv, _, _ = transition
if bhv in behavior_list and src_name == place:
accessible_places.add(dst_name)
return accessible_places
......@@ -90,22 +90,22 @@ class Dependency(object):
return self.type
def get_data(self):
if self.get_type() is not DepType.DATA_PROVIDE:
if self.get_type() is not DepType.DATA_PROVIDE and self.get_type() is not DepType.PROVIDE:
raise Exception(
"Trying to get data from dependency '%s' which is not of type data provide" % self.get_name())
"Trying to get data from dependency '%s' which is not of type provide or data provide" % self.get_name())
return self.data
def read(self):
if self.get_type() is not DepType.DATA_USE:
raise Exception("Trying to read from dependency '%s' which is not of type data use" % self.get_name())
if self.get_type() is not DepType.DATA_USE and self.get_type() is not DepType.USE:
raise Exception("Trying to read from dependency '%s' which is not of type use or data use" % self.get_name())
for c in self.connections:
if c.is_active():
return c.get_provide_dep().get_data()
raise Exception("Trying to read from dependency '%s' which is not served" % self.get_name())
def write(self, data):
if self.get_type() is not DepType.DATA_PROVIDE:
raise Exception("Trying to write to dependency '%s' which is not of type data provide" % self.get_name())
if self.get_type() is not DepType.DATA_PROVIDE and self.get_type() is not DepType.PROVIDE:
raise Exception("Trying to write to dependency '%s' which is not of type provide or data provide" % self.get_name())
self.data = data
def is_connected(self) -> bool:
......
......@@ -3,4 +3,6 @@
from concerto.madeus.madeus_assembly import MadeusAssembly
from concerto.madeus.madeus_component import MadeusComponent
from concerto.madeus.old_madeus_assembly import OldMadeusAssembly
from concerto.madeus.old_madeus_component import OldMadeusComponent
from concerto.dependency import DepType
from abc import ABCMeta, abstractmethod
from typing import Dict, Tuple, List
from typing import Dict, Tuple, List, Optional, Union
from concerto.component import Component
from concerto.dependency import DepType
class MadeusComponent(metaclass=ABCMeta):
......@@ -12,9 +13,8 @@ class MadeusComponent(metaclass=ABCMeta):
def __init__(self):
self.places: List[str] = []
self.transitions: Dict[str, Tuple] = {}
self.groups: Dict[str, List[str]] = {}
self.dependencies: Dict[str, Tuple] = {}
self.initial_place: str = None
self.dependencies: Dict[str, Tuple[DepType, Union[List[str], List[List[str]]]]] = {}
self.initial_place: Optional[str] = None
self.create()
......@@ -40,8 +40,8 @@ class _MadeusConcertoComponent(Component):
def create(self):
self.places = self.mc.places
self.groups = self.mc.groups
self.dependencies = self.mc.dependencies
# self.groups = self.mc.groups
# self.dependencies = self.mc.dependencies
self.initial_place = self.mc.initial_place
# Converting transitions
......@@ -50,3 +50,21 @@ class _MadeusConcertoComponent(Component):
raise Exception("Error: invalid Madeus transition '%s'!" % t)
(source, destination, action) = self.mc.transitions[t]
self.transitions[t] = (source, destination, self.AUTO_BEHAVIOR, 0, action)
# Converting dependencies
self.dependencies = dict()
group_id = 0
for dep_name, dep_details in self.mc.dependencies.items():
dep_type, bindings = dep_details
if dep_type == DepType.USE:
self.dependencies[dep_name] = (DepType.USE, bindings)
else:
# bindings is a list of lists of places
current_group_list: List[str] = []
for source_places in bindings:
self.groups["_group%d" % group_id] = self.get_accessible_places_from(source_places,
[self.AUTO_BEHAVIOR])
current_group_list.append("_group%d" % group_id)
group_id += 1
self.dependencies[dep_name] = (DepType.PROVIDE, current_group_list)
from abc import ABCMeta, abstractmethod
from typing import Dict, Tuple, List
from concerto.assembly import Assembly
from concerto.reconfiguration import Reconfiguration
from concerto.madeus.old_madeus_component import OldMadeusComponent, _OldMadeusConcertoComponent
class OldMadeusAssembly(Assembly, metaclass=ABCMeta):
@abstractmethod
def create(self):
pass
def __init__(self, dryrun: bool = False, gantt_chart: bool = False, verbosity: int = 0, print_time: bool = False):
super().__init__()
self.components: Dict[str, OldMadeusComponent] = dict()
self.dependencies: List[Tuple[str, str, str, str]] = []
self.create()
self.set_dryrun(dryrun)
self.set_record_gantt(gantt_chart)
self.set_verbosity(verbosity)
self.set_print_time(print_time)
self._reconf = Reconfiguration()
for component_name, component in self.components.items():
self._reconf.add(component_name, _OldMadeusConcertoComponent, component)
for component_name, component in self.components.items():
if len(component.transitions) > 0:
self._reconf.push_behavior(component_name, _OldMadeusConcertoComponent.AUTO_BEHAVIOR)
for (c1, p1, c2, p2) in self.dependencies:
self._reconf.connect(c1, p1, c2, p2)
self._reconf.wait_all()
def get_concerto_reconfiguration(self):
"""
Returns the Concerto reconfiguration object generated by the Madeus abstraction layer.
:return: a Concerto reconfiguration.
"""
return self._reconf
def run(self, auto_synchronize: bool = True):
"""
Runs the Concerto deployment.
:param auto_synchronize: If True (default), will block until the deployment is over and return the
deployment execution time. If False, will return the start time of the deployment and return immediately.
:return: Deployment time if auto_synchronize is true (default), start time of the deployment (as given by
time.perf_counter) if auto_synchronize is False.
"""
from time import perf_counter
reconf = self.get_concerto_reconfiguration()
start_time = perf_counter()
self.run_reconfiguration(reconf)
if auto_synchronize:
self.synchronize()
end_time = perf_counter()
self.terminate()
return end_time-start_time
else:
return start_time
def run_timeout(self, max_time: int):
"""
Runs the Concerto deployment with an integer timeout.
:param max_time: Maximum deployment time.
:return: A tuple (finished, debug_info, running_time) where finished is true iff the timeout wasn't reached,
debug_info contains the debug info (string) if the timeout was reached and None otherwise, and running_time
is a float containing the running time.
"""
from time import perf_counter
start_time = self.run(auto_synchronize=False)
finished, debug_info = self.synchronize_timeout(max_time)
end_time = perf_counter()
return finished, debug_info, end_time-start_time
from abc import ABCMeta, abstractmethod
from typing import Dict, Tuple, List, Optional
from concerto.component import Component
class OldMadeusComponent(metaclass=ABCMeta):
@abstractmethod
def create(self):
pass
def __init__(self):
self.places: List[str] = []
self.transitions: Dict[str, Tuple] = {}
self.groups: Dict[str, List[str]] = {}
self.dependencies: Dict[str, Tuple] = {}
self.initial_place: Optional[str] = None
self.create()
self._concerto_component = None
def print_color(self, string: str):
self._concerto_component.print_color(string)
def read(self, name: str):
return self._concerto_component.read(name)
def write(self, name: str, val):
return self._concerto_component.write(name, val)
class _OldMadeusConcertoComponent(Component):
AUTO_BEHAVIOR = 'autodeploy'
def __init__(self, mc: OldMadeusComponent):
mc._concerto_component = self
self.mc = mc
super().__init__()
def create(self):
self.places = self.mc.places
self.groups = self.mc.groups
self.dependencies = self.mc.dependencies
self.initial_place = self.mc.initial_place
# Converting transitions
for t in self.mc.transitions:
if len(self.mc.transitions[t]) != 3:
raise Exception("Error: invalid Madeus transition '%s'!" % t)
(source, destination, action) = self.mc.transitions[t]
self.transitions[t] = (source, destination, self.AUTO_BEHAVIOR, 0, action)
from concerto.madeus.all import *
from concerto.madeus.madeus_component import MadeusComponent
from concerto.madeus.madeus_assembly import MadeusAssembly
from concerto.dependency import DepType
from concerto.meta import ReconfigurationPerfAnalyzer
......@@ -21,12 +23,9 @@ class Server(MadeusComponent):
'run': ('configured', 'running', self.run),
'check': ('running', 'running_checked', self.check),
}
self.groups = {
'providing_service': ['running', 'running_checked']
}
self.dependencies = {
'ip': (DepType.DATA_PROVIDE, ['vm_started']),
'service': (DepType.PROVIDE, ['providing_service'])
'ip': (DepType.PROVIDE, [['vm_started']]),
'service': (DepType.PROVIDE, [['running']])
}
def start_vm(self):
......@@ -47,7 +46,7 @@ class Server(MadeusComponent):
def check(self):
sleep_print(self, "Checking...", 5, "Checked!")
raise Exception("Check went wrong!!!")
print(self._concerto_component.groups)
class Client(MadeusComponent):
......@@ -61,7 +60,7 @@ class Client(MadeusComponent):
'run': ('configured', 'running', self.run),
}
self.dependencies = {
'server_ip': (DepType.DATA_USE, ['configure1']),
'server_ip': (DepType.USE, ['configure1']),
'server_service': (DepType.USE, ['run'])
}
......
from concerto.madeus.all import *
from concerto.meta import ReconfigurationPerfAnalyzer
def sleep_print(component: OldMadeusComponent, start_message: str, time: float, end_message: str):
from time import sleep
component.print_color(start_message)
sleep(time)
component.print_color(end_message)
class Server(OldMadeusComponent):
def create(self):
self.places = ['undeployed', 'vm_started', 'downloaded', 'configured', 'running', 'running_checked']
self.initial_place = "undeployed"
self.transitions = {
'start_vm': ('undeployed', 'vm_started', self.start_vm),
'download': ('vm_started', 'downloaded', self.download),
'configure': ('vm_started', 'configured', self.configure),
'install': ('downloaded', 'configured', self.install),
'run': ('configured', 'running', self.run),
'check': ('running', 'running_checked', self.check),
}
self.groups = {
'providing_service': ['running', 'running_checked']
}
self.dependencies = {
'ip': (DepType.DATA_PROVIDE, ['vm_started']),
'service': (DepType.PROVIDE, ['providing_service'])
}
def start_vm(self):
sleep_print(self, "Starting VM...", 3, "VM started!")
self.write("ip", "121.94.42.42")
def download(self):
sleep_print(self, "Downloading...", 3, "Downloaded!")
def configure(self):
sleep_print(self, "Configuring...", 3, "Configured!")
def install(self):
sleep_print(self, "Installing...", 4, "Installed!")
def run(self):
sleep_print(self, "Running...", 2, "Running!")
def check(self):
sleep_print(self, "Checking...", 5, "Checked!")
raise Exception("Check went wrong!!!")
class Client(OldMadeusComponent):
def create(self):
self.places = ['undeployed', 'downloaded', 'configured', 'running']
self.initial_place = "undeployed"
self.transitions = {
'download': ('undeployed', 'downloaded', self.download),
'configure1': ('downloaded', 'configured', self.configure1),
'configure2': ('downloaded', 'configured', self.configure2),
'run': ('configured', 'running', self.run),
}
self.dependencies = {
'server_ip': (DepType.DATA_USE, ['configure1']),
'server_service': (DepType.USE, ['run'])
}
def download(self):
sleep_print(self, "Downloading...", 1, "Downloaded!")
def configure1(self):
server_ip = self.read('server_ip')
sleep_print(self, "Configuring (part 1) with server IP %s..." % server_ip, 2, "Configured (part 1)!")
def configure2(self):
sleep_print(self, "Configuring (part 2)...", 5, "Configured (part 2)!")
def run(self):
sleep_print(self, "Running...", 1, "Running!")
class ServerClientAssembly(OldMadeusAssembly):
def create(self):
self.components = {
'server': Server(),
'client': Client()
}
self.dependencies = [
('server', 'ip',
'client', 'server_ip'),
('server', 'service',
'client', 'server_service'),
]
if __name__ == '__main__':
sca = ServerClientAssembly()
# Analysis
pa = ReconfigurationPerfAnalyzer(sca.get_concerto_reconfiguration())
pa.get_graph().save_as_dot("graph.dot")
# Running the deployment
sca.set_print_time(True)
sca.set_record_gantt(True)
sca.run()
errors = sca.get_error_reports()
if errors:
print("Errors:\n- %s" % '\n- '.join(errors))
# Gantt chart
gc = sca.get_gantt_record().get_gantt_chart()
gc.export_json("gantt_chart.json")
......@@ -8,7 +8,7 @@ with open("README.md", "r") as fh:
setup(
name="concerto",
version="0.1.2",
version="0.1.3",
description="Preliminary implementation in Python 3 of the Concerto reconfiguration model.",
long_description=long_description,
long_description_content_type="text/markdown",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment