13 Oct, 2011, Kline wrote in the 1st comment:
Votes: 0
Been trying to wrap my head around what I need to change/how here but I think I'm to the point I need a second set of eyes and no one I work with has a clue about TCL or programming in general.

This needs to remain a TCL solution as my current script is in TCL due to it being the only thing I could find an interpreter for in my tightly locked down work environment. I'm actually using the interpreter built into Expect since the server I have to use has no real tclsh package…

My existing script is designed to pole various points on a network. It achieves this by looping an array of network element names each containing a list of ports paired to a human readable name. It telnets the node, queries all specified ports, outputs some data, and moves on. It is flexible enough to run on "all" nodes built into the script or to accept a handful of user-specified ones (if they are built into the script). I would like to make it flexible enough to also accept a human recognizable port but am having difficulty getting my head around how I need to re-arrange my data storage to easily do this while retaining existing functionality with minimal data duplication.

Here's some samples:
set db(NODE1) [list {PORT-1-2-3-4 "LINK TO BLDG 3"} {PORT-5-4-3 "LINK TO BLDG 54"}]
set db(NODE2) [list {PORT-1-4 "LINK TO ZONE C"} {PORT-7-8-3 LINK TO ZONE D"}]

So currently it is possible to loop through all db(*) elements then run queries on every item in the list within them. I am trying to find a simple way to also support a query directly on items within the list that are within a node. Some items within the node list may persist across 2+ nodes, depicted as:
NODE1(LINKABC) -> NODE2(LINKABC) -> NODE3(LINKABC) -> NODE4(LINKABC)

Can anyone suggest an elegant solution to this? I can certainly think of ways to shoehorn it, but I am trying to maintain as simple an interface as possible for my co-workers who use this script, only requiring they supply a node/port name.

I'd be happy to supply some more details on exact implementation details or anything else that may be helpful…Just let me know. Really tired of repeatedly attacking this and then realizing the results won't be quite what I need. This is not a production/must have/saleable product. Just a tool I made to assist my section to do our jobs more efficiently, that I'd like to improve.
13 Oct, 2011, David Haley wrote in the 2nd comment:
Votes: 0
What is the current cmdline interface (exactly) and what is the desired interface?

Are human-friendly names unique? If so, it seems that you have an easy solution: have a map from human-friendly name to port… if you have to do it by node, then have a map from node to map from human name to port name.
14 Oct, 2011, Kline wrote in the 3rd comment:
Votes: 0
The current interface is a prompt for the user to enter either a list of nodes, space delimited, or "all". Entering "all" will poll every port within the array on each node. If the user specifies just a list of specific nodes only ports on those nodes will be polled.

The human-friendly names are not unique, no. For example I may have a human-friendly name be identical across 4-5 or more nodes, on either the same or different ports at each node. Not sure if it will help you visualize it, but the purpose of this script is to query a SONET node and check two ports per circuit (friendly name) to determine which is currently active (working/protection diverse routes).
14 Oct, 2011, David Haley wrote in the 4th comment:
Votes: 0
Well, if the long names aren't unique, how is it supposed to know what to check?

Since you already have the list of short/long port names, can't you just iterate over each node, and look for the pairs that have the relevant long name?

You could also have a map like this:

long name –>
[node_name short_name]
[node_name short_name]

etc

in other words, a map from the long name to the list of relevant node/shortname pairs.
15 Oct, 2011, Kline wrote in the 5th comment:
Votes: 0
David Haley said:
Well, if the long names aren't unique, how is it supposed to know what to check?

I don't quite understand your question. Currently the names of ports does not matter as my script only works to check all ports known to it on each node, so the name of them doesn't matter except to output to the user so they don't have to cross reference what port is what name.

David Haley said:
Since you already have the list of short/long port names, can't you just iterate over each node, and look for the pairs that have the relevant long name?

I think this might be the solution I've been unable to realize on my own, thanks! I've been trying to do things so much more complicated but it may be simplest for me to accept any amount of port names then just process my node list as normal but only run actual queries on the specified ports. I've been trying to do all kinds of crazy multimap/nested array crap. Should have tried to KISS it instead :(

David Haley said:
You could also have a map like this:

long name –>
[node_name short_name]
[node_name short_name]

etc

in other words, a map from the long name to the list of relevant node/shortname pairs.

This would not work due to the fact that long (non-friendly) names are not unique. The only truly unique object I have to use as a reference is a node itself.

Let me see if I can explain the layout I'm stuck dealing with a bit better..

Network of unique node names. Each node has a multitude of virtual port interfaces (VT-X-X-X-X, etc) with an associated name/label (DAL_LNK1, etc). Within each node each name/label is built across two virtual interfaces: working and protection paths within the network. Ports are only unique within the node: each node can have VT-1-1-1 for example, like any switch can have physical interfaces on port 1, 2, 3, etc.

Due to the working/protect split within each node labels are appended to denote that, typically (but not guaranteed..sigh, lol). So DAL_LNK1 ends up being DAL_LNK1-W and DAL_LNK1-P. However, users will still refer to it as only "DAL_LNK1" and it's up to my section to determine which is the active data path (working/protection) at each node within the network for all specified links. So, using your drawing…

[user circuits listing: DAL_LNK1, DAL_LNK2]
[node1]
`-DAL_LNK1-W (port 1-2-3-4)
`-DAL_LNK1-P (port 1-2-3-5)
`-DAL_LNK2-W (port 1-2-3-5)
`-DAL_LNK2-P (port 1-2-3-4)
[node2]
`-DAL_LNK1-W (port 3-4-1-6)
`-DAL_LNK1-P (port 2-5-7-1)
`-DAL_LNK2-W (port 6-1-0-8)
`-DAL_LNK2-P (port 4-0-9-9)

Hopefully this makes more sense? Although I think your suggestion of iterating all nodes looking for my specific object will work (and it feels so painfully obvious…hence this topic, just couldn't see it!) so I'll try that out when I go back to work Sunday night if I have enough down time. Thanks again!
16 Oct, 2011, David Haley wrote in the 6th comment:
Votes: 0
Sorry, that map was supposed to be a map from {long name} to list of {node_name short_name} pairs. In other words, a map fom long name to all relevant node/short name pairs.

I think that iteration will work here… it might not be the most efficient or perfect per se, but it seems that your network structures are small enough that a little iteration won't kill you. Maps in Tcl (aka "arrays", which personally confuses the hell out of me) are a real pain to deal with. In fact, Tcl as a whole has a bunch of idiosyncrasies that make it sometimes fun and sometimes, err, challenging to work with. (I spent about 3 years writing Tcl code as part of my job, so I feel your pain!!)
16 Oct, 2011, Kline wrote in the 7th comment:
Votes: 0
Yeah, arrays are painful. My main data set is an array with nested lists. I love a lot about TCL but it does make a few things challenging, and it's also added difficulty that I've shoehorned a solution into running everything within Expect since I have no actual tclsh package available to me. The network isn't overly large (yet…supposed to grow, sometime, but who knows, lol): only about 350 or so "unique points" to query across 40-50 different nodes. The default behavior is already to iterate the node list then just poll every link listed for it so I don't think this will be too difficult to just skip over any link not specified. I might try to add some intelligence to avoid making a telnet connection if that means some nodes are "empty" based on user input, but worst case I just end up telnet/login/disconnect and cost a few seconds. It only takes 3-4 minutes to run the entire network so far, so it's wouldn't even be noticeable if I can't get an intelligence solution to ignore empties.
17 Oct, 2011, Kline wrote in the 8th comment:
Votes: 0
Working :D!

Had to make some concessions to a few deeply nested loops and other hacks since whatever version of TCL is compiled into this Expect doesn't support things like lsearch -all. To keep my sanity I ended up prompting for two modes, either all/a list of nodes (existing functionality) or all/a list of circuits ('all circuits' just processes 'all nodes').

Very happy with the result, and while I see the path ahead of me to accepting a unified input list of either nodes/circuits mixed, I don't believe the time investment required would be worth such a minor improvement. Thanks again for showing me what was already in front of my face DH :)
17 Oct, 2011, David Haley wrote in the 9th comment:
Votes: 0
Woot! Glad you got it working :smile:

I have a love/hate relationship with Tcl… it seems you are developing one too. :wink:
0.0/9