% ------------------------------------------------------------------------------------------------------
% SLA Contract between DynDNS (Provider) and PowerConsulting (Consumer)
% 
% Implements the SLA between these two companies
% ------------------------------------------------------------------------------------------------------

module("sla_escalation.prova").


:-eval(consult('ContractLog/math.prova')).
:-eval(consult('ContractLog/list.prova')).
:-eval(consult('ContractLog/list_math.prova')).
:-eval(consult('ContractLog/datetime.prova')).
:-eval(consult('ContractLog/ecaruntime.prova')).
:-eval(consult('ContractLog/deontic.prova')).
:-eval(consult('ContractLog/update.prova')).
:-eval(consult('ContractLog/utils.prova')).
:-eval(consult('ContractLog/ec.prova')).


% ------------------------------------------------------------------------------------------------------
% Contract
% ------------------------------------------------------------------------------------------------------

% +++++++++++++++  static contract definitions ++++++++++++++++++++++

contract("sla_DynDNS_PowerConulting").
provider("DynDNS").
customer("PowerConsulting").
validity(datetime(2006,1,1,0,0,0),datetime(2006,12,31,23,59,0)).

service("\"http://ibis.in.tum.de/staff/paschke/rbsla/index.htm\"").
%service("\"http://www.google.de\"").

