Skip to content

Commit 1e44b66

Browse files
committed
Merge branch 'develop'
2 parents e3ac3f7 + 53087a9 commit 1e44b66

File tree

9 files changed

+206
-4
lines changed

9 files changed

+206
-4
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.2.4
2+
current_version = 0.3.0
33
commit = False
44
tag = False
55
files = setup.py netuitive/__init__.py

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ RUN pip install -r /opt/app/test_requirements.txt
1313

1414
ADD . /opt/app/
1515

16+
RUN flake8 netuitive
1617
RUN python setup.py test
1718
RUN python setup.py install
1819

example/example.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
MyElement.add_tag('Production', 'True')
1515
MyElement.add_tag('app_tier', 'True')
1616

17-
timestamp = int(time.mktime(time.gmtime()))
17+
timestamp = int(time.mktime(time.localtime()))
1818
MyElement.add_sample('app.error', timestamp, 1, host='appserver01')
1919
MyElement.add_sample('app.request', timestamp, 10, host='appserver01')
2020

@@ -26,5 +26,9 @@
2626

2727
ApiClient.post_event(MyEvent)
2828

29+
MyCheck = netuitive.Check('heartbeat', 'element', 60)
30+
31+
ApiClient.post_check(MyCheck)
32+
2933
if ApiClient.time_insync():
3034
print('we have time sync with the server')

netuitive/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# -*- coding: utf-8 -*-
22

33
__author__ = 'Netuitive, Inc'
4-
__version__ = '0.2.4'
4+
__version__ = '0.3.0'
55

66
from .client import Client # nopep8 # flake8: noqa
77
from .element import Element # nopep8 # flake8: noqa
88
from .event import Event # nopep8 # flake8: noqa
9+
from .check import Check # nopep8 # flake8: noqa
910
from .util import to_ms_timestamp # nopep8 # flake8: noqa

netuitive/check.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
class Check(object):
3+
4+
"""
5+
A Check model
6+
:param name: Check name
7+
:type name: string
8+
:param elementId: Associated Element ID
9+
:type elementId: string
10+
:param interval: Check interval in seconds
11+
:type interval: int
12+
"""
13+
14+
def __init__(self,
15+
name,
16+
elementId,
17+
interval):
18+
19+
self.name = name
20+
self.elementId = elementId
21+
self.interval = interval

netuitive/client.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ def __init__(self, url='https://api.app.netuitive.com/ingest',
4141
self.timeurl = '{uri.scheme}://{uri.netloc}/time'.format(
4242
uri=urlparse(url))
4343
self.eventurl = self.dataurl.replace('/ingest/', '/ingest/events/', 1)
44+
self.checkurl = self.dataurl.replace('/ingest/', '/check/', 1) \
45+
.replace('/infrastructure', '', 1)
4446
self.agent = agent
4547
self.disabled = False
4648
self.kill_codes = [410, 418]
@@ -149,6 +151,48 @@ def post_event(self, event):
149151
'error posting payload to api ingest endpoint (%s): %s',
150152
self.eventurl, e)
151153

