Matteo Scandolo | 48d3d2d | 2017-08-08 13:05:27 -0700 | [diff] [blame] | 1 | |
| 2 | # Copyright 2017-present Open Networking Foundation |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | |
Chetan Gaonker | cfcce78 | 2016-05-10 10:10:42 -0700 | [diff] [blame] | 17 | # |
| 18 | # Copyright 2016-present Ciena Corporation |
| 19 | # |
| 20 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 21 | # you may not use this file except in compliance with the License. |
| 22 | # You may obtain a copy of the License at |
| 23 | # |
| 24 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 25 | # |
| 26 | # Unless required by applicable law or agreed to in writing, software |
| 27 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 28 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 29 | # See the License for the specific language governing permissions and |
| 30 | # limitations under the License. |
| 31 | # |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 32 | |
| 33 | import yaml, pprint, sys, pdb |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 34 | |
| 35 | stateHash = {} |
A R Karthick | 85ed65e | 2016-02-22 09:49:57 -0800 | [diff] [blame] | 36 | header = '''#!/usr/bin/env python |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 37 | ''' |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 38 | # ---------------------------- DOT ----------------------------------- |
| 39 | colorList = ['aquamarine4', 'crimson', 'chartreuse4', 'darkolivegreen', 'darkgoldenrod', 'dodgerblue3', 'blue4', 'cyan4'] |
| 40 | rankdict = {} |
| 41 | # ---------------------------- DOT ----------------------------------- |
| 42 | |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 43 | if __name__ == '__main__': |
| 44 | |
| 45 | usage = '' |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 46 | from optparse import OptionParser |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 47 | parser = OptionParser(usage) |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 48 | parser.add_option('-p', '--prefix', dest='prefix', type='string', action='store', help='prefix for state table') |
| 49 | parser.add_option('-f', '--file', dest='file', type='string', action='store', help='input yaml filename') |
| 50 | parser.add_option('-d', '--dot', dest='dot', default=False, action='store_true', help='output DOT') |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 51 | (opts, args) = parser.parse_args() |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 52 | prefix = opts.prefix |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 53 | f = open(opts.file, 'r') |
| 54 | y = yaml.load(f) |
| 55 | f.close() |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 56 | stateHash = y['States'] |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 57 | eventHash = {} |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 58 | # GLOBAL DOT DIRECTIVES |
| 59 | stateRadiate = y.get('DOT_StateRadiate') |
| 60 | ignoredIntensity = abs(int(y.get('DOT_IgnoredIntensity', 100)) - 100) |
| 61 | eventGroups = y.get('DOT_EventGroups') |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 62 | if stateRadiate is not None: |
| 63 | stateRadiate = str(stateRadiate) |
| 64 | |
| 65 | actionStrLen = [0] |
| 66 | stateColorIdx = 0 |
| 67 | for k, v in stateHash.iteritems(): |
| 68 | events = v.get('Events') |
| 69 | if events: |
| 70 | for event in events.keys(): |
| 71 | eventHash[event] = {} |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 72 | actionStr = '' |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 73 | for ev in events.values(): |
| 74 | if ev.get('Actions'): |
| 75 | actionStr = ','.join(['obj.%s' % action for action in ev['Actions']]) + ',' |
| 76 | actionStrLen.append(len(actionStr)) |
| 77 | |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 78 | ievents = v.get('IgnoredEvents') |
| 79 | if ievents: |
| 80 | for event in ievents.keys(): |
| 81 | eventHash[event] = {} |
| 82 | |
| 83 | # ---------------------------- DOT ----------------------------------- |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 84 | # rankdict setup |
| 85 | rank = v.get('DOT_Rank') |
| 86 | if rank: |
| 87 | print >>sys.stderr, '%s rank %s' % (k, str(rank)) |
| 88 | rankdict.setdefault(rank, []).append(k) |
| 89 | |
| 90 | # assign a possible color if not specified |
| 91 | color = v.get('DOT_Color') |
| 92 | if color: |
| 93 | print >>sys.stderr, 'using user assigned color %s for %s' % (color, k) |
| 94 | else: |
| 95 | if stateRadiate and stateRadiate.lower() == 'auto': |
| 96 | color = colorList[stateColorIdx % len(colorList)] |
| 97 | stateColorIdx+= 1 |
| 98 | else: |
| 99 | color = 'black' |
| 100 | |
| 101 | stateHash[k]['DOT_Color'] = color |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 102 | # ---------------------------- DOT ----------------------------------- |
| 103 | |
| 104 | # ---------------------------- DOT ----------------------------------- |
| 105 | # update the event hash with information from the event groups (if present) |
| 106 | if eventGroups: |
| 107 | for group in eventGroups.values(): |
| 108 | for event in group['Events'].keys(): |
| 109 | for attr, val in group['Attrs'].iteritems(): |
| 110 | eventHash[event][attr] = val |
| 111 | print >>sys.stderr, 'assigning event group attr event %s attr %s val %s' % (event, attr, val) |
| 112 | # ---------------------------- DOT ----------------------------------- |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 113 | |
| 114 | maxStateLen = reduce(max, [len(x) for x in stateHash.keys()]) + 5 + len(prefix) |
| 115 | maxEventLen = reduce(max, [len(x) for x in eventHash.keys()]) + 5 + len(prefix) |
| 116 | maxActionLen = reduce(max, actionStrLen) + 5 |
| 117 | |
| 118 | if opts.dot: |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 119 | print 'digraph G {' |
| 120 | print ' edge [fontname="Tahoma", fontsize="10", minlen=2];' |
| 121 | print ' node [fontname="Tahoma", fontsize="10"];' |
| 122 | print ' graph [fontname="Tahoma", label="%s"];' % prefix |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 123 | print >>sys.stderr, 'stateRadiate:%s\nignoredIntensity:%d' % (stateRadiate, ignoredIntensity) |
| 124 | |
| 125 | # emit state declarations |
| 126 | for state in stateHash.keys(): |
| 127 | print ' %s[color="%s"];' % (state, stateHash[state]['DOT_Color']) |
| 128 | |
| 129 | # emit rankings |
| 130 | for k, v in rankdict.iteritems(): |
| 131 | print >>sys.stderr, '%s rank %s' % (k, str(v)) |
| 132 | |
| 133 | print 'subgraph { rank = same;' |
| 134 | for state in v: |
| 135 | print ' %s;' % state |
| 136 | print '}' |
| 137 | |
| 138 | for state, va in stateHash.iteritems(): |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 139 | # emit ignored events |
| 140 | if va.get('IgnoredEvents'): |
| 141 | for event, v in va['IgnoredEvents'].iteritems(): |
| 142 | stateStr = state |
| 143 | eventStr = event |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 144 | print '%s -> %s [label="%s/",minlen=1, fontcolor="grey%d", color="grey%d"];' % (stateStr, stateStr, eventStr, ignoredIntensity, ignoredIntensity) |
| 145 | |
| 146 | # emit transitions |
| 147 | if va.get('Events'): |
| 148 | for event, v in va['Events'].iteritems(): |
| 149 | stateStr = state |
| 150 | eventStr = event |
| 151 | actionStr = '' |
| 152 | if v.get('Actions'): |
| 153 | actionStr = '\\n'.join([a.strip('_') for a in v['Actions']]) |
| 154 | nextStr = v['NextState'] |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 155 | labelStr = '%s/\\n%s' % (eventStr, actionStr) |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 156 | if stateRadiate: |
| 157 | color = va['DOT_Color'] |
| 158 | elif len(eventHash[event]): |
| 159 | color = eventHash[event]['Color'] |
| 160 | else: |
| 161 | color = 'black' |
| 162 | |
| 163 | fontColor = color |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 164 | styleStr = '' |
| 165 | style = eventHash[event].get('Style') |
| 166 | if style: |
| 167 | styleStr = ',style="%s"' % (style) |
| 168 | |
| 169 | if style == 'invis': |
| 170 | fontColor = 'white' |
| 171 | |
| 172 | print '%s -> %s [label="%s", color="%s", fontcolor="%s" %s];' % (stateStr, nextStr, labelStr, color, fontColor, styleStr) |
| 173 | |
| 174 | print |
| 175 | |
| 176 | print '}' |
| 177 | |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 178 | else: |
| 179 | |
| 180 | ### emit it |
| 181 | |
| 182 | print header |
| 183 | |
| 184 | ### enumerations |
| 185 | ''' |
| 186 | print '%sSt = Enumeration("%sState",(' % (prefix, prefix) |
| 187 | for state in stateHash.keys(): |
| 188 | print '%s"%s",' % (' '*12, state) |
| 189 | print '%s))' % (' '*12) |
| 190 | |
| 191 | print |
| 192 | |
| 193 | print '%sEv = Enumeration("%sEvent",(' % (prefix, prefix) |
| 194 | for event in eventHash.keys(): |
| 195 | print '%s"%s",' % (' '*12, event) |
| 196 | print '%s))' % (' '*12) |
| 197 | ''' |
A R Karthick | a2e53d6 | 2016-02-19 17:38:30 -0800 | [diff] [blame] | 198 | ### table |
| 199 | |
| 200 | fmt = ' (%' + '-%d.%ds' % (maxStateLen, maxStateLen) + '%' + '-%d.%ds' % (maxEventLen, maxEventLen) + '):( %' +' -%d.%ds' % (maxActionLen, maxActionLen) + '%s),' |
| 201 | cfmt= ' ## %' + '-%d.%ds' % (maxStateLen, maxStateLen) + '%' + '-%d.%ds' % (maxEventLen, maxEventLen) + ' %' +' -%d.%ds' % (maxActionLen, maxActionLen) + '%s' |
| 202 | |
| 203 | print 'def init%s%sFsmTable(obj,St,Ev):' % (prefix[0].upper(), prefix[1:]) |
| 204 | # print " %sFsmTable = {" % prefix |
| 205 | print " return {" |
| 206 | print |
| 207 | |
| 208 | for state, va in stateHash.iteritems(): |
| 209 | |
| 210 | print cfmt % ('CurrentState', 'Event', 'Actions', 'NextState') |
| 211 | print |
| 212 | |
| 213 | if va.get('IgnoredEvents'): |
| 214 | for event, v in va['IgnoredEvents'].iteritems(): |
| 215 | stateStr = '%sSt.' % ('') + state + ',' |
| 216 | eventStr = '%sEv.' % ('') + event |
| 217 | |
| 218 | print fmt % (stateStr, eventStr, '(),', stateStr.strip(',')) |
| 219 | |
| 220 | if va.get('Events'): |
| 221 | for event, v in va['Events'].iteritems(): |
| 222 | stateStr = '%sSt.' % ('') + state + ',' |
| 223 | eventStr = '%sEv.' % ('') + event |
| 224 | actionStr = '' |
| 225 | if v.get('Actions'): |
| 226 | actionStr = ','.join(['obj.%s' % action for action in v['Actions']]) + ',' |
| 227 | |
| 228 | nextStr = '%sSt.' % ('') + v['NextState'] |
| 229 | |
| 230 | print fmt % (stateStr, eventStr, '(%s),' % actionStr , nextStr) |
| 231 | |
| 232 | print |
| 233 | |
| 234 | print "}" |
| 235 | print |
| 236 | |
| 237 | |