2
2
from functools import cmp_to_key
3
3
from typing import Optional , Dict , Tuple
4
4
from seedemu .core .Scope import *
5
- from seedemu .core .Option import BaseOption , OptionMode
5
+ from seedemu .core .Option import BaseOption , OptionMode , OptionDomain
6
6
7
7
class Customizable (object ):
8
8
@@ -16,17 +16,22 @@ def __init__(self): # scope param. actually only for debug/tests , scope: Scop
16
16
self ._config = {}
17
17
self ._scope = None
18
18
19
- def scope (self )-> Scope :
20
- """!@brief returns a scope that includes only this very customizable instance ,nothing else"""
19
+ def scope (self , domain : OptionDomain = None )-> Scope :
20
+ """!@brief returns a scope that includes only this very customizable instance ,nothing else
21
+ @param domain depending on what you need the scope object for
22
+ (i.e. for which kind of Option you want to specify the scope for)
23
+ you might need a different kind of scope
24
+ """
21
25
# it's only natural for a customizable to know its place in the hierarchy
22
- if not self ._scope : return Scope (NodeScopeTier .Global ) # maybe introduce a ScopeTier.NONE for this...
26
+ if not self ._scope : return NodeScope (NodeScopeTier .Global ) # maybe introduce a ScopeTier.NONE for this...
23
27
else : return self ._scope
24
28
25
29
26
30
def getScopedOption (self , key : str , scope : Scope = None , prefix : str = None ) -> Optional [Tuple [BaseOption , Scope ]]:
27
31
"""! @brief retrieves an option along with the most specific Scope in which it was set.
28
32
"""
29
- if not scope : scope = self .scope ()
33
+ from seedemu .core .OptionRegistry import OptionRegistry
34
+ if not scope : scope = self .scope (domain = OptionRegistry ().getDomain (key , prefix ))
30
35
31
36
keys = [key ]
32
37
@@ -76,15 +81,32 @@ def getOption(self, key: str, scope: Scope = None, prefix: str = None ) -> Optio
76
81
return None
77
82
78
83
def _possible_scopes (scope : Scope ) -> List [Scope ]:
79
- possible_scopes = [
80
- Scope (NodeScopeTier .Node , scope ._node_type ,
81
- as_id = scope .asn , node_id = scope ._node_id ) if scope ._node_id and scope ._as_id and scope ._node_type else None , # Node-specific + type
82
- Scope (NodeScopeTier .Node ,node_id = scope ._node_id , as_id = scope ._as_id ) if scope ._node_id and scope ._as_id else None , # Node-specific
83
- Scope (NodeScopeTier .AS , scope ._node_type , as_id = scope ._as_id ) if scope ._as_id and scope ._node_type else None , # AS & Type
84
- Scope (NodeScopeTier .AS , NodeScopeType .ANY , as_id = scope ._as_id ) if scope ._as_id else None , # AS-wide
85
- Scope (NodeScopeTier .Global , scope ._node_type ), # Global & Type
86
- Scope (NodeScopeTier .Global ) # Global (fallback)
87
- ]
84
+ if isinstance (scope , NodeScope ):
85
+ possible_scopes = [
86
+ NodeScope (NodeScopeTier .Node , scope ._node_type ,
87
+ as_id = scope .asn , node_id = scope ._node_id ) if scope ._node_id and scope ._as_id and scope ._node_type else None , # Node-specific + type
88
+ NodeScope (NodeScopeTier .Node ,node_id = scope ._node_id , as_id = scope ._as_id ) if scope ._node_id and scope ._as_id else None , # Node-specific
89
+ NodeScope (NodeScopeTier .AS , scope ._node_type , as_id = scope ._as_id ) if scope ._as_id and scope ._node_type else None , # AS & Type
90
+ NodeScope (NodeScopeTier .AS , NodeScopeType .ANY , as_id = scope ._as_id ) if scope ._as_id else None , # AS-wide
91
+ NodeScope (NodeScopeTier .Global , scope ._node_type ), # Global & Type
92
+ NodeScope (NodeScopeTier .Global ) # Global (fallback)
93
+ ]
94
+ if isinstance (scope , NetScope ):
95
+ possible_scopes = [
96
+ NetScope (NetScopeTier .Individual ,net_type = scope .type , scope_id = scope .scope , net_id = scope .net )
97
+ if scope .scope and scope .net and scope .type else None , # Net specific + type
98
+ NetScope (NetScopeTier .Individual , scope_id = scope .scope , net_id = scope .net )
99
+ if scope .scope and scope .net else None , # Net specific
100
+
101
+ NetScope (NetScopeTier .Scoped , scope .type , scope_id = scope .scope )
102
+ if scope .scope and scope .type else None , # scope & Type
103
+ NetScope (NetScopeTier .Scoped , NetScopeType .ANY , scope_id = scope .scope )
104
+ if scope .scope else None , # scope-wide
105
+
106
+ NetScope (NetScopeTier .Global , net_type = scope .type ),
107
+ NetScope (NetScopeTier .Global )
108
+ ]
109
+
88
110
return possible_scopes
89
111
90
112
def _getKeys (self ) -> List [str ]:
@@ -108,15 +130,29 @@ def handDown(self, child: 'Customizable'):
108
130
i.e. ASes are a collection of Nodes.
109
131
This methods performs the inheritance of options from parent to child.
110
132
"""
111
-
112
- try : # scopes could be incomparable
113
- assert self .scope ()> child .scope (), 'logic error - cannot inherit options from more general scopes'
114
- except :
115
- pass
133
+ from .Network import Network
134
+ from .Node import Node
135
+ dom = OptionDomain .NET if type (child )== Network else OptionDomain .NODE
136
+ s1 = self .scope (dom )
137
+ s2 = child .scope (dom )
138
+
139
+
140
+ assert not s1 < s2 , 'logic error - cannot inherit options from more general scopes'
116
141
117
142
for k , val in self ._config .items ():
118
143
for (op , s ) in val :
119
- child .setOption (op , s )
144
+ if self .valid_down (op ,child ):
145
+ child .setOption (op , s )
146
+
147
+ @staticmethod
148
+ def valid_down (op , child ):
149
+ from .Network import Network
150
+ from .Node import Node
151
+ # enforce option-domains only at the lowest granularity (customizable hierarchy): Nodes and Networks
152
+ # Any aggregates of higher levels i.e. ASes, ISDs (that don't inherit neither Node nor Network)
153
+ # can have Options of mixed domains
154
+ return not ((op .optiondomain () == OptionDomain .NET and issubclass (type (child ), Node )) or
155
+ (issubclass ( type (child ), Network ) and op .optiondomain ()== OptionDomain .NODE ) )
120
156
121
157
def setOption (self , op : BaseOption , scope : Scope = None ):
122
158
"""! @brief set option within the given scope.
@@ -126,6 +162,8 @@ def setOption(self, op: BaseOption, scope: Scope = None ):
126
162
# Everything else would be counterintuitive i.e. setting individual node overrides through the
127
163
# API of the AS , rather than the respective node's itself
128
164
165
+ assert self .valid_down (op , self ), 'input error'
166
+
129
167
if not scope : scope = self .scope ()
130
168
131
169
opname = op .name
0 commit comments