description("

The SLA defines three monitoring schedules, Prime, Standard and Maintenance:

Schedule	Time				Availability						Response Time
Prime		8 a.m. -18 p.m.		98%[99%]100%;pinged every 10s		4 sec.; pinged every 10s
Standard	18 p.m. -8 a.m.		95%[97%]99%; pinged every min.		10[14]16 sec.; pinged every min.
Maintenance	0 a.m.-  4 a.m.*	20%[50%]80%;pinged every 10 min	   	No monitoring

During prime time the average availability has a low value of 98%, 
a median of 99% and a high value of 100% and a response time which must be below 4s. 
The service metrics are calculated via a ping every 10 sec-onds. 
During standard time the average availability is {high:99%;low:95%;median:97%} 
and response time {high:10sec.;low:16sec.;median:14sec.} monitored via a ping every minute. 
Maintenance is permitted to take place between midnight and 4a.m. 
During this period the average availability is {high:80%; low:20%; median:50%} monitored 
every 10 minutes. Response time will not be monitored in this case. 

Further the SLA defines a bonus-malus policy

Price		Base			Bonus										Malus
Prime		pprime			pprime + (xhigh-xmedian) *pbonus %			pprime - (xmedian-xlow) *pmalus %
Standard	pstandard		pstandard + (xhigh-xmedian) *pbonus %		pstandard - (xmedian-xlow) *pmalus %
Maintenance	pmaintenance	pmaintenance+ (xhigh-xmedian) *pbonus %		pmaintenance - (xmedian-xlow) *pmalus %
Incident Penalty	- pincident per incident/outage

According to the monitoring schedules a differentiated base price is defined if the 
service levels are met. If the service levels are exceeded (median to high) a dependent 
bonus is added and if they fall below the agreed upon service levels (median to low)
 a discount is deducted. The bonus and malus are defined as a percentage value of the base price. 
If a service level is missed, i.e. the actual value falls below the low service level (<low) an 
additional penalty has to be paid which increases expo-nentially with the number of incidents 
during the ac-counting period. In case of outages/incidents the SLA defines two escalation levels:

Level		Role				Time-to-Repair (TTR)		Rights / Obligations
1		Process Manager			10 Min.						Start / Stop Service / Servicing*
2		Quality Manager			Max. Time-to-Repair (MTTR)	Change MTTR
3		Control Committee 		---							Find solution with Customer
		Customer				---							Cancel contract

Each escalation level defines clear responsibilities in terms of associated roles which have 
certain rights and are obliged to do certain remedial actions in case of inci-dents which 
initiate the respective escalation level. In the SLAs’ escalation level 1 the process manager 
is obliged to restart an unavailable service within time-to-repair = 10 minutes.
 Accordingly, she has the right (permission) to restart the service and start servicing
 between 0-4 a.m. If she fails to do so, escalation level 2 is trig-gered and the 
 quality manager is informed. The quality manager has more rights, e.g. the right (permission) 
 to adapt/change the SLA management systems respectively the service levels. 
The quality manager might discuss the time needed to repair with the process manager and 
extend it up to a maximum time to repair (MTTR) level (change request). 
In case of very critical incidents the system might directly proceed to escalation level 2 
and skip level 1. If the process manager fails to restart the service within the 
maximum time-to-repair escalation level 3 is triggered and the control committee is informed. 
The control committee consists of decision makers from both parties, i.e. provider and customer,
which discuss possible solutions, e.g. negotiate an extra penalty.
In escalation level 3 the service consumer is permitted to cancel the contract. 

A monthly report is created.


").

% +++++++++++++++  Dynamic SLA rules ++++++++++++++++++++++

% role model and escalation levels
initially(escl_lvl(0)).	% initially escalation level 0
% if escalation level 1 then process_manager
role(process_manager) :- holdsAt(escl_lvl(1),T).
% if escalation level 2 then chief quality manager
role(chief_quality_manager) :-  holdsAt(escl_lvl(2),T).
% if escalation level 3 then control committee
role(control_committee) :- holdsAt(escl_lvl(3),T).

% time schedules standard, prime, maintenance and monitoring intervals
% before 8 and after 18 every minute
schedule(standard, Service):- 
	sysTime(datetime(Y,M,D,H,Min,S)), 
	more(datetime(Y,M,D,H,Min,S), datetime(Y,M,D,18,0,0)), 
	interval(timespan(0,0,1,0), datetime(Y,M,D,H,Min,S)), 
	service(Service),
	not(maintenance(Service)).  % not maintenance
schedule(standard, Service):- 
	sysTime(datetime(Y,M,D,H,Min,S)), 	
	less(datetime(Y,M,D,H,Min,S), datetime(Y,M,D,8,0,0)), 
	interval(timespan(0,0,1,0), datetime(Y,M,D,H,Min,S)), 
	service(Service),
	not(maintenance(Service)).  % not maintenance
% between 8 and 18 every 10 seconds
schedule(prime, Service):- 
	sysTime(datetime(Y,M,D,H,Min,S)), 
	lessequ(datetime(Y,M,D,H,Min,S),
	datetime(Y,M,D,18,0,0)), 
	moreequ(datetime(Y,M,D,H,Min,S),datetime(Y,M,D,8,0,0)),
	interval(timespan(0,0,0,10), datetime(Y,M,D,H,Min,S)), service(Service). 
% between 0 and 4 if maintenance every 10 minutes
schedule(maintenance, Service) :- 
	sysTime(datetime(Y,M,D,H,Min,S)), 
	lessequ(datetime(Y,M,D,H,Min,S),datetime(Y,M,D,4,0,0)), 
	interval(timespan(0,0,10,0), datetime(Y,M,D,H,Min,S)),
	service(Service),
	maintenance(Service). % servicing 


% initiate/terminate maintenance if permitted
initiates(startServicing(S),maintenance(S),T). % start maintenance
terminates(stopServicing(S), maintenance(S),T). % stop maintenance

happens(startServicing(Service),T):- % check permission
	happens(requestServicing(Role,Service),T), 
	holdsAt(permit(Role,Service, startServicing(Service)),T).



% ECA rule: "If the ping on the service fails and not maintenance then 
% trigger escalation level 1 and notify process manager 
% else if ping succeeds and service down update service state to up".
eca(schedule(T,S),not(available(S)),not(maintenance(S)),escalate(S),_,restart(S)). % ECA rule
		
available(S) :- println(["ping ",S]), rbsla.utils.WebsiteAvailable.testWebserver(S),println([S," alive"]).  	% ping service
maintenance(S) :- ,println([S," not alive"]), sysTime(T), holdsAt(maintenance(S),T). 
escalate(S) :- 
	sysTime(T),  % notify	
	not(holdsAt(unavailable(S),T)), % escalate only once	
	add("outages","happens(outage(_0),_1).",[S,T]), % add event to KB
	notify ("process_manager", unavailable(S)).
restart(S) :- 
	sysTime(T), holdsAt(unavailable(S),T),
	add("outages","happens(restart(_0),_1).",[S,T]),% add event to KB
	role(R), notify(R,restart(S)).	% update + notify

% notify - Note in real-world setting this might be, e.g. a JMS message or an eMail
notify(Role,Message):-println(["Notification for ",Role,": ",Message]).


% initiate unavailable state if outage event happens
initiates(outage(S),unavailable(S),T). 
terminates(restart(S),unavailable(S),T).

% initiate escalation level 1 if outage event happens
terminates(outage(S),escl_lvl(0),T). initiates(outage(S),escl_lvl(1),T).
% terminate escalation level 1/2/3 if restart event happens
initiates(restart(S),escl_lvl(0),T). terminates(restart(S),escl_lvl(1),T). 
terminates(restart(S),escl_lvl(2),T). terminates(restart(S), escl_lvl(3), T). 
% terminate escalation level 1/2/3 if servicing is started
initiates(startServicing(S),escl_lvl(0),T). terminates(startServicing(S), escl_lvl(1),T).
terminates(startServicing(S), escl_lvl(2),T). terminates(startServicing(S),escl_lvl(3),T). 


% permit process manager to start servicing between 0-4 a.m.
holdsAt(permit(process_manager,Service, startServicing(Service)), datetime(Y,M,D,H,Min,S)):-
	lessequ(datetime(Y,M,D,H,Min,S),datetime(Y,M,D,4,0,0)),!.
% else forbid process manager to start servicing.
holdsAt(forbid(process_manager,Service, startServicing(Service)), datetime(Y,M,D,H,Min,S)):- 
	more(datetime(Y,M,D,H,Min,S),datetime(Y,M,D,4,0,0)),!.

% derive obligation to start the service if service unavailable
derivedFluent(oblige(process_manager, Service , restart(Service))).
holdsAt(oblige(process_manager, Service , restart(Service)), T) :-
	holdsAt(unavailable(Service),T). % oblige process manager


% define time-to-repair deadline and trigger escalation level 2 if deadline is elapsed
time_to_repair(timespan(0,0,10,0)). % relative time to repair value
max_ttr(timespan(0,1,0,0)). % maximum time to repair

trajectory(escl_lvl(1),T1,deadline,T2,X):-
	math_sub(T2,T1,X).	% deadline function
derivedEvent(elapsed).	
happens(elapsed,T) :- 
	time_to_repair(TTR),   
	valueAt(deadline,T, TTR). 
terminates(elapsed, escl_lvl(1),T).% terminate escalation level 1
initiates(elapsed, escl_lvl(2),T). % initiate escalation level 2

% trigger escalation level 3 if T > max time-to-repair
happens(exceeded,T) :- 
	happens(elapsed,T1),
	max_ttr(MTTR), math_add(T1,MTTR,T). 
terminates(exceeded,escl_lvl(2),T). initiates(exceeded, escl_lvl(3),T).

% service customer is permitted to cancel the contract in escl_lvl3
derivedFluent(permit(customer(Customer), contract(Name) , cancel(contract(Name)))).
holdsAt(permit(customer(Customer), contract(Name) , cancel(contract(Name))), T) :- 
	holdsAt(escl_lvl(3),T). 





% Note: In real-world settings these aggregations should be externalized 
% to procedural code or database solutions, e.g. outage facts can be stored 
% in rel. database and highly-optimized SQL can be used !!!!!!


% average availability for service per month
availability(S,Percent) :- 
			overallMVI(unavailable(S),V),	
			timespan_epoch(V,MS),
%			timespan_epoch(timespan(31,0,0,0),MS2),			
			timespan_epoch(timespan(0,0,3,0),MS2),			
			math_div(MS,MS2,P),
			math_mult(P,100,Percent).
			
			
% create report
createReport():-	
		sysTime(T),
		println([""]),
		println(["Monthly Report - ",T]),
		println(["------------------------------------"]),
		!,
		service(SS),
		happens(outage(S),TT),
		println([" "]),		
		println(["Service ",S]),				
		countMVIs(unavailable(S),O),
		println(["Outages: ",O]),
%		outageTime(S,OT),
		derive(mvi(unavailable(S),OT)),
		println(["Outage Times: ",OT]),
%		overallOutageTime(S,OOT),
		overallMVI(unavailable(S),OOT),
		println(["Overall Outage Time: ",OOT]),
		availability(S,A),
		println(["Average Availability: ",A]),
		remove(outages). % clean up
		
		
		


% +++++++++++++++  ECA Runtime Simulation ++++++++++++++++++++++		

%-----------------------------------------------------------------------
% Start the ECA runtime
%-----------------------------------------------------------------------


% ECA rule: "Create Report every month"

eca(everyMonth(),_,_,createReport(),_,_). % ECA rule
everyMonth():-
	sysTime(T), 
	interval(timespan(0,0,3,0), T). % here all three minutes

start():-
	showTimer(), % show the timer on console
	showConsole(), % print console output
	startECARuntimeMultiThreading(".\examples\sla_examples\RIF_use_case\sla_escalation.prova").
	
:- solve(start()).
	




% +++++++++++++++  Hard-Coded Test Values ++++++++++++++++++++++		

%happens(outage("http://ibis.in.tum.de/staff/paschke/rbsla/index.htm"), datetime(2006,1,1,0,0,0)).
%happens(outage("http://www.google.de"), datetime(2006,1,1,0,0,0)).
%happens(restart("http://ibis.in.tum.de/staff/paschke/rbsla/index.htm"), datetime(2006,1,1,0,5,0)).
%happens(requestServicing(process_manager,"http://ibis.in.tum.de/staff/paschke/rbsla/index.htm"), datetime(2006,1,1,0,5,0)).
%happens(restart("http://ibis.in.tum.de/staff/paschke/rbsla/index.htm"), datetime(2006,1,3,13,22,0)).
%happens(restart("http://www.google.de"), datetime(2006,1,16,0,0,0)).

%happens(serverAwakes, datetime(2006,1,1,13,24,20)).

%happens(serverGoesDown, datetime(2006,1,1,13,30,0)).

%happens(serverAwakes, datetime(2006,1,1,13,35,0)).

%happens(serverGoesDown, datetime(2006,1,1,13,40,0)).

%:-solve(holdsAt(F,datetime(2006,1,1,5,22,0))).
%:-solve(holdsAt(escl_lvl(X),datetime(2005,1,1,0,5,0))).	
%:-solve(holdsAt(escl_lvl(X),datetime(2006,1,1,0,5,0))).
%:-solve(holdsAt(unavailable(S),datetime(2006,1,1,0,5,0))).	
%:-solve(holdsAt(escl_lvl(X),datetime(2006,1,1,0,11,0))).
%:-solve(holdsAt(unavailable(S),datetime(2006,1,1,0,11,0))).			
%:-solve(holdsAt(escl_lvl(X),datetime(2006,1,2,13,11,0))).
%:-solve(holdsAt(unavailable(S),datetime(2006,1,2,13,11,0))).

%:-eval(createReport()).


