TECHZEN Zenoss User Community ARCHIVE  

[SOLVED] [Zenoss API] HTTP Error 503 on API updateNotification call - On call sc ...

Subject: [SOLVED] [Zenoss API] HTTP Error 503 on API updateNotification call - On call schedule rotation
Author: [Not Specified]
Posted: 2015-10-08 08:29

Hello everyone!

First, for the lazy.
TLDR:
-Call to updateNotification fails with HTTP error 503
-Uid of notification to update is correct
-The notification is set to "Everyone can view" + edit content + manage subscriptions

I am trying to setup an on-call rotation mechanism using Python and Zenoss's API. So far I can retreive the information I need from the notifications module, modify the user that is "on-call" and then send the data to the server.

That's where I am stuck. After the call to the API to update the notification, I am greeted by the server with an error 503. I am pretty sure that my code is OK, though the documentation is pretty scarce.

Here we go. The custom call I made to update the Notification:

def set_notification(self, in_data):
return self._router_request('TriggersRouter', 'updateNotification', in_data);

The actual error I get while calling the function:

urllib2.HTTPError: HTTP Error 503: Service Unavailable

I know from looking at the documentation that the 'updateNotification' call to the API is defined like this:

def updateNotification(self, **data):
notificationUid = data['uid']
response = self._getFacade().updateNotification(**data)
audit('UI.Notification.Edit', notificationUid, data_=data)
return DirectResponse.succeed(msg="Notification updated successfully.", data=Zuul.marshal(response))

As far as I can understand this code, it seems to extract the uid from the parameter "data". I have also confirmed that the uid is correct and extractable exactly like in the function, so that's not where the problem lies.

I also checked the Notification's permissions in the Web UI, and it's set to the broadest.

Thanks for any tips'n tricks on how to actually update a Notification with an API call!



Subject: My first guess is that you're
Author: [Not Specified]
Posted: 2015-10-08 09:18

My first guess is that you're POSTing to the wrong place, it should be:
http://yourzenoss:8080/zport/dmd/Events/triggers_router
(note it is "Events/triggers_router" whereas all or most of the other routers live right under /zport/dmd/...)

Or it might be a case of just malformed JSON. Try using "Firebug" or equivalent to watch the JSON post-response when you update a notification in the GUI.



Subject: Thank you for that quick
Author: [Not Specified]
Posted: 2015-10-08 09:24

Thank you for that quick response.

I doubt that I'm posting in the wrong place, since all my GET requests are working using TriggersRouter (and the examples provided with the API also do). It's worth a try though!

Also, thanks for pointing out the use of Firebug. I began working on the API using it but I kind of progressively stopped while getting better and better with the API... I'll post back with updates!



Subject: The reason I thought the
Author: [Not Specified]
Posted: 2015-10-08 09:28

The reason I thought the wrong place:

def set_notification(self, in_data):
return self._router_request('TriggersRouter', 'updateNotification', in_data);

That should be

return self._router_request('Events/TriggersRouter', 'updateNotification', in_data);

I think

Edited to add: Oh, maybe not, confusing what you have there with the actual URLs, but it's worth checking.



Subject: I think I'm on to something.
Author: [Not Specified]
Posted: 2015-10-08 09:51

I think I'm on to something. The request gets sent at the right place, but it was not properly "Jsoned". I modified the method:

def set_notification(self, in_data):
data=[in_data];
return self._router_request('TriggersRouter', 'updateNotification', data);

Now I am faced with something different, my first guess would be that it's an encoding issue:
{
"msg": "ServiceResponseError: java.lang.NumberFormatException: For input string: \"{'name': 'CPU_Critique', 'uuid': '2317207b\"",
"type": "exception",
"success": false
}

It seems like a character is added somewhere during the processing of data to the uuid of one of the concerned triggers.

As always, thanks for helping! I really appreciate any comment or suggestion being posted.



Subject: Project Update
Author: [Not Specified]
Posted: 2015-10-08 12:36

Project Update

