Last active
August 29, 2015 14:03
-
-
Save jupemara/7dfbcbfdae0488dc3629 to your computer and use it in GitHub Desktop.
This script create zabbix screen. This script is compatible for Python 2.6.x.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
""" | |
Create zabbix screen script. | |
This script creates new own screen | |
by x-axis elements and y-axis elements of user definition. | |
""" | |
import hashlib | |
import logging | |
import urllib2 | |
import json | |
import optparse | |
import sys | |
DEFAULT = { | |
'zabbix_server_schema': 'http', | |
'zabbix_server_host': '127.0.0.1', | |
'zabbix_server_port': '80', | |
'zabbix_api_username': 'Admin', | |
'zabbix_api_password': 'zabbix', | |
'zabbix_api_userid': 1, | |
'log_level': 'INFO', | |
'name': None, | |
'x_elements': list(), | |
'y_elements': list(), | |
'element_width': 320, | |
'force': False, | |
'inverse': False, | |
'leave_old_screen': False, | |
} | |
def get_args(): | |
usage = ( | |
'This script creates new screen ' | |
'by using x-axis elements and y-axis elements of user definition.' | |
) | |
parser = optparse.OptionParser(usage=usage) | |
parser.add_option( | |
'--zabbix-server-schema', '-S', | |
type='string', default=DEFAULT['zabbix_server_schema'], | |
dest='zabbix_server_schema', | |
help='Schema to access to zabbix server API. e.g: http, https.' | |
) | |
parser.add_option( | |
'--zabbix-server-host', '-H', | |
type='string', default=DEFAULT['zabbix_server_host'], | |
dest='zabbix_server_host', | |
help='Zabbix server hostname or IP address.' | |
) | |
parser.add_option( | |
'--zabbix-server-port', '-P', | |
type='string', default=DEFAULT['zabbix_server_port'], | |
dest='zabbix_server_port', | |
help='Zabbix server API port number.' | |
) | |
parser.add_option( | |
'--zabbix-api-username', '-u', | |
type='string', default=DEFAULT['zabbix_api_username'], | |
dest='zabbix_api_username', | |
help='Zabbix API username.' | |
) | |
parser.add_option( | |
'--zabbix-api-password', '-p', | |
type='string', default=DEFAULT['zabbix_api_password'], | |
dest='zabbix_api_password', | |
help='Zabbix API password.' | |
), | |
parser.add_option( | |
'--zabbix-api-userid', '-i', | |
type='string', default=DEFAULT['zabbix_api_userid'], | |
dest='zabbix_api_userid', | |
help='Zabbix API user id.' | |
) | |
parser.add_option( | |
'--basic-username', '-U', | |
type='string', | |
dest='basic_username', | |
help='Basic authentication username.' | |
) | |
parser.add_option( | |
'--basic-password', '-B', | |
type='string', | |
dest='basic_password', | |
help='Basic authentication password.' | |
) | |
parser.add_option( | |
'--log-level', '-l', | |
type='choice', default=DEFAULT['log_level'], | |
dest='log_level', | |
choices=[ | |
'DEBUG', | |
'INFO', | |
'WARNING', | |
'ERROR', | |
'CRITICAL' | |
], | |
help=( | |
'Script log level. You can choose one in ' | |
'"DEBUG", "INFO", "WARNING", "ERROR" or "CRITICAL".' | |
) | |
) | |
parser.add_option( | |
'--name', '-n', | |
type='string', default=DEFAULT['name'], | |
help='Screen name.' | |
) | |
parser.add_option( | |
'--x-elements', '-x', | |
type='string', default=DEFAULT['x_elements'], | |
help='X-axis elements. Please input comma separated strings.' | |
) | |
parser.add_option( | |
'--y-elements', '-y', | |
type='string', default=DEFAULT['y_elements'], | |
help='Y-axis elements. Please input comma separated strings.' | |
) | |
parser.add_option( | |
'--element-width', '-w', | |
type='int', default=DEFAULT['element_width'], | |
dest='element_width', | |
help='One screen element(screenitem) width.' | |
) | |
parser.add_option( | |
'--screen-list-file', '-F', | |
type='string', dest='graph_list_file', | |
help=( | |
'Screen list file. ' | |
'If you set this parameter, ' | |
'script ignores "--x-elements" and "--y-elements" options.' | |
) | |
) | |
parser.add_option( | |
'--force', '-f', | |
action='store_true', dest='force', default=DEFAULT['force'], | |
help=( | |
'If you set this option, ' | |
'this script compulsory overwrites exists screen.' | |
) | |
) | |
parser.add_option( | |
'--inverse', '-I', | |
action='store_true', dest='inverse', default=DEFAULT['inverse'], | |
help=( | |
'If you set this option, ' | |
'script assume y-axis elements is hostname.' | |
) | |
) | |
parser.add_option( | |
'--leave-old-screen', '-L', | |
action='store_true', dest='leave_old_screen', | |
default=DEFAULT['leave_old_screen'], | |
help=( | |
'If you set this option, script leave old screen. ' | |
'Old screen prefix is "old_"' | |
) | |
) | |
options = parser.parse_args()[0] | |
return options | |
def set_log_level(log_level='DEBUG'): | |
logging.basicConfig( | |
format='[%(levelname)s] %(message)s', | |
level=getattr(logging, log_level) | |
) | |
class ZabbixCreateScreenScriptException(BaseException): | |
def __init__(self, message): | |
super(ZabbixCreateScreenScriptException, self).__init__(message) | |
class ZabbixAPI(object): | |
headers = {'Content-type': 'application/json'} | |
def __init__(self, | |
zabbix_server_schema=DEFAULT['zabbix_server_schema'], | |
zabbix_server_host=DEFAULT['zabbix_server_host'], | |
zabbix_server_port=DEFAULT['zabbix_server_port'], | |
zabbix_api_username=DEFAULT['zabbix_api_username'], | |
zabbix_api_password=DEFAULT['zabbix_api_password'], | |
zabbix_api_userid=DEFAULT['zabbix_api_userid'] | |
): | |
self.api_userid = zabbix_api_userid | |
self.url = ( | |
'{schema}://{host}:{port}/zabbix/api_jsonrpc.php' | |
''.format( | |
schema=zabbix_server_schema, | |
host=zabbix_server_host, | |
port=zabbix_server_port | |
) | |
) | |
self.token = None | |
response = self.api_call( | |
method='user.login', | |
params={ | |
'user': zabbix_api_username, | |
'password': zabbix_api_password | |
} | |
) | |
if 'result' in response: | |
self.token = response['result'] | |
else: | |
raise ZabbixCreateScreenScriptException( | |
'{0}'.format(response['error']['data']) | |
) | |
def api_call(self, method, params): | |
data = { | |
'auth': self.token, | |
'method': method, | |
'id': self.api_userid, | |
'params': params, | |
'jsonrpc': 2.0 | |
} | |
request = urllib2.Request( | |
url=self.url, | |
data=json.dumps(data), | |
headers=self.headers | |
) | |
response = json.loads(urllib2.urlopen(request).next()) | |
return response | |
class Graph(object): | |
def __init__(self, | |
zabbix_api, | |
hostname, | |
graph_name, | |
x_coordinate, | |
y_coordinate, | |
width): | |
self.zabbix_api = zabbix_api | |
self.hostname = hostname | |
self.graph_name = graph_name | |
self.host_id = self._get_hostid() | |
self.graph_id = self._get_graphid() | |
self.x_coordinate = x_coordinate | |
self.y_coordinate = y_coordinate | |
self.width = width | |
def _get_hostid(self): | |
response = self.zabbix_api.api_call( | |
method='host.get', | |
params={ | |
'output': 'hostid', | |
'search': { | |
'name': self.hostname | |
} | |
} | |
) | |
if len(response['result']) > 0: | |
hostid = response['result'][0]['hostid'] | |
else: | |
raise ZabbixCreateScreenScriptException( | |
'Maybe {0} does not exist!! '.format(self.hostname) | |
) | |
return hostid | |
def _get_graphid(self): | |
response = self.zabbix_api.api_call( | |
method='graph.get', | |
params={ | |
'output': ['graphid', 'name'], | |
'hostids': self.host_id, | |
'search': { | |
'name': self.graph_name | |
} | |
} | |
) | |
graphid = None | |
for entry in response['result']: | |
graph_name = entry.get('name') | |
if self.graph_name == graph_name: | |
graphid = entry.get('graphid') | |
if graphid is None: | |
raise ZabbixCreateScreenScriptException( | |
'Maybe {0} graph does not exist!!'.format(self.graph_name) | |
) | |
return graphid | |
class ScreenCreator(object): | |
def __init__(self, zabbix_api, screen_name, x_axis_length, y_axis_length): | |
self.zabbix_api = zabbix_api | |
self.screen_name = screen_name | |
self.x_axis_length = x_axis_length | |
self.y_axis_length = y_axis_length | |
self.graph_list = None | |
def set_graph_list(self, raw_graph_list): | |
""" | |
Generate graph list method. | |
About "raw_graph_list" format detail, | |
see the "create_raw_graph_list" function. | |
""" | |
result = list() | |
progress = { | |
'x-axis': 0, | |
'y-axis': 0 | |
} | |
for vertical_line in raw_graph_list: | |
progress['x-axis'] = 0 | |
for element in vertical_line: | |
logging.debug( | |
'Now "{0}: {1}" of position x:{2}, y:{3} in progress...' | |
''.format( | |
element['hostname'], | |
element['graph_name'], | |
progress['x-axis'], | |
progress['y-axis'], | |
) | |
) | |
result.append( | |
Graph( | |
zabbix_api=self.zabbix_api, | |
hostname=element['hostname'], | |
graph_name=element['graph_name'], | |
width=element.get('width'), | |
x_coordinate=progress['x-axis'], | |
y_coordinate=progress['y-axis'] | |
) | |
) | |
progress['x-axis'] += 1 | |
progress['y-axis'] += 1 | |
self.graph_list = result | |
def generate_screenitems(self, graph_list=None): | |
if graph_list is None: | |
graph_list = self.graph_list | |
screen_items = list() | |
for entry in graph_list: | |
screen_items.append({ | |
'resourcetype': 0, | |
'resourceid': entry.graph_id, | |
'x': entry.x_coordinate, | |
'y': entry.y_coordinate, | |
'width': entry.width, | |
'colspan': 1, | |
'rowspan': 1, | |
}) | |
return screen_items | |
def create_temporary_screen(self): | |
temporary_name = hashlib.sha256(self.screen_name).hexdigest() | |
screenitems = self.generate_screenitems() | |
response = self.zabbix_api.api_call( | |
method='screen.create', | |
params={ | |
'name': temporary_name, | |
'hsize': self.x_axis_length, | |
'vsize': self.y_axis_length, | |
'screenitems': screenitems | |
} | |
) | |
if 'result' in response: | |
created_screenids = response['result'].get('screenids') | |
else: | |
if response['error']['code'] == -32602: | |
raise ZabbixCreateScreenScriptException( | |
'Are you executing this script with "--name={0}" option?' | |
''.format(self.screen_name) | |
) | |
raise ZabbixCreateScreenScriptException( | |
'{0}'.format(response['error']['data']) | |
) | |
if created_screenids is None: | |
raise ZabbixCreateScreenScriptException( | |
'Sorry, failed to create temporary screen {0}.' | |
''.format(temporary_name) | |
) | |
else: | |
logging.info( | |
'Succeed to create temporary screen {0}.' | |
''.format(temporary_name) | |
) | |
return created_screenids[0] | |
def rename_current_screen_to_old_screen(self): | |
response = self.zabbix_api.api_call( | |
method='screen.get', | |
params={ | |
'output': 'screenid', | |
'search': { | |
'name': self.screen_name | |
} | |
} | |
) | |
if len(response['result']) > 0: | |
current_screen_id = response['result'][0]['screenid'] | |
else: | |
raise ZabbixCreateScreenScriptException( | |
'Screen {0} does not exist...' | |
''.format(self.screen_name) | |
) | |
old_screen_name = 'old_' + self.screen_name | |
logging.debug( | |
'Start rename screen from {0} to {1}.' | |
''.format(self.screen_name, old_screen_name) | |
) | |
response = self.zabbix_api.api_call( | |
method='screen.update', | |
params={ | |
'screenid': current_screen_id, | |
'name': old_screen_name | |
} | |
) | |
if not 'result' in response: | |
raise ZabbixCreateScreenScriptException( | |
'{0}'.format(response['error']['data']) | |
) | |
def delete_old_screen(self): | |
old_screen_name = 'old_' + self.screen_name | |
response = self.zabbix_api.api_call( | |
method='screen.exists', | |
params={ | |
'name': old_screen_name | |
} | |
) | |
is_exists = response['result'] | |
if is_exists is True: | |
response = self.zabbix_api.api_call( | |
method='screen.get', | |
params={ | |
'output': 'screenid', | |
'search': { | |
'name': old_screen_name | |
} | |
} | |
) | |
if len(response['result']) > 0: | |
old_screenid = response['result'][0]['screenid'] | |
else: | |
raise ZabbixCreateScreenScriptException( | |
'Old screen {0} does not exist.'.format(old_screen_name) | |
) | |
response = self.zabbix_api.api_call( | |
method='screen.delete', | |
params=[old_screenid] | |
) | |
if 'result' in response: | |
logging.info( | |
'Delete old screen {0}.'.format(old_screen_name) | |
) | |
else: | |
raise ZabbixCreateScreenScriptException( | |
'{0}'.format(response['error']['data']) | |
) | |
def execute(self, force=False, leave_old_screen=False): | |
logging.debug( | |
'Start to check which does {0} exist...' | |
''.format(self.screen_name) | |
) | |
response = self.zabbix_api.api_call( | |
method='screen.exists', | |
params={ | |
'name': self.screen_name | |
} | |
) | |
is_exists = response['result'] | |
logging.debug( | |
'Finish to check which does {0} exist!' | |
''.format(self.screen_name) | |
) | |
if force is False and is_exists is True: | |
raise ZabbixCreateScreenScriptException( | |
'{screen_name} is already exists!! ' | |
'Please execute this script after deleting {screen_name}.' | |
'Or set "--force" option.' | |
''.format(screen_name=self.screen_name) | |
) | |
elif force is False and is_exists is False: | |
logging.info( | |
'{0} not found. Start creating temporary screen.' | |
''.format(self.screen_name) | |
) | |
elif force is True and is_exists is True: | |
logging.warn( | |
'{0} found. You set "--force" option. ' | |
'So, start creating temporary screen.' | |
''.format(self.screen_name) | |
) | |
temporary_screenid = self.create_temporary_screen() | |
if is_exists: | |
logging.debug( | |
'Screen {0} exists.'.format(self.screen_name) | |
) | |
try: | |
self.rename_current_screen_to_old_screen() | |
except ZabbixCreateScreenScriptException as error: | |
logging.error( | |
'An error occurred: {0} ' | |
'Script delete temporary screen.' | |
''.format(error) | |
) | |
self.zabbix_api.api_call( | |
method='screen.delete', | |
params=[temporary_screenid] | |
) | |
logging.debug( | |
'Finish to rename screen from {0} to {1}!' | |
''.format(self.screen_name, 'old_'+self.screen_name) | |
) | |
if leave_old_screen is False: | |
self.delete_old_screen() | |
response = self.zabbix_api.api_call( | |
method='screen.update', | |
params={ | |
'screenid': temporary_screenid, | |
'name': self.screen_name | |
} | |
) | |
if 'result' in response: | |
logging.debug( | |
'Rename temporary screen to {0}.' | |
''.format(self.screen_name) | |
) | |
logging.info( | |
'Created your specified screen {0}.' | |
''.format(self.screen_name) | |
) | |
else: | |
raise ZabbixCreateScreenScriptException( | |
'{0}'.format(response['error']['data']) | |
) | |
return temporary_screenid | |
def create_raw_graph_list(options): | |
""" | |
This function creates raw graph list. | |
"raw graph list" is following two dimensions list. | |
[ | |
[ | |
{ | |
"hostname": "server01", | |
"graph_name": "Disk I/O", | |
"width": 320, | |
}, | |
{ | |
"hostname": "server02", | |
"graph_name": "Disk I/O", | |
"width": 320, | |
}, | |
], | |
[ | |
{ | |
"hostname": "server01", | |
"graph_name": "CPU Usage", | |
"width": 320, | |
}, | |
{ | |
"hostname": "server02", | |
"graph_name": "CPU Usage", | |
"width": 320, | |
}, | |
], | |
... | |
] | |
So screen like following is completed. | |
|---------------------|---------------------| | |
| server01: Disk I/O | server02: Disk I/O | | |
| server01: CPI Usage | server02: CPU Usage | | |
""" | |
result = dict() | |
if options.graph_list_file is not None: | |
logging.info( | |
'Use "--graph-list-file={0}" option.' | |
''.format(options.graph_list_file) | |
) | |
with open(options.graph_list_file) as graph_list_file: | |
try: | |
raw_graph_list = json.loads(graph_list_file.read()) | |
result['raw_graph_list'] = raw_graph_list | |
except Exception as error: | |
raise ZabbixCreateScreenScriptException( | |
error.__str__() | |
) | |
try: | |
x_axis_length = 0 | |
for entry in raw_graph_list: | |
entry_length = len(entry) | |
if x_axis_length < entry_length: | |
x_axis_length = entry_length | |
y_axis_length = len(raw_graph_list) | |
logging.debug( | |
'x_axis_length is {0}. y_axis_length is {1}' | |
''.format(x_axis_length, y_axis_length) | |
) | |
except: | |
raise ZabbixCreateScreenScriptException( | |
'Seems to be {0} is not two dimensions array.' | |
''.format(options.graph_list_file) | |
) | |
else: | |
if len(options.x_elements) > 0: | |
x_axis_length = len(options.x_elements.split(',')) | |
else: | |
raise ZabbixCreateScreenScriptException( | |
'Please set "--graph-list-file" or "--x-elements" option.' | |
) | |
if len(options.y_elements) > 0: | |
y_axis_length = len(options.y_elements.split(',')) | |
else: | |
raise ZabbixCreateScreenScriptException( | |
'Please set "--graph-list-file" or "--y-elements" option.' | |
) | |
logging.info( | |
'Use "--x-elements={0}" and "--y-elements={1}" options.' | |
''.format(options.x_elements, options.y_elements) | |
) | |
logging.debug( | |
'x_axis_length is {0}. y_axis_length is {1}' | |
''.format(x_axis_length, y_axis_length) | |
) | |
raw_graph_list = list() | |
x_elements = [x.lstrip() for x in options.x_elements.split(',')] | |
logging.debug( | |
'x_elements is {0}.'.format(x_elements) | |
) | |
y_elements = [y.lstrip() for y in options.y_elements.split(',')] | |
logging.debug( | |
'y_elements is {0}.'.format(y_elements) | |
) | |
for y in y_elements: | |
vertical_line = list() | |
for x in x_elements: | |
if not options.inverse: | |
element = { | |
'hostname': x, | |
'graph_name': y, | |
'width': options.element_width | |
} | |
else: | |
element = { | |
'graph_name': x, | |
'hostname': y, | |
'width': options.element_width | |
} | |
vertical_line.append(element) | |
raw_graph_list.append(vertical_line) | |
result['raw_graph_list'] = raw_graph_list | |
logging.debug( | |
'raw_graph_list is {0}.' | |
''.format(raw_graph_list) | |
) | |
result['x_axis_length'] = x_axis_length | |
result['y_axis_length'] = y_axis_length | |
return result | |
def main(): | |
options = get_args() | |
if ( | |
options.basic_username is not None | |
and | |
options.basic_password is not None | |
): | |
password_mng = urllib2.HTTPPasswordMgrWithDefaultRealm() | |
password_mng.add_password( | |
None, | |
( | |
'{schema}://{host}:{port}' | |
''.format( | |
schema=options.zabbix_server_schema, | |
host=options.zabbix_server_host, | |
port=options.zabbix_server_port | |
) | |
), | |
options.basic_username, | |
options.basic_password | |
) | |
handler = urllib2.HTTPBasicAuthHandler(password_mng) | |
opener = urllib2.build_opener(handler) | |
urllib2.install_opener(opener) | |
set_log_level(options.log_level) | |
zabbix_api = ZabbixAPI( | |
zabbix_server_schema=options.zabbix_server_schema, | |
zabbix_server_host=options.zabbix_server_host, | |
zabbix_server_port=options.zabbix_server_port, | |
zabbix_api_username=options.zabbix_api_username, | |
zabbix_api_password=options.zabbix_api_password, | |
zabbix_api_userid=options.zabbix_api_userid | |
) | |
raw_graph_list = create_raw_graph_list(options) | |
screen_creator = ScreenCreator( | |
zabbix_api=zabbix_api, | |
screen_name=options.name, | |
x_axis_length=raw_graph_list['x_axis_length'], | |
y_axis_length=raw_graph_list['y_axis_length'] | |
) | |
screen_creator.set_graph_list(raw_graph_list['raw_graph_list']) | |
new_screenid = screen_creator.execute( | |
force=options.force, | |
leave_old_screen=options.leave_old_screen | |
) | |
logging.warn( | |
'Succeed to create new screen {new_screen_name}!!' | |
'New screen url is ' | |
'{schema}://{host}:{port}/zabbix/screens.php?elementid={screenid}' | |
''.format( | |
new_screen_name=options.name, | |
schema=options.zabbix_server_schema, | |
host=options.zabbix_server_host, | |
port=options.zabbix_server_port, | |
screenid=new_screenid | |
) | |
) | |
if __name__ == '__main__': | |
try: | |
main() | |
except ZabbixCreateScreenScriptException as error: | |
logging.error('{0}'.format(error)) | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment