├── README.md ├── setup.py ├── zabbixcli ├── zabbixcli-worker └── zabbixlib ├── __init__.py ├── app.py ├── autoreg.py ├── cli.py ├── defaults.py ├── discovery.py ├── graph.py ├── group.py ├── item.py ├── macro.py ├── object.py ├── template.py ├── trigger.py └── trigger_action.py /README.md: -------------------------------------------------------------------------------- 1 | # zabbixcli 2 | This tool allow manipulate on Zabbix objects, like template, over the restful API, keep congituration in YAML files and store them in git. 3 | 4 | It current supports the following: 5 | * Templates (with almost full set of objects) 6 | * Hostgroups 7 | * Autoregistration 8 | * Alerts 9 | * Macros 10 | 11 | What it's doesn't support yet, but highly desirable: 12 | * It doesn't flush zabbix configuration 13 | * No users\groups management yet 14 | * No medias yet 15 | 16 | ### Requirements 17 | The zabbixcli use [py-zabbix](https://github.com/blacked/py-zabbix) module. Which can be installed with pip. 18 | ```bash 19 | pip install py-zabbix 20 | ``` 21 | 22 | # How it works 23 | This tool takes yaml formated template files, resolve dependencies, and make appropriate API calls to zabbix server for create template hierarchy or make another actions. 24 | > **Important:** I highly recommend remove any current templates before use this tool, and manage your zabbix templates only with zabbixcli. 25 | 26 | ### Templates 27 | Feel free to use any of those templates [zabbixcli-templates](https://github.com/blacked/zabbixcli-templates), modify them or make your own. 28 | 29 | ### Usage 30 | The tool usage guide can be found by running zabbixcli with `-h` flag 31 | ```bash 32 | $ zabbixcli -h 33 | 34 | usage: zabbixcli [-h] [-t TEMPLATE] [-s SERVER] [-u USER] [-p PASS] [-o] [-d] 35 | [-D DELETE [DELETE ...]] 36 | 37 | Template based zabbix configuration tool 38 | 39 | optional arguments: 40 | -h, --help show this help message and exit 41 | -t TEMPLATE, --template TEMPLATE 42 | Template name for sync 43 | -s SERVER, --server SERVER 44 | Zabbix server URL 45 | -u USER, --user USER Zabbix user name 46 | -p PASS, --pass PASS Zabbix user password 47 | -o, --only Sync only specified templates 48 | -d, --debug Enable debug mode 49 | -D DELETE [DELETE ...], --delete DELETE [DELETE ...] 50 | Delete object from zabbix. Example: -D item "Template 51 | OS Linux" "Available memory" 52 | ``` 53 | 54 | #### Configure zabbixcli 55 | First you should configure zabbixcli to works with appropriate zabbix server and use right credentials. 56 | You can either specify these as command arguments, or use environment varible, or mix them. 57 | >**Notice:** Command line arguments have precedence over environment variables. 58 | 59 | ```bash 60 | cat >> ~/.bash_profile <<'EOM' 61 | # Cretentials for zabbixcli 62 | export ZBXCLI_USER=admin 63 | export ZBXCLI_PASS=zabbix 64 | export ZBXCLI_URL=https://localhost 65 | export ZBXCLI_TEMPLATES=~/zabbix_templates 66 | EOM 67 | ``` 68 | 69 | #### Apply default template 70 | Just run: 71 | ```bash 72 | $ zabbixcli -t "Template OS Linux" 73 | [05/29/2015 23:48:54] Template 'Template OS Linux' was fully loaded. 74 | ... 75 | [05/29/2015 23:48:55] Done. 76 | ``` 77 | or go to template directory and run: 78 | ```bash 79 | $ zabbixcli -t ./ 80 | ``` 81 | 82 | #### Delete object from zabbix 83 | You can delete single object from zabbix. 84 | To delete an item from specific template do: 85 | ``` 86 | $ zabbixcli -D item "Template OS Linux" "Available memory" 87 | ``` 88 | 89 | ### Automatic changes apply 90 | Ok, now you know something about zabbixcli, and started store your zabbix config in repo. We all love automation, so it's time to configure automatic changes apply. 91 | 92 | You can use [zabbixcli-worker](https://github.com/blacked/zabbixcli/blob/master/zabbixcli-worker) as cronjob to run every minute: 93 | 94 | ```bash 95 | $ crontab -e 96 | # Apply changes to zabbix 97 | */1 * * * * /usr/local/bin/zabbixcli-worker ~/repo/ configs/zabbix/templates/ >> /var/log/zabbixcli-worker 2>&1 98 | ``` 99 | 100 | That's it. Now as soon as you will merge your changes to master, they will applied to zabbix. 101 | 102 | >I'd preffer configure `sparce-checkout` in git to pull only folder with templates (because templates folder was part of saltstack states repo in my case). 103 | 104 | >I will not detailed describe how to configure sparce-checkout. You can google it. 105 | But basicaly you should add in `~/repo/.git/config`: 106 | ```yaml 107 | [core] 108 | sparcecheckout = true 109 | ``` 110 | and in `~/repo/.git/info/sparce-checkout` you should add relative path to dir which you only want to pull: 111 | ```yaml 112 | configs/zabbix/templates/ 113 | ``` 114 | 115 | ### Creating first template 116 | This is kind of tutorual will help you create your first template and apply 117 | it to zabbix. 118 | 119 | #### Describe a template 120 | First we need to create a directory for our template: 121 | ```bash 122 | $ mkdir "Template MyApp" 123 | $ cd ./"Template MyApp" 124 | ``` 125 | Then, we should to create init template file. 126 | > Template should be written in yaml format. 127 | 128 | When zabbixcli runs it search all `*.yaml` files in this directory, subdirectories and merge them. So you can specify all setting in one huge init.yaml file, or split it to multiple. 129 | 130 | ```yaml 131 | $ cat >> ./init.yaml <<'EOM' 132 | name: "Template MyApp" # Name of template in Zabbix 133 | groups: 134 | - "Templates" # All templates should be added to Templates group 135 | EOM 136 | ``` 137 | 138 | This will create "Template MyApp" and add it to group "Templates". 139 | 140 | #### Describe an applications and items 141 | Lets try to add an item to monitoring: 142 | ```yaml 143 | $ mkdir apps 144 | $ cat >> ./apps/myapp.yaml <<'EOM' 145 | applications: 146 | "MyApp": # Application name 147 | - name: "MyApp service running" # Item name 148 | key: "proc.num[,,,myapp]" # Item key 149 | description: | 150 | Monitor if MyApp service running or not. 151 | EOM 152 | ``` 153 | 154 | As you can see many of parameters were not specified. All of them have predefined values, if you not specify something, that values will be use. 155 | 156 | Also you can specify just needed section and pass an other. 157 | 158 | #### Describe triggers 159 | ```yaml 160 | $ cat >> triggers.yaml <<'EOM' 161 | triggers: 162 | - # Describe trigger 163 | name: "MyApp service is not running on {HOST.NAME}" 164 | warn_level: "Warning" 165 | expression: "{Template MyApp:proc.num[,,,myapp].last(#1)}=0" 166 | EOM 167 | ``` 168 | 169 | #### Apply template to zabbix 170 | Now we have next structure: 171 | 172 | ```yaml 173 | $ tree ./"Template MyApp" 174 | ./Template\ MyApp 175 | ├── init.yaml 176 | ├── apps 177 | │   └── myapp.yaml 178 | └── triggers.yaml 179 | ``` 180 | 181 | Which will be compile into (yes, you can define all of these in one file): 182 | 183 | ```yaml 184 | name: "Template MyApp" 185 | 186 | groups: 187 | - "Templates" 188 | 189 | applications: 190 | "MyApp": 191 | - name: "MyApp service running" 192 | key: "proc.num[,,,myapp]" 193 | description: | 194 | Monitor if MyApp service running or not. 195 | 196 | triggers: 197 | - 198 | name: "MyApp service is not running on {HOST.NAME}" 199 | warn_level: "Warning" 200 | expression: "{Template MyApp:proc.num[,,,myapp].last(#1)}=0" 201 | ``` 202 | 203 | All you need to do now to apply this template to zabbix is run zabbixcli: 204 | ```bash 205 | cd ./"Template MyApp" 206 | zabbixcli -t ./ 207 | ``` 208 | 209 | #### Create a Role 210 | You can aggregate multiple templates into the Role. 211 | >**Notice**: The Role official not implemented in zabbix, so this kind of template aggregation. It will shows under `Roles` hostgroup in templates (That's weird that zabbix mix hostgroups with templates! That's driving me crazy.) 212 | 213 | Basically Role is just a template with specific tags and linked templates. So lets create it to see what it is: 214 | 215 | ```yaml 216 | $ cd .. 217 | $ mkdir "Role MyApp Server" 218 | $ cat >> ./"Role MyApp Server"/init.yaml <<'EOM' 219 | name: "Role MyApp Server" 220 | templates: # Describe a list of linked templates 221 | - "Template MyApp" 222 | autoreg: # Enable Autoregistration node 223 | metadata: "my_app_role" # If this metadata is found in zabbix_agent.config 224 | add_to_group: # then add discovered host to specifig hostgroup 225 | - "MyApp Servers" 226 | groups: 227 | - "Roles" # Put this role to Roles hostgroup 228 | EOM 229 | ``` 230 | 231 | It will do next: 232 | - Create template "Role MyApp Server" 233 | - Create "MyApp Servers" hostgroup 234 | - Add "Role MyApp Server" to hostgroup "Roles" 235 | - Link "Template MyApp" to "Role MyApp Server" 236 | - Create AutoRegistration rule: 237 | - If metadata field in zabbix_agent.conf on host contain: 238 | "Role MyApp Server" then add host to "MyApp Servers" group and apply "Role MyApp Server" template on it. 239 | 240 | Lets apply it to local zabbix server: 241 | ```bash 242 | $ zabbixcli -t ./"Role MyApp Server" 243 | ``` 244 | 245 | #### Alert targeting 246 | You can target alerts from specific Role to specific user or groups. 247 | 248 | ```yaml 249 | alert: 250 | do: 251 | - 252 | to: "Email" # Media type 253 | to_group: "Zabbix administrators" # Zabbix Group 254 | ``` 255 | 256 | It will create zabbix action with trigger as an event source: 257 | ``` 258 | Name: Alert for "{role name}" Team 259 | 260 | Maintenance status not in maintenance 261 | Template = Role Gateway Server 262 | Trigger value = PROBLEM 263 | Trigger severity >= Warning 264 | 265 | Send message to user groups: Zabbix administrators via SMS 266 | ``` 267 | 268 | ### Default values 269 | zabbixcli have default values for mostly objects, so no need specify exactly every parameter in template. If it's not specified, it will use default value. 270 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup(name='zabbixcli', 4 | version = '1.0.6', 5 | description = 'Tool for manage zabbix templates as YAML files.', 6 | author = 'Alexey Dubkov', 7 | author_email = 'alexey.dubkov@gmail.com', 8 | packages = find_packages(), 9 | scripts = ['zabbixcli','zabbixcli-worker'], 10 | install_requires = ["argparse", "py-zabbix>=0.5.6"], 11 | url = 'https://github.com/blacked/zabbixcli', 12 | ) 13 | -------------------------------------------------------------------------------- /zabbixcli: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | 4 | try: 5 | from zabbixlib.cli import ZabbixCLI 6 | except: 7 | raise Exception("ZabbixCLI tool require zabbixlib module be installed.") 8 | 9 | # TODO: Flush database 10 | # TODO: User management 11 | # TODO: Check existence and remove unnecesery components (items, triggers etc.) 12 | 13 | if __name__ == '__main__': 14 | ZabbixCLI() 15 | -------------------------------------------------------------------------------- /zabbixcli-worker: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # This script check if zabbix templates were changed and run zabbixcli to sync with zabbix 3 | 4 | # absolute path to repo, eg. /opt/devops/ 5 | REPO_DIR=$1 6 | 7 | # relative path to zabbix templates, eg. configs/zabbix/templates 8 | TEMPLATES_DIR=$2 9 | 10 | # Path to save latest commit sha 11 | TMP_SHA=/tmp/template-repo-last-sha 12 | 13 | pushd $REPO_DIR 14 | 15 | git pull origin master 16 | 17 | if [[ -f $TMP_SHA ]]; 18 | then 19 | PREV_SHA=`cat $TMP_SHA` 20 | GIT_CHECK=`git log $PREV_SHA..HEAD --pretty=format:"" --name-only $TEMPLATES_DIR | sort -r | uniq` 21 | fi 22 | 23 | # Save latest SHA to temp file 24 | git log --pretty=format:"%H" -1 > $TMP_SHA 25 | 26 | echo $(date) 27 | 28 | pushd $TEMPLATES_DIR 29 | 30 | if [[ "$GIT_CHECK" != "" ]]; 31 | then 32 | IFS=$(echo -en "\n\b") 33 | for i in $GIT_CHECK; 34 | do 35 | DIR_NAME=`dirname "$i"` 36 | if [[ "$i" == $TEMPLATES_DIR* ]] 37 | then 38 | TEMPLATE=${DIR_NAME##*/} 39 | echo $TEMPLATE 40 | /usr/bin/python /usr/bin/zabbixcli -t=./${TEMPLATE} --only 41 | fi 42 | done 43 | fi 44 | 45 | popd 46 | -------------------------------------------------------------------------------- /zabbixlib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adubkov/zabbixcli/3f8dd2785ece39f9bbce9eb559724dc29f6bb0da/zabbixlib/__init__.py -------------------------------------------------------------------------------- /zabbixlib/app.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from object import ZabbixObject 3 | 4 | # Connect to logger object 5 | log = logging.getLogger(__name__) 6 | 7 | 8 | class ZabbixApp(ZabbixObject): 9 | 10 | """ 11 | Implements working with zabbix application objects. 12 | 13 | Arguments: 14 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 15 | obj (dict) Dictionary discribed zabbix application template. 16 | """ 17 | 18 | def __init__(self, zapi, obj, template_id): 19 | self.zapi = zapi 20 | self.obj = obj 21 | self.template_id = template_id 22 | self.obj_type = 'application' 23 | ZabbixObject(self.zapi, self.obj) 24 | 25 | def apply(self): 26 | """ 27 | Push application object to zabbix server. 28 | """ 29 | result = None 30 | 31 | log.info("%s: '%s'", str(self.obj_type).capitalize(), self.obj) 32 | 33 | # Get 'application' object id 34 | obj_id = self.zapi.get_id( 35 | 'application', 36 | self.obj, 37 | hostid=self.template_id) 38 | 39 | if obj_id: 40 | result = obj_id 41 | else: 42 | app = { 43 | 'name': self.obj, 44 | 'hostid': self.template_id 45 | } 46 | 47 | log.debug('call: sync_app({name}, {hostid})'.format(**app)) 48 | result = self.zapi.application.create(app) 49 | result = result['applicationids'][0] 50 | return result 51 | -------------------------------------------------------------------------------- /zabbixlib/autoreg.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from group import ZabbixGroups 3 | from object import ZabbixObject 4 | 5 | # Connect to logger object 6 | log = logging.getLogger(__name__) 7 | 8 | 9 | class ZabbixAutoreg(ZabbixObject): 10 | 11 | """ 12 | Implements working with zabbix autoregister action objects. 13 | 14 | Arguments: 15 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 16 | obj (dict) Dictionary discribed zabbix application template. 17 | """ 18 | 19 | def __init__(self, zapi, obj): 20 | self.zapi = zapi 21 | self.obj = obj 22 | self.obj_type = 'action' 23 | ZabbixObject(self.zapi, self.obj) 24 | 25 | def _create_request(self): 26 | """ 27 | Create request for changes. 28 | 29 | Return (str) Request for changes. 30 | """ 31 | 32 | result = {} 33 | result['name'] = 'Auto registration {role}'.format( 34 | role=self.obj['name']) 35 | 36 | # if contains metadata tag then use it 37 | if isinstance( 38 | self.obj['autoreg'], 39 | dict) and self.obj['autoreg'].get('metadata'): 40 | metadata = self.obj['autoreg']['metadata'] 41 | else: 42 | metadata = self.obj['name'] 43 | 44 | result['conditions'] = [ 45 | # actionid: host metadata - 24, like - 2 46 | {'conditiontype': 24, 'operator': 2, 'value': metadata} 47 | ] 48 | 49 | result['operations'] = [ 50 | { 51 | # actionid: link template - 6 52 | 'operationtype': 6, 'esc_step_to': 1, 'esc_step_from': 1, 'esc_period': 0, 53 | 'optemplate': [self.zapi.get_id('template', self.obj['name'], with_id=True)], 54 | }, 55 | # Add host 56 | {'esc_step_from': 1, 57 | 'esc_period': 0, 58 | 'operationtype': 2, 59 | 'esc_step_to': 1}, 60 | # Disable host 61 | {'esc_step_from': 1, 62 | 'esc_period': 0, 63 | 'operationtype': 9, 64 | 'esc_step_to': 1}, 65 | ] 66 | 67 | # if contains add_to_group 68 | if isinstance( 69 | self.obj['autoreg'], 70 | dict) and self.obj['autoreg'].get('add_to_group'): 71 | result['operations'].append( 72 | { 73 | # actionid: add to hostgroup - 4 74 | 'operationtype': 4, 'esc_step_to': 1, 'esc_step_from': 1, 'esc_period': 0, 75 | 'opgroup': ZabbixGroups( 76 | self.zapi, 77 | self.obj.get('autoreg')['add_to_group']).apply() 78 | }, 79 | ) 80 | return result 81 | 82 | def apply(self): 83 | """ 84 | Push action object to zabbix server. 85 | """ 86 | 87 | result = None 88 | req = self._create_request() 89 | 90 | log.info("Auto-registration: '%s'", req['name']) 91 | 92 | # Get 'action' object id 93 | log.debug('ZabbixAutoreg._create_request: %s', req) 94 | obj_id = self.zapi.get_id('action', req['name']) 95 | 96 | if obj_id: 97 | result = self.zapi.action.update( 98 | actionid=obj_id, 99 | eventsource=2, 100 | status=0, 101 | esc_period=0, 102 | evaltype=0, 103 | conditions=req['conditions'], 104 | operations=req['operations']) 105 | else: 106 | result = self.zapi.action.create( 107 | name=req['name'], 108 | eventsource=2, 109 | status=0, 110 | esc_period=0, 111 | evaltype=0, 112 | conditions=req['conditions'], 113 | operations=req['operations']) 114 | return result 115 | -------------------------------------------------------------------------------- /zabbixlib/cli.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import json 3 | import logging 4 | import sys 5 | import os 6 | 7 | try: 8 | import argparse 9 | except: 10 | raise Exception( 11 | "You need python version 2.7+ or installed argparse module") 12 | 13 | from app import ZabbixApp 14 | from autoreg import ZabbixAutoreg 15 | from defaults import ZabbixDefaults 16 | from discovery import ZabbixDiscovery 17 | from group import ZabbixGroup 18 | from graph import ZabbixGraph, ZabbixGraphPrototype 19 | from item import ZabbixItem, ZabbixItemPrototype 20 | from macro import ZabbixMacro 21 | from object import ZabbixObject 22 | from template import ZabbixTemplate, ZabbixTemplateFile 23 | from trigger import ZabbixTrigger, ZabbixTriggerPrototype 24 | from trigger_action import ZabbixTriggerAction 25 | from zabbix.api import ZabbixAPI 26 | 27 | # Connect to logger object 28 | log = logging.getLogger(__name__) 29 | 30 | 31 | class ZabbixCLIArguments(object): 32 | 33 | """ 34 | Manage zabbixcli arguments 35 | """ 36 | 37 | def __init__(self): 38 | # Create arguments perser object 39 | self.argparser = argparse.ArgumentParser( 40 | description='Template based zabbix configuration tool') 41 | self.args = {} 42 | self._loadFromEnvironment() 43 | self._parse() 44 | 45 | def _loadFromEnvironment(self): 46 | """ 47 | Load arguments from enviroment variables 48 | """ 49 | 50 | # Map env variables to cli arguments 51 | args_map = { 52 | 'ZBXCLI_USER': 'user', 53 | 'ZBXCLI_PASS': 'pass', 54 | 'ZBXCLI_URL': 'server', 55 | 'ZBXCLI_TEMPLATES': 'templates_dir',} 56 | 57 | # Load env variables 58 | for ev, arg in args_map.iteritems(): 59 | if ev in os.environ: 60 | self.args[arg] = os.environ[ev] 61 | 62 | def _parse(self): 63 | """ 64 | Parse CLI arguments into self.args 65 | """ 66 | 67 | # Add arguments 68 | self.argparser.add_argument( 69 | '-t', 70 | '--template', 71 | action='store', 72 | type=str, 73 | help='Template name for sync') 74 | self.argparser.add_argument( 75 | '-s', 76 | '--server', 77 | action='store', 78 | type=str, 79 | help='Zabbix server URL') 80 | self.argparser.add_argument( 81 | '-u', 82 | '--user', 83 | action='store', 84 | type=str, 85 | help='Zabbix user name') 86 | self.argparser.add_argument( 87 | '-p', 88 | '--pass', 89 | action='store', 90 | type=str, 91 | help='Zabbix user password') 92 | self.argparser.add_argument( 93 | '-o', 94 | '--only', 95 | action='store_true', 96 | help='Sync only specified templates') 97 | self.argparser.add_argument( 98 | '-d', 99 | '--debug', 100 | action='store_true', 101 | help='Enable debug mode') 102 | self.argparser.add_argument( 103 | '-D', 104 | '--delete', 105 | action='store', 106 | type=str, 107 | nargs='+', 108 | help='Delete object from zabbix. Example: -D item "Template OS Linux" "Available memory"') 109 | 110 | # Updage arguments from CLI 111 | self.args.update( 112 | # filter out Null arguments 113 | filter( 114 | lambda x: x[1], 115 | vars( 116 | # Parse arguments 117 | self.argparser.parse_args()).items())) 118 | 119 | 120 | class ZabbixCLI(ZabbixCLIArguments): 121 | 122 | def __init__(self, template=None): 123 | ZabbixCLIArguments.__init__(self) 124 | self._configureLogging() 125 | log.debug('Parser arguments: %s', self.args) 126 | 127 | # if no arguments, jsut print help 128 | if len(sys.argv) <= 1: 129 | self.argparser.print_help() 130 | sys.exit() 131 | 132 | if not self.args.get('template'): 133 | sys.exit('Template should be specified.') 134 | 135 | self.url = self.args['server'] 136 | try: 137 | self.zapi = ZabbixAPI( 138 | self.url, 139 | user=self.args['user'], 140 | password=self.args['pass']) 141 | except: 142 | log.error('Error while trying open connection to zabbix server: %s', 143 | self.url) 144 | 145 | # If we need to delete an object and exit 146 | if self.args.get('delete'): 147 | template_id = self.zapi.get_id('template', self.args['delete'][1]) 148 | if ZabbixObject(self.zapi, 149 | {'name': self.args['delete'][2]}, 150 | template_id=template_id, 151 | obj_type=self.args['delete'][0]).delete(): 152 | log.info( 153 | '"{2}" {0} was deleted from "{1}"'.format( 154 | *self.args['delete'])) 155 | else: 156 | log.exit( 157 | 'Error while trying to delete: "{2}" {0} from "{1}"'.format( 158 | *self.args['delete'])) 159 | exit() 160 | 161 | # Set template name from __init__ params or args 162 | if template: 163 | self.template_name = template 164 | else: 165 | self.template_name = self.args.get('template') 166 | 167 | # Load template from file 168 | self.template = ZabbixTemplateFile(self.template_name, templates_dir=self.args.get('templates_dir')) 169 | self.template_id = None 170 | 171 | # When template loaded, set defaults and run apply process 172 | if self.template: 173 | self.config = ZabbixDefaults() 174 | self.apply() 175 | 176 | def _configureLogging(self): 177 | """ 178 | Configure logging output. Format and colors. 179 | """ 180 | 181 | # Set logging level 182 | if self.args.get('debug'): 183 | logLevel = logging.DEBUG 184 | else: 185 | logLevel = logging.INFO 186 | 187 | # Set colored output 188 | colors = {'reset': '\033[0m', 'green': '\x1b[32m', 'cyan': '\x1b[36m'} 189 | logFormat = '{reset}{cyan}[{green}%(asctime)s{cyan}]{reset} %(message)s'.format( 190 | **colors) 191 | logging.basicConfig( 192 | level=logLevel, 193 | format=logFormat, 194 | datefmt='%d/%m/%Y %H:%M:%S') 195 | 196 | def _apply_linked_templates(self): 197 | """ 198 | Recursive apply list of linked templates. They will applied before main 199 | template will start applying. 200 | """ 201 | 202 | if self.template.get('templates') and not self.args.get('only', False): 203 | log.info('%s depends from:', self.template.get('name')) 204 | # Show linked template list before applying 205 | for linked_template in self.template.get('templates', []): 206 | log.info("\t\t%s", linked_template) 207 | # Apply list of linked templates 208 | for linked_template in self.template.get('templates', []): 209 | ZabbixCLI(template=linked_template) 210 | 211 | def _apply_template(self, template): 212 | return ZabbixTemplate(self.zapi, template).apply() 213 | 214 | def _apply_macro(self, macro): 215 | ZabbixMacro(self.zapi, macro, self.template_id).apply() 216 | 217 | def _apply_macros(self): 218 | for macro in self.template.get('macros', []): 219 | self._apply_macro(macro) 220 | 221 | def _apply_app(self, app): 222 | return ZabbixApp(self.zapi, app, self.template_id).apply() 223 | 224 | def _apply_item(self, item): 225 | ZabbixItem(self.zapi, item, self.config, self.template_id).apply() 226 | 227 | def _apply_items(self, items, app_id): 228 | for item in items: 229 | item['app_id'] = app_id 230 | self._apply_item(item) 231 | 232 | def _apply_item_prototype(self, prototype): 233 | ZabbixItemPrototype(self.zapi, prototype, self.config, self.template_id).apply() 234 | 235 | def _apply_item_prototypes(self, discovery, app_id): 236 | items = discovery.get('items', []) 237 | rule_id = self.zapi.get_id( 238 | 'discoveryrule', 239 | discovery['name'], 240 | templateid=self.template_id) 241 | for item in items: 242 | item.update({'rule_id': rule_id, 'app_id': app_id}) 243 | self._apply_item_prototype(item) 244 | 245 | def _apply_graph(self, graph): 246 | ZabbixGraph(self.zapi, graph, self.config, self.template_id).apply() 247 | 248 | def _apply_graphs(self): 249 | for graph in self.template.get('graphs', []): 250 | self._apply_graph(graph) 251 | 252 | def _apply_graph_prototype(self, prototype): 253 | ZabbixGraphPrototype(self.zapi, prototype, self.config, self.template_id).apply() 254 | 255 | def _apply_graph_prototypes(self, discovery): 256 | graphs = discovery.get('graphs', []) 257 | for graph in graphs: 258 | self._apply_graph_prototype(graph) 259 | 260 | def _apply_trigger(self, trigger): 261 | ZabbixTrigger(self.zapi, trigger, self.config, self.template_id).apply() 262 | 263 | def _apply_triggers(self): 264 | for trigger in self.template.get('triggers', []): 265 | self._apply_trigger(trigger) 266 | 267 | def _apply_trigger_prototype(self, prototype): 268 | ZabbixTriggerPrototype(self.zapi, prototype, self.config, self.template_id).apply() 269 | 270 | def _apply_trigger_prototypes(self, discovery): 271 | triggers = discovery.get('triggers', []) 272 | for triggers in triggers: 273 | self._apply_trigger_prototype(triggers) 274 | 275 | def _apply_autoreg(self): 276 | autoreg = self.template.get('autoreg') 277 | if autoreg: 278 | ZabbixAutoreg(self.zapi, self.template).apply() 279 | 280 | def _apply_trigger_action(self): 281 | alerts = self.template.get('alerts', []) 282 | for alert in alerts: 283 | ZabbixTriggerAction(self.zapi, alert, self.config, self.template_id, self.template_name).apply() 284 | 285 | def _apply_discovery(self, discovery): 286 | ZabbixDiscovery(self.zapi, discovery, self.config, self.template_id).apply() 287 | 288 | def _apply_discoveries(self): 289 | discoveries = self.template.get('discovery', {}) 290 | 291 | for app, discovery in discoveries.iteritems(): 292 | app_id = self._apply_app(app) 293 | self._apply_discovery(discovery) 294 | self._apply_item_prototypes(discovery, app_id) 295 | self._apply_graph_prototypes(discovery) 296 | self._apply_trigger_prototypes(discovery) 297 | 298 | def _disable_item(self, id_): 299 | ZabbixItem(self.zapi).disable(id_) 300 | 301 | def _disable_app(self, app): 302 | items = self.zapi.get_id( 303 | 'item', 304 | None, 305 | hostid=self.template_id, 306 | app_name=app) 307 | for item in items: 308 | self._disable_item(item) 309 | 310 | def clean(self): 311 | """ 312 | Find and clean unused zabbix objects in current template. 313 | """ 314 | 315 | def getUnusedObjects(type_, o): 316 | """ 317 | Return list of unused zabbix objects of specific type in current template 318 | """ 319 | 320 | unused_items = [] 321 | # Get current objects from current template 322 | current_items = self.zapi.get_id(type_, templateids=self.template_id, name=True) 323 | if current_items: 324 | log.debug("Current %s: %s", type_, current_items) 325 | template_items = [] 326 | for item in o: 327 | if isinstance(item, dict): 328 | template_items.append(item.get('name')) 329 | else: 330 | template_items.append(item) 331 | log.debug("Template %s: %s", type_, template_items) 332 | # Filter out similar objects from zabbix and template 333 | unused_items = filter(lambda x: x not in template_items, current_items) 334 | log.debug("Unused %s: %s", type_, unused_items) 335 | return { type_: unused_items } 336 | 337 | def removeObjects(template_objects): 338 | """ 339 | Remove unused zabbix objects in current template. 340 | """ 341 | 342 | # Find unused objects 343 | for objects in template_objects: 344 | unused_objects = getUnusedObjects(*objects) 345 | # Process each object type 346 | for type_, objects_list in unused_objects.iteritems(): 347 | # Get zabbix id for each unused object 348 | for name in objects_list: 349 | object_id = self.zapi.get_id(type_, name) 350 | if object_id: 351 | # Make function to remove object 352 | func = 'self.zapi.{object_type}.delete'.format(object_type=type_) 353 | log.info('Unused: %s \'%s\' was removed', type_, name) 354 | eval(func)(object_id) 355 | 356 | # Init lists for objects 357 | items = apps = discovery = itemprototype = graphprototype = triggerprototype = [] 358 | 359 | for app, item in self.template.get('applications', {}).iteritems(): 360 | apps.append(app) 361 | items.extend(item) 362 | for app, disc in self.template.get('discovery', {}).iteritems(): 363 | apps.append(app) 364 | discovery.append(disc) 365 | itemprototype.extend(disc.get('items', {})) 366 | graphprototype.extend(disc.get('graphs',{})) 367 | triggerprototype.extend(disc.get('triggers', {})) 368 | 369 | # Cleanup should be executed in folowing order 370 | obj_for_cleanup = collections.OrderedDict() 371 | obj_for_cleanup['application'] = apps 372 | obj_for_cleanup['item'] = items 373 | obj_for_cleanup['usermacro'] = map(lambda x: {'name':x.get('macro')}, self.template.get('macros', [])) 374 | obj_for_cleanup['graph'] = self.template.get('graphs', []) 375 | obj_for_cleanup['trigger'] = self.template.get('triggers', []) 376 | obj_for_cleanup['discoveryrule'] = discovery 377 | obj_for_cleanup['itemprototype'] = itemprototype 378 | obj_for_cleanup['graphprototype'] = graphprototype 379 | obj_for_cleanup['triggerprototype'] = triggerprototype 380 | 381 | # Make tuple (obj_type, value) to compare with 382 | template_objects = [] 383 | for k,v in obj_for_cleanup.iteritems(): 384 | template_objects.append((k,v)) 385 | 386 | # Remove unused objects 387 | removeObjects(template_objects) 388 | 389 | def apply(self): 390 | """ 391 | Apply current template to zabbix. 392 | """ 393 | 394 | self._apply_linked_templates() 395 | self.template_id = self._apply_template(self.template) 396 | 397 | # Cleanup unused objects 398 | self.clean() 399 | 400 | apps = self.template.get('applications', {}) 401 | for app, items in apps.iteritems(): 402 | # check if disabled whole app 403 | if str(items).lower() == 'disabled': 404 | self._disable_app(app) 405 | else: 406 | app_id = self._apply_app(app) 407 | self._apply_items(items, app_id) 408 | 409 | self._apply_macros() 410 | self._apply_graphs() 411 | self._apply_triggers() 412 | self._apply_discoveries() 413 | self._apply_autoreg() 414 | self._apply_trigger_action() 415 | log.info("Done: '%s'", self.template.get('name')) 416 | -------------------------------------------------------------------------------- /zabbixlib/defaults.py: -------------------------------------------------------------------------------- 1 | import pprint 2 | 3 | 4 | class ZabbixDefaults(dict): 5 | 6 | """ 7 | Store default values for zabbix settings, and map template names to zabbix id 8 | 9 | Example: 10 | # Override defaults 11 | c = ZabbixDefauls(disabled=True, item={'interval': 100}) 12 | """ 13 | 14 | def __init__(self, **args): 15 | # Return value constant 16 | self.__dict__['return_type'] = ( 17 | 'float', 18 | 'char', 19 | 'log', 20 | 'numeric', 21 | 'text') 22 | 23 | # Checking method constants 24 | self.__dict__['method'] = ('agent', 'snmp v1', 'trapper', 25 | 'simple', 'snmp v2', 'internal', 'snmp v3', 26 | 'active', 'aggregate', '', 'external', 27 | 'database monitor', 'ipmi', 'ssh', 'telnet', 28 | 'calculated', 'jmx', 'snmp trap') 29 | 30 | self.__dict__['store_as'] = ('as is', 'speed', 'change') 31 | 32 | # Graph constants 33 | self.__dict__['graph_type'] = ('normal', 'stacked', 'pie', 'exploded') 34 | self.__dict__['graph_y_type'] = ('calculated', 'fixed', 'item') 35 | self.__dict__['graph_func'] = { 36 | 'min': 1, 37 | 'avg': 2, 38 | 'max': 4, 39 | 'all': 7, 40 | 'last': 9} 41 | self.__dict__['graph_style'] = ('line', 'filled region', 'bold line', 42 | 'dot', 'dashed line', 'gradient line') 43 | self.__dict__['y_min_max_type'] = ('calculated', 'fixed', 'item') 44 | 45 | # Trigger severety level constants 46 | self.__dict__['warn_level'] = ( 47 | 'none', 48 | 'info', 49 | 'warning', 50 | 'average', 51 | 'high', 52 | 'disaster') 53 | 54 | # Comparsion, for severety use in alerts 55 | self.__dict__['cmp'] = {'=': 0, '!=': 1, '>=': 5, '<=': 6} 56 | 57 | # Trigger status, for alerts 58 | self.__dict__['trigger_status'] = ('ok', 'problem') 59 | 60 | # Default parameters 61 | self.__dict__['default'] = { 62 | 'disabled': False, 63 | 'item': { 64 | 'return_type': 'numeric', 65 | 'method': 'agent', 66 | 'interval': 60, 67 | 'history': 7, 68 | 'trends': 365, 69 | 'store_as': 'as is', 70 | }, 71 | 'trigger': { 72 | 'warn_level': 'none', 73 | 'multiple_warn': False, 74 | }, 75 | 'graph': { 76 | 'height': 200, 77 | 'width': 900, 78 | 'type': 'normal', 79 | 'func': 'avg', 80 | 'color': '009900', 81 | 'y_side': 'left', 82 | 'style': 'line', 83 | 'gitype': 'simple', 84 | '3d_view': 0, 85 | 'show_legend': 1, 86 | 'show_working_time': 0, 87 | 'show_triggers': 0, 88 | 'y_min_type': 'calculated', 89 | 'y_max_type': 'calculated', 90 | 'percent_right': 0.0, 91 | 'percent_left': 0.0, 92 | }, 93 | 'discovery': { 94 | 'delay': 3600, 95 | 'lifetime': 30, 96 | }, 97 | 'alert': { 98 | 'recovery': True, 99 | 'trigger_status': 'problem', 100 | 'warn_level': 'warning', 101 | 'subject': '[{EVENT.ID}] {TRIGGER.STATUS}: {TRIGGER.NAME} on {HOST.NAME1}', 102 | 'text': ("{TRIGGER.SEVERITY}:\n" 103 | "{TRIGGER.DESCRIPTION}\n" 104 | "{HOST.NAME1}:[{ITEM.NAME1}]: {ITEM.VALUE1}"), 105 | 'recovery_subject': '[{EVENT.ID}] {TRIGGER.STATUS}: {TRIGGER.NAME} on {HOST.NAME1}', 106 | 'recovery_text': ("{TRIGGER.SEVERITY}:\n" 107 | "{TRIGGER.DESCRIPTION}\n" 108 | "{HOST.NAME1}:[{ITEM.NAME1}]: {ITEM.VALUE1}"), 109 | 'eventsource': 0, # Trigger handle 110 | 'eval': 0, # AND/OR: 0, AND: 1, OR: 2 111 | 'escalation_time': 300, # Must be >60s 112 | 'over': 'Email', # Email: 1 113 | 'action': 'message', 114 | 'cmp': '>=', 115 | }, 116 | } 117 | 118 | # Override settings with argumentsi 119 | for k, v in args.iteritems(): 120 | if isinstance(v, dict): 121 | self.__dict__['default'][k].update(v) 122 | else: 123 | self.__dict__['default'][k] = v 124 | 125 | def __getitem__(self, item): 126 | return self.__dict__.get(item) 127 | 128 | def get(self, item): 129 | return self.__getitem__(item) 130 | 131 | def __repr__(self): 132 | pf = pprint.PrettyPrinter(indent=4).pformat 133 | return pf(self.__dict__) 134 | -------------------------------------------------------------------------------- /zabbixlib/discovery.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from object import ZabbixObject 3 | 4 | log = logging.getLogger(__name__) 5 | 6 | 7 | class ZabbixDiscovery(ZabbixObject): 8 | 9 | """ 10 | Implements working with zabbix discovery objects. 11 | 12 | Arguments: 13 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 14 | obj (dict) Dictionary discribed zabbix discovery template. 15 | defaults (ZabbixDefaults) Default values. 16 | template_id (int) Zabbix Template id. 17 | """ 18 | 19 | def __init__(self, zapi, obj, defaults, template_id): 20 | self.zapi = zapi 21 | self.obj = obj 22 | self.defaults = defaults 23 | self.template_id = template_id 24 | self.obj_type = 'discoveryrule' 25 | ZabbixObject(self.zapi, self.obj, self.template_id) 26 | 27 | def _create_request(self): 28 | """ 29 | Create request for changes. 30 | 31 | Return (str) Request for changes. 32 | """ 33 | 34 | result = None 35 | result = { 36 | 'name': self.obj['name'], 37 | 'key_': self.obj['key'], 38 | 'description': self.obj.get('description'), 39 | 'delay': self.obj.get( 40 | 'interval', 41 | self.defaults['default']['discovery']['delay']), 42 | 'lifetime': self.obj.get( 43 | 'keep_days', 44 | self.defaults['default']['discovery']['lifetime']), 45 | 'type': self.defaults['method'].index( 46 | self.obj.get( 47 | 'method', 48 | 'agent').lower()), 49 | 'hostid': self.template_id, 50 | 'status': int( 51 | bool( 52 | self.obj.get( 53 | 'disabled', 54 | self.defaults['default']['disabled']))), 55 | 'filter': "{0}:{1}".format( 56 | self.obj.get( 57 | 'filter', 58 | {}).get('macro'), 59 | self.obj.get( 60 | 'filter', 61 | {}).get('regexp')), 62 | } 63 | return result 64 | -------------------------------------------------------------------------------- /zabbixlib/graph.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from object import ZabbixObject 3 | 4 | log = logging.getLogger(__name__) 5 | 6 | 7 | class ZabbixGraph(ZabbixObject): 8 | 9 | """ 10 | Implements working with zabbix graph objects. 11 | 12 | Arguments: 13 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 14 | obj (dict) Dictionary discribed zabbix graph template. 15 | defaults (ZabbixDefaults) Default values. 16 | template_id (int) Zabbix Template id. 17 | """ 18 | 19 | def __init__(self, zapi, obj, defaults, template_id): 20 | self.zapi = zapi 21 | self.obj = obj 22 | self.defaults = defaults 23 | self.template_id = template_id 24 | self.obj_type = 'graph' 25 | self.zbx_item_class = 'item' 26 | ZabbixObject(self.zapi, self.obj, self.template_id) 27 | 28 | def _get_y_value(self, type_, value): 29 | result = None 30 | if type_ == self.defaults['y_min_max_type'].index('fixed'): 31 | result = float(value) 32 | elif type_ == self.defaults['y_min_max_type'].index('item'): 33 | result = self.zapi.get_id( 34 | self.zbx_item_class, 35 | value, 36 | hostid=self.template_id) 37 | logging.debug( 38 | '_get_y_valye({0},{1}): {2}'.format( 39 | type_, 40 | value, 41 | result)) 42 | return result 43 | 44 | def _create_graph_items_req(self, req): 45 | """ 46 | Create request for graph items changes. 47 | 48 | Return (str) Request for changes. 49 | """ 50 | 51 | gitems = self.obj.get('items', []) 52 | req['gitems'] = [] 53 | 54 | for gitem in gitems: 55 | item_id = self.zapi.get_id( 56 | self.zbx_item_class, 57 | gitem['item'], 58 | hostid=self.template_id) 59 | 60 | item = { 61 | 'itemid': item_id, 62 | 'color': gitem.get( 63 | 'color', 64 | self.defaults['default']['graph']['color']), 65 | 'sorted': gitems.index(gitem), 66 | 'calc_fnc': self.defaults['graph_func'].get( 67 | gitem.get( 68 | 'func', 69 | self.defaults['default']['graph']['func']).lower()), 70 | 'yaxisside': { 71 | 'left': 0, 72 | 'right': 1}.get( 73 | gitem.get( 74 | 'y_side', 75 | self.defaults['default']['graph']['y_side']).lower()), 76 | } 77 | 78 | type_ = self.obj.get( 79 | 'type', 80 | self.defaults['default']['graph']['type']).lower() 81 | 82 | item.update( 83 | { 84 | 'normal': { 85 | 'drawtype': self.defaults['graph_style'].index( 86 | gitem.get( 87 | 'style', self.defaults['default']['graph']['style']).lower())}, 'pie': { 88 | 'type': { 89 | 'simple': 0, 'graph sum': 2}.get( 90 | gitem.get( 91 | 'type', self.defaults['default']['graph']['gitype']).lower())}}.get( 92 | type_, {})) 93 | 94 | req['gitems'].append(item) 95 | 96 | def _create_request(self): 97 | """ 98 | Create request for changes. 99 | 100 | Return (str) Request for changes. 101 | """ 102 | 103 | result = { 104 | 'name': self.obj['name'], 105 | 'width': int( 106 | self.obj.get( 107 | 'width', 108 | self.defaults['default']['graph']['width'])), 109 | 'height': int( 110 | self.obj.get( 111 | 'height', 112 | self.defaults['default']['graph']['height'])), 113 | 'graphtype': self.defaults['graph_type'].index( 114 | self.obj.get( 115 | 'type', 116 | self.defaults['default']['graph']['type']).lower()), 117 | } 118 | 119 | type_ = self.obj.get( 120 | 'type', 121 | self.defaults['default']['graph']['type']).lower() 122 | 123 | { 124 | 'normal': self._normal_graph_req, 125 | 'stacked': self._stacked_graph_req, 126 | 'pie': self._pie_graph_req, 127 | 'exploded': self._exploded_graph_req, 128 | }[type_](result) 129 | 130 | return result 131 | 132 | def _stacked_graph_req(self, req): 133 | """ 134 | Create request for Stacked graph changes. 135 | 136 | Return (str) Request for changes. 137 | """ 138 | 139 | self._create_graph_items_req(req) 140 | 141 | req.update( 142 | { 143 | 'show_legend': int( 144 | bool( 145 | self.obj.get( 146 | 'show_legend', 147 | self.defaults['default']['graph']['show_legend']))), 148 | 'show_work_period': int( 149 | bool( 150 | self.obj.get( 151 | 'show_working_time', 152 | self.defaults['default']['graph']['show_working_time']))), 153 | 'show_triggers': int( 154 | bool( 155 | self.obj.get( 156 | 'show_triggers', 157 | self.defaults['default']['graph']['show_triggers']))), 158 | 'ymin_type': self.defaults['graph_y_type'].index( 159 | self.obj.get( 160 | 'y_min_type', 161 | self.defaults['default']['graph']['y_min_type']).lower()), 162 | 'ymax_type': self.defaults['graph_y_type'].index( 163 | self.obj.get( 164 | 'y_max_type', 165 | self.defaults['default']['graph']['y_max_type']).lower()), 166 | }) 167 | 168 | if req['ymin_type'] == self.defaults['y_min_max_type'].index('fixed'): 169 | req.update( 170 | {'yaxismin': self._get_y_value(req['ymin_type'], self.obj.get('y_min')), }) 171 | elif req['ymin_type'] == self.defaults['y_min_max_type'].index('item'): 172 | req.update( 173 | {'ymin_itemid': self._get_y_value(req['ymin_type'], self.obj.get('y_min')), }) 174 | 175 | if req['ymax_type'] == self.defaults['y_min_max_type'].index('fixed'): 176 | req.update( 177 | {'yaxismax': self._get_y_value(req['ymax_type'], self.obj.get('y_max')), }) 178 | elif req['ymax_type'] == self.defaults['y_min_max_type'].index('item'): 179 | req.update( 180 | {'ymax_itemid': self._get_y_value(req['ymax_type'], self.obj.get('y_max')), }) 181 | 182 | log.debug('Stacked graph:') 183 | 184 | def _normal_graph_req(self, req): 185 | """ 186 | Create request for Normal graph changes. 187 | 188 | Return (str) Request for changes. 189 | """ 190 | 191 | self._stacked_graph_req(req) 192 | 193 | req.update({'percent_right': self.obj.get('percent_right', 194 | self.defaults['default']['graph']['percent_right']), 195 | 'percent_left': self.obj.get('percent_left', 196 | self.defaults['default']['graph']['percent_left']), 197 | }) 198 | log.debug('Normal graph:') 199 | 200 | def _pie_graph_req(self, req): 201 | """ 202 | Create request for Pie graph changes. 203 | 204 | Return (str) Request for changes. 205 | """ 206 | 207 | self._create_graph_items_req(req) 208 | 209 | req.update( 210 | { 211 | 'show_legend': int( 212 | bool( 213 | self.obj.get( 214 | 'show_legend', 215 | self.defaults['default']['graph']['show_legend']))), 216 | 'show_3d': int( 217 | bool( 218 | self.obj.get( 219 | '3d_view', 220 | self.defaults['default']['graph']['show_legend'])))}) 221 | log.debug('Pie graph:') 222 | 223 | def _exploded_graph_req(self, req): 224 | """ 225 | Create request for Exploded graph changes. 226 | 227 | Return (str) Request for changes. 228 | """ 229 | 230 | self._pie_graph_req(req) 231 | log.debug('Exploded graph:') 232 | 233 | def apply(self): 234 | """ 235 | Push graph object to zabbix server. 236 | """ 237 | 238 | result = None 239 | req = self._create_request() 240 | 241 | log.info("%s: '%s'", str(self.obj_type).capitalize(), self.obj['name']) 242 | 243 | # Get 'graph' or 'graphprototype' object id 244 | obj_id = self.zapi.get_id( 245 | self.obj_type, 246 | self.obj['name'], 247 | hostid=self.template_id) 248 | 249 | if obj_id: 250 | req.update({'graphid': obj_id}) 251 | zbx_method = 'update' 252 | else: 253 | zbx_method = 'create' 254 | 255 | func = "self.zapi.{obj_type}.{zbx_method}".format( 256 | obj_type=self.obj_type, 257 | zbx_method=zbx_method) 258 | log.debug('%s: %s', func, req) 259 | result = eval(func)(req) 260 | 261 | return result 262 | 263 | 264 | class ZabbixGraphPrototype(ZabbixGraph): 265 | 266 | """ 267 | Implements working with zabbix graph prototype objects. 268 | 269 | Arguments: 270 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 271 | obj (dict) Dictionary discribed zabbix graph prototype template. 272 | defaults (ZabbixDefaults) Default values. 273 | template_id (int) Zabbix Template id. 274 | """ 275 | 276 | def __init__(self, zapi, obj, defaults, template_id): 277 | self.zapi = zapi 278 | self.obj = obj 279 | self.defaults = defaults 280 | self.template_id = template_id 281 | ZabbixGraph(self.zapi, self.obj, self.defaults, self.template_id) 282 | 283 | def _create_request(self): 284 | """ 285 | Create request for graph prototype changes. 286 | 287 | Return (str) Request for changes. 288 | """ 289 | 290 | self.obj_type = 'graphprototype' 291 | self.zbx_item_class = 'itemprototype' 292 | return super(ZabbixGraphPrototype, self)._create_request() 293 | -------------------------------------------------------------------------------- /zabbixlib/group.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | log = logging.getLogger(__name__) 4 | 5 | 6 | class ZabbixGroup(object): 7 | 8 | """ 9 | Implements working with zabbix hostgroup\group objects. 10 | 11 | Arguments: 12 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 13 | group (str) Group name. 14 | with_id (bool) Return values in zabbix format. 15 | """ 16 | 17 | def __init__(self, zapi, group, with_id=False): 18 | self.zapi = zapi 19 | self.group = group 20 | self.with_id = with_id 21 | self.obj_type = 'hostgroup' 22 | 23 | def apply(self): 24 | """ 25 | Push hostgroup\group object to zabbix server. 26 | """ 27 | 28 | result = None 29 | 30 | log.info("%s: '%s'", str(self.obj_type).capitalize(), self.group) 31 | 32 | result = self.zapi.get_id('hostgroup', self.group) 33 | if not result: 34 | result = int( 35 | self.zapi.hostgroup.create( 36 | name=self.group)['groupids'][0]) 37 | if self.with_id: 38 | result = {'groupid': result} 39 | return result 40 | 41 | 42 | class ZabbixGroups(object): 43 | 44 | """ 45 | Implements working with zabbix hostgroups\groups objects. 46 | 47 | Arguments: 48 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 49 | groups (list of str) List of group names. 50 | """ 51 | 52 | def __init__(self, zapi, groups): 53 | self.zapi = zapi 54 | self.groups = groups 55 | 56 | def apply(self): 57 | """ 58 | Push hostgroups\groups object to zabbix server. 59 | """ 60 | 61 | result = [] 62 | for group in self.groups: 63 | groupid = ZabbixGroup(self.zapi, group, with_id=True).apply() 64 | if groupid: 65 | result.append(groupid) 66 | return result 67 | -------------------------------------------------------------------------------- /zabbixlib/item.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from object import ZabbixObject 3 | 4 | log = logging.getLogger(__name__) 5 | 6 | 7 | class ZabbixItem(ZabbixObject): 8 | 9 | """ 10 | Implements working with zabbix item objects. 11 | 12 | Arguments: 13 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 14 | obj (dict) Dictionary discribed zabbix item template. 15 | defaults (ZabbixDefaults) Default values. 16 | template_id (int) Zabbix Template id. 17 | """ 18 | 19 | def __init__(self, zapi, obj=None, defaults=None, template_id=None): 20 | self.zapi = zapi 21 | self.obj = obj 22 | self.defaults = defaults 23 | self.template_id = template_id 24 | self.obj_type = 'item' 25 | ZabbixObject(self.zapi, self.obj, self.template_id) 26 | 27 | def _create_request(self): 28 | """ 29 | Create request for item changes. 30 | 31 | Return (str) Request for changes. 32 | """ 33 | 34 | value_type = self.defaults['return_type'].index( 35 | self.obj.get( 36 | 'return_type', 37 | 'numeric').lower()) 38 | status = int( 39 | bool( 40 | self.obj.get( 41 | 'disabled', 42 | self.defaults['default']['disabled']))) 43 | delay = int( 44 | self.obj.get( 45 | 'interval', 46 | self.defaults['default']['item']['interval'])) 47 | history = int( 48 | self.obj.get( 49 | 'history', 50 | self.defaults['default']['item']['history'])) 51 | trends = int( 52 | self.obj.get( 53 | 'trends', 54 | self.defaults['default']['item']['trends'])) 55 | type_ = self.defaults['method'].index( 56 | self.obj.get( 57 | 'method', 58 | self.defaults['default']['item']['method']).lower()) 59 | delta = self.defaults['store_as'].index( 60 | self.obj.get( 61 | 'store_as', 62 | self.defaults['default']['item']['store_as']).lower()) 63 | 64 | result = { 65 | 'name': self.obj['name'], 66 | 'type': type_, 67 | 'key_': self.obj['key'], 68 | 'value_type': value_type, 69 | 'status': status, 70 | 'applications': [self.obj.get('app_id')], 71 | 'hostid': self.template_id, 72 | 'delay': delay, 73 | 'history': history, 74 | 'trends': trends, 75 | 'description': self.obj.get('description', ''), 76 | 'delta': delta, 77 | } 78 | 79 | if 'params' in self.obj: 80 | result.update({'params': self.obj['params']}) 81 | 82 | if self.obj.get( 83 | 'return_type', 84 | 'numeric').lower() != 'boolean' and self.obj.get('units'): 85 | result.update({ 86 | 'units': self.obj.get('units'), 87 | 'multiplier': int(bool(self.obj.get('multiplier', 0))), 88 | 'formula': self.obj.get('multiplier', 0), 89 | }) 90 | return result 91 | 92 | def disable(self, id_): 93 | """ 94 | Disable specifiec zabbix item. 95 | 96 | Arguments: 97 | id_ (int) Zabbix item ID. 98 | """ 99 | 100 | return self.zapi.item.update({'itemid': id_, 'status': 1}) 101 | 102 | 103 | class ZabbixItemPrototype(ZabbixItem): 104 | 105 | """ 106 | Implements working with zabbix item prototype objects. 107 | 108 | Arguments: 109 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 110 | obj (dict) Dictionary discribed zabbix item template. 111 | defaults (ZabbixDefaults) Default values. 112 | template_id (int) Zabbix Template id. 113 | """ 114 | 115 | def __init__(self, zapi, obj, defaults, template_id): 116 | self.zapi = zapi 117 | self.obj = obj 118 | self.defaults = defaults 119 | self.template_id = template_id 120 | ZabbixItem(self.zapi, self.obj, self.defaults, self.template_id) 121 | 122 | def _create_request(self): 123 | """ 124 | Create request for item prototype changes. 125 | 126 | Return (str) Request for changes. 127 | """ 128 | 129 | result = None 130 | result = super(ZabbixItemPrototype, self)._create_request() 131 | result.update({'ruleid': self.obj.get('rule_id')}) 132 | self.obj_type = 'itemprototype' 133 | return result 134 | -------------------------------------------------------------------------------- /zabbixlib/macro.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from object import ZabbixObject 3 | 4 | log = logging.getLogger(__name__) 5 | 6 | 7 | class ZabbixMacro(ZabbixObject): 8 | 9 | """ 10 | Implements working with zabbix usermacro objects. 11 | 12 | Arguments: 13 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 14 | obj (dict) Dictionary discribed zabbix usermacro template. 15 | defaults (ZabbixDefaults) Default values. 16 | template_id (int) Zabbix Template id. 17 | """ 18 | 19 | def __init__(self, zapi, obj, template_id): 20 | self.zapi = zapi 21 | self.obj = obj 22 | self.template_id = template_id 23 | self.obj_type = 'usermacro' 24 | ZabbixObject(self.zapi, self.obj, self.template_id) 25 | 26 | def _create_request(self): 27 | """ 28 | Create request for usermacro changes. 29 | 30 | Return (str) Request for changes. 31 | """ 32 | 33 | result = None 34 | result = { 35 | 'macro': self.obj['macro'], 36 | 'value': self.obj['value'], 37 | 'hostid': self.template_id, 38 | } 39 | return result 40 | 41 | def apply(self): 42 | """ 43 | Push usermacro object to zabbix server. 44 | """ 45 | result = None 46 | req = self._create_request() 47 | 48 | log.info("%s: '%s'", str(self.obj_type).capitalize(), req['macro']) 49 | 50 | # Get 'macro' object id 51 | log.debug('ZabbixMacro._create_request: %s', req) 52 | obj_id = self.zapi.get_id( 53 | 'usermacro', 54 | req['macro'], 55 | hostid=self.template_id) 56 | 57 | if obj_id: 58 | result = self.zapi.usermacro.update( 59 | hostmacroid=obj_id, 60 | value=req['value']) 61 | else: 62 | result = self.zapi.usermacro.create(req) 63 | return result 64 | -------------------------------------------------------------------------------- /zabbixlib/object.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | log = logging.getLogger(__name__) 4 | 5 | 6 | class ZabbixObject(object): 7 | 8 | """ 9 | Base class for all zabbix objects. 10 | 11 | Arguments: 12 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 13 | obj (dict) Dictionary discribed zabbix template. 14 | template_id (int) Zabbix Template id. 15 | """ 16 | 17 | def __init__(self, zapi, obj, template_id=None, obj_type=None): 18 | self.zapi = zapi 19 | self.obj = obj 20 | self.template_id = template_id 21 | self.obj_type = obj_type 22 | 23 | def _get_id_name(self): 24 | """ 25 | Return id name by object type (Zabbix use different name for id). 26 | """ 27 | 28 | result = None 29 | id_name = {'discoveryrule': 'item', 30 | 'hostgroup': 'group', 31 | 'graphptototype': 'graph', 32 | 'itemprototype': 'item', 33 | 'triggerprototype': 'trigger', 34 | }.get(self.obj_type, self.obj_type) 35 | result = '{0}id'.format(id_name) 36 | return result 37 | 38 | def _func(self, req): 39 | """ 40 | Generate zapi function name. 41 | """ 42 | 43 | result = None 44 | if self.template_id: 45 | obj_id = self.zapi.get_id( 46 | self.obj_type, 47 | self.obj['name'], 48 | hostid=self.template_id) 49 | if obj_id: 50 | req.update({self._get_id_name(): obj_id}) 51 | zbx_method = 'update' 52 | else: 53 | zbx_method = 'create' 54 | 55 | result = "self.zapi.{obj_type}.{zbx_method}".format( 56 | obj_type=self.obj_type, 57 | zbx_method=zbx_method) 58 | 59 | return result 60 | 61 | def apply(self): 62 | """ 63 | Push this object to zabbix server. 64 | """ 65 | 66 | result = None 67 | req = self._create_request() 68 | log.info( 69 | "%s: '%s'", 70 | str(self.obj_type).capitalize(), 71 | self.obj.get('name')) 72 | func = self._func(req) 73 | log.debug('%s: %s', func, req) 74 | result = eval(func)(req) 75 | 76 | return result 77 | 78 | def delete(self): 79 | """ 80 | Delete this object from zabbix. 81 | """ 82 | 83 | result = None 84 | obj_id = self.zapi.get_id(self.obj_type, self.obj['name']) 85 | if obj_id: 86 | func = 'self.zapi.{obj_type}.delete'.format(obj_type=self.obj_type) 87 | result = eval(func)(obj_id) 88 | 89 | return result 90 | -------------------------------------------------------------------------------- /zabbixlib/template.py: -------------------------------------------------------------------------------- 1 | import fnmatch 2 | import logging 3 | import os 4 | import pprint 5 | import yaml 6 | from group import ZabbixGroups 7 | 8 | log = logging.getLogger(__name__) 9 | 10 | 11 | class ZabbixTemplate(object): 12 | 13 | """ 14 | Implements working with zabbix template objects. 15 | 16 | Arguments: 17 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 18 | obj (dict) Dictionary discribed zabbix template. 19 | """ 20 | 21 | def __init__(self, zapi, obj): 22 | self.zapi = zapi 23 | self.obj = obj 24 | self.obj_type = 'template' 25 | 26 | def _create_request(self): 27 | """ 28 | Create request for template changes. 29 | 30 | Return (str) Request for changes. 31 | """ 32 | 33 | return {'groups': ZabbixGroups(self.zapi, self.obj['groups']).apply()} 34 | 35 | def apply(self): 36 | """ 37 | Push template object to zabbix server. 38 | """ 39 | 40 | result = None 41 | req = self._create_request() 42 | log.info("%s: '%s'", str(self.obj_type).capitalize(), self.obj['name']) 43 | 44 | # Get linked templates id 45 | if self.obj.get('templates'): 46 | req['templates'] = self.zapi.get_id( 47 | 'template', 48 | self.obj['templates']) 49 | 50 | # Get current template id 51 | self.template_id = self.zapi.get_id('template', self.obj['name']) 52 | 53 | if self.template_id: 54 | req['templateid'] = self.template_id 55 | result = self.zapi.template.update(req) 56 | else: 57 | req['host'] = self.obj['name'] 58 | result = self.zapi.template.create(req) 59 | 60 | result = result['templateids'][0] 61 | return result 62 | 63 | 64 | class ZabbixTemplateFile(dict): 65 | 66 | """ 67 | Load and Save locally resulting zabbix template. 68 | 69 | Attributes: 70 | name (str): Name of template for load 71 | pattern (str): Pattern to search for templates. Default: '*' 72 | basedir (str): Directory that store zabbix templates. 73 | Default: './templates' 74 | file_extension (str): Extension for template files. Default: '.yaml' 75 | """ 76 | 77 | def __init__( 78 | self, 79 | name, 80 | pattern='*', 81 | basedir='./', 82 | file_extension='.yaml', 83 | templates_dir=None): 84 | self.name = name 85 | self.file_extension = file_extension 86 | self.pattern = pattern + self.file_extension 87 | self.basedir = '{0}/{1}'.format(basedir, name) 88 | self.templates_dir = templates_dir 89 | # Load template from files 90 | self.template = {} 91 | self.processed_items = 0 92 | self.template = self._load(self.basedir) 93 | 94 | def _walk(self, basedir): 95 | """ 96 | Return list of files for current template 97 | """ 98 | 99 | result = [] 100 | 101 | for root, dirs, files in os.walk(basedir): 102 | for file_ in fnmatch.filter(files, self.pattern): 103 | result.append(os.path.join(root, file_)) 104 | 105 | return result 106 | 107 | def _search(self): 108 | """ 109 | Try to find template in template_dir 110 | """ 111 | 112 | result = None 113 | 114 | # get list of files 115 | files_list = self._walk(self.templates_dir) 116 | 117 | for file_ in files_list: 118 | with open(file_, 'r') as f: 119 | line = f.readline() 120 | if line[0:5] == 'name:': 121 | name = line[5:].strip(' \'\"\n') 122 | if name == self.name: 123 | result = os.path.dirname(file_) 124 | log.debug('Found Template: "%s" in %s', name, result) 125 | break 126 | return result 127 | 128 | def _merge(self, t1, t2): 129 | """ 130 | Merge two templates. 131 | 132 | Attributes: 133 | t1 (dict) 134 | t2 (dict) 135 | """ 136 | 137 | for k, v in t2.iteritems(): 138 | if t1.get(k, {}) == {}: 139 | t1[k] = v 140 | else: 141 | if isinstance(t2.get(k, {}), dict): 142 | t1.get(k, {}).update(v) 143 | elif isinstance(t2.get(k), list): 144 | t1.get(k).extend(v) 145 | else: 146 | t1[k] = v 147 | 148 | log.debug('Template result:\n%s', t1) 149 | 150 | def _load(self, basedir): 151 | """ 152 | Load current template from files and save it class variable. 153 | """ 154 | 155 | result = {} 156 | 157 | files_list = self._walk(basedir) 158 | log.debug("Template files list: %s", files_list) 159 | 160 | for file_ in files_list: 161 | # Read template file 162 | with open(file_) as f: 163 | str_buf = f.read() 164 | # Load template 165 | template = yaml.safe_load(str_buf) 166 | log.debug( 167 | 'Template loaded from "%s":\n%s', 168 | file_, 169 | template) 170 | # Merge template 171 | self._merge(result, template) 172 | 173 | if not result: 174 | log.debug("Trying find template in %s", self.templates_dir) 175 | template_dir = self._search() 176 | if template_dir: 177 | result = self._load(template_dir) 178 | else: 179 | # Save template in class variable 180 | log.debug('Combined template:\n%s', result) 181 | log.info("Template '%s' was fully loaded.", result['name']) 182 | 183 | return result 184 | 185 | def __getitem__(self, item, value=None): 186 | return self.template.get(item, value) 187 | 188 | def __setitem__(self, item, value): 189 | self.template[item] = value 190 | 191 | def __repr__(self): 192 | pf = pprint.PrettyPrinter(indent=4).pformat 193 | return pf(self.template) 194 | 195 | def iteritems(self): 196 | return iter(self.template.iteritems()) 197 | 198 | def get(self, item, value=None): 199 | return self.__getitem__(item, value) 200 | 201 | def __bool__(self): 202 | return bool(self.template) 203 | 204 | __nonzero__ = __bool__ 205 | -------------------------------------------------------------------------------- /zabbixlib/trigger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from object import ZabbixObject 3 | 4 | log = logging.getLogger(__name__) 5 | 6 | 7 | class ZabbixTrigger(ZabbixObject): 8 | 9 | """ 10 | Implements working with zabbix trigger objects. 11 | 12 | Arguments: 13 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 14 | obj (dict) Dictionary discribed zabbix trigger template. 15 | defaults (ZabbixDefaults) Default values. 16 | template_id (int) Zabbix Template id. 17 | """ 18 | 19 | def __init__(self, zapi, obj, defaults, template_id): 20 | self.zapi = zapi 21 | self.obj = obj 22 | self.defaults = defaults 23 | self.template_id = template_id 24 | self.obj_type = 'trigger' 25 | ZabbixObject(self.zapi, self.obj, self.template_id) 26 | 27 | def _create_request(self): 28 | """ 29 | Create request for trigger changes. 30 | 31 | Return (str) Request for changes. 32 | """ 33 | 34 | result = None 35 | result = { 36 | # In trigger objects 'description' = 'name' 37 | 'description': self.obj['name'], 38 | 'expression': self.obj['expression'], 39 | 'status': int(bool(self.obj.get('disabled', self.defaults['default']['disabled']))), 40 | 'priority': self.defaults['warn_level'].index(self.obj.get('warn_level', self.defaults['default']['trigger']['warn_level']).lower()), 41 | 'type': int(bool(self.obj.get('multiple_warn', self.defaults['default']['trigger']['multiple_warn']))), 42 | 'url': self.obj.get('url', ''), 43 | } 44 | return result 45 | 46 | 47 | class ZabbixTriggerPrototype(ZabbixTrigger): 48 | 49 | """ 50 | Implements working with zabbix trigger prototype objects. 51 | 52 | Arguments: 53 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 54 | obj (dict) Dictionary discribed zabbix trigger prototype template. 55 | defaults (ZabbixDefaults) Default values. 56 | template_id (int) Zabbix Template id. 57 | """ 58 | 59 | def __init__(self, zapi, obj, defaults, template_id): 60 | self.zapi = zapi 61 | self.obj = obj 62 | self.defaults = defaults 63 | self.template_id = template_id 64 | ZabbixTrigger(self.zapi, self.obj, self.defaults, self.template_id) 65 | 66 | def _create_request(self): 67 | """ 68 | Create request for trigger changes. 69 | 70 | Return (str) Request for changes. 71 | """ 72 | 73 | result = None 74 | result = super(ZabbixTriggerPrototype, self)._create_request() 75 | self.obj_type = 'triggerprototype' 76 | return result 77 | -------------------------------------------------------------------------------- /zabbixlib/trigger_action.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from group import ZabbixGroups 3 | from object import ZabbixObject 4 | 5 | # Connect to logger object 6 | log = logging.getLogger(__name__) 7 | 8 | 9 | class ZabbixTriggerAction(ZabbixObject): 10 | 11 | """ 12 | Implements working with zabbix trigger action objects. 13 | 14 | Arguments: 15 | zapi (ZabbixAPI) ZabbixAPI connector to send request. 16 | obj (dict) Dictionary discribed zabbix application template. 17 | """ 18 | 19 | def __init__(self, zapi, obj, defaults, template_id, template_name): 20 | self.zapi = zapi 21 | self.obj = obj 22 | self.obj_type = 'action' 23 | self.defaults = defaults 24 | self.template_id = template_id 25 | self.template_name = template_name 26 | ZabbixObject(self.zapi, self.obj) 27 | 28 | def _create_request(self): 29 | """ 30 | Create request for changes. 31 | 32 | Return (str) Request for changes. 33 | """ 34 | 35 | result = {} 36 | 37 | if self.obj: 38 | result['name'] = '{0}: {1}'.format(self.template_name, self.obj['name']) 39 | result['def_shortdata'] = self.obj.get('subject', 40 | self.defaults['default']['alert']['subject']) 41 | result['def_longdata'] = self.obj.get('text', 42 | self.defaults['default']['alert']['text']) 43 | 44 | if bool( 45 | self.obj.get( 46 | 'recovery', 47 | self.defaults['default']['alert']['recovery'])): 48 | result['recovery_msg'] = 1 49 | result['r_shortdata'] = self.obj.get('recovery_subject', 50 | self.defaults['default']['alert']['recovery_subject']) 51 | result['r_longdata'] = self.obj.get('recovery_text', 52 | self.defaults['default']['alert']['recovery_text']) 53 | 54 | result['eventsource'] = self.defaults[ 55 | 'default']['alert']['eventsource'] 56 | result['status'] = int( 57 | bool( 58 | self.obj.get( 59 | 'disabled', 60 | self.defaults['default']['disabled']))) 61 | result['esc_period'] = self.obj.get( 62 | 'escalation_time', 63 | self.defaults['default']['alert']['escalation_time']) 64 | result['evaltype'] = self.obj.get( 65 | 'eval', 66 | self.defaults['default']['alert']['eval']) 67 | 68 | alert_severity = self.defaults['warn_level'].index( 69 | self.obj.get( 70 | 'severity', 71 | self.defaults['default']['alert']['warn_level']).lower()) 72 | alert_severity_cmp = self.defaults['cmp'][ 73 | self.obj.get( 74 | 'severity_cmp', 75 | self.defaults['default']['alert']['cmp']).lower()] 76 | alert_trigger_status = self.defaults['trigger_status'].index( 77 | self.obj.get( 78 | 'trigger_status', 79 | self.defaults['default']['alert']['trigger_status']).lower()) 80 | 81 | result['conditions'] = [ 82 | # actionid: Mainenance status - 16, not in - 7 83 | {'conditiontype': 16, 'operator': 7}, 84 | # actionid: Trigger value - 5, equal - 0, PROBLEM - 1 85 | {'conditiontype': 5, 86 | 'operator': 0, 87 | 'value': alert_trigger_status}, 88 | # actionid: Trigger severity - 4, equal - 0, Warning - 2 89 | {'conditiontype': 4, 90 | 'operator': alert_severity_cmp, 91 | 'value': alert_severity}, 92 | ] 93 | 94 | if 'group' in self.obj: 95 | result['conditions'].append({ 96 | 'conditiontype': 0, 97 | 'operator': 0, 98 | 'value': self.zapi.get_id( 99 | 'hostgroup', 100 | self.obj['group']) 101 | }) 102 | elif not 'all' in self.obj: 103 | # actionid: Template - 13, like - 2 104 | result['conditions'].append({ 105 | 'conditiontype': 13, 106 | 'operator': 0, 107 | 'value': self.template_id}) 108 | 109 | result['operations'] = [] 110 | 111 | # fill operations for alert 112 | for op in self.obj.get('do', []): 113 | # check if we need to send a message to user or group 114 | if op.get( 115 | 'action', 116 | self.defaults['default']['alert']['action']) == 'message': 117 | # basic config for message 118 | do_obj = { 119 | 'operationtype': 0, 120 | 'esc_step_to': 1, 121 | 'esc_step_from': 1, 122 | 'esc_period': 0, 123 | 'evaltype': 0, 124 | } 125 | do_obj.update( 126 | { 127 | 'opmessage': { 128 | 'mediatypeid': self.zapi.get_id( 129 | 'mediatype', 130 | op.get( 131 | 'over', 132 | self.defaults['default']['alert']['over'])), 133 | 'default_msg': 1, 134 | }}) 135 | 136 | if op.get('to_user'): 137 | do_obj.update( 138 | {'opmessage_usr': [self.zapi.get_id('user', op['to_user'], with_id=True)]}) 139 | 140 | if op.get('to_group'): 141 | do_obj.update( 142 | {'opmessage_grp': [self.zapi.get_id('usergroup', op['to_group'], with_id=True)]}) 143 | 144 | result['operations'].append(do_obj) 145 | # TODO: elif = 'exec' ... run 146 | 147 | return result 148 | 149 | def apply(self): 150 | """ 151 | Push action object to zabbix server. 152 | """ 153 | 154 | result = None 155 | req = self._create_request() 156 | 157 | log.info("%s: '%s'", str(self.obj_type).capitalize(), req['name']) 158 | 159 | # Get 'action' object id 160 | log.debug( 161 | 'ZabbixTriggerAction._create_request: {req}'.format( 162 | req=req)) 163 | obj_id = self.zapi.get_id('action', req['name']) 164 | 165 | if obj_id: 166 | req['actionid'] = obj_id 167 | req.pop('name') 168 | obj_action = 'update' 169 | else: 170 | obj_action = 'create' 171 | 172 | func = 'self.zapi.{obj_type}.{obj_action}'.format( 173 | obj_type=self.obj_type, 174 | obj_action=obj_action) 175 | result = eval(func)(req) 176 | 177 | return result 178 | --------------------------------------------------------------------------------