blob: b17c6a99594af36279b0eab730dabc0daeae0dca [file] [log] [blame]
# Copyright 2017-present Open Networking Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright 2016-present Ciena Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import yaml, pprint, sys, pdb
stateHash = {}
header = '''#!/usr/bin/env python
'''
# ---------------------------- DOT -----------------------------------
colorList = ['aquamarine4', 'crimson', 'chartreuse4', 'darkolivegreen', 'darkgoldenrod', 'dodgerblue3', 'blue4', 'cyan4']
rankdict = {}
# ---------------------------- DOT -----------------------------------
if __name__ == '__main__':
usage = ''
from optparse import OptionParser
parser = OptionParser(usage)
parser.add_option('-p', '--prefix', dest='prefix', type='string', action='store', help='prefix for state table')
parser.add_option('-f', '--file', dest='file', type='string', action='store', help='input yaml filename')
parser.add_option('-d', '--dot', dest='dot', default=False, action='store_true', help='output DOT')
(opts, args) = parser.parse_args()
prefix = opts.prefix
f = open(opts.file, 'r')
y = yaml.load(f)
f.close()
stateHash = y['States']
eventHash = {}
# GLOBAL DOT DIRECTIVES
stateRadiate = y.get('DOT_StateRadiate')
ignoredIntensity = abs(int(y.get('DOT_IgnoredIntensity', 100)) - 100)
eventGroups = y.get('DOT_EventGroups')
if stateRadiate is not None:
stateRadiate = str(stateRadiate)
actionStrLen = [0]
stateColorIdx = 0
for k, v in stateHash.iteritems():
events = v.get('Events')
if events:
for event in events.keys():
eventHash[event] = {}
actionStr = ''
for ev in events.values():
if ev.get('Actions'):
actionStr = ','.join(['obj.%s' % action for action in ev['Actions']]) + ','
actionStrLen.append(len(actionStr))
ievents = v.get('IgnoredEvents')
if ievents:
for event in ievents.keys():
eventHash[event] = {}
# ---------------------------- DOT -----------------------------------
# rankdict setup
rank = v.get('DOT_Rank')
if rank:
print >>sys.stderr, '%s rank %s' % (k, str(rank))
rankdict.setdefault(rank, []).append(k)
# assign a possible color if not specified
color = v.get('DOT_Color')
if color:
print >>sys.stderr, 'using user assigned color %s for %s' % (color, k)
else:
if stateRadiate and stateRadiate.lower() == 'auto':
color = colorList[stateColorIdx % len(colorList)]
stateColorIdx+= 1
else:
color = 'black'
stateHash[k]['DOT_Color'] = color
# ---------------------------- DOT -----------------------------------
# ---------------------------- DOT -----------------------------------
# update the event hash with information from the event groups (if present)
if eventGroups:
for group in eventGroups.values():
for event in group['Events'].keys():
for attr, val in group['Attrs'].iteritems():
eventHash[event][attr] = val
print >>sys.stderr, 'assigning event group attr event %s attr %s val %s' % (event, attr, val)
# ---------------------------- DOT -----------------------------------
maxStateLen = reduce(max, [len(x) for x in stateHash.keys()]) + 5 + len(prefix)
maxEventLen = reduce(max, [len(x) for x in eventHash.keys()]) + 5 + len(prefix)
maxActionLen = reduce(max, actionStrLen) + 5
if opts.dot:
print 'digraph G {'
print ' edge [fontname="Tahoma", fontsize="10", minlen=2];'
print ' node [fontname="Tahoma", fontsize="10"];'
print ' graph [fontname="Tahoma", label="%s"];' % prefix
print >>sys.stderr, 'stateRadiate:%s\nignoredIntensity:%d' % (stateRadiate, ignoredIntensity)
# emit state declarations
for state in stateHash.keys():
print ' %s[color="%s"];' % (state, stateHash[state]['DOT_Color'])
# emit rankings
for k, v in rankdict.iteritems():
print >>sys.stderr, '%s rank %s' % (k, str(v))
print 'subgraph { rank = same;'
for state in v:
print ' %s;' % state
print '}'
for state, va in stateHash.iteritems():
# emit ignored events
if va.get('IgnoredEvents'):
for event, v in va['IgnoredEvents'].iteritems():
stateStr = state
eventStr = event
print '%s -> %s [label="%s/",minlen=1, fontcolor="grey%d", color="grey%d"];' % (stateStr, stateStr, eventStr, ignoredIntensity, ignoredIntensity)
# emit transitions
if va.get('Events'):
for event, v in va['Events'].iteritems():
stateStr = state
eventStr = event
actionStr = ''
if v.get('Actions'):
actionStr = '\\n'.join([a.strip('_') for a in v['Actions']])
nextStr = v['NextState']
labelStr = '%s/\\n%s' % (eventStr, actionStr)
if stateRadiate:
color = va['DOT_Color']
elif len(eventHash[event]):
color = eventHash[event]['Color']
else:
color = 'black'
fontColor = color
styleStr = ''
style = eventHash[event].get('Style')
if style:
styleStr = ',style="%s"' % (style)
if style == 'invis':
fontColor = 'white'
print '%s -> %s [label="%s", color="%s", fontcolor="%s" %s];' % (stateStr, nextStr, labelStr, color, fontColor, styleStr)
print
print '}'
else:
### emit it
print header
### enumerations
'''
print '%sSt = Enumeration("%sState",(' % (prefix, prefix)
for state in stateHash.keys():
print '%s"%s",' % (' '*12, state)
print '%s))' % (' '*12)
print
print '%sEv = Enumeration("%sEvent",(' % (prefix, prefix)
for event in eventHash.keys():
print '%s"%s",' % (' '*12, event)
print '%s))' % (' '*12)
'''
### table
fmt = ' (%' + '-%d.%ds' % (maxStateLen, maxStateLen) + '%' + '-%d.%ds' % (maxEventLen, maxEventLen) + '):( %' +' -%d.%ds' % (maxActionLen, maxActionLen) + '%s),'
cfmt= ' ## %' + '-%d.%ds' % (maxStateLen, maxStateLen) + '%' + '-%d.%ds' % (maxEventLen, maxEventLen) + ' %' +' -%d.%ds' % (maxActionLen, maxActionLen) + '%s'
print 'def init%s%sFsmTable(obj,St,Ev):' % (prefix[0].upper(), prefix[1:])
# print " %sFsmTable = {" % prefix
print " return {"
print
for state, va in stateHash.iteritems():
print cfmt % ('CurrentState', 'Event', 'Actions', 'NextState')
print
if va.get('IgnoredEvents'):
for event, v in va['IgnoredEvents'].iteritems():
stateStr = '%sSt.' % ('') + state + ','
eventStr = '%sEv.' % ('') + event
print fmt % (stateStr, eventStr, '(),', stateStr.strip(','))
if va.get('Events'):
for event, v in va['Events'].iteritems():
stateStr = '%sSt.' % ('') + state + ','
eventStr = '%sEv.' % ('') + event
actionStr = ''
if v.get('Actions'):
actionStr = ','.join(['obj.%s' % action for action in v['Actions']]) + ','
nextStr = '%sSt.' % ('') + v['NextState']
print fmt % (stateStr, eventStr, '(%s),' % actionStr , nextStr)
print
print "}"
print