SNMPTraps: pysnmp and "disableAuthorization" - pysnmp

I have written an SNMP trap receiver but currently I have to hardcode all the SNMPv2 community strings to be able to receive the traps.
How do I emulate the 'disableAuthorization' functionality from snmptrapd in pysnmp?
I have tried to not set the community string: config.addV1System(snmpEngine, 'my-area') but this errors about a missing param. I have also tried an empty string: config.addV1System(snmpEngine, 'my-area', '') but this stops all traps being processed.
What is the best way to allow receiving all traps through pysnmp regardless of the community string they were sent with? I haven't found anything in the pysnmp docs that could help me

I had made progress on setting up an observer for V1/2 (V3 to be added later) that picked up on notifications with an unknown community string and then called addV1System on the fly to dynamically add it in, like so:
When setting up the transportDispatcher:
snmpEngine.observer.registerObserver(_handle_unauthenticated_snmptrap,
"rfc2576.prepareDataElements:sm-failure", "rfc3412.prepareDataElements:sm-failure")
And then:
def _handle_unauthenticated_snmptrap(snmpEngine, execpoint, variables, cbCtx):
if variables["securityLevel"] in [ 1, 2 ] and variables["statusInformation"]["errorIndication"] == errind.unknownCommunityName:
new_comm_string = "%s" % variables["statusInformation"].get("communityName", "")
config.addV1System(my_snmpEngine, 'my-area', new_comm_string)
return
else:
msg = "%s" % variables["statusInformation"]
print(f"Trap: { msg }")
However, this will always throw away the first trap received while adding any new community string (and then there is the problem whereby when the daemon is restarted the updated list of community strings is lost).
In looking to improve this I then found hidden away in the docs this little gem:
https://pysnmp.readthedocs.io/en/latest/examples/v3arch/asyncore/manager/ntfrcv/advanced-topics.html#serve-snmp-community-names-defined-by-regexp
This example receives a notification and rewrites the community string into 'public' so all traps will be correctly received.
In essence, when setting up the transportDispatcher:
my_snmpEngine.observer.registerObserver(_trap_observer,
'rfc2576.processIncomingMsg:writable', cbCtx='public')
And then:
def _trap_observer(snmpEngine, execpoint, variables, community_string):
variables['communityName'] = variables['communityName'].clone(community_string)

Related

Detect and prevent processing of sequential duplicate Tradingview webhook json