I was erring with my transformation of the input dictionary. I took a better look at the documentation provided and the code that is going to answer a call for the updateNotification function goes like that:

@serviceConnectionError
def updateNotification(self, **data):
notificationUid = data['uid']
response = self._getFacade().updateNotification(**data)
audit('UI.Notification.Edit', notificationUid, data_=data)
return DirectResponse.succeed(msg="Notification updated successfully.", data=Zuul.marshal(response))

So the first thing that this function does is to extract the uid of the concerned notification. I modified my set_notification function:
def set_notification(self, in_data):
return self._router_request('TriggersRouter', 'updateNotification', in_data)['result'];

Also, a "print in_data['uid']" provides me with a "valid" uid for the object I am trying to modify (it prints "/zport/dmd/NotificationSubscriptions/Monitoring"), so I know for a fact that the function server-side will be able to extract the UID.

Unfortunately that brings back the HTTP Error 503...

Is there a config file or something somewhere that I missed during the setup that would prevent me to make write calls to the API from the outside



Subject: Good morning everyone!
Author: [Not Specified]
Posted: 2015-10-09 09:50

Good morning everyone!

Great news! It's alive!

The problem was "simple", though counter-intuitive. I solved the problem by copy-pasting the object detected by firebird as being sent to the server into my code, then modifying the recipients section.

Then, I compared the object with the one returned by getNotification. They were not the same!
This means that you cannot use the api to get a notification, modify it, then return that same object to the server through updateNotification...
For future reference, here is the format of the object that must be returned to the server using "updateNotification" after scavenging the information from the "get_Notification" object (ignore the semicolons, it's a deformation from my C programming side). Things to know before reading the code:
leRetour --> Object that is built in order to return it to the server and update a Notification
laNotification --> The object I got from calling the function get_Notification (a function in the API example)

Here we go:

leRetour = {};
leRetour['uid'] = laNotification['uid'];
leRetour['enabled'] = true;
leRetour['send_clear'] = true;#Etait false
leRetour['send_initial_occurrence'] = true;
leRetour['delay_seconds'] = 0;
leRetour['repeat_seconds'] = 0;
leRetour['body_content_type'] = "html";
leRetour['subject_format'] = "[zenoss] ${evt/device} ${evt/summary}";
leRetour['body_format'] = "\nDevice: ${evt/device}\nComponent: ${evt/component}\nSeverity: ${evt/severity}\nTime: ${evt/lastTime}\nMessage:\n${evt/message}\n Event Detail\n Acknowledge\n Close\n Device Events\n";
leRetour['clear_subject_format'] = "[zenoss] CLEAR: ${evt/device} ${clearEvt/summary}";
leRetour['clear_body_format'] = "\nEvent: '${evt/summary}'\nCleared by: '${evt/clearid}'\nAt: ${evt/stateChange}\nDevice: ${evt/device}\nComponent: ${evt/component}\nSeverity: ${evt/severity}\nMessage:\n${evt/message}\n Reopen\n";
leRetour['email_from'] = "monitoring@myCompany.ca";
leRetour['host'] = "192.168.1.1";
leRetour['port"'] = 25;
leRetour['useTls'] = false;
leRetour['user'] = "";
leRetour['password'] = "";
leRetour['notification_globalRead'] = true;
leRetour['notification_globalWrite'] = true;
leRetour['notification_globalManage'] = true;
leRetour['recipients'] = laNotification['recipients'];
leRetour['subscriptions'] = [];
for sub in laNotification['subscriptions']:
leRetour['subscriptions'].append(sub['uuid']);
wrap=[leRetour];
resultat = z.set_notification(wrap);

Also, here is the code of the function I added in the provided api example file:
def set_notification(self, in_data):
return self._router_request('TriggersRouter', 'updateNotification', in_data)['result'];

Hope this can help someone in the future for updating a notification. I am going to use this as a substitute for the lack of proper on-call scheduling in Zenoss Core, to emulate the behavior of Nagios regarding who's receiving notifications at various times.



< Previous
interface graphs become dashes
  Next
Zenoss 5 Multiple Collectors
>