11#!/usr/bin/env python
22# -*- coding: utf-8 -*-
3- ''' Copyright (c) 2013 Jean Baptiste Favre.
4- Sample script for Zabbix integration SSL endpoints.
5- '''
3+
64import optparse
75import yaml
86import protobix
1311import sys
1412from datetime import datetime
1513
16- class SSLEndpointCheck ( object ):
14+ CA_CERTS = "/etc/ssl/certs/ca-certificates.crt"
1715
18- __version__ = '0.0.8'
19- ZBX_CONN_ERR = 'ERR - unable to send data to Zabbix [%s]'
16+ class SSLEndpointCheck (protobix .SampleProbe ):
2017
21- CA_CERTS = "/etc/ssl/certs/ca-certificates.crt"
18+ __version__ = '0.0.9'
2219
2320 def _check_expiration (self , cert ):
2421 ''' Return the numbers of day before expiration. False if expired. '''
@@ -27,49 +24,65 @@ def _check_expiration(self, cert):
2724 expire_date = datetime .strptime (cert ['notAfter' ],
2825 "%b %d %H:%M:%S %Y %Z" )
2926 except :
30- raise Exception ( 'Certificate date format unknow.' )
27+ exit_error ( 1 , 'Certificate date format unknow.' )
3128 expire_in = expire_date - datetime .now ()
3229 if expire_in .days > 0 :
3330 return expire_in .days
3431 else :
3532 return False
3633
37- def _get_certificate (self , HOST , PORT = 443 ):
34+ def _get_certificate (self , host , port = 443 ):
3835 # Connect to the host and get the certificate
3936 sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
40- sock .connect ((HOST , PORT ))
37+ sock .connect ((host , port ))
4138 ssl_sock = ssl .wrap_socket (sock , cert_reqs = ssl .CERT_REQUIRED ,
4239 ca_certs = CA_CERTS )
4340 cert = ssl_sock .getpeercert ()
4441 sock .shutdown (socket .SHUT_RDWR )
4542 sock .close ()
4643 return cert
4744
48- def _get_discovery (self ):
49- discovery_data = { 'ssl.certificate.discovery' : []}
45+ def _parse_args (self ):
46+ # Parse the script arguments
47+ # Common part
48+ parser = super ( SSLEndpointCheck , self )._parse_args ()
49+
50+ (options , args ) = parser .parse_args ()
51+ return (options , args )
52+
53+ def _init_probe (self ):
54+ self .hostname = socket .getfqdn ()
55+
56+ ''' Load config file '''
57+ with open (self .options .config , 'r' ) as f :
58+ config = yaml .load (f )
59+ self .endpoints = config ['endpoints' ]
5060
61+ def _get_discovery (self , hostname ):
62+ data = { 'ssl.certificate.discovery' : [] }
5163 for endpoint in self .endpoints :
5264 try :
53- cert = self ._get_certificate (endpoint , 443 )
65+ cert = self ._get_certificate ( host = endpoint ,
66+ port = 443 )
5467 common_name = cert ['subjectAltName' ][0 ][1 ]
5568 element = { '{#SSLCERTSERIAL}' : common_name + endpoint ,
5669 '{#SSLCERTNAME}' : common_name ,
5770 '{#SSLCERTENDPOINT}' : endpoint }
58- discovery_data ['ssl.certificate.discovery' ].append (element )
71+ data ['ssl.certificate.discovery' ].append (element )
5972 except :
6073 pass
74+ return { hostname : data }
6175
62- return discovery_data
63-
64- def _get_metrics (self ):
76+ def _get_metrics (self , hostname ):
6577 data = {}
6678 for endpoint in self .endpoints :
6779 try :
68- cert = self .get_certificate (endpoint , 443 )
80+ cert = self ._get_certificate ( host = endpoint ,
81+ port = 443 )
6982 common_name = cert ['subjectAltName' ][0 ][1 ]
7083 zbx_key = "ssl.certificate.expires_in_days[{0},{1}]"
7184 zbx_key = zbx_key .format (common_name , endpoint )
72- data [zbx_key ] = self .check_expiration (cert )
85+ data [zbx_key ] = self ._check_expiration (cert )
7386
7487 zbx_key = "ssl.certificate.check_status[{0}]"
7588 zbx_key = zbx_key .format (endpoint )
@@ -80,107 +93,9 @@ def _get_metrics(self):
8093 data [zbx_key ] = 0
8194 pass
8295 data ['ssl.certificate.zbx_version' ] = self .__version__
83-
84- return data
85-
86- def _parse_args (self ):
87- ''' Parse the script arguments'''
88- parser = optparse .OptionParser ()
89-
90- parser .add_option ("-d" , "--dry" , action = "store_true" ,
91- help = "Performs SSL certificates checks but do not send "
92- "anything to the Zabbix server. Can be used "
93- "for both Update & Discovery mode" )
94- parser .add_option ("-D" , "--debug" , action = "store_true" ,
95- help = "Enable debug mode. This will prevent bulk send "
96- "operations and force sending items one after the "
97- "other, displaying result for each one" )
98- parser .add_option ("-v" , "--verbose" , action = "store_true" ,
99- help = "When used with debug option, will force value "
100- "display for each items managed. Beware that it "
101- "can be pretty too much verbose, specialy for LLD" )
102-
103- mode_group = optparse .OptionGroup (parser , "Program Mode" )
104- mode_group .add_option ("--update-items" , action = "store_const" ,
105- dest = "mode" , const = "update_items" ,
106- help = "Get & send items to Zabbix. This is the default "
107- "behaviour even if option is not specified" )
108- mode_group .add_option ("--discovery" , action = "store_const" ,
109- dest = "mode" , const = "discovery" ,
110- help = "If specified, will perform Zabbix Low Level "
111- "Discovery against domain names to check. "
112- "Default is to get & send items" )
113- parser .add_option_group (mode_group )
114- parser .set_defaults (mode = "update_items" )
115-
116- polling_options = optparse .OptionGroup (parser , "Zabbix configuration" )
117- polling_options .add_option ("--zabbix-server" , metavar = "HOST" ,
118- default = "localhost" ,
119- help = "The hostname of Zabbix server or "
120- "proxy, default is localhost." )
121- polling_options .add_option ("--zabbix-port" , metavar = "PORT" , default = 10051 ,
122- help = "The port on which the Zabbix server or "
123- "proxy is running, default is 10051." )
124- parser .add_option_group (polling_options )
125-
126- (options , args ) = parser .parse_args ()
127-
128- return (options , args )
129-
130- def _init_container (self ):
131- zbx_container = protobix .DataContainer (
132- data_type = 'items' ,
133- zbx_host = self .options .zabbix_server ,
134- zbx_port = int (self .options .zabbix_port ),
135- debug = self .options .debug ,
136- dryrun = self .options .dry
137- )
138- return zbx_container
139-
140- def run (self , conf_file = '/etc/zabbix/ssl_certificates_check.yaml' ):
141- (self .options , args ) = self ._parse_args ()
142- hostname = socket .getfqdn ()
143-
144- # Step 1: init container
145- try :
146- zbx_container = self ._init_container ()
147- except :
148- return 1
149-
150- # Step 2: get data
151- try :
152- ''' Load config file '''
153- with open (conf_file , 'r' ) as f :
154- config = yaml .load (f )
155- self .endpoints = config ['endpoints' ]
156-
157- data = {}
158- if self .options .mode == "update_items" :
159- zbx_container .set_type ("items" )
160- data [hostname ] = self ._get_metrics ()
161- elif self .options .mode == "discovery" :
162- zbx_container .set_type ("lld" )
163- data [hostname ] = self ._get_discovery ()
164- except :
165- return 2
166-
167- # Step 3: format & load data into container
168- try :
169- zbx_container .add (data )
170- except :
171- return 3
172-
173- # Step 4: send container data to Zabbix server
174- try :
175- zbx_container .send (zbx_container )
176- except protobix .SenderException as zbx_e :
177- if self .options .debug :
178- print self .ZBX_CONN_ERR % zbx_e .err_text
179- return 4
180- # Everything went fine. Let's return 0 and exit
181- return 0
96+ return { hostname : data }
18297
18398if __name__ == '__main__' :
18499 ret = SSLEndpointCheck ().run ()
185100 print ret
186- sys .exit (ret )
101+ sys .exit (ret )
0 commit comments