154+
def post_check(self, check):
155+
"""
156+
:param check: Check to post to Metricly
157+
:type check: object
158+
"""
159+
160+
if self.disabled is True:
161+
logging.error('Posting has been disabled. '
162+
'See previous errors for details.')
163+
return(False)
164+
165+
url = self.checkurl + '/' \
166+
+ check.name + '/' \
167+
+ check.elementId + '/' \
168+
+ str(check.interval)
169+
try:
170+
headers = {'User-Agent': self.agent}
171+
request = urllib2.Request(
172+
url, data='', headers=headers)
173+
resp = urllib2.urlopen(request)
174+
logging.debug("Response code: %d", resp.getcode())
175+
resp.close()
176+
177+
return(True)
178+
179+
except urllib2.HTTPError as e:
180+
logging.debug("Response code: %d", e.code)
181+
182+
if e.code in self.kill_codes:
183+
self.disabled = True
184+
logging.exception('Posting has been disabled.'
185+
'See previous errors for details.')
186+
else:
187+
logging.exception(
188+
'error posting payload to api ingest endpoint (%s): %s',
189+
url, e)
190+
191+
except Exception as e:
192+
logging.exception(
193+
'error posting payload to api ingest endpoint (%s): %s',
194+
url, e)
195+
152196
def check_time_offset(self, epoch=None):
153197
req = urllib2.Request(self.timeurl,
154198
headers={'User-Agent': self.agent})

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
setup(
2626
name='netuitive',
27-
version='0.2.4',
27+
version='0.3.0',
2828
description="Python Client for Netuitive Cloud",
2929
long_description=readme + '\n\n' + history,
3030
author="Netuitive",

tests/test_netuitive.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,5 +509,20 @@ def tearDown(self):
509509
pass
510510

511511

512+
class TestCheck(unittest.TestCase):
513+
514+
def setUp(self):
515+
self.check = netuitive.Check('checkName', 'elementId', 60)
516+
517+
def test_check(self):
518+
519+
self.assertEqual(self.check.name, 'checkName')
520+
self.assertEqual(self.check.elementId, 'elementId')
521+
self.assertEqual(self.check.interval, 60)
522+
523+
def tearDown(self):
524+
pass
525+
526+
512527
if __name__ == '__main__':
513528
unittest.main()

tests/test_netuitive_client.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,122 @@ def test_not_kill_switch_504(self, mock_logging, mock_post):
397397
def tearDown(self):
398398
pass
399399

400+
class TestClientCheckPost(unittest.TestCase):
401+
402+
def setUp(self):
403+
pass
404+
405+
@mock.patch('netuitive.client.urllib2.urlopen')
406+
@mock.patch('netuitive.client.logging')
407+
def test_success(self, mock_logging, mock_post):
408+
409+
mock_post.return_value = MockResponse(code=202)
410+
411+
# test infrastructure endpoint url creation
412+
a = netuitive.Client(api_key='apikey')
413+
414+
c = netuitive.Check('check', 'test', 60)
415+
416+
resp = a.post_check(c)
417+
418+
self.assertTrue(resp)
419+
420+
self.assertEqual(mock_logging.exception.call_args_list, [])
421+
422+
@mock.patch('netuitive.client.urllib2.urlopen')
423+
@mock.patch('netuitive.client.logging')
424+
def test_failure_general_http(self, mock_logging, mock_post):
425+
426+
mock_post.return_value = MockResponse(code=500)
427+
428+
# test infrastructure endpoint url creation
429+
a = netuitive.Client(api_key='apikey')
430+
mock_post.side_effect = urllib2.HTTPError(a.url, 500, '', {}, None)
431+
432+
e = netuitive.Check('check', 'test', 60)
433+
434+
resp = a.post_event(e)
435+
436+
self.assertNotEqual(resp, True)
437+
438+
self.assertEqual(mock_logging.exception.call_args_list[0][0][0], 'error posting payload to api ingest endpoint (%s): %s')
439+
440+
@mock.patch('netuitive.client.urllib2.urlopen')
441+
@mock.patch('netuitive.client.logging')
442+
def test_failure_general(self, mock_logging, mock_post):
443+
mock_post.side_effect = urllib2.URLError('something')
444+
445+
# test infrastructure endpoint url creation
446+
a = netuitive.Client(api_key='apikey')
447+
448+
c = netuitive.Check('check', 'test', 60)
449+
450+
resp = a.post_check(c)
451+
452+
self.assertNotEqual(resp, True)
453+
454+
self.assertEqual(mock_logging.exception.call_args_list[0][0][0], 'error posting payload to api ingest endpoint (%s): %s')
455+
456+
@mock.patch('netuitive.client.urllib2.urlopen')
457+
@mock.patch('netuitive.client.logging')
458+
def test_kill_switch_410(self, mock_logging, mock_post):
459+
460+
mock_post.return_value = MockResponse(code=410)
461+
# test infrastructure endpoint url creation
462+
a = netuitive.Client(api_key='apikey')
463+
mock_post.side_effect = urllib2.HTTPError(a.url, 410, '', {}, None)
464+
465+
c = netuitive.Check('check', 'test', 60)
466+
467+
resp = a.post_check(c)
468+
resp2 = a.post_check(c)
469+
470+
self.assertNotEqual(resp, True)
471+
self.assertFalse(resp2)
472+
self.assertTrue(a.disabled)
473+
self.assertEqual(mock_logging.exception.call_args_list[0][0][0], 'Posting has been disabled.See previous errors for details.')
474+
475+
@mock.patch('netuitive.client.urllib2.urlopen')
476+
@mock.patch('netuitive.client.logging')
477+
def test_kill_switch_418(self, mock_logging, mock_post):
478+
479+
mock_post.return_value = MockResponse(code=418)
480+
481+
# test infrastructure endpoint url creation
482+
a = netuitive.Client(api_key='apikey')
483+
mock_post.side_effect = urllib2.HTTPError(a.url, 418, '', {}, None)
484+
485+
c = netuitive.Check('check', 'test', 60)
486+
487+
resp = a.post_check(c)
488+
resp2 = a.post_check(c)
489+
490+
self.assertNotEqual(resp, True)
491+
self.assertFalse(resp2)
492+
self.assertTrue(a.disabled)
493+
self.assertEqual(mock_logging.exception.call_args_list[0][0][0], 'Posting has been disabled.See previous errors for details.')
494+
495+
@mock.patch('netuitive.client.urllib2.urlopen')
496+
@mock.patch('netuitive.client.logging')
497+
def test_not_kill_switch_504(self, mock_logging, mock_post):
498+
499+
mock_post.return_value = MockResponse(code=504)
500+
# test infrastructure endpoint url creation
501+
a = netuitive.Client(api_key='apikey')
502+
mock_post.side_effect = urllib2.HTTPError(a.url, 504, '', {}, None)
503+
504+
c = netuitive.Check('check', 'test', 60)
505+
506+
resp = a.post_check(c)
507+
resp2 = a.post_check(c)
508+
509+
self.assertNotEqual(resp, True)
510+
self.assertFalse(resp2)
511+
self.assertFalse(a.disabled)
512+
self.assertEqual(mock_logging.exception.call_args_list[0][0][0], 'error posting payload to api ingest endpoint (%s): %s')
513+
514+
def tearDown(self):
515+
pass
400516

401517
class TestClientTimeOffset(unittest.TestCase):
402518

0 commit comments

Comments
 (0)