I am not very well acquainted with python, but have by much trial and error, and building upon the work of others, developed a simple working and reliable interface between Tradingview (TV) and Interactive Brokers (IB).
I have situation where occasional apparent repainting of TV charts results in duplicate orders being submitted. (Yes, I have researched methods whereby such repainting can be reduced or eliminated, but the effect of these methods greatly reduces the proven profitability of my trading algo.) I am attempting to modify my code to detect and prevent processing of duplicate orders received in sequence, as I never intend to have more than one order working for any given security and any given time. My modification attempt (see below) is quite rudimentary--simply detect whether the just-received webhook json is essentially the same as that received just previously, and ignore if so.
This is where, if you wish, you can throw stones and tell me to go read about 'ver' and 'let' and 'global'. I've tried--for hours, and just don't "get it". I'm in my 70s and come from the era of Fortran, Cobol, and Basic, when variables were simply declared (if necessary), initialized, and used. Could someone kindly help me simply to get some starting values into the two variables, xticker and xorder, in the code below? Or better yet, show me a better way to accomplish my objective?
Many thanks for any help offered!
[Edit] - Repainting noted above may possibly have resulted from my setting "calc_on_order_fills=true" and/or "process_orders_on_close="true" while also setting "calc_on_every_tick=true". I have changed the first two of these settings to "false", but have no way to ascertain if doing so gets rid of the TV alert/webhook duplicates. But irrespective of whether these script modifications are beneficial, I would still like to add a "detect and ignore duplicates" feature to my TV to IB bridge as described.
#Create root
#app.route('/', methods=['GET','POST'])
async def root(request):
return response.text('online')
#Listen for signals and execute orders
#app.route('/webhook', methods=['GET','POST'])
async def webhook(request):
if request.method == 'POST':
await checkIfReconnect()
#Parse alert data
alert = request.json
order = MarketOrder(alert['order_action'],alert['order_contracts'],account='aannnnnnn')
ticker = alert['ticker']
# Attempt to detect and prevent processing of duplicate webhook json
# Fails since xticker and xorder are undefined and have no value.
# Need to initialize xticker='dummy' and xorder='dummy' at start
# Where/how to place these two initializing statements?
if not ticker == xticker and xorder == order:
#Do stuff (process and submit valid order)
#then ...
xticker = ticker
xorder = order
return HTTPResponse("ok", 200)
return HTTPResponse("", 405)
I have tried setting xticker and xorder directly using =, var, and let, and have tried but failed to understand how local and global variable assignment works within Python. My next effort, if no assistance is offered, will be to make use of read & write operations to an external file in order to draw in initial values and then to keep track of the last valid json data-- Crude but perhaps workable-- and there must be a great many simpler and better methods, all of which are beyond my ken.
Solved my own problem using global variables after finding some examples online. Solution works as intended, with sequential duplicate orders being ignored. Relevant code extract follows:
#Create root
#app.route('/', methods=['GET','POST'])
async def root(request):
return response.text('online')
#Listen for signals and execute orders
#app.route('/webhook', methods=['GET','POST'])
async def webhook(request):
if request.method == 'POST':
await checkIfReconnect()
#Parse alert data
alert = request.json
order = MarketOrder(alert['order_action'],alert['order_contracts'],account='aannnnnnn')
ticker = alert['ticker']
action = alert['order_action']
source = alert['source']
if not (ticker == xticker and xaction == action and xsource == source):
def inner():
global xticker
xticker = ticker
global xaction
xaction = action
global xsource
xsource = source
inner()
#Do stuff (prepare and submit order to broker)
return HTTPResponse("ok", 200)
return HTTPResponse("", 405)
#Reconnect if needed
async def checkIfReconnect():
if not app.ib.isConnected() or not app.ib.client.isConnected():
app.ib.disconnect()
app.ib = IB()
app.ib.connect('127.0.0.1',7497,clientId=int(int((time.time()*1000)-1667740000000)/1000000))
#Run app
if __name__ == '__main__':
#Connect to IB
app.ib = IB()
xticker = "ticker"
xaction = "action"
xsource = "source"
app.ib.connectAsync('127.0.0.1',7497,clientId=int(int((time.time()*1000)-1667740000000)/1000000))
app.run(port=5000)

Protractor - check if element is present and either stop test or continue

I have a Protractor test that pulls various values from the UI and stores them as variables for comparison with values from a different database.
Now this test needs to run against multiple sites BUT of the 25 maximum data points recorded, some sites only have 22.
Clearly the test fails on those "22" sites since the elements are not present.
What I want to achieve is where there's a "22" site, the tests against the not present elements are ignored and the test proceeds to the end. Conveniently, the "missing" elements are the last ones in the spec.
Crudely speaking...
if element-y is not present end test or if element-y is present continue
Grateful if anyone could advise.
Thanks #sergey. I've modified your example as below....
if (!(await element(by.xpath('//*[#id="root"]/div/div[2]/main/div/div/section[5]/div/div/div[1]/section/div/span')).isPresent())) {
console.warn ('Functions are not present, closing the session')
await browser.close()
I get this error:
if (!(await element(by.xpath('//*[#id="root"]/div/div[2]/main/div/div/section[5]/div/div/div[1]/section/div/span')).isPresent())) {
^^^^^^^
SyntaxError: Unexpected identifier
I've tried using a 'var' instead of the actual element, but get the same result.
Thanks
well the best option that I recall is still pretty dirty... you can do something like this
if (!(await element.isPresent())) {
console.warn('Element not present, closing the session')
await browser.close()
}
And then the rest of test cases will fail as session not found or similar error
The reason you can't do anything better because in protractor you can't do conditional test cases based on a Promise-like condition, if that makes sense...

Using QCMDEXC to call QEZSNDMG via DB2 stored procedure

Working on a side project where I use a set of views to identify contention of records within an iSeries set of physical files.
What I would like to do once identified is pull the user profile locking the record, and then send a break message to their terminal as an informational break message.
What I have found is the QEZSNDMG API. Simple enough to use interactively, but I'm trying to put together a command that would be used in conjunction with QCMDEXC API to issue the call to QEZSNDMG and alert the user that they are locking a record.
Reviewing the IBM documentation of the QEZSNDMG API, I see that there are two sets of option parameters, but nothing as required (which seems odd to me, but another topic for another day). But I continue to receive the error "Parameters passed on CALL do not match those required."
Here are some examples that I have tried from the command line so far:
CALL PGM(QEZSNDMG) PARM('*INFO' '*BREAK' 'TEST' '4' 'DOUGLAS' '1' '1' '-4')
CALL PGM(QEZSNDMG) PARM('*INFO' '*BREAK' 'TEST' '4' 'DOUGLAS')
CALL PGM(QEZSNDMG) PARM('*INFO' '*BREAK' 'TEST' '4' 'DOUGLAS' '1')
Note: I would like to avoid using a CL or RPG program if possible but understand it may come to that using one of many examples I found before posting. Just want to exhaust this option before going down that road.
Update
While logged in, I used WRKMSGQ to see the message queues assigned to my station. There were two: QSYS/DOUGLAS and QUSRSYS/DOUGLAS. I then issued SNDBRKMSG with no affect on my workstation (IE, the message didn't break my session):
SNDBRKMSG MSG(TESTING) TOMSGQ(QSYS/DOUGLAS)
SNDBRKMSG MSG(TESTING) TOMSGQ(QUSRSYS/DOUGLAS)
I realized if I provide the workstation session name in the TOMSG parameter it worked:
SNDBRKMSG MSG(TESTING) TOMSGQ(*LIBL/QPADEV0003)
Using SNDBRKMSG was what I was looking for.
Some nudging in the right direction lead me to realize that the workstation session ID is located within QSYS2.RCD_LOCK in field JOB_NAME (job number/username/workstation).
Extracting the workstation ID allowed me to create a correctly formatted SNDBRKMSG command to QCMDEXC and alert the user that they are locking a record needed by another process.

perl6 Changes in IO::Socket::INET from last year and broken promises

When I asked a question last year about promises, my echo server was working (see this link: perl6 how to get specific identity of promises? ). However, with the new versions of perl6, my echo server is no longer working.
I guess I can try the example from the perl6 documentation site ( https://docs.perl6.org/type/IO::Socket::INET ), but I want to find out what mistake I have made in my code. My current level has precluded me from seeing the difference between my codes and the codes on the perl6 documentation site. Please give me a hint; thanks !
my #result;
for 0 .. 2 -> $index {
#result[$index] = start {
my $myPromiseID = $index;
say "======> $myPromiseID\n";
my $rsSocket = IO::Socket::INET.new:
localhost => 'localhost',
localport => 1234 + $index,
listen => 1;
while $rsSocket.accept -> $rsConnection {
say "Promise $myPromiseID accepted connection";
while $rsConnection.recv -> $stuff {
say "Promise $myPromiseID Echoing $stuff";
$rsConnection.print($stuff);
}
$rsConnection.close;
}
}
}
await #result;
And the error messages are:
Tried to get the result of a broken Promise
in block <unit> at p6EchoMulti.pl line 24
Original exception:
Nothing given for new socket to connect or bind to
in block at p6EchoMulti.pl line 8
Actually thrown at:
in block at p6EchoMulti.pl line 13
This commit, which was announced in the Jan 2017 section of Rakudo's changelog as "Fixed bug where IPv6 URIs were not parsed correctly" did a lot more that just fix a URI parsing bug. It also completely redid the parameter binding/validation of an IO::Socket::INET.new call, and one consequence is it broke your code because the updated code requires that listen be an actual Bool, not merely coerce to one.
The old code (the code on the left of the commit link above) had a simple method new (*%args is copy). This matched your call. The error (fail "Nothing given for new socket to connect or bind to") did not trigger because 1 evaluates to True in a boolean context so %args<host> || %args<listen> was also True. So the rest of the code ran with listen set to 1 and it all worked out fine.
Rakudos from 2017.01 have the code on the right at the commit link above. Note how there are now multiple new methods (i.e. multiple multi method new ... declarations).
The multi(s) intended to handle a call that specifies a listen argument is/are of the form multi method new (..., Bool:D :$listen!, ...). Note the Bool:D.
A call to new, with the listen parameter set to True, matches this multi and works as expected.
But a call with :listen(1) will just match the generic multi method new (*%args) signature instead. This latter does an unconditional fail "Nothing given for new socket to connect or bind to";.
Okay, after some struggling, it seems to have improved if I changed listen=>1 to listen=>True.
Can anyone care to explain why 1 was not evaluated to True, and why it worked before?
Thanks.

Apply Command to String-type custom fields with YouTrack Rest API

and thanks for looking!
I have an instance of YouTrack with several custom fields, some of which are String-type. I'm implementing a module to create a new issue via the YouTrack REST API's PUT request, and then updating its fields with user-submitted values by applying commands. This works great---most of the time.
I know that I can apply multiple commands to an issue at the same time by concatenating them into the query string, like so:
Type Bug Priority Critical add Fix versions 5.1 tag regression
will result in
Type: Bug
Priority: Critical
Fix versions: 5.1
in their respective fields (as well as adding the regression tag). But, if I try to do the same thing with multiple String-type custom fields, then:
Foo something Example Something else Bar P0001
results in
Foo: something Example Something else Bar P0001
Example:
Bar:
The command only applies to the first field, and the rest of the query string is treated like its String value. I can apply the command individually for each field, but is there an easier way to combine these requests?
Thanks again!
This is an expected result because all string after foo is considered a value of this field, and spaces are also valid symbols for string custom fields.
If you try to apply this command via command window in the UI, you will actually see the same result.
Such a good question.
I encountered the same issue and have spent an unhealthy amount of time in frustration.
Using the command window from the YouTrack UI I noticed it leaves trailing quotations and I was unable to find anything in the documentation which discussed finalizing or identifying the end of a string value. I was also unable to find any mention of setting string field values in the command reference, grammer documentation or examples.
For my solution I am using Python with the requests and urllib modules. - Though I expect you could turn the solution to any language.
The rest API will accept explicit strings in the POST
import requests
import urllib
from collections import OrderedDict
URL = 'http://youtrack.your.address:8000/rest/issue/{issue}/execute?'.format(issue='TEST-1234')
params = OrderedDict({
'State': 'New',
'Priority': 'Critical',
'String Field': '"Message to submit"',
'Other Details': '"Fold the toilet paper to a point when you are finished."'
})
str_cmd = ' '.join(' '.join([k, v]) for k, v in params.items())
command_url = URL + urllib.urlencode({'command':str_cmd})
result = requests.post(command_url)
# The command result:
# http://youtrack.your.address:8000/rest/issue/TEST-1234/execute?command=Priority+Critical+State+New+String+Field+%22Message+to+submit%22+Other+Details+%22Fold+the+toilet+paper+to+a+point+when+you+are+finished.%22
I'm sad to see this one go unanswered for so long. - Hope this helps!
edit:
After continuing my work, I have concluded that sending all the field
updates as a single POST is marginally better for the YouTrack
server, but requires more effort than it's worth to:
1) know all fields in the Issues which are string values
2) pre-process all the string values into string literals
3) If you were to send all your field updates as a single request and just one of them was missing, failed to set, or was an unexpected value, then the entire request will fail and you potentially lose all the other information.
I wish the YouTrack documentation had some mention or discussion of
these considerations.