├── .gitignore
├── LICENSE
├── README.md
├── template_elasticsearch
├── README.md
└── check_es.py
├── template_mongodb
├── README.md
├── install
│ ├── conf
│ │ ├── mdb_sstat.py
│ │ └── mongodb.conf
│ └── install.sh
└── templates
│ └── templates_mongodb.xml
├── template_mylinux
├── README.md
├── install
│ ├── conf
│ │ └── Mylinux.conf
│ └── install.sh
└── template
│ └── templates_mylinux.xml
├── template_mysql
├── README.md
├── install
│ ├── conf
│ │ └── MySQL.conf
│ ├── install.sh
│ └── scripts
│ │ ├── .mysql.ini
│ │ ├── my_lib
│ │ ├── QCmd.py
│ │ ├── QLog.py
│ │ └── __init__.py
│ │ ├── mysql_func.py
│ │ ├── mysql_perf.py
│ │ └── mysql_status.py
└── template
│ └── template_mysql.xml
├── template_raid
├── README.md
├── install
│ ├── conf
│ │ ├── disk.conf
│ │ └── raid.py
│ ├── install.sh
│ └── linux
│ │ ├── MegaCli-8.07.14-1.noarch.rpm
│ │ └── readme.txt
└── templates
│ └── meetbill_raid.xml
├── template_redis
├── README.md
├── install
│ ├── conf
│ │ ├── redis.conf
│ │ └── redis.py
│ └── install.sh
└── templates
│ └── templates_redis.xml
└── template_service
├── README.md
├── install
├── conf
│ ├── service.conf
│ └── service.py
└── install.sh
└── templates
└── service.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .coverage
41 | .coverage.*
42 | .cache
43 | nosetests.xml
44 | coverage.xml
45 | *,cover
46 | .hypothesis/
47 |
48 | # Translations
49 | *.mo
50 | *.pot
51 |
52 | # Django stuff:
53 | *.log
54 | local_settings.py
55 |
56 | # Flask stuff:
57 | instance/
58 | .webassets-cache
59 |
60 | # Scrapy stuff:
61 | .scrapy
62 |
63 | # Sphinx documentation
64 | docs/_build/
65 |
66 | # PyBuilder
67 | target/
68 |
69 | # IPython Notebook
70 | .ipynb_checkpoints
71 |
72 | # pyenv
73 | .python-version
74 |
75 | # celery beat schedule file
76 | celerybeat-schedule
77 |
78 | # dotenv
79 | .env
80 |
81 | # virtualenv
82 | venv/
83 | ENV/
84 |
85 | # Spyder project settings
86 | .spyderproject
87 |
88 | # Rope project settings
89 | .ropeproject
90 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # zabbix_templates
2 |
3 | * [1 简介](#1-简介)
4 | * [2 模板](#2-模板)
5 | * [2.1 硬件层](#21-硬件层)
6 | * [2.2 系统层](#22-系统层)
7 | * [2.3 应用层](#23-应用层)
8 | * [3 相关项目](#3-相关项目)
9 | * [4 参加步骤](#4-参加步骤)
10 |
11 |
12 |
13 |
14 | ## 1 简介
15 |
16 | zabbix 常用模板
17 |
18 | 1. 需要导入 xxx.xml 模板文件。
19 |
20 | 2. 在被监控机上部署收集数据的程序
21 |
22 | 这里主要汇总了一些在使用 zabbix 过程中经常用的监控模板。
23 |
24 | ## 2 模板
25 |
26 | ### 2.1 硬件层
27 |
28 | > * [raid](template_raid/)
29 |
30 | ### 2.2 系统层
31 |
32 | > * [Mylinux](./template_mylinux/)
33 |
34 | ### 2.3 应用层
35 |
36 | > * [mysql](./template_mysql/)
37 | > * [redis](./template_redis/)
38 | > * [mongodb](./template_mongodb/)
39 | > * [es](./template_elasticsearch/)
40 | > * [service](./template_service/)
41 |
42 | ## 3 相关项目
43 |
44 | > * zabbix 安装 -------------------------------------------------[zabbix_install](https://github.com/BillWang139967/zabbix_install)
45 | > * zabbix 报警工具 ---------------------------------------------[zabbix_alert](https://github.com/BillWang139967/zabbix_alert)
46 | > * zabbix 管理工具 ---------------------------------------------[zabbix_manager](https://github.com/BillWang139967/zabbix_manager)
47 |
48 | ## 4 参加步骤
49 | * 在 GitHub 上 `fork` 到自己的仓库,然后 `clone` 到本地,并设置用户信息。
50 | ```
51 | $ git clone https://github.com/BillWang139967/zabbix_templates.git
52 | $ cd zabbix_templates
53 | $ git config user.name "yourname"
54 | $ git config user.email "your email"
55 | ```
56 | * 修改代码后提交,并推送到自己的仓库。
57 | ```
58 | $ #do some change on the content
59 | $ git commit -am "Fix issue #1: change helo to hello"
60 | $ git push
61 | ```
62 | * 在 GitHub 网站上提交 pull request。
63 | * 定期使用项目仓库内容更新自己仓库内容。
64 | ```
65 | $ git remote add upstream https://github.com/BillWang139967/zabbix_templates.git
66 | $ git fetch upstream
67 | $ git checkout master
68 | $ git rebase upstream/master
69 | $ git push -f origin master
70 | ```
71 |
--------------------------------------------------------------------------------
/template_elasticsearch/README.md:
--------------------------------------------------------------------------------
1 | ## elasticsearch 监控
2 |
3 | * [1 原理](#1-原理)
4 | * [2 操作方法](#2-操作方法)
5 | * [3 相关](#3-相关)
6 |
7 |
8 |
9 | ## 1 原理
10 | 查看 es 集群健康状态
11 |
12 | ```
13 | curl -sXGET 'http://localhost:9200/_cluster/health?pretty'
14 | {
15 | "cluster_name" : "elasticsearch",
16 | "status" : "green", #集群状态:green,yellow,red
17 | "timed_out" : false,
18 | "number_of_nodes" : 3, #集群中 node 节点数
19 | "number_of_data_nodes" : 2, #集群中 data 节点数
20 | "active_primary_shards" : 186,
21 | "active_shards" : 372,
22 | "relocating_shards" : 0, #迁移分片到新的 node
23 | "initializing_shards" : 0, #初始化分片
24 | "unassigned_shards" : 0,
25 | "delayed_unassigned_shards" : 0,
26 | "number_of_pending_tasks" : 0,
27 | "number_of_in_flight_fetch" : 0
28 | }
29 |
30 | ```
31 |
32 | 检测方法
33 | ```
34 | curl -s -XGET "http://localhost:9200/_cluster/health?pretty" | grep "status"|awk -F '[ "]+' '{print $4}'|grep -c 'green'
35 | ```
36 | ## 2 操作方法
37 |
38 | ```
39 | python check_es.py status
40 | ```
41 | * green 返回 0
42 | * yellow 返回 1
43 | * red/无法请求到结果/超时 返回 2
44 |
45 | ## 3 相关
46 |
47 | 使用此程序时,假如系统无响应时无法返回结果,可通过以下链接方法避免
48 |
49 | [python 调用 shell(超时设置)](https://github.com/BillWang139967/MyPythonLib/blob/master/My_lib/easyrun/README.md)
50 |
--------------------------------------------------------------------------------
/template_elasticsearch/check_es.py:
--------------------------------------------------------------------------------
1 | #coding:utf8
2 |
3 | import sys
4 | import json
5 | import time
6 | import subprocess
7 |
8 |
9 | class Result(object):
10 | def __init__(self, command=None, retcode=None, output=None):
11 | self.command = command or ''
12 | self.retcode = retcode
13 | self.output = output
14 | self.success = False
15 | if retcode == 0:
16 | self.success = True
17 |
18 | def _run_timeout(command,timeout=10):
19 | timeout=int(timeout)
20 | process = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True)
21 | t_beginning = time.time()
22 | seconds_passed = 0
23 | while True:
24 | if process.poll() is not None:
25 | break
26 | seconds_passed = time.time() - t_beginning
27 | if timeout and seconds_passed > timeout:
28 | process.terminate()
29 | return Result(command=command, retcode=124,output="timeout")
30 | time.sleep(0.1)
31 | output, _ = process.communicate()
32 | return Result(command=command, retcode=process.returncode,output=output)
33 |
34 | def status():
35 | r = _run_timeout('curl -sXGET http://127.0.0.1:9200/_cluster/health/?pretty', timeout=2)
36 | if r.success:
37 | elastic_outputInfo = r.output
38 | elastic_outputInfo = json.loads(elastic_outputInfo)
39 | if elastic_outputInfo["status"] == "green":
40 | return 0
41 | if elastic_outputInfo["status"] == "yellow":
42 | return 1
43 | else:
44 | return 2
45 | else:
46 | return 2
47 |
48 |
49 | if __name__ == "__main__":
50 | import inspect
51 | if len(sys.argv) < 2:
52 | print "Usage:"
53 | for k,v in globals().items():
54 | if inspect.isfunction(v) and k[0] != "_":
55 | print sys.argv[0], k, str(v.func_code.co_varnames[:v.func_code.co_argcount])[1:-1].replace(",", "")
56 | sys.exit(-1)
57 | else:
58 | print status()
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/template_mongodb/README.md:
--------------------------------------------------------------------------------
1 | ## template_mongodb
2 |
3 | * [1 安装](#1-安装)
4 | * [2 检验](#2-检验)
5 | * [3 原理](#3-原理)
6 | * [4 运维修改](#4-运维修改)
7 | * [5 说明](#5-说明)
8 |
9 |
10 |
11 |
12 | ## 1 安装
13 | **agent**
14 |
15 | install 中安装执行 install.sh
16 |
17 | 修改 agent 检测程序中 mongo 客户端位置
18 |
19 | /usr/lib/zabbix/externalscripts/mdb_sstat.py
20 | ```
21 | pbinpaths = [
22 | "/opt/mongodb/bin/mongo",
23 | "/home/mongodb/mongodb/bin/mongo",
24 | ]
25 |
26 | ```
27 |
28 | **server**
29 |
30 | * 导入 templates 的模板
31 |
32 | * 对要监控的机器关联 templates 模板
33 |
34 | ## 2 检验
35 |
36 | 获取本机器 mongodb 所有信息
37 | ```
38 | /usr/lib/zabbix/externalscripts/mdb_sstat.py -a
39 | ```
40 |
41 | ## 3 原理
42 |
43 | * install 里面安装的程序是可以使 agent 采集到要监控的数据
44 | * templates 中包括了要监控机器要监控的指标及报警条件,导入后关联要监控的主机即可
45 |
46 | ## 4 运维修改
47 |
48 | (1) 本程序默认设置 AllowRoot=1,即允许使用 root 身份运行 zabbix-agent
49 |
50 | 若需要使用普通用户运行,则需要以下设置
51 |
52 | 在 sudoers 中添加 zabbix 用户
53 | ```
54 | echo "zabbix ALL=(root) NOPASSWD:/bin/netstat" > /etc/sudoers.d/zabbix
55 | echo 'Defaults:zabbix !requiretty' >> /etc/sudoers.d/zabbix
56 | chmod 600 /etc/sudoers.d/zabbix
57 | ```
58 | 更改 /usr/lib/zabbix/externalscripts/mdb_sstat.py
59 | ```
60 |
61 | 将 cmdstr = "netstat -nlpt | grep '%s' | awk '{print $4}'|awk -F: '{print $2}'|uniq" % (binname)
62 | 修改为:cmdstr = "sudo netstat -nlpt | grep '%s' | awk '{print $4}'|awk -F: '{print $2}'|uniq" % (binname)
63 | ```
64 |
65 | (2) 如果连接 MongoDB 需要账号密码,则需要配置端口、账号、密码的对应关系,配置文件路径如下:
66 |
67 | /usr/local/public-ops/conf/.mongodb.passwd
68 |
69 | 内容如下:
70 | 27017 test xxxxx
71 |
72 | (3) 程序默认为只汇报指定端口 mongodb
73 |
74 | 旧版程序每次检测时会通过 netstat -nlpt | grep '%s' | awk '{print $4}'|awk -F: '{print $2}'|uniq 进行检测所有实例的 mongodb 端口
75 |
76 | 即可以自动检测多实例 mongodb, 即 agent 机器上跑着多个 mongodb 实例
77 |
78 | 某些机器的机器数连接过多的时候,会导致程序执行超时,故默认为手动进行配置需要监控的 mongodb 的端口
79 |
80 | 修改方式如下:
81 |
82 | /usr/lib/zabbix/externalscripts/mdb_sstat.py
83 |
84 | ```
85 | port_list=[27017]
86 | ```
87 |
88 | ## 5 说明
89 |
90 | > * 检测时间:2m
91 | > * history 保留时间:7d
92 | > * trend 保留时间:365d
93 |
94 |
--------------------------------------------------------------------------------
/template_mongodb/install/conf/mdb_sstat.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #coding=utf8
3 | """
4 | # Author: Bill
5 | # Created Time : 2016-07-27 23:18:24
6 |
7 | # File Name: mdb_sstat.py
8 | # Description:
9 |
10 | """
11 | import sys
12 | import os
13 | from optparse import OptionParser
14 | import re
15 | import time
16 | import platform
17 | import json
18 | import types
19 | #######Log
20 | import logging
21 | from logging.handlers import RotatingFileHandler
22 | class ColoredFormatter(logging.Formatter):
23 | '''A colorful formatter.'''
24 |
25 | def __init__(self, fmt = None, datefmt = None):
26 | logging.Formatter.__init__(self, fmt, datefmt)
27 | # Color escape string
28 | COLOR_RED='\033[1;31m'
29 | COLOR_GREEN='\033[1;32m'
30 | COLOR_YELLOW='\033[1;33m'
31 | COLOR_BLUE='\033[1;34m'
32 | COLOR_PURPLE='\033[1;35m'
33 | COLOR_CYAN='\033[1;36m'
34 | COLOR_GRAY='\033[1;37m'
35 | COLOR_WHITE='\033[1;38m'
36 | COLOR_RESET='\033[1;0m'
37 |
38 | # Define log color
39 | self.LOG_COLORS = {
40 | 'DEBUG': '%s',
41 | 'INFO': COLOR_GREEN + '%s' + COLOR_RESET,
42 | 'WARNING': COLOR_YELLOW + '%s' + COLOR_RESET,
43 | 'ERROR': COLOR_RED + '%s' + COLOR_RESET,
44 | 'CRITICAL': COLOR_RED + '%s' + COLOR_RESET,
45 | 'EXCEPTION': COLOR_RED + '%s' + COLOR_RESET,
46 | }
47 |
48 | def format(self, record):
49 | level_name = record.levelname
50 | msg = logging.Formatter.format(self, record)
51 |
52 | return self.LOG_COLORS.get(level_name, '%s') % msg
53 | class Log(object):
54 |
55 | '''
56 | log
57 | '''
58 | def __init__(self, filename, level="debug", logid="qiueer", mbs=20, count=10, is_console=True):
59 | '''
60 | mbs: how many MB
61 | count: the count of remain
62 | '''
63 | try:
64 | self._level = level
65 | #print "init,level:",level,"\t","get_map_level:",self._level
66 | self._filename = filename
67 | self._logid = logid
68 |
69 | self._logger = logging.getLogger(self._logid)
70 |
71 |
72 | if not len(self._logger.handlers):
73 | self._logger.setLevel(self.get_map_level(self._level))
74 |
75 | fmt = '[%(asctime)s] %(levelname)s\n%(message)s'
76 | datefmt = '%Y-%m-%d %H:%M:%S'
77 | formatter = logging.Formatter(fmt, datefmt)
78 |
79 | maxBytes = int(mbs) * 1024 * 1024
80 | file_handler = RotatingFileHandler(self._filename, mode='a',maxBytes=maxBytes,backupCount=count)
81 | self._logger.setLevel(self.get_map_level(self._level))
82 | file_handler.setFormatter(formatter)
83 | self._logger.addHandler(file_handler)
84 |
85 | if is_console == True:
86 | stream_handler = logging.StreamHandler(sys.stderr)
87 | console_formatter = ColoredFormatter(fmt, datefmt)
88 | stream_handler.setFormatter(console_formatter)
89 | self._logger.addHandler(stream_handler)
90 |
91 | except Exception as expt:
92 | print expt
93 |
94 | def tolog(self, msg, level=None):
95 | try:
96 | level = level if level else self._level
97 | level = str(level).lower()
98 | level = self.get_map_level(level)
99 | if level == logging.DEBUG:
100 | self._logger.debug(msg)
101 | if level == logging.INFO:
102 | self._logger.info(msg)
103 | if level == logging.WARN:
104 | self._logger.warn(msg)
105 | if level == logging.ERROR:
106 | self._logger.error(msg)
107 | if level == logging.CRITICAL:
108 | self._logger.critical(msg)
109 | except Exception as expt:
110 | print expt
111 |
112 | def debug(self,msg):
113 | self.tolog(msg, level="debug")
114 |
115 | def info(self,msg):
116 | self.tolog(msg, level="info")
117 |
118 | def warn(self,msg):
119 | self.tolog(msg, level="warn")
120 |
121 | def error(self,msg):
122 | self.tolog(msg, level="error")
123 |
124 | def critical(self,msg):
125 | self.tolog(msg, level="critical")
126 |
127 | def get_map_level(self,level="debug"):
128 | level = str(level).lower()
129 | #print "get_map_level:",level
130 | if level == "debug":
131 | return logging.DEBUG
132 | if level == "info":
133 | return logging.INFO
134 | if level == "warn":
135 | return logging.WARN
136 | if level == "error":
137 | return logging.ERROR
138 | if level == "critical":
139 | return logging.CRITICAL
140 |
141 | def docmd(command,timeout=300, raw=False):
142 | '''
143 | 功能:
144 | 执行命令
145 | 参数:command,命令以及其参数/选项
146 | timeout,命令超时时间,单位秒
147 | debug,是否debug,True输出debug信息,False不输出
148 | raw,命令输出是否为元素的输出,True是,False会将结果的每一行去除空格、换行符、制表符等,默认False
149 | 返回:
150 | 含有3个元素的元组,前两个元素类型是list,第三个元素类型是int,第一个list存储stdout的输出,第二个list存储stderr的输出,第三int存储命令执行的返回码,其中-1表示命令执行超时
151 | 示例:
152 | cmd.docmd("ls -alt")
153 | '''
154 | import subprocess, datetime, os, time, signal
155 | start = datetime.datetime.now()
156 |
157 | ps = None
158 | retcode = 0
159 | if platform.system() == "Linux":
160 | ps = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
161 | else:
162 | ps = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
163 | while ps.poll() is None:
164 | time.sleep(0.2)
165 | now = datetime.datetime.now()
166 | if (now - start).seconds > timeout:
167 | os.kill(ps.pid, signal.SIGINT)
168 | retcode = -1
169 | return (None,None,retcode)
170 | stdo = ps.stdout.readlines()
171 | stde = ps.stderr.readlines()
172 |
173 | if not ps.returncode:
174 | retcode = ps.returncode
175 | if raw == True: #去除行末换行符
176 | stdo = [line.strip("\n") for line in stdo]
177 | stde = [line.strip("\n") for line in stde]
178 | if raw == False: #去除行末换行符,制表符、空格等
179 | stdo = [str.strip(line) for line in stdo]
180 | stde = [str.strip(line) for line in stde]
181 | return (stdo,stde,retcode)
182 | def get_logstr(list_dict, max_key_len=16, join_str="\n"):
183 | log_str = ""
184 | for conf in list_dict:
185 | for (key,val) in dict(conf).iteritems():
186 | log_str = log_str + str(key).ljust(max_key_len) + ": " + str(val) + join_str
187 | log_str = log_str.strip() # 去掉尾部 \n
188 | return log_str
189 | def get_user_passwd_by_port(conffile, port):
190 | if os.path.exists(conffile) == False:
191 | return (None,None)
192 | with open(conffile,'r') as fd:
193 | alllines = fd.readlines()
194 | for line in alllines:
195 | line = str(line).strip()
196 | if not line or line.startswith("#"):continue
197 | ln_ary = re.split('[ ,;]+', line)
198 | if len(ln_ary) < 3:continue
199 | if str(port) == ln_ary[0]:
200 | return (ln_ary[1],ln_ary[2])
201 | return (None, None)
202 | class MGdb(object):
203 | def __init__(self, iphost="127.0.0.1", port=27017, username=None, password=None, force=False, debug=True):
204 | self._iphost = iphost
205 | self._port = port
206 | self._username = username
207 | self._password = password
208 | self._force = force
209 |
210 | self._logpath = "/tmp/zabbix_mongodb.log"
211 | self._cache_file = "/tmp/zabbix_mongodb_cache_%s.txt" %(port)
212 | if not port:
213 | self._cache_file = "/tmp/zabbix_mongodb_cache.txt"
214 |
215 | self._logger = Log(self._logpath,level="error",is_console=debug, mbs=5, count=5)
216 |
217 | def get_logger(self):
218 | return self._logger
219 |
220 | def get_port_list(self,port_list=""):
221 | # sudo权限,必须授予
222 | # [root@localhost ~]# tail -n 2 /etc/sudoers
223 | # Defaults:zabbix !requiretty
224 | # zabbix ALL=(root) NOPASSWD:/bin/netstat
225 | data = list()
226 | if port_list:
227 | for port in port_list:
228 | data.append({"{#MONGODB_PORT}": port})
229 | else:
230 | binname = "mongod"
231 | cmdstr = "netstat -nlpt | grep '%s' | awk '{print $4}'|awk -F: '{print $2}'|uniq" % (binname)
232 | disk_space_info = []
233 | (stdo_list, stde_list, retcode) = docmd(cmdstr, timeout=3, raw = False)
234 |
235 | log_da = [{"cmdstr": cmdstr},{"ret": retcode},{"stdo": "".join(stdo_list)}, {"stde": "".join(stde_list)}]
236 | logstr = get_logstr(log_da, max_key_len=10)
237 |
238 | if retcode !=0:
239 | self._logger.error(logstr)
240 | return {}
241 | else:
242 | self._logger.info(logstr)
243 |
244 | for port in stdo_list:
245 | port = int(str(port).strip())
246 | data.append({"{#MONGODB_PORT}": port})
247 | import json
248 | return json.dumps({'data': data}, sort_keys=True, indent=7, separators=(",",":"))
249 |
250 | def _get_result(self, iphost=None, port=None, username=None, password=None):
251 | try:
252 | hostname= iphost if iphost else self._iphost
253 | port = port if port else self._port
254 | username = username if username else self._username
255 | password = password if password else self._password
256 | resobj = None
257 |
258 | if self._force == False:
259 | if os.path.exists(self._cache_file):
260 | with open(self._cache_file, "r") as fd:
261 | alllines = fd.readlines()
262 | fd.close()
263 | if alllines and len(alllines)>1:
264 | old_unixtime = int(str(alllines[0]).strip())
265 | now_unixtime = int(time.time())
266 | if (now_unixtime - old_unixtime) <= 60: ## 1min内
267 | resobj = str(alllines[1]).strip()
268 | resobj = json.loads(resobj)
269 |
270 | if resobj:
271 | log_da = [{"msg": "Get From Cache File"}, {"content": str(resobj)}]
272 | logstr = get_logstr(log_da, max_key_len=10)
273 | self._logger.info(logstr)
274 | return resobj
275 |
276 | pbinpaths = [
277 | "/usr/local/mongodb/bin/mongo",
278 | "/opt/mongodb/bin/mongo",
279 | "/home/mongodb/mongodb/bin/mongo",
280 | ]
281 | cmdstr = None
282 | for bp in pbinpaths:
283 | if os.path.exists(bp):
284 | if username and password:
285 | cmdstr = "echo 'db.serverStatus()' | %s admin --host '%s' --port %s -u %s -p %s --quiet" % (bp, hostname, port, username, password)
286 | else:
287 | cmdstr = "echo 'db.serverStatus()' | %s admin --host '%s' --port %s --quiet" % (bp, hostname, port)
288 | break
289 | if not cmdstr:
290 | print "the mongo not find"
291 | return None
292 |
293 | (stdo_list, stde_list, retcode) = docmd(cmdstr, timeout=3, raw = False)
294 |
295 | log_da = [{"cmdstr": cmdstr},{"ret": retcode},{"stdo": None if not stdo_list else "".join(stdo_list)}, {"stde": None if not stde_list else"".join(stde_list)}]
296 | logstr = get_logstr(log_da, max_key_len=10)
297 |
298 | if retcode !=0:
299 | self._logger.error(logstr)
300 | return None
301 | else:
302 | self._logger.info(logstr)
303 |
304 | stdo_str = "".join(stdo_list)
305 | stdo_str = stdo_str.replace("NumberLong(", "").replace(")","").replace("ISODate(","").replace("ObjectId(","")
306 | #print stdo_str
307 | resobj = json.loads(stdo_str)
308 | now_unixtime = int(time.time())
309 | with open(self._cache_file, "w") as fd:
310 | fd.write(str(now_unixtime)+"\n")
311 | fd.write(stdo_str)
312 | fd.close()
313 |
314 | return resobj
315 | except Exception as expt:
316 | import traceback
317 | tb = traceback.format_exc()
318 | self._logger.error(tb)
319 |
320 | def get_item_val(self, *items):
321 | resobj = self._get_result()
322 | src_res = resobj
323 | for item in items:
324 | if resobj and type(resobj) == types.DictType and resobj.has_key(item):
325 | resobj = resobj[item]
326 | if resobj == None or resobj == src_res:
327 | resobj = 0
328 | return resobj
329 |
330 | def get_result(self):
331 | return self._get_result()
332 |
333 | def get_item_tval(self, items, val_type="int"):
334 | val = self.get_item_val(*items)
335 | if val == None:return None #0也满足此条件
336 | if val_type == "int":
337 | return int(val)
338 | if val_type == "float":
339 | fval = "%.2f" % (val)
340 | return float(fval)
341 | if val_type == "str":
342 | return str(val)
343 |
344 | return int(val)
345 |
346 | def print_all_key_val(self):
347 | resobj = self._get_result()
348 | print json.dumps(resobj, indent=4)
349 | def main():
350 | usage = "usage: %prog [options]\n Fetch mongodb status"
351 | parser = OptionParser(usage)
352 |
353 | parser.add_option("-l", "--list",
354 | action="store_true", dest="is_list", default=False,
355 | help="if list all port")
356 |
357 | parser.add_option("-H", "--host", action="store", dest="host", type="string", default='localhost', help="Connect to mongod host.")
358 |
359 | parser.add_option("-p",
360 | "--port",
361 | action="store",
362 | dest="port",
363 | type="int",
364 | default=27017,
365 | help="the port for mongodb, for example: 27017")
366 |
367 | parser.add_option("-u",
368 | "--user",
369 | action="store",
370 | dest="username",
371 | type="string",
372 | default=None,
373 | help="username")
374 |
375 | parser.add_option("-P",
376 | "--password",
377 | action="store",
378 | dest="password",
379 | type="string",
380 | default=None,
381 | help="password")
382 |
383 | parser.add_option("-i",
384 | "--item",
385 | dest="item",
386 | action="store",
387 | type="string",
388 | default=None,
389 | help="which item to fetch")
390 |
391 | parser.add_option("-f", "--force",
392 | action="store_true", dest="force", default=False,
393 | help="if get from cache")
394 |
395 | parser.add_option("-d", "--debug",
396 | action="store_true", dest="debug", default=False,
397 | help="if open debug mode")
398 | parser.add_option("-a", "--all",
399 | action="store_true",dest="all", default=False,
400 | help="output all info")
401 | (options, args) = parser.parse_args()
402 | if 1 >= len(sys.argv):
403 | parser.print_help()
404 | return
405 | hostname = options.host
406 | port = options.port
407 |
408 | conffile = "/usr/local/public-ops/conf/.mongodb.passwd"
409 | username = options.username
410 | password = options.password
411 |
412 | if password == None or username == None:
413 | (username, password) = get_user_passwd_by_port(conffile, port)
414 | #print "Get (username=%s,password=%s) From Config File By port:%s" % (username, password, port)
415 |
416 | monitor_obj = MGdb(iphost=hostname, port=port, username=username, password=password, debug=options.debug, force=options.force)
417 | #################start
418 | port_list=[27017]
419 | if options.is_list == True:
420 | print monitor_obj.get_port_list(port_list)
421 | return
422 |
423 | if options.all == True:
424 | mg = MGdb(debug=False)
425 | mg.print_all_key_val()
426 | sys.exit(0)
427 |
428 | try:
429 | item = options.item
430 | item_ary = re.split("\.", item)
431 | print monitor_obj.get_item_tval(item_ary)
432 |
433 | except Exception as expt:
434 | import traceback
435 | tb = traceback.format_exc()
436 | monitor_obj.get_logger().error(tb)
437 |
438 |
439 | if __name__ == '__main__':
440 | main()
441 |
--------------------------------------------------------------------------------
/template_mongodb/install/conf/mongodb.conf:
--------------------------------------------------------------------------------
1 | UserParameter=mongodb.discovery, python /usr/lib/zabbix/externalscripts/mdb_sstat.py --list
2 | UserParameter=mongodb.status[*],python /usr/lib/zabbix/externalscripts/mdb_sstat.py -p $1 -i $2
3 |
--------------------------------------------------------------------------------
/template_mongodb/install/install.sh:
--------------------------------------------------------------------------------
1 | # conf
2 | mkdir -p /etc/zabbix/zabbix_agentd.d/
3 | cp conf/mongodb.conf /etc/zabbix/zabbix_agentd.d/
4 |
5 | # scripts
6 | mkdir -p /usr/lib/zabbix/externalscripts/
7 | cp conf/mdb_sstat.py /usr/lib/zabbix/externalscripts/
8 | cp -rf conf/qiueer/ /usr/lib/zabbix/externalscripts/
9 | chmod 777 /usr/lib/zabbix/externalscripts/mdb_sstat.py
10 |
11 | # UnsafeUserParameters=1
12 | CHECK=`grep "^Include=/etc/zabbix/zabbix_agentd.d/" /etc/zabbix/zabbix_agentd.conf|wc -l`
13 | if [[ "w$CHECK" == "w0" ]]
14 | then
15 | echo 'Include=/etc/zabbix/zabbix_agentd.d/' >> /etc/zabbix/zabbix_agentd.conf
16 | fi
17 |
18 | # UnsafeUserParameters=1
19 | CHECK=`grep "^UnsafeUserParameters=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
20 | if [[ "w$CHECK" == "w0" ]]
21 | then
22 | sed -ri '/UnsafeUserParameters=/a UnsafeUserParameters=1' /etc/zabbix/zabbix_agentd.conf
23 | fi
24 |
25 | # Timeout=10
26 | CHECK=`grep "^Timeout=3" /etc/zabbix/zabbix_agentd.conf|wc -l`
27 | if [[ "w$CHECK" == "w0" ]]
28 | then
29 | sed -ri '/Timeout=3/a Timeout=10' /etc/zabbix/zabbix_agentd.conf
30 | fi
31 |
32 | # AllowRoot=1
33 | CHECK=`grep "^AllowRoot=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
34 | if [[ "w$CHECK" == "w0" ]]
35 | then
36 | sed -ri '/AllowRoot=0/a AllowRoot=1' /etc/zabbix/zabbix_agentd.conf
37 | fi
38 | /etc/init.d/zabbix-agent restart
39 |
--------------------------------------------------------------------------------
/template_mylinux/README.md:
--------------------------------------------------------------------------------
1 | ## template_MyLinux
2 |
3 |
4 |
5 | * [1 安装](#1-安装)
6 | * [2 检验](#2-检验)
7 | * [3 原理](#3-原理)
8 |
9 |
10 | ## 1 安装
11 |
12 | **agent**
13 |
14 | install 中安装执行 install.sh
15 |
16 | **server**
17 |
18 | * 导入 templates 的模板
19 |
20 | * 对要监控的机器关联 templates 模板 (Template OS MyLinux)
21 |
22 | ## 2 检验
23 |
24 | 在 agent 上查看检测结果
25 | ```
26 | mount | awk '{print $NF}'|cut -c 2-3|awk '{if($1~/ro/) {print 0}}'|wc -l|awk '{if($1<=0) {print 1 } else {print 0}}'
27 | ```
28 | 输出 1 则说明分区为可读写,如果输出 0 则说明磁盘为只读状态
29 |
30 | ## 3 原理
31 |
32 | * templates 中包括了要监控机器要监控的指标及报警条件,导入后关联要监控的主机即可
33 | * install 里面安装的程序是可以使 agent 采集到要监控的数据
34 |
35 | mount 命令会输出分区的可读写情况最后的,ro 就表示只读,如果是可读写,就是 rw
36 |
37 | ```
38 | [root@Linux ~]# mount
39 | /dev/mapper/vg_linux-lv_root on / type ext4 (rw)
40 | proc on /proc type proc (rw)
41 | sysfs on /sys type sysfs (rw)
42 | devpts on /dev/pts type devpts (rw,gid=5,mode=620)
43 | tmpfs on /dev/shm type tmpfs (rw)
44 | /dev/sda1 on /boot type ext4 (rw)
45 | none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
46 | /dev/sdb on /data4 type ext4 (ro)
47 | ```
48 |
--------------------------------------------------------------------------------
/template_mylinux/install/conf/Mylinux.conf:
--------------------------------------------------------------------------------
1 | ## disk-status @meetbill20161114
2 | UserParameter=check_disk_status,mount | awk '{print $NF}'|cut -c 2-3|awk '{if($1~/ro/) {print 0}}'|wc -l|awk '{if($1<=0) {print 1 } else {print 0}}'
3 |
--------------------------------------------------------------------------------
/template_mylinux/install/install.sh:
--------------------------------------------------------------------------------
1 | # conf
2 | mkdir -p /etc/zabbix/zabbix_agentd.d/
3 | cp conf/*.conf /etc/zabbix/zabbix_agentd.d/
4 |
5 | # scripts
6 | #mkdir -p /usr/lib/zabbix/externalscripts/
7 | #cp -rf scripts/* /usr/lib/zabbix/externalscripts/
8 | #chmod +x -R /usr/lib/zabbix/externalscripts/
9 |
10 | # UnsafeUserParameters=1
11 | CHECK=`grep "^Include=/etc/zabbix/zabbix_agentd.d/" /etc/zabbix/zabbix_agentd.conf|wc -l`
12 | if [[ "w$CHECK" == "w0" ]]
13 | then
14 | echo 'Include=/etc/zabbix/zabbix_agentd.d/' >> /etc/zabbix/zabbix_agentd.conf
15 | fi
16 |
17 | # UnsafeUserParameters=1
18 | CHECK=`grep "^UnsafeUserParameters=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
19 | if [[ "w$CHECK" == "w0" ]]
20 | then
21 | sed -ri '/UnsafeUserParameters=/a UnsafeUserParameters=1' /etc/zabbix/zabbix_agentd.conf
22 | fi
23 |
24 | # Timeout=10
25 | CHECK=`grep "^Timeout=3" /etc/zabbix/zabbix_agentd.conf|wc -l`
26 | if [[ "w$CHECK" == "w0" ]]
27 | then
28 | sed -ri '/Timeout=3/a Timeout=10' /etc/zabbix/zabbix_agentd.conf
29 | fi
30 |
31 | # AllowRoot=1
32 | CHECK=`grep "^AllowRoot=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
33 | if [[ "w$CHECK" == "w0" ]]
34 | then
35 | sed -ri '/AllowRoot=0/a AllowRoot=1' /etc/zabbix/zabbix_agentd.conf
36 | fi
37 | /etc/init.d/zabbix-agent restart
38 |
--------------------------------------------------------------------------------
/template_mylinux/template/templates_mylinux.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 3.0
4 | 2016-11-14T10:34:23Z
5 |
6 |
7 | Templates
8 |
9 |
10 |
11 |
12 | Template OS MyLinux
13 | Template OS MyLinux
14 |
15 |
16 |
17 | Templates
18 |
19 |
20 |
21 |
22 | disk
23 |
24 |
25 |
26 | -
27 | check disk status
28 | 0
29 |
30 | 0
31 |
32 | check_disk_status
33 | 300
34 | 7
35 | 90
36 | 0
37 | 3
38 |
39 |
40 | 0
41 |
42 |
43 | 0
44 | 0
45 |
46 | 0
47 |
48 | 1
49 |
50 |
51 |
52 | 0
53 | 0
54 |
55 |
56 |
57 |
58 |
59 |
60 | 0
61 |
62 |
63 | disk
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | {Template OS MyLinux:check_disk_status.last(#3)}=0
79 | {HOST.NAME} 磁盘读写状态出现问题
80 |
81 | 0
82 | 4
83 |
84 | 0
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/template_mysql/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title:
4 | subtitle:
5 | date: 2016-11-07 14:42:31
6 | category:
7 | author: 遇见王斌
8 | tags:
9 | -
10 | ---
11 | ```
12 | CREATE TABLE 't_zabbix' ('insert_timestamp' TIMESTAMP (8) );
13 | ```
14 |
--------------------------------------------------------------------------------
/template_mysql/install/conf/MySQL.conf:
--------------------------------------------------------------------------------
1 | ## mysql-status for mysql @20160125
2 | UserParameter=mysql.status[*],python /usr/lib/zabbix/externalscripts/mysql_status.py -i $1
3 |
4 | ## MySQL for Check MySQL Function @20160125
5 | UserParameter=mysql.function[*],python /usr/lib/zabbix/externalscripts/mysql_func.py -i $1
6 |
7 | ## MySQL for Perf @20160126
8 | UserParameter=mysql.perf[*],python /usr/lib/zabbix/externalscripts/mysql_perf.py -i $1
9 |
--------------------------------------------------------------------------------
/template_mysql/install/install.sh:
--------------------------------------------------------------------------------
1 | # conf
2 | mkdir -p /etc/zabbix/zabbix_agentd.d/
3 | cp conf/*.conf /etc/zabbix/zabbix_agentd.d/
4 |
5 | # scripts
6 | mkdir -p /usr/lib/zabbix/externalscripts/
7 | cp -rf scripts/* /usr/lib/zabbix/externalscripts/
8 | cp -rf scripts/.mysql.ini /usr/lib/zabbix/externalscripts/
9 | chmod +x -R /usr/lib/zabbix/externalscripts/
10 |
11 | # UnsafeUserParameters=1
12 | CHECK=`grep "^Include=/etc/zabbix/zabbix_agentd.d/" /etc/zabbix/zabbix_agentd.conf|wc -l`
13 | if [[ "w$CHECK" == "w0" ]]
14 | then
15 | echo 'Include=/etc/zabbix/zabbix_agentd.d/' >> /etc/zabbix/zabbix_agentd.conf
16 | fi
17 |
18 | # UnsafeUserParameters=1
19 | CHECK=`grep "^UnsafeUserParameters=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
20 | if [[ "w$CHECK" == "w0" ]]
21 | then
22 | sed -ri '/UnsafeUserParameters=/a UnsafeUserParameters=1' /etc/zabbix/zabbix_agentd.conf
23 | fi
24 |
25 | # Timeout=10
26 | CHECK=`grep "^Timeout=3" /etc/zabbix/zabbix_agentd.conf|wc -l`
27 | if [[ "w$CHECK" == "w0" ]]
28 | then
29 | sed -ri '/Timeout=3/a Timeout=10' /etc/zabbix/zabbix_agentd.conf
30 | fi
31 |
32 | # AllowRoot=1
33 | CHECK=`grep "^AllowRoot=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
34 | if [[ "w$CHECK" == "w0" ]]
35 | then
36 | sed -ri '/AllowRoot=0/a AllowRoot=1' /etc/zabbix/zabbix_agentd.conf
37 | fi
38 | /etc/init.d/zabbix-agent restart
39 |
--------------------------------------------------------------------------------
/template_mysql/install/scripts/.mysql.ini:
--------------------------------------------------------------------------------
1 | [mysql]
2 | ip = 127.0.0.1
3 | port = 3306
4 | user = test
5 | password = test
6 | [log]
7 | logpath = /tmp/zabbix_mysql_func.log
8 | [bin]
9 | mysql_path = /usr/bin/mysql
10 | mysqladmin_path = /usr/bin/mysqladmin
11 |
12 |
--------------------------------------------------------------------------------
/template_mysql/install/scripts/my_lib/QCmd.py:
--------------------------------------------------------------------------------
1 | #-*- encoding:utf-8 -*-
2 | '''
3 | @author: qiueer
4 | '''
5 | import re, types
6 | import platform
7 |
8 |
9 | def docmd(command,timeout=300, debug=False, raw=False):
10 | '''
11 | 功能:
12 | 执行命令
13 | 参数:command,命令以及其参数/选项
14 | timeout,命令超时时间,单位秒
15 | debug,是否debug,True输出debug信息,False不输出
16 | raw,命令输出是否为元素的输出,True是,False会将结果的每一行去除空格、换行符、制表符等,默认False
17 | 返回:
18 | 含有3个元素的元组,前两个元素类型是list,第三个元素类型是int,第一个list存储stdout的输出,第二个list存储stderr的输出,第三int存储命令执行的返回码,其中-1表示命令执行超时
19 | 示例:
20 | cmd.docmd("ls -alt")
21 | '''
22 | import subprocess, datetime, os, time, signal
23 | start = datetime.datetime.now()
24 |
25 | ps = None
26 | retcode = 0
27 | if platform.system() == "Linux":
28 | ps = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
29 | else:
30 | ps = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
31 | while ps.poll() is None:
32 | time.sleep(0.2)
33 | now = datetime.datetime.now()
34 | if (now - start).seconds > timeout:
35 | os.kill(ps.pid, signal.SIGINT)
36 | retcode = -1
37 | return (None,None,retcode)
38 | stdo = ps.stdout.readlines()
39 | stde = ps.stderr.readlines()
40 |
41 | if not ps.returncode:
42 | retcode = ps.returncode
43 |
44 | if raw == True: #去除行末换行符
45 | stdo = [line.strip("\n") for line in stdo]
46 | stde = [line.strip("\n") for line in stde]
47 |
48 | if raw == False: #去除行末换行符,制表符、空格等
49 | stdo = [str.strip(line) for line in stdo]
50 | stde = [str.strip(line) for line in stde]
51 | return (stdo,stde,retcode)
52 |
53 |
54 | def docmd_ex(command,timeout=300, debug=False, raw=False, pure=True):
55 | '''
56 | 功能:
57 | 执行命令
58 | 参数:command,命令以及其参数/选项
59 | timeout,命令超时时间,单位秒
60 | debug,是否debug,True输出debug信息,False不输出
61 | raw,命令输出是否为元素的输出,True是,False会将结果的每一行去除空格、换行符、制表符等,默认False
62 | 返回:
63 | 含有3个元素的元组,前两个元素类型是list,第三个元素类型是int,第一个list存储stdout的输出,第二个list存储stderr的输出,第三int存储命令执行的返回码,其中-1表示命令执行超时
64 | 示例:
65 | cmd.docmd("ls -alt")
66 | '''
67 | import subprocess, datetime, os, time, signal
68 | start = datetime.datetime.now()
69 | (stdo,stde, retcode) = ([], [], -1)
70 | ps = None
71 | if platform.system() == "Linux":
72 | ps = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
73 | else:
74 | ps = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
75 | while ps.poll() is None:
76 | time.sleep(0.2)
77 | now = datetime.datetime.now()
78 | if (now - start).seconds > timeout:
79 | os.kill(ps.pid, signal.SIGINT)
80 | return None,None,-1
81 |
82 | if pure == True:
83 | stdo = ps.stdout.read()
84 | stde = ps.stderr.read()
85 | elif pure == False:
86 | stdo = ps.stdout.readlines()
87 | stde = ps.stderr.readlines()
88 |
89 | retcode = ps.returncode
90 |
91 | if raw == True and pure == False: #去除行末换行符
92 | stdo = [line.strip("\n") for line in stdo]
93 | stde = [line.strip("\n") for line in stde]
94 |
95 | if raw == False and pure == False: #去除行末换行符,制表符、空格等
96 | stdo = [str.strip(line) for line in stdo]
97 | stde = [str.strip(line) for line in stde]
98 |
99 | return stdo,stde,retcode
100 |
101 | def docmds(commands,timeout=300, debug=False, raw=False):
102 | '''
103 | 功能:执行多个命令,每个命令之间用 , 或 ; 号分割
104 | 返回:哈希,key为每个命令,key对应的value为一元组,元组值请参看docmd的说明
105 | '''
106 | cmds = re.split('[,;]+' , commands)
107 | result = {}
108 | for cmdline in cmds:
109 | (stdo,stde,retcode) = docmd(cmdline, timeout, debug=debug, raw=raw)
110 | result[cmdline] = (stdo,stde,retcode)
111 | return result
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/template_mysql/install/scripts/my_lib/QLog.py:
--------------------------------------------------------------------------------
1 | #encoding=UTF8
2 | '''
3 | Created on 2016年1月19日
4 |
5 | @author: qiujingqin
6 | '''
7 |
8 | import sys
9 | import logging
10 | from logging.handlers import RotatingFileHandler
11 | import os
12 |
13 | class ColoredFormatter(logging.Formatter):
14 | '''A colorful formatter.'''
15 |
16 | def __init__(self, fmt = None, datefmt = None):
17 | logging.Formatter.__init__(self, fmt, datefmt)
18 | # Color escape string
19 | COLOR_RED='\033[1;31m'
20 | COLOR_GREEN='\033[1;32m'
21 | COLOR_YELLOW='\033[1;33m'
22 | COLOR_BLUE='\033[1;34m'
23 | COLOR_PURPLE='\033[1;35m'
24 | COLOR_CYAN='\033[1;36m'
25 | COLOR_GRAY='\033[1;37m'
26 | COLOR_WHITE='\033[1;38m'
27 | COLOR_RESET='\033[1;0m'
28 |
29 | # Define log color
30 | self.LOG_COLORS = {
31 | 'DEBUG': '%s',
32 | 'INFO': COLOR_GREEN + '%s' + COLOR_RESET,
33 | 'WARNING': COLOR_YELLOW + '%s' + COLOR_RESET,
34 | 'ERROR': COLOR_RED + '%s' + COLOR_RESET,
35 | 'CRITICAL': COLOR_RED + '%s' + COLOR_RESET,
36 | 'EXCEPTION': COLOR_RED + '%s' + COLOR_RESET,
37 | }
38 |
39 | def format(self, record):
40 | level_name = record.levelname
41 | msg = logging.Formatter.format(self, record)
42 |
43 | return self.LOG_COLORS.get(level_name, '%s') % msg
44 |
45 | class Log(object):
46 |
47 | '''
48 | log
49 | '''
50 | def __init__(self, filename, level="debug", logid="qiueer", mbs=20, count=10, is_console=True):
51 | '''
52 | mbs: how many MB
53 | count: the count of remain
54 | '''
55 | try:
56 | self._level = level
57 | #print "init,level:",level,"\t","get_map_level:",self._level
58 | self._filename = filename
59 | self._logid = logid
60 |
61 | self._logger = logging.getLogger(self._logid)
62 |
63 |
64 | if not len(self._logger.handlers):
65 | self._logger.setLevel(self.get_map_level(self._level))
66 |
67 | fmt = '[%(asctime)s] %(levelname)s\n%(message)s'
68 | datefmt = '%Y-%m-%d %H:%M:%S'
69 | formatter = logging.Formatter(fmt, datefmt)
70 |
71 | maxBytes = int(mbs) * 1024 * 1024
72 | file_handler = RotatingFileHandler(self._filename, mode='a',maxBytes=maxBytes,backupCount=count)
73 | self._logger.setLevel(self.get_map_level(self._level))
74 | file_handler.setFormatter(formatter)
75 | self._logger.addHandler(file_handler)
76 |
77 | if is_console == True:
78 | stream_handler = logging.StreamHandler(sys.stderr)
79 | console_formatter = ColoredFormatter(fmt, datefmt)
80 | stream_handler.setFormatter(console_formatter)
81 | self._logger.addHandler(stream_handler)
82 |
83 | except Exception as expt:
84 | print expt
85 |
86 | def tolog(self, msg, level=None):
87 | try:
88 | level = level if level else self._level
89 | level = str(level).lower()
90 | level = self.get_map_level(level)
91 | if level == logging.DEBUG:
92 | self._logger.debug(msg)
93 | if level == logging.INFO:
94 | self._logger.info(msg)
95 | if level == logging.WARN:
96 | self._logger.warn(msg)
97 | if level == logging.ERROR:
98 | self._logger.error(msg)
99 | if level == logging.CRITICAL:
100 | self._logger.critical(msg)
101 | except Exception as expt:
102 | print expt
103 |
104 | def debug(self,msg):
105 | self.tolog(msg, level="debug")
106 |
107 | def info(self,msg):
108 | self.tolog(msg, level="info")
109 |
110 | def warn(self,msg):
111 | self.tolog(msg, level="warn")
112 |
113 | def error(self,msg):
114 | self.tolog(msg, level="error")
115 |
116 | def critical(self,msg):
117 | self.tolog(msg, level="critical")
118 |
119 | def get_map_level(self,level="debug"):
120 | level = str(level).lower()
121 | #print "get_map_level:",level
122 | if level == "debug":
123 | return logging.DEBUG
124 | if level == "info":
125 | return logging.INFO
126 | if level == "warn":
127 | return logging.WARN
128 | if level == "error":
129 | return logging.ERROR
130 | if level == "critical":
131 | return logging.CRITICAL
132 |
133 |
--------------------------------------------------------------------------------
/template_mysql/install/scripts/my_lib/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- encoding=utf-8 -*-
2 |
--------------------------------------------------------------------------------
/template_mysql/install/scripts/mysql_func.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #encoding=UTF8
3 | '''
4 | @author: 遇见王斌
5 | 2016-11-06
6 |
7 | 功能:检测 mysql 是否可写
8 |
9 | 测试方法
10 | #python mysql_func.py -i is_can_write
11 | '''
12 |
13 | import commands
14 | import sys
15 | import os
16 | from optparse import OptionParser
17 | import re
18 |
19 | from my_lib.QLog import Log
20 | from my_lib import QCmd
21 | import ConfigParser
22 |
23 | class Mysql(object):
24 | def __init__(self,debug=True):
25 | config = ConfigParser.ConfigParser()
26 | config.read(".mysql.ini")
27 | self._iphost = config.get("mysql", "ip")
28 | self._username = config.get("mysql","user")
29 | self._password = config.get("mysql","password")
30 | self._port = config.get("mysql","port")
31 | self.logpath = config.get("log","logpath")
32 | self._mysql_path = config.get("bin","mysql_path")
33 | self._logger = Log(self.logpath,is_console=debug, mbs=10, count=5)
34 |
35 | def get_logger(self):
36 | return self._logger
37 |
38 | def get_mysql_cmd_output(self, cmdstr, hostname=None,username=None,password=None,port=None):
39 | try:
40 | hostname= hostname if hostname else self._iphost
41 | username = username if username else self._username
42 | passwd = password if password else self._password
43 | port = port if port else self._port
44 |
45 | mysql_bin_path = "mysql"
46 | if os.path.isfile(self._mysql_path):
47 | mysql_bin_path = self._mysql_path
48 | sql_cmstr = '%s -h%s -P%s -u%s -p%s -e "%s"' % (mysql_bin_path,hostname,port,username, passwd, cmdstr)
49 |
50 | (stdo,stde,retcode) = QCmd.docmd(sql_cmstr, timeout=1, raw=True)
51 | #(ret, result) = commands.getstatusoutput(sql_cmstr)
52 |
53 | logstr = "sql_cmdstr:%s\nret:%s\nstdo:%s\nstde:%s" % (sql_cmstr, retcode, stdo, stde)
54 | if retcode == 0:
55 | self._logger.info(logstr)
56 | return stdo
57 | else:
58 | self._logger.error(logstr)
59 | result = None
60 |
61 | return result
62 | except Exception as expt:
63 | import traceback
64 | tb = traceback.format_exc()
65 | self._logger.error(tb)
66 |
67 | def get_item_from_sql_output(self,result, item):
68 | try:
69 | if not result:
70 | return '0'
71 |
72 | output_list = re.split("[\n]+", str(result).strip())
73 | item = str(item).lower().strip()
74 | for line in output_list:
75 | line = str(line).strip().replace(" ", "").lower().strip("|")
76 | line_ary = re.split("\|", line)
77 | if item == line_ary[0]:
78 | return line_ary[1]
79 | return '0'
80 | except Exception as expt:
81 | import traceback
82 | tb = traceback.format_exc()
83 | self._logger.error(tb)
84 |
85 | def is_mysql_can_write(self, hostname=None, port=None):
86 | cmdstr = "insert into test.t_zabbix(insert_timestamp)values(current_timestamp());"
87 | result = self.get_mysql_cmd_output(cmdstr,hostname=hostname,port=port)
88 | if result == None: ## 超时写入,判定为不可写入
89 | return 0
90 | return 1
91 |
92 |
93 | def main():
94 |
95 | usage = "usage: %prog [options]\n Check MySQL Function"
96 | parser = OptionParser(usage)
97 | parser.add_option("-d", "--debug",
98 | action="store_true", dest="debug", default=False,
99 | help="if output all process")
100 | parser.add_option("-i",
101 | "--item",
102 | action="store",
103 | dest="item",
104 | type="string",
105 | default='Uptime',
106 | help="which item to fetch")
107 |
108 | (options, args) = parser.parse_args()
109 | if 1 >= len(sys.argv):
110 | parser.print_help()
111 | return
112 |
113 | mysql = Mysql(debug=options.debug)
114 | try:
115 |
116 | item = options.item
117 | if item == "is_can_write":
118 | print mysql.is_mysql_can_write()
119 | #print mysql.get_item_val(options.item)
120 |
121 | except Exception as expt:
122 | import traceback
123 | tb = traceback.format_exc()
124 | mysql.get_logger().error(tb)
125 |
126 |
127 | if __name__ == '__main__':
128 | root_path = os.path.split(os.path.realpath(__file__))[0]
129 | os.chdir(root_path)
130 | main()
131 |
--------------------------------------------------------------------------------
/template_mysql/install/scripts/mysql_perf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #encoding=UTF8
3 | '''
4 | @author: 遇见王斌
5 | 2016-11-06
6 | '''
7 |
8 | import commands
9 | import sys
10 | import os
11 | from optparse import OptionParser
12 | import re
13 | import ConfigParser
14 |
15 | from my_lib.QLog import Log
16 |
17 | class Mysql(object):
18 | def __init__(self,debug=True):
19 | config = ConfigParser.ConfigParser()
20 | config.read(".mysql.ini")
21 | self._iphost = config.get("mysql", "ip")
22 | self._username = config.get("mysql","user")
23 | self._password = config.get("mysql","password")
24 | self._port = config.get("mysql","port")
25 | self.logpath = config.get("log","logpath")
26 | self._mysqladmin_path = config.get("bin","mysqladmin_path")
27 | self._logger = Log(self.logpath,is_console=debug, mbs=5, count=5)
28 | self._sql_result = self._get_mysql_cmd_output()
29 |
30 | def get_logger(self):
31 | return self._logger
32 |
33 | def _get_mysql_cmd_output(self, hostname=None,username=None,password=None,port=None):
34 | try:
35 | hostname= hostname if hostname else self._iphost
36 | username = username if username else self._username
37 | passwd = password if password else self._password
38 | port = port if port else self._port
39 |
40 | cmdstr = "extended-status"
41 | mysql_path = "mysqladmin"
42 | if os.path.isfile(self._mysqladmin_path):
43 | mysql_path = self._mysqladmin_path
44 | sql_cmstr = '%s -h%s -P%s -u%s -p%s %s' % (mysql_path,hostname,port,username,passwd, cmdstr)
45 | (ret, result) = commands.getstatusoutput(sql_cmstr)
46 |
47 | logstr = "sql_cmdstr:%s\nret:%s\nresult:%s\n" % (sql_cmstr,ret,result)
48 | if ret == 0:
49 | self._logger.info(logstr)
50 | return result
51 | else:
52 | self._logger.error(logstr)
53 | result = None
54 |
55 | return result
56 | except Exception as expt:
57 | import traceback
58 | tb = traceback.format_exc()
59 | self._logger.error(tb)
60 |
61 | def _get_item_from_sql_output(self, item):
62 | try:
63 | result = self._sql_result
64 | if not result:
65 | return '0'
66 |
67 | output_list = re.split("[\n]+", str(result).strip())
68 | item = str(item).lower().strip()
69 | for line in output_list:
70 | line = str(line).strip().replace(" ", "").lower().strip("|")
71 | line_ary = re.split("\|", line)
72 | if item == line_ary[0]:
73 | return line_ary[1]
74 |
75 | return '0'
76 | except Exception as expt:
77 | import traceback
78 | tb = traceback.format_exc()
79 | self._logger.error(tb)
80 |
81 | def get_item_val(self,item):
82 | return self._get_item_from_sql_output(item)
83 |
84 | def get_item_tval(self, item, val_type="int"):
85 | val = self.get_item_val(item)
86 | if val_type == "int":
87 | return int(val)
88 | if val_type == "float":
89 | fval = "%.2f" % (val)
90 | return float(fval)
91 | if val_type == "str":
92 | return str(val)
93 |
94 | return int(val)
95 |
96 | def get_keybuf_read_hit_rate(self):
97 | """
98 | key Buffer 命中率 -- 读
99 | """
100 | key_reads = self.get_item_tval("key_reads")
101 | key_read_requests = self.get_item_tval("key_read_requests")
102 |
103 | if key_read_requests == 0:
104 | return 100.0
105 |
106 | hitrate = "%.2f" % ((1 - key_reads/float(key_read_requests))*100)
107 | return float(hitrate)
108 |
109 | def get_keybuf_write_hit_rate(self):
110 | """
111 | key Buffer 命中率 -- 写
112 | """
113 | key_writes = self.get_item_tval("key_writes")
114 | key_write_requests = self.get_item_tval("key_write_requests")
115 |
116 | if key_write_requests == 0:
117 | return 100.0
118 |
119 | hitrate = "%.2f" % ((1 - key_writes/float(key_write_requests))*100)
120 | return float(hitrate)
121 |
122 | def get_innodbbuf_read_hit_rate(self):
123 | """
124 | Innodb Buffer 命中率 -- 写
125 | """
126 | innodb_buffer_pool_reads = self.get_item_tval("innodb_buffer_pool_reads")
127 | innodb_buffer_pool_read_requests = self.get_item_tval("innodb_buffer_pool_read_requests")
128 |
129 | if innodb_buffer_pool_read_requests == 0:
130 | return 100.0
131 |
132 | hitrate = "%.2f" % ((1 - innodb_buffer_pool_reads/float(innodb_buffer_pool_read_requests))*100)
133 | return float(hitrate)
134 |
135 | def get_query_hit_rate(self):
136 | """
137 | Query Cache命中率
138 | """
139 | Qcache_hits = self.get_item_tval("Qcache_hits")
140 | Qcache_inserts = self.get_item_tval( "Qcache_inserts")
141 |
142 | total = int(Qcache_hits) + int(Qcache_inserts)
143 | if total == 0:
144 | return 100.0
145 |
146 | hitrate = "%.2f" % (Qcache_hits/float(total)*100)
147 | return float(hitrate)
148 |
149 | def get_thread_cache_hit_rate(self):
150 | """
151 | Thread Cache命中率
152 | """
153 | Threads_created = self.get_item_tval("Threads_created")
154 | Connections = self.get_item_tval( "Connections")
155 |
156 | if Connections == 0:
157 | return 100.0
158 |
159 | hitrate = "%.2f" % ((1-Threads_created/float(Connections))*100)
160 | return float(hitrate)
161 |
162 | def get_lock_scale(self):
163 | """
164 | Table_locks_waited/Table_locks_immediate=0.3% 如果这个比值比较大的话,说明表锁造成的阻塞比较严重
165 | """
166 | Table_locks_waited = self.get_item_tval("Table_locks_waited")
167 | Table_locks_immediate = self.get_item_tval( "Table_locks_immediate")
168 | if Table_locks_immediate == 0:
169 | return 100.0
170 | hitrate = Table_locks_waited/float(Table_locks_immediate)*100
171 | hitrate = "%.2f" % (hitrate)
172 | return float(hitrate)
173 |
174 | def get_table_scale(self):
175 | """
176 | Created_tmp_disk_tables/Created_tmp_tables比值最好不要超过10%,如果Created_tmp_tables值比较大, 可能是排序句子过多或者是连接句子不够优化
177 | """
178 | Created_tmp_disk_tables = self.get_item_tval("Created_tmp_disk_tables")
179 | Created_tmp_tables = self.get_item_tval( "Created_tmp_tables")
180 | if Created_tmp_tables == 0:
181 | return 100.0
182 | hitrate = Created_tmp_disk_tables/float(Created_tmp_tables)*100
183 | hitrate = "%.2f" % (hitrate)
184 | return float(hitrate)
185 |
186 |
187 | def main():
188 |
189 | usage = "usage: %prog [options]\n Fetch mysql status"
190 | parser = OptionParser(usage)
191 | parser.add_option("-d", "--debug",
192 | action="store_true", dest="debug", default=False,
193 | help="if output all process")
194 | parser.add_option("-i",
195 | "--item",
196 | action="store",
197 | dest="item",
198 | type="string",
199 | default='Uptime',
200 | help="which item to fetch")
201 |
202 | (options, args) = parser.parse_args()
203 | if 1 >= len(sys.argv):
204 | parser.print_help()
205 | return
206 |
207 | mysql = Mysql(debug=options.debug)
208 | try:
209 | item = options.item
210 | keys = ["Key_read_hitrate", "Key_write_hitrate", "Innodb_buf_read_hitrate", "Query_hitrate"]
211 | if item == "Key_read_hitrate":
212 | print mysql.get_keybuf_read_hit_rate()
213 | if item == "Key_write_hitrate":
214 | print mysql.get_keybuf_write_hit_rate()
215 | if item == "Innodb_buf_read_hitrate":
216 | print mysql.get_innodbbuf_read_hit_rate()
217 | if item == "Query_hitrate":
218 | print mysql.get_query_hit_rate()
219 | if item == "Thread_cached_hitrate":
220 | print mysql.get_thread_cache_hit_rate()
221 | if item == "Lock_status":
222 | print mysql.get_lock_scale()
223 | if item == "Tmp_table_status":
224 | print mysql.get_table_scale()
225 |
226 | except Exception as expt:
227 | import traceback
228 | tb = traceback.format_exc()
229 | mysql.get_logger().error(tb)
230 |
231 |
232 | if __name__ == '__main__':
233 | root_path = os.path.split(os.path.realpath(__file__))[0]
234 | os.chdir(root_path)
235 | main()
236 |
--------------------------------------------------------------------------------
/template_mysql/install/scripts/mysql_status.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #encoding=UTF8
3 | '''
4 | @author: 遇见王斌
5 | 2016-01-19
6 | '''
7 |
8 | import commands
9 | import sys
10 | import os
11 | from optparse import OptionParser
12 | import re
13 | import ConfigParser
14 |
15 | from my_lib.QLog import Log
16 |
17 | class Mysql(object):
18 |
19 | def __init__(self,debug=True):
20 | config = ConfigParser.ConfigParser()
21 | config.read(".mysql.ini")
22 | self._iphost = config.get("mysql", "ip")
23 | self._username = config.get("mysql","user")
24 | self._password = config.get("mysql","password")
25 | self._port = config.get("mysql","port")
26 | self.logpath = config.get("log","logpath")
27 | self._mysqladmin_path = config.get("bin","mysqladmin_path")
28 | self._logger = Log(self.logpath,is_console=debug)
29 |
30 | def get_logger(self):
31 | return self._logger
32 |
33 |
34 | def get_mysql_cmd_output(self, hostname=None,username=None,password=None,port=None):
35 | try:
36 | hostname= hostname if hostname else self._iphost
37 | username = username if username else self._username
38 | passwd = password if password else self._password
39 | port = port if port else self._port
40 |
41 | cmdstr = "extended-status"
42 | mysql_path = "mysqladmin"
43 | if os.path.isfile(self._mysqladmin_path):
44 | mysql_path = self._mysqladmin_path
45 | sql_cmstr = '%s -h%s -P%s -u%s -p%s %s' % (mysql_path,hostname,port,username,passwd, cmdstr)
46 | (ret, result) = commands.getstatusoutput(sql_cmstr)
47 |
48 | logstr = "sql_cmdstr:%s\nret:%s\nresult:%s\n" % (sql_cmstr,ret,result)
49 | if ret == 0:
50 | self._logger.info(logstr)
51 | return result
52 | else:
53 | self._logger.error(logstr)
54 | result = None
55 |
56 | return result
57 | except Exception as expt:
58 | import traceback
59 | tb = traceback.format_exc()
60 | self._logger.error(tb)
61 |
62 | def get_item_from_sql_output(self,result, item):
63 | try:
64 | if not result:
65 | return '0'
66 |
67 | output_list = re.split("[\n]+", str(result).strip())
68 | item = str(item).lower().strip()
69 | for line in output_list:
70 | line = str(line).strip().replace(" ", "").lower().strip("|")
71 | line_ary = re.split("\|", line)
72 | if item == line_ary[0]:
73 | return line_ary[1]
74 |
75 | return '0'
76 | except Exception as expt:
77 | import traceback
78 | tb = traceback.format_exc()
79 | self._logger.error(tb)
80 |
81 | def get_item_val(self, item, hostname=None, port=None):
82 | result = self.get_mysql_cmd_output(hostname=hostname,port=port)
83 | return self.get_item_from_sql_output(result,item)
84 |
85 |
86 | def main():
87 |
88 | usage = "usage: %prog [options]\n Fetch mysql status"
89 | parser = OptionParser(usage)
90 | parser.add_option("-d", "--debug",
91 | action="store_true", dest="debug", default=False,
92 | help="if output all process")
93 | parser.add_option("-i",
94 | "--item",
95 | action="store",
96 | dest="item",
97 | type="string",
98 | default='Uptime',
99 | help="which item to fetch")
100 |
101 | (options, args) = parser.parse_args()
102 | if 1 >= len(sys.argv):
103 | parser.print_help()
104 | return
105 |
106 | mysql = Mysql(debug=options.debug)
107 | try:
108 | print mysql.get_item_val(options.item)
109 |
110 | except Exception as expt:
111 | import traceback
112 | tb = traceback.format_exc()
113 | mysql.get_logger().error(tb)
114 |
115 |
116 | if __name__ == '__main__':
117 | root_path = os.path.split(os.path.realpath(__file__))[0]
118 | os.chdir(root_path)
119 | main()
120 |
--------------------------------------------------------------------------------
/template_raid/README.md:
--------------------------------------------------------------------------------
1 | ## template_raid
2 |
3 |
4 | * [1 使用](#1-使用)
5 | * [1.1 安装](#11-安装)
6 | * [1.2 检验](#12-检验)
7 | * [1.2.1 agent 端检验](#121-agent-端检验)
8 | * [1.2.2 server 端检验](#122-server-端检验)
9 | * [2 原理](#2-原理)
10 | * [2.1 megacli](#21-megacli)
11 | * [2.2 监控值说明](#22-监控值说明)
12 | * [3 版本](#3-版本)
13 | * [4 相关项目](#4-相关项目)
14 |
15 |
16 |
17 | ## 1 使用
18 |
19 | ### 1.1 安装
20 |
21 | **agent**
22 |
23 | install 中安装执行 install.sh
24 |
25 | **server**
26 |
27 | * 导入 templates 的模板
28 |
29 | * 对要监控的机器关联 templates 模板
30 |
31 | ### 1.2 检验
32 | #### 1.2.1 agent 端检验
33 | 在 agent 上查看检测到的硬盘标号
34 | ```
35 | /usr/lib/zabbix/externalscripts/raid.py pd_discovery
36 | ```
37 | #### 1.2.2 server 端检验
38 | ```
39 | zabbix_get -s 10.20.129.183 -k raid.phy.discovery
40 | ```
41 | 将其中 IP 更换为对应 IP 即可
42 |
43 | ## 2 原理
44 |
45 | * install 里面安装的程序是可以使 agent 采集到要监控的数据
46 | * templates 中包括了要监控机器要监控的指标及报警条件,导入后关联要监控的主机即可
47 |
48 | ### 2.1 megacli
49 |
50 | megacli 程序需要 sudo 权限执行
51 |
52 | ### 2.2 监控值说明
53 |
54 | > * 监控项应用名为`MegaRAID`
55 | > * 物理磁盘使用`/opt/MegaRAID/MegaCli/MegaCli64 -PDList -aALL -nolog` 中的 `Device Id` 作为标识符
56 | > * 逻辑磁盘使用`/opt/MegaRAID/MegaCli/MegaCli64 -LDInfo -Lall -aALL -nolog` 中的 `Virtual Drive`作为标识符
57 |
58 | |监控项|key|更新时间|历史数据保留时间|趋势数据保留时间|触发器|
59 | |---|---|---|---|---|---|
60 | |物理磁盘状态|raid.phy.fw_state[{#DISK_ID}]|1m|7d|365d|Unconfigured(bad),Failed(连续3次)
61 | |物理磁盘mec|raid.phy.mec[{#DISK_ID}]|2m|7d|365d|>30(连续3次)|
62 | |物理磁盘oec|raid.phy.oec[{#DISK_ID}]|2m|7d|365d|>1000(连续3次)|
63 | |物理磁盘pfc|raid.phy.pfc[{#DISK_ID}]|2m|7d|365d|>2(连续3次)|
64 | |逻辑磁盘状态|raid.ld.state[{#LD_ID}]|1m|7d|365d|不是Optimal状态(连续3次)|
65 |
66 | ## 3 版本
67 |
68 | * v1.0.3 20171104: 添加对逻辑磁盘的监控
69 | * v1.0.2 --------: 优化执行速度
70 |
71 | ## 4 相关项目
72 |
73 | * raid 终端查看工具 [megacli_tui](https://github.com/BillWang139967/megacli_tui)
74 |
--------------------------------------------------------------------------------
/template_raid/install/conf/disk.conf:
--------------------------------------------------------------------------------
1 | UserParameter=raid.phy.discovery,sudo python /usr/lib/zabbix/externalscripts/raid.py pd_discovery
2 | UserParameter=raid.phy.mec[*],sudo python /usr/lib/zabbix/externalscripts/raid.py media_error_count $1
3 | UserParameter=raid.phy.oec[*],sudo python /usr/lib/zabbix/externalscripts/raid.py other_error_count $1
4 | UserParameter=raid.phy.pfc[*],sudo python /usr/lib/zabbix/externalscripts/raid.py predictive_error_count $1
5 | UserParameter=raid.phy.fw_state[*],sudo python /usr/lib/zabbix/externalscripts/raid.py fw_state $1
6 | UserParameter=raid.ld.discovery,sudo python /usr/lib/zabbix/externalscripts/raid.py ld_discovery
7 | UserParameter=raid.ld.state[*],sudo python /usr/lib/zabbix/externalscripts/raid.py ld_state $1
8 |
--------------------------------------------------------------------------------
/template_raid/install/conf/raid.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #coding=utf8
3 | """
4 | # Author: meetbill
5 | # Created Time : 2017-11-03 00:54:10
6 |
7 | # File Name: raid.py
8 | # Description:
9 |
10 | """
11 | import commands
12 | import os
13 | import sys
14 | import json
15 |
16 |
17 | MEGACLI_EXEC = '/opt/MegaRAID/MegaCli/MegaCli64'
18 | LIST_DISK_OPT = '-PDList -aALL -NoLog'
19 | LIST_LDDISK_OPT = '-LDInfo -Lall -aALL -NoLog'
20 |
21 | SLOT_NUMBER = 'Slot Number'
22 | DEVICE_ID = 'Device Id'
23 | WWN = 'WWN'
24 | MEC = 'Media Error Count'
25 | OEC = 'Other Error Count'
26 | PFC = 'Predictive Failure Count'
27 | PD_TYPE = 'PD Type'
28 | FIRMWARE_STATE = 'Firmware state'
29 |
30 |
31 | def _check_megacli(cli_path):
32 | if not os.path.exists(cli_path) or not os.access(cli_path, os.X_OK):
33 | print 'MegaCLI is needed in %s with executable priviledge.' % (cli_path)
34 | sys.exit(1)
35 | def _line_generator(string):
36 | line = []
37 | for c in string:
38 | if c != '\n':
39 | line.append(c)
40 | else:
41 | yield ''.join(line)
42 | line = []
43 | def _get_value(line):
44 | return line.split(':')[1].strip()
45 | def _make_disk_dict(mega_output):
46 | disk_dict_all = {}
47 | for line in _line_generator(mega_output):
48 | if line.startswith(SLOT_NUMBER):
49 | slot_number = _get_value(line)
50 | elif line.startswith(DEVICE_ID):
51 | dev_id = _get_value(line)
52 | elif line.startswith(MEC):
53 | mec = _get_value(line)
54 | elif line.startswith(OEC):
55 | oec = _get_value(line)
56 | elif line.startswith(PFC):
57 | pfc = _get_value(line)
58 | elif line.startswith(PD_TYPE):
59 | pd_type = _get_value(line)
60 | elif line.startswith(FIRMWARE_STATE):
61 | fw_state = _get_value(line)
62 |
63 | device_dict = {}
64 | device_dict["slot_number"] = slot_number
65 | device_dict["dev_id"] = dev_id
66 | device_dict["mec"] = mec
67 | device_dict["oec"] = oec
68 | device_dict["pfc"] = pfc
69 | device_dict["pd_type"] = pd_type
70 | device_dict["fw_state"] = fw_state
71 |
72 | disk_dict_all[dev_id]=device_dict
73 | return disk_dict_all
74 | def _make_lddisk_dict(mega_output):
75 | ld_dict_all = {}
76 | for line in _line_generator(mega_output):
77 | if line.startswith("Virtual Drive"):
78 | ld_id = _get_value(line).split(' ')[0]
79 | elif line.startswith("State"):
80 | ld_state = _get_value(line)
81 |
82 | ld_dict = {}
83 | ld_dict["ld_id"] = ld_id
84 | ld_dict["ld_state"] = ld_state
85 |
86 | ld_dict_all[ld_id]=ld_dict
87 | return ld_dict_all
88 | def _get_disk_dict():
89 | _check_megacli(MEGACLI_EXEC)
90 | (status, output) = commands.getstatusoutput('%s %s' % (MEGACLI_EXEC, LIST_DISK_OPT))
91 | if status != 0:
92 | print 'Exec MegaCLI failed, please check the log.'
93 | sys.exit(1)
94 | #print output
95 | disk_dict = _make_disk_dict(output)
96 | return disk_dict
97 | def _get_ld_dict():
98 | _check_megacli(MEGACLI_EXEC)
99 | (status, output) = commands.getstatusoutput('%s %s' % (MEGACLI_EXEC, LIST_LDDISK_OPT))
100 | if status != 0:
101 | print 'Exec MegaCLI failed, please check the log.'
102 | sys.exit(1)
103 | #print output
104 | ld_dict_all = _make_lddisk_dict(output)
105 | return ld_dict_all
106 | def pd_discovery():
107 | """
108 | discovery_physical_disk
109 | """
110 | disk_dict_all = _get_disk_dict()
111 | array = []
112 | for dev_id in disk_dict_all:
113 | disk = {}
114 | disk['{#DISK_ID}'] = disk_dict_all[dev_id]["dev_id"]
115 | disk['{#SLOT_NUMBER}'] = disk_dict_all[dev_id]["slot_number"]
116 | array.append(disk)
117 | return json.dumps({'data': array}, indent=4, separators=(',',':'))
118 | def media_error_count(disk_id):
119 | disk_dict_all = _get_disk_dict()
120 | try:
121 | return disk_dict_all[disk_id]["mec"]
122 | except:
123 | return '-1'
124 | def other_error_count(disk_id):
125 | disk_dict_all = _get_disk_dict()
126 | try:
127 | return disk_dict_all[disk_id]["oec"]
128 | except:
129 | return '-1'
130 | def predictive_error_count(disk_id):
131 | disk_dict_all = _get_disk_dict()
132 | try:
133 | return disk_dict_all[disk_id]["pfc"]
134 | except:
135 | return '-1'
136 | def fw_state(disk_id):
137 | disk_dict_all = _get_disk_dict()
138 | try:
139 | fw = disk_dict_all[disk_id]["fw_state"]
140 | if fw == "Unconfigured(bad)" or fw.startswith("Failed"):
141 | return 0
142 | else:
143 | return 1
144 | except:
145 | return '-1'
146 |
147 | def ld_discovery():
148 | """
149 | discovery_logical_disk
150 | """
151 | ld_dict_all = _get_ld_dict()
152 | array = []
153 | for ld_id in ld_dict_all:
154 | disk = {}
155 | disk['{#LD_ID}'] = ld_dict_all[ld_id]["ld_id"]
156 | array.append(disk)
157 | return json.dumps({'data': array}, indent=4, separators=(',',':'))
158 | def ld_state(ld_id):
159 | ld_dict_all = _get_ld_dict()
160 | try:
161 | ldstatus = ld_dict_all[ld_id]["ld_state"]
162 | if ldstatus == "Optimal":
163 | return 1
164 | else:
165 | return 0
166 | except:
167 | return '-1'
168 |
169 | if __name__ == '__main__':
170 | import sys, inspect
171 | if len(sys.argv) < 2:
172 | print "Usage(1.0.2):"
173 | for k, v in sorted(globals().items(), key=lambda item: item[0]):
174 | if inspect.isfunction(v) and k[0] != "_":
175 | args, __, __, defaults = inspect.getargspec(v)
176 | if defaults:
177 | print sys.argv[0], k, str(args[:-len(defaults)])[1:-1].replace(",", ""), \
178 | str(["%s=%s" % (a, b) for a, b in zip(args[-len(defaults):], defaults)])[1:-1].replace(",", "")
179 | else:
180 | print sys.argv[0], k, str(v.func_code.co_varnames[:v.func_code.co_argcount])[1:-1].replace(",", "")
181 | sys.exit(-1)
182 | else:
183 | func = eval(sys.argv[1])
184 | args = sys.argv[2:]
185 | try:
186 | r = func(*args)
187 | print r
188 | except Exception, e:
189 | print "Usage:"
190 | print "\t", "python %s" % sys.argv[1], str(func.func_code.co_varnames[:func.func_code.co_argcount])[1:-1].replace(",", "")
191 | if func.func_doc:
192 | print "\n".join(["\t\t" + line.strip() for line in func.func_doc.strip().split("\n")])
193 | print e
194 | r = -1
195 | import traceback
196 | traceback.print_exc()
197 | if isinstance(r, int):
198 | sys.exit(r)
199 |
--------------------------------------------------------------------------------
/template_raid/install/install.sh:
--------------------------------------------------------------------------------
1 | mkdir -p /etc/zabbix/zabbix_agentd.conf.d/
2 | cp conf/disk.conf /etc/zabbix/zabbix_agentd.conf.d
3 |
4 | mkdir -p /usr/lib/zabbix/externalscripts/
5 | cp conf/raid.py /usr/lib/zabbix/externalscripts/
6 | chmod +x /usr/lib/zabbix/externalscripts/raid.py
7 | if [[ ! -f "/etc/sudoers.d/zabbix" ]]
8 | then
9 | echo 'zabbix ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/zabbix
10 | fi
11 |
12 | # config dir
13 | CHECK=`grep "^Include=/etc/zabbix/zabbix_agentd.conf.d/" /etc/zabbix/zabbix_agentd.conf|wc -l`
14 | if [[ "w$CHECK" == "w0" ]]
15 | then
16 | echo 'Include=/etc/zabbix/zabbix_agentd.conf.d/' >> /etc/zabbix/zabbix_agentd.conf
17 | fi
18 |
19 | # UnsafeUserParameters=1
20 | CHECK=`grep "^UnsafeUserParameters=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
21 | if [[ "w$CHECK" == "w0" ]]
22 | then
23 | sed -ri '/UnsafeUserParameters=/a UnsafeUserParameters=1' /etc/zabbix/zabbix_agentd.conf
24 | fi
25 |
26 | # Timeout=10
27 | CHECK=`grep "^Timeout=3" /etc/zabbix/zabbix_agentd.conf|wc -l`
28 | if [[ "w$CHECK" == "w0" ]]
29 | then
30 | sed -ri '/Timeout=3/a Timeout=10' /etc/zabbix/zabbix_agentd.conf
31 | fi
32 |
33 | # AllowRoot=1
34 | CHECK=`grep "^AllowRoot=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
35 | if [[ "w$CHECK" == "w0" ]]
36 | then
37 | sed -ri '/AllowRoot=0/a AllowRoot=1' /etc/zabbix/zabbix_agentd.conf
38 | fi
39 |
40 | rpm -ivh ./linux/MegaCli-8.07.14-1.noarch.rpm
41 |
42 | if [[ -e "/etc/init.d/zabbix-agent" ]]
43 | then
44 | /etc/init.d/zabbix-agent restart
45 | else
46 | systemctl restart zabbix-agentd.service
47 | fi
48 |
--------------------------------------------------------------------------------
/template_raid/install/linux/MegaCli-8.07.14-1.noarch.rpm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meetbill/zabbix_templates/8a43e1efe404206617e91917843b263ef608d890/template_raid/install/linux/MegaCli-8.07.14-1.noarch.rpm
--------------------------------------------------------------------------------
/template_raid/install/linux/readme.txt:
--------------------------------------------------------------------------------
1 | rpm -ivh MegaCli-8.07.14-1.noarch.rpm
2 |
--------------------------------------------------------------------------------
/template_raid/templates/meetbill_raid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 3.0
4 | 2017-11-07T07:01:57Z
5 |
6 |
7 | meetbill
8 |
9 |
10 |
11 |
12 | Template Raid
13 | Template Raid
14 |
15 |
16 |
17 | meetbill
18 |
19 |
20 |
21 |
22 | MegaRAID
23 |
24 |
25 |
26 |
27 |
28 | Logical Disk Discovery
29 | 7
30 |
31 |
32 | raid.ld.discovery
33 | 3600
34 | 0
35 |
36 |
37 |
38 | 0
39 | 0
40 |
41 | 0
42 |
43 |
44 |
45 |
46 | 0
47 |
48 |
49 |
50 |
51 |
52 |
53 | 0
54 |
55 |
56 |
57 | {#DISK_ID}
58 |
59 | 8
60 | A
61 |
62 |
63 |
64 | 30
65 |
66 |
67 |
68 | Logical disk state on $1
69 | 7
70 |
71 | 0
72 |
73 | raid.ld.state[{#LD_ID}]
74 | 60
75 | 7
76 | 365
77 | 0
78 | 3
79 |
80 |
81 | 0
82 |
83 |
84 | 0
85 | 0
86 |
87 | 0
88 |
89 | 1
90 |
91 |
92 |
93 | 0
94 | 0
95 |
96 |
97 |
98 |
99 |
100 |
101 | 0
102 |
103 |
104 | MegaRAID
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | {Template Raid:raid.ld.state[{#LD_ID}].last(#3)}=0
115 | Logical Disk State Check on [{#LD_ID}]
116 |
117 | 0
118 | 4
119 |
120 | 0
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | Physical Disk Discovery
129 | 7
130 |
131 |
132 | raid.phy.discovery
133 | 3600
134 | 0
135 |
136 |
137 |
138 | 0
139 | 0
140 |
141 | 0
142 |
143 |
144 |
145 |
146 | 0
147 |
148 |
149 |
150 |
151 |
152 |
153 | 0
154 |
155 |
156 |
157 | {#DISK_ID}
158 |
159 | 8
160 | A
161 |
162 |
163 |
164 | 30
165 |
166 |
167 |
168 | Physical disks Fw State on $1
169 | 7
170 |
171 | 0
172 |
173 | raid.phy.fw_state[{#DISK_ID}]
174 | 60
175 | 7
176 | 365
177 | 0
178 | 3
179 |
180 |
181 | 0
182 |
183 |
184 | 0
185 | 0
186 |
187 | 0
188 |
189 | 1
190 |
191 |
192 |
193 | 0
194 | 0
195 |
196 |
197 |
198 |
199 |
200 |
201 | 0
202 |
203 |
204 | MegaRAID
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 | Media Error Count on $1
213 | 7
214 |
215 | 0
216 |
217 | raid.phy.mec[{#DISK_ID}]
218 | 120
219 | 7
220 | 365
221 | 0
222 | 3
223 |
224 |
225 | 0
226 |
227 |
228 | 0
229 | 0
230 |
231 | 0
232 |
233 | 1
234 |
235 |
236 |
237 | 0
238 | 0
239 |
240 |
241 |
242 |
243 |
244 |
245 | 0
246 |
247 |
248 | MegaRAID
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 | OtherrError Count on $1
257 | 7
258 |
259 | 0
260 |
261 | raid.phy.oec[{#DISK_ID}]
262 | 120
263 | 7
264 | 365
265 | 0
266 | 3
267 |
268 |
269 | 0
270 |
271 |
272 | 0
273 | 0
274 |
275 | 0
276 |
277 | 1
278 |
279 |
280 |
281 | 0
282 | 0
283 |
284 |
285 |
286 |
287 |
288 |
289 | 0
290 |
291 |
292 | MegaRAID
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 | Predictive Error Count on $1
301 | 7
302 |
303 | 0
304 |
305 | raid.phy.pfc[{#DISK_ID}]
306 | 120
307 | 7
308 | 365
309 | 0
310 | 3
311 |
312 |
313 | 0
314 |
315 |
316 | 0
317 | 0
318 |
319 | 0
320 |
321 | 1
322 |
323 |
324 |
325 | 0
326 | 0
327 |
328 |
329 |
330 |
331 |
332 |
333 | 0
334 |
335 |
336 | MegaRAID
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 | {Template Raid:raid.phy.mec[{#DISK_ID}].last(#3)}>30
347 | Media Error Count Check [{#DISK_ID}]
348 |
349 | 0
350 | 2
351 |
352 | 0
353 |
354 |
355 |
356 | {Template Raid:raid.phy.oec[{#DISK_ID}].last(#3)}>1000
357 | Other Error Count Check {#DISK_ID}
358 |
359 | 0
360 | 2
361 |
362 | 0
363 |
364 |
365 |
366 | {Template Raid:raid.phy.fw_state[{#DISK_ID}].last(,3)}=0
367 | Physical disks fw state Check {#DISK_ID}
368 |
369 | 0
370 | 2
371 |
372 | 0
373 |
374 |
375 |
376 | {Template Raid:raid.phy.pfc[{#DISK_ID}].last(#3)}>2
377 | Predictive Error Count Check {#DISK_ID}
378 |
379 | 0
380 | 2
381 |
382 | 0
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
--------------------------------------------------------------------------------
/template_redis/README.md:
--------------------------------------------------------------------------------
1 | ## template_redis
2 |
3 | * [1 安装](#1-安装)
4 | * [2 检验](#2-检验)
5 | * [3 原理](#3-原理)
6 | * [4 运维修改](#4-运维修改)
7 | * [5 说明](#5-说明)
8 |
9 |
10 |
11 | ## 1 安装
12 |
13 |
14 | **agent**
15 |
16 | install中安装执行install.sh
17 |
18 | 修改agent检测程序中redis客户端位置
19 |
20 | /usr/lib/zabbix/externalscripts/redis.py
21 | ```
22 | pbinpaths = [
23 | "/usr/local/bin/redis-cli",
24 | ]
25 |
26 | ```
27 |
28 | **server**
29 |
30 | * 导入templates的模板
31 |
32 | * 对要监控的机器关联templates模板
33 |
34 | ## 2 检验
35 |
36 | 获取本机器redis端口
37 | ```
38 | /usr/lib/zabbix/externalscripts/redis.py -l
39 | ```
40 | 获取本机器redis 使用内存
41 | ```
42 | /usr/lib/zabbix/externalscripts/redis.py -p 6379 -k used_memory
43 | ```
44 |
45 | ## 3 原理
46 |
47 | * install里面安装的程序是可以使agent采集到要监控的数据
48 | * templates中包括了要监控机器要监控的指标及报警条件,导入后关联要监控的主机即可
49 |
50 | ## 4 运维修改
51 |
52 | (1)本程序默认设置AllowRoot=1,即允许使用root身份运行zabbix-agent
53 |
54 | 若需要使用普通用户运行,则需要以下设置
55 |
56 | 在sudoers中添加zabbix用户
57 | ```
58 | echo "zabbix ALL=(root) NOPASSWD:/bin/netstat" > /etc/sudoers.d/zabbix
59 | echo 'Defaults:zabbix !requiretty' >> /etc/sudoers.d/zabbix
60 | chmod 600 /etc/sudoers.d/zabbix
61 | ```
62 |
63 | (2)如果连接redis需要账号密码,则需要配置端口、账号、密码的对应关系,配置文件路径如下:
64 |
65 | /usr/local/public-ops/conf/.redis.passwd
66 |
67 | 内容如下:
68 | 6379 passwd
69 |
70 | (3)程序默认为只汇报指定端口redis
71 |
72 |
73 | 修改方式如下:
74 |
75 | /usr/lib/zabbix/externalscripts/redis.py
76 |
77 | ```
78 | port_list=[6379]
79 | ```
80 |
81 | ## 5 说明
82 |
83 | > * 检测时间:1m
84 | > * history保留时间:14d
85 | > * trend保留时间:365d
86 |
--------------------------------------------------------------------------------
/template_redis/install/conf/redis.conf:
--------------------------------------------------------------------------------
1 | ## qjq redis-stat for discovery @20151123
2 | UserParameter=custom.redis.discovery,python /usr/lib/zabbix/externalscripts/redis.py --list
3 | UserParameter=custom.redis.item[*],python /usr/lib/zabbix/externalscripts/redis.py -p $1 -k $2
4 |
--------------------------------------------------------------------------------
/template_redis/install/conf/redis.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #coding=utf8
3 | """
4 | # Author: Bill
5 | # Created Time : 2016-08-08 13:33:47
6 |
7 | # File Name: redis.py
8 | # Description:
9 |
10 | """
11 |
12 | import commands
13 | import sys
14 | from optparse import OptionParser
15 | import re
16 | import platform
17 |
18 | import logging
19 | from logging.handlers import RotatingFileHandler
20 | import os
21 |
22 | #{{{docmd
23 | def docmd(command,timeout=300, raw=False):
24 | '''
25 | 功能:
26 | 执行命令
27 | 参数:command,命令以及其参数/选项
28 | timeout,命令超时时间,单位秒
29 | debug,是否debug,True输出debug信息,False不输出
30 | raw,命令输出是否为元素的输出,True是,False会将结果的每一行去除空格、换行符、制表符等,默认False
31 | 返回:
32 | 含有3个元素的元组,前两个元素类型是list,第三个元素类型是int,第一个list存储stdout的输出,第二个list存储stderr的输出,第三int存储命令执行的返回码,其中-1表示命令执行超时
33 | 示例:
34 | cmd.docmd("ls -alt")
35 | '''
36 | import subprocess, datetime, os, time, signal
37 | start = datetime.datetime.now()
38 |
39 | ps = None
40 | retcode = 0
41 | if platform.system() == "Linux":
42 | ps = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
43 | else:
44 | ps = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
45 | while ps.poll() is None:
46 | time.sleep(0.2)
47 | now = datetime.datetime.now()
48 | if (now - start).seconds > timeout:
49 | os.kill(ps.pid, signal.SIGINT)
50 | retcode = -1
51 | return (None,None,retcode)
52 | stdo = ps.stdout.readlines()
53 | stde = ps.stderr.readlines()
54 |
55 | if not ps.returncode:
56 | retcode = ps.returncode
57 |
58 | if raw == True: #去除行末换行符
59 | stdo = [line.strip("\n") for line in stdo]
60 | stde = [line.strip("\n") for line in stde]
61 |
62 | if raw == False: #去除行末换行符,制表符、空格等
63 | stdo = [str.strip(line) for line in stdo]
64 | stde = [str.strip(line) for line in stde]
65 |
66 | return (stdo,stde,retcode)
67 | #}}}
68 | #{{{get_logstr
69 | def get_logstr(list_dict, max_key_len=16, join_str="\n"):
70 | log_str = ""
71 | for conf in list_dict:
72 | for (key,val) in dict(conf).iteritems():
73 | log_str = log_str + str(key).ljust(max_key_len) + ": " + str(val) + join_str
74 | log_str = log_str.strip() # 去掉尾部 \n
75 | return log_str
76 | #}}}
77 | #{{{ColoredFormatter
78 | class ColoredFormatter(logging.Formatter):
79 | '''A colorful formatter.'''
80 |
81 | def __init__(self, fmt = None, datefmt = None):
82 | logging.Formatter.__init__(self, fmt, datefmt)
83 | # Color escape string
84 | COLOR_RED='\033[1;31m'
85 | COLOR_GREEN='\033[1;32m'
86 | COLOR_YELLOW='\033[1;33m'
87 | COLOR_BLUE='\033[1;34m'
88 | COLOR_PURPLE='\033[1;35m'
89 | COLOR_CYAN='\033[1;36m'
90 | COLOR_GRAY='\033[1;37m'
91 | COLOR_WHITE='\033[1;38m'
92 | COLOR_RESET='\033[1;0m'
93 |
94 | # Define log color
95 | self.LOG_COLORS = {
96 | 'DEBUG': '%s',
97 | 'INFO': COLOR_GREEN + '%s' + COLOR_RESET,
98 | 'WARNING': COLOR_YELLOW + '%s' + COLOR_RESET,
99 | 'ERROR': COLOR_RED + '%s' + COLOR_RESET,
100 | 'CRITICAL': COLOR_RED + '%s' + COLOR_RESET,
101 | 'EXCEPTION': COLOR_RED + '%s' + COLOR_RESET,
102 | }
103 |
104 | def format(self, record):
105 | level_name = record.levelname
106 | msg = logging.Formatter.format(self, record)
107 |
108 | return self.LOG_COLORS.get(level_name, '%s') % msg
109 | #}}}
110 | #{{{Log
111 | class Log(object):
112 | '''
113 | log
114 | '''
115 | def __init__(self, filename, level="debug", logid="qiueer", mbs=20, count=10,is_console=False):
116 | '''
117 | mbs: how many MB
118 | count: the count of remain
119 | '''
120 | try:
121 | self._level = level
122 | self._filename = filename
123 | self._logid = logid
124 | self._logger = logging.getLogger(self._logid)
125 |
126 | if not len(self._logger.handlers):
127 | self._logger.setLevel(self.get_map_level(self._level))
128 |
129 | fmt = '[%(asctime)s] %(levelname)s\n%(message)s'
130 | datefmt = '%Y-%m-%d %H:%M:%S'
131 | formatter = logging.Formatter(fmt, datefmt)
132 |
133 | maxBytes = int(mbs) * 1024 * 1024
134 | file_handler = RotatingFileHandler(self._filename, mode='a',maxBytes=maxBytes,backupCount=count)
135 | self._logger.setLevel(self.get_map_level(self._level))
136 | file_handler.setFormatter(formatter)
137 | self._logger.addHandler(file_handler)
138 |
139 | if is_console == True:
140 | stream_handler = logging.StreamHandler(sys.stderr)
141 | console_formatter = ColoredFormatter(fmt, datefmt)
142 | stream_handler.setFormatter(console_formatter)
143 | self._logger.addHandler(stream_handler)
144 |
145 | except Exception as expt:
146 | print expt
147 |
148 | def tolog(self, msg, level=None):
149 | try:
150 | level = level if level else self._level
151 | level = str(level).lower()
152 | level = self.get_map_level(level)
153 | if level == logging.DEBUG:
154 | self._logger.debug(msg)
155 | if level == logging.INFO:
156 | self._logger.info(msg)
157 | if level == logging.WARN:
158 | self._logger.warn(msg)
159 | if level == logging.ERROR:
160 | self._logger.error(msg)
161 | if level == logging.CRITICAL:
162 | self._logger.critical(msg)
163 | except Exception as expt:
164 | print expt
165 |
166 | def debug(self,msg):
167 | self.tolog(msg, level="debug")
168 |
169 | def info(self,msg):
170 | self.tolog(msg, level="info")
171 |
172 | def warn(self,msg):
173 | self.tolog(msg, level="warn")
174 |
175 | def error(self,msg):
176 | self.tolog(msg, level="error")
177 |
178 | def critical(self,msg):
179 | self.tolog(msg, level="critical")
180 |
181 | def get_map_level(self,level="debug"):
182 | level = str(level).lower()
183 | #print "get_map_level:",level
184 | if level == "debug":
185 | return logging.DEBUG
186 | if level == "info":
187 | return logging.INFO
188 | if level == "warn":
189 | return logging.WARN
190 | if level == "error":
191 | return logging.ERROR
192 | if level == "critical":
193 | return logging.CRITICAL
194 |
195 | #}}}
196 | #{{{Redis
197 | class Redis(object):
198 | def __init__(self, logpath, password=None, port=6379, debug=False):
199 | self._logpath = logpath
200 | self._password = password
201 | self._port = port if port else 6379
202 | self._debug = debug
203 | self._logger = Log(logpath,level="error",is_console=self._debug,mbs=5,count=3)
204 |
205 | def get_redis_port_list(self,port_list=""):
206 | # sudo权限,必须授予
207 | # [root@localhost ~]# tail -n 2 /etc/sudoers
208 | # Defaults:zabbix !requiretty
209 | # zabbix ALL=(root) NOPASSWD:/bin/netstat
210 | data = list()
211 | if port_list:
212 | for port in port_list:
213 | data.append({"{#REDIS_PORT}": port})
214 |
215 | else:
216 | cmdstr = "netstat -nlpt | grep 'redis-server' | awk '{print $4}'|awk -F: '{print $2}'|uniq"
217 | disk_space_info = []
218 | (stdo_list, stde_list, retcode) = docmd(cmdstr, timeout=3, raw = False)
219 |
220 | log_da = [{"cmdstr": cmdstr},{"ret": retcode},{"stdo": "".join(stdo_list)}, {"stde": "".join(stde_list)}]
221 | logstr = get_logstr(log_da, max_key_len=10)
222 |
223 | if retcode !=0:
224 | self._logger.error(logstr)
225 | return disk_space_info
226 | else:
227 | self._logger.info(logstr)
228 |
229 | data = list()
230 |
231 | for port in stdo_list:
232 | port = int(str(port).strip())
233 | data.append({"{#REDIS_PORT}": port})
234 | import json
235 | return json.dumps({'data': data}, sort_keys=True, indent=7, separators=(",",":"))
236 |
237 | def get_item(self, key, port=None, password=None):
238 | """
239 | 参数:
240 | """
241 | # cmdstr = "redis-cli -h 127.0.0.1 -p 6379 info | grep 'used_cpu_sys' "
242 | port = port if port else self._port
243 | password = password if password else self._password
244 | pbinpaths = [
245 | "/usr/local/bin/redis-cli",
246 | ]
247 |
248 | cmdstr = None
249 | for bp in pbinpaths:
250 | if os.path.exists(bp):
251 | if password:
252 | cmdstr = "%s -h 127.0.0.1 -a %s -p %s info | grep '%s' " % (bp,password, port, key)
253 | else:
254 | cmdstr = "%s -h 127.0.0.1 -p %s info | grep '%s' " % (bp,port, key)
255 | break
256 | if not cmdstr:
257 | print "the redis-cli not find"
258 | return None
259 |
260 | (stdo_list, stde_list, retcode) = docmd(cmdstr, timeout=5, raw = False)
261 |
262 | log_da = [{"cmdstr": cmdstr},{"ret": retcode},{"stdo": "".join(stdo_list)}, {"stde": "".join(stde_list)}]
263 | logstr = get_logstr(log_da, max_key_len=10)
264 |
265 | if retcode !=0:
266 | self._logger.error(logstr)
267 | return None
268 | else:
269 | self._logger.info(logstr)
270 |
271 | for line in stdo_list:
272 | line = str(line).strip()
273 | ln_ary = re.split(":", line)
274 | if ln_ary and len(ln_ary) != 2:continue
275 | dst_key = str(ln_ary[0]).strip()
276 | dst_val = str(ln_ary[1]).strip()
277 | if key == dst_key:
278 | return dst_val
279 | return None
280 | #}}}
281 | def main():
282 | try:
283 | usage = "usage: %prog [options]\ngGet Redis Stat"
284 | parser = OptionParser(usage)
285 |
286 | parser.add_option("-l", "--list",
287 | action="store_true", dest="is_list", default=False,
288 | help="if list all redis port")
289 |
290 | parser.add_option("-k",
291 | "--key",
292 | action="store",
293 | dest="key",
294 | type="string",
295 | default='blocked_clients',
296 | help="execute 'redis-cli info' to see more infomation")
297 |
298 | parser.add_option("-a",
299 | "--password",
300 | action="store",
301 | dest="password",
302 | type="string",
303 | default="",
304 | help="the password for redis-server")
305 |
306 | parser.add_option("-p",
307 | "--port",
308 | action="store",
309 | dest="port",
310 | type="int",
311 | default=None,
312 | help="the port for redis-server, for example: 6379")
313 |
314 | parser.add_option("-d", "--debug",
315 | action="store_true", dest="debug", default=False,
316 | help="if output all")
317 |
318 | (options, args) = parser.parse_args()
319 | if 1 >= len(sys.argv):
320 | parser.print_help()
321 | return
322 |
323 | logpath = "/tmp/zabbix_redis_info.log"
324 |
325 | redis_ins = Redis(logpath, password=options.password, port=options.port, debug=options.debug)
326 | #################start
327 | port_list=[6379]
328 | if options.is_list == True:
329 | print redis_ins.get_redis_port_list(port_list)
330 | return
331 |
332 | print redis_ins.get_item(options.key)
333 |
334 | except Exception as expt:
335 | import traceback
336 | tb = traceback.format_exc()
337 | print tb
338 |
339 | if __name__ == '__main__':
340 | main()
341 |
--------------------------------------------------------------------------------
/template_redis/install/install.sh:
--------------------------------------------------------------------------------
1 | # conf
2 | mkdir -p /etc/zabbix/zabbix_agentd.d/
3 | cp conf/redis.conf /etc/zabbix/zabbix_agentd.d/
4 |
5 | # scripts
6 | mkdir -p /usr/lib/zabbix/externalscripts/
7 | cp conf/redis.py /usr/lib/zabbix/externalscripts/
8 | chmod 777 /usr/lib/zabbix/externalscripts/redis.py
9 |
10 | # UnsafeUserParameters=1
11 | CHECK=`grep "^Include=/etc/zabbix/zabbix_agentd.d/" /etc/zabbix/zabbix_agentd.conf|wc -l`
12 | if [[ "w$CHECK" == "w0" ]]
13 | then
14 | echo 'Include=/etc/zabbix/zabbix_agentd.d/' >> /etc/zabbix/zabbix_agentd.conf
15 | fi
16 |
17 | # UnsafeUserParameters=1
18 | CHECK=`grep "^UnsafeUserParameters=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
19 | if [[ "w$CHECK" == "w0" ]]
20 | then
21 | sed -ri '/UnsafeUserParameters=/a UnsafeUserParameters=1' /etc/zabbix/zabbix_agentd.conf
22 | fi
23 |
24 | # Timeout=10
25 | CHECK=`grep "^Timeout=3" /etc/zabbix/zabbix_agentd.conf|wc -l`
26 | if [[ "w$CHECK" == "w0" ]]
27 | then
28 | sed -ri '/Timeout=3/a Timeout=10' /etc/zabbix/zabbix_agentd.conf
29 | fi
30 |
31 | # AllowRoot=1
32 | CHECK=`grep "^AllowRoot=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
33 | if [[ "w$CHECK" == "w0" ]]
34 | then
35 | sed -ri '/AllowRoot=0/a AllowRoot=1' /etc/zabbix/zabbix_agentd.conf
36 | fi
37 | /etc/init.d/zabbix-agent restart
38 |
--------------------------------------------------------------------------------
/template_redis/templates/templates_redis.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 3.0
4 | 2016-08-15T16:04:32Z
5 |
6 |
7 | Templates
8 |
9 |
10 |
11 |
12 | TPL-business-redis-discovery
13 | 业务-Redis-自动发现
14 |
15 |
16 |
17 | Templates
18 |
19 |
20 |
21 |
22 | app-redis-discovery
23 |
24 |
25 |
26 |
27 |
28 | Redis-性能数据
29 | 0
30 |
31 |
32 | custom.redis.discovery
33 | 60
34 | 0
35 |
36 |
37 |
38 | 0
39 | 0
40 |
41 | 0
42 |
43 |
44 |
45 |
46 | 0
47 |
48 |
49 |
50 |
51 |
52 |
53 | 0
54 |
55 |
56 |
57 | {#REDIS_PORT}
58 |
59 | 8
60 | A
61 |
62 |
63 |
64 | 30
65 |
66 |
67 |
68 | [$1]Redis-性能数据-堵塞的链接数
69 | 0
70 |
71 | 0
72 |
73 | custom.redis.item[{#REDIS_PORT},blocked_clients]
74 | 60
75 | 14
76 | 365
77 | 0
78 | 3
79 |
80 |
81 | 0
82 |
83 |
84 | 0
85 | 0
86 |
87 | 0
88 |
89 | 1
90 |
91 |
92 |
93 | 0
94 | 0
95 |
96 |
97 |
98 |
99 |
100 |
101 | 0
102 |
103 |
104 | app-redis-discovery
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | [$1]Redis-性能数据-已链接的链接数
113 | 0
114 |
115 | 0
116 |
117 | custom.redis.item[{#REDIS_PORT},connected_clients]
118 | 60
119 | 14
120 | 365
121 | 0
122 | 3
123 |
124 |
125 | 0
126 |
127 |
128 | 0
129 | 0
130 |
131 | 0
132 |
133 | 1
134 |
135 |
136 |
137 | 0
138 | 0
139 |
140 |
141 |
142 |
143 |
144 |
145 | 0
146 |
147 |
148 | app-redis-discovery
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | [$1]Redis-性能数据-没有命中Key的次数
157 | 0
158 |
159 | 0
160 |
161 | custom.redis.item[{#REDIS_PORT},keyspace_misses]
162 | 60
163 | 14
164 | 365
165 | 0
166 | 3
167 |
168 |
169 | 0
170 |
171 |
172 | 0
173 | 0
174 |
175 | 0
176 |
177 | 1
178 |
179 |
180 |
181 | 0
182 | 0
183 |
184 |
185 |
186 |
187 |
188 |
189 | 0
190 |
191 |
192 | app-redis-discovery
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 | [$1]Redis-性能数据-$2
201 | 0
202 |
203 | 0
204 |
205 | custom.redis.item[{#REDIS_PORT},lru_clock]
206 | 60
207 | 14
208 | 365
209 | 0
210 | 3
211 |
212 |
213 | 0
214 |
215 |
216 | 0
217 | 0
218 |
219 | 0
220 |
221 | 1
222 |
223 |
224 |
225 | 0
226 | 0
227 |
228 |
229 |
230 |
231 |
232 |
233 | 0
234 |
235 |
236 | app-redis-discovery
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 | [$1]Redis-性能数据-内存碎片比
245 | 0
246 |
247 | 0
248 |
249 | custom.redis.item[{#REDIS_PORT},mem_fragmentation_ratio]
250 | 60
251 | 14
252 | 365
253 | 0
254 | 0
255 |
256 |
257 | 0
258 |
259 |
260 | 0
261 | 0
262 |
263 | 0
264 |
265 | 1
266 |
267 |
268 |
269 | 0
270 | 0
271 |
272 |
273 |
274 |
275 |
276 |
277 | 0
278 |
279 |
280 | app-redis-discovery
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 | [$1]Redis-性能数据-拒绝的链接数
289 | 0
290 |
291 | 0
292 |
293 | custom.redis.item[{#REDIS_PORT},rejected_connections]
294 | 60
295 | 14
296 | 365
297 | 0
298 | 3
299 |
300 |
301 | 0
302 |
303 |
304 | 0
305 | 0
306 |
307 | 0
308 |
309 | 1
310 |
311 |
312 |
313 | 0
314 | 0
315 |
316 |
317 |
318 |
319 |
320 |
321 | 0
322 |
323 |
324 | app-redis-discovery
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 | [$1]Redis-性能数据-QPS
333 | 0
334 |
335 | 0
336 |
337 | custom.redis.item[{#REDIS_PORT},total_commands_processed]
338 | 60
339 | 14
340 | 365
341 | 0
342 | 3
343 |
344 |
345 | 1
346 |
347 |
348 | 0
349 | 0
350 |
351 | 0
352 |
353 | 1
354 |
355 |
356 |
357 | 0
358 | 0
359 |
360 |
361 |
362 |
363 |
364 |
365 | 0
366 |
367 |
368 | app-redis-discovery
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 | [$1]Redis-性能数据-收到的总链接数
377 | 0
378 |
379 | 0
380 |
381 | custom.redis.item[{#REDIS_PORT},total_connections_received]
382 | 60
383 | 14
384 | 365
385 | 0
386 | 0
387 |
388 |
389 | 1
390 |
391 |
392 | 0
393 | 0
394 |
395 | 0
396 |
397 | 1
398 |
399 |
400 |
401 | 0
402 | 0
403 |
404 |
405 |
406 |
407 |
408 |
409 | 0
410 |
411 |
412 | app-redis-discovery
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 | [$1]Redis-性能数据-内存总量
421 | 0
422 |
423 | 0
424 |
425 | custom.redis.item[{#REDIS_PORT},used_memory]
426 | 60
427 | 14
428 | 365
429 | 0
430 | 3
431 |
432 |
433 | 0
434 |
435 |
436 | 0
437 | 0
438 |
439 | 0
440 |
441 | 1
442 |
443 |
444 |
445 | 0
446 | 0
447 |
448 |
449 |
450 |
451 |
452 |
453 | 0
454 |
455 |
456 | app-redis-discovery
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 | [$1]Redis-性能数据-内存高峰值
465 | 0
466 |
467 | 0
468 |
469 | custom.redis.item[{#REDIS_PORT},used_memory_peak]
470 | 60
471 | 14
472 | 365
473 | 0
474 | 3
475 |
476 |
477 | 0
478 |
479 |
480 | 0
481 | 0
482 |
483 | 0
484 |
485 | 1
486 |
487 |
488 |
489 | 0
490 | 0
491 |
492 |
493 |
494 |
495 |
496 |
497 | 0
498 |
499 |
500 | app-redis-discovery
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 | [$1]Redis-性能数据-物理内存总量
509 | 0
510 |
511 | 0
512 |
513 | custom.redis.item[{#REDIS_PORT},used_memory_rss]
514 | 60
515 | 14
516 | 365
517 | 0
518 | 3
519 |
520 |
521 | 0
522 |
523 |
524 | 0
525 | 0
526 |
527 | 0
528 |
529 | 1
530 |
531 |
532 |
533 | 0
534 | 0
535 |
536 |
537 |
538 |
539 |
540 |
541 | 0
542 |
543 |
544 | app-redis-discovery
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 | {TPL-business-redis-discovery:custom.redis.item[{#REDIS_PORT},used_memory_rss].last(#3)}>48318382080
555 | Redis_Buffer_Warning
556 |
557 | 0
558 | 4
559 |
560 | 0
561 |
562 |
563 |
564 |
565 |
566 | [{#REDIS_PORT}]::Redis-QPS
567 | 900
568 | 200
569 | 0.0000
570 | 100.0000
571 | 1
572 | 1
573 | 0
574 | 1
575 | 0
576 | 0.0000
577 | 0.0000
578 | 0
579 | 0
580 | 0
581 | 0
582 |
583 |
584 | 0
585 | 0
586 | 00C8C8
587 | 0
588 | 2
589 | 0
590 | -
591 | TPL-business-redis-discovery
592 | custom.redis.item[{#REDIS_PORT},total_commands_processed]
593 |
594 |
595 |
596 |
597 |
598 | [{#REDIS_PORT}]::Redis-内存
599 | 900
600 | 200
601 | 0.0000
602 | 100.0000
603 | 1
604 | 1
605 | 0
606 | 1
607 | 0
608 | 0.0000
609 | 0.0000
610 | 0
611 | 0
612 | 0
613 | 0
614 |
615 |
616 | 0
617 | 0
618 | 0000C8
619 | 0
620 | 2
621 | 0
622 | -
623 | TPL-business-redis-discovery
624 | custom.redis.item[{#REDIS_PORT},used_memory]
625 |
626 |
627 |
628 | 1
629 | 0
630 | C800C8
631 | 0
632 | 2
633 | 0
634 | -
635 | TPL-business-redis-discovery
636 | custom.redis.item[{#REDIS_PORT},used_memory_peak]
637 |
638 |
639 |
640 | 2
641 | 0
642 | 00C8C8
643 | 0
644 | 2
645 | 0
646 | -
647 | TPL-business-redis-discovery
648 | custom.redis.item[{#REDIS_PORT},used_memory_rss]
649 |
650 |
651 |
652 |
653 |
654 | [{#REDIS_PORT}]::Redis-链接数
655 | 900
656 | 200
657 | 0.0000
658 | 100.0000
659 | 1
660 | 1
661 | 0
662 | 1
663 | 0
664 | 0.0000
665 | 0.0000
666 | 0
667 | 0
668 | 0
669 | 0
670 |
671 |
672 | 0
673 | 0
674 | 00C800
675 | 0
676 | 2
677 | 0
678 | -
679 | TPL-business-redis-discovery
680 | custom.redis.item[{#REDIS_PORT},blocked_clients]
681 |
682 |
683 |
684 | 1
685 | 0
686 | C80000
687 | 0
688 | 2
689 | 0
690 | -
691 | TPL-business-redis-discovery
692 | custom.redis.item[{#REDIS_PORT},connected_clients]
693 |
694 |
695 |
696 | 2
697 | 0
698 | 0000C8
699 | 0
700 | 2
701 | 0
702 | -
703 | TPL-business-redis-discovery
704 | custom.redis.item[{#REDIS_PORT},rejected_connections]
705 |
706 |
707 |
708 | 3
709 | 0
710 | C800C8
711 | 0
712 | 2
713 | 0
714 | -
715 | TPL-business-redis-discovery
716 | custom.redis.item[{#REDIS_PORT},total_connections_received]
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
--------------------------------------------------------------------------------
/template_service/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## 应用自动注册
3 |
4 | * [1 说明](#1-说明)
5 | * [1.1 背景](#11-背景)
6 | * [1.2 使用](#12-使用)
7 | * [2 实现](#2-实现)
8 | * [2.1 客户端自动发现规则并上报自己机器上的应用](#21-客户端自动发现规则并上报自己机器上的应用)
9 | * [2.2 应用监控信息](#22-应用监控信息)
10 | * [3 原理](#3-原理)
11 | * [4 程序说明](#4-程序说明)
12 | * [5 二次开发](#5-二次开发)
13 | * [5.1 修改模板](#51-修改模板)
14 | * [5.2 agent 采集程序](#52-agent-采集程序)
15 |
16 |
17 |
18 |
19 | ## 1 说明
20 |
21 | ### 1.1 背景
22 |
23 | 服务部署时,需要自动将监控服务部署到服务器上,同时将需要监控的项目关联 OK ,所以有如下两种解决方案
24 |
25 | > * 服务端配置关联模板
26 | > * [操作:] 客户端机器自动注册后,通过 zabbix 服务端配置关联模板
27 | > * [优点:] 监控配置统一配置,集中管理
28 | > * 客户端机器通过 lld 自动上报服务
29 | > * [操作:] 客户端机器自动注册后,并自动关联(应用自动注册 lld) 模板,然后上报自己的监控项信息
30 | > * [优点:] 客户端机器新增机器时,无需配置 zabbix 服务端
31 | > * [缺点:] 客户端上报的应用信息有限,比如仅仅返回应用运行状态,应用版本号
32 |
33 | ### 1.2 使用
34 |
35 | **agent**
36 |
37 | install 中安装执行 install.sh
38 |
39 | **server**
40 |
41 | * 导入 templates 的模板
42 |
43 | * 对要监控的机器关联 templates 模板
44 |
45 | ## 2 实现
46 |
47 | 程序实现客户端机器通过 lld 自动上报服务
48 |
49 | ### 2.1 客户端自动发现规则并上报自己机器上的应用
50 |
51 | > * 应用名配置文件 /etc/zabbix/zabbix_service
52 | > * 配置文件规则 `应用名1|应用名2|应用名3`
53 |
54 | ### 2.2 应用监控信息
55 |
56 | zabbix server 根据应用名获取应用的监控项信息
57 |
58 | > * 应用运行状态
59 | > * 正常 0
60 | > * 警告 1
61 | > * 错误 2
62 | > * 没有找到对应key -1
63 | > * 未知状态 -2
64 | > * 应用版本号
65 | > * 没有获取到版本号 -1
66 | > * 版本号 xxx
67 |
68 |
69 | ## 3 原理
70 |
71 | * install 里面安装的程序是可以使 agent 采集到要监控的数据
72 | * templates 中包括了要监控机器要监控的指标及报警条件,导入后关联要监控的主机即可
73 |
74 | ## 4 程序说明
75 |
76 | 文件位置:./install/conf/service.py
77 |
78 | ```
79 | usage:
80 | service.py discovery # 输出程序中数组中的服务
81 | service.py discovery_file 'config_file' # 输出配置文件中中的服务,配置文件中将服务依次进行编写即可
82 | service.py server_status 'server_name' # 获取服务状态
83 | ```
84 | ## 5 二次开发
85 |
86 | ### 5.1 修改模板
87 |
88 | > * 模板名(Template name),如 service 修改为 s3
89 | > * 应用名(Application)a,如 service 修改为 s3
90 | > * 发现规则(Discovery rules),如 service.discovery 修改为 s3.discovery,当然 Name 部分也修改下
91 | > * 监控项原型的 Name 和 Key
92 | > * 触发器原型的 Name
93 |
94 | ### 5.2 agent 采集程序
95 |
96 | 编写对应的 discovery 以及不同服务返回的状态
97 |
--------------------------------------------------------------------------------
/template_service/install/conf/service.conf:
--------------------------------------------------------------------------------
1 | UserParameter=service.discovery,python /usr/lib/zabbix/externalscripts/service.py discovery
2 | UserParameter=service.[*],python /usr/lib/zabbix/externalscripts/service.py status $1
3 |
4 |
--------------------------------------------------------------------------------
/template_service/install/conf/service.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #coding=utf8
3 | """
4 | # Author: meetbill
5 | # Created Time : 2018-01-24 22:06:02
6 |
7 | # File Name: server.py
8 | # Description:
9 |
10 | """
11 |
12 | import os
13 | import sys
14 | import json
15 |
16 | server_array = ['xserver', 'reifs','xserver_guard']
17 | def discovery():
18 | array = []
19 | for d in server_array:
20 | disk = {}
21 | disk['{#SERVER_NAME}'] = d
22 | array.append(disk)
23 | print json.dumps({'data': array}, indent=4, separators=(',',':'))
24 |
25 | def discovery_file(config_file):
26 | server_array = []
27 | if os.path.exists(config_file):
28 | with open(config_file,"r") as f:
29 | for line in f.readlines():
30 | server_array.append(line.strip())
31 | array = []
32 | for d in server_array:
33 | disk = {}
34 | disk['{#SERVER_NAME}'] = d
35 | array.append(disk)
36 | print json.dumps({'data': array}, indent=4, separators=(',',':'))
37 |
38 | def server_status(server_name):
39 | if server_name == 'xserver':
40 | check=os.popen('ps -ef |grep -java |grep xserver |grep -v grep |wc -l').readlines()
41 | elif server_name == 'xserver_guard':
42 | check=os.popen('ps -ef |grep xserver_guard.py|grep -v grep | wc -l').readlines()
43 | elif server_name == 'reifs':
44 | check=os.popen('ps -ef |grep reifs |grep -v grep | wc -l').readlines()
45 | else:
46 | check=" "
47 | if check[0] < "1":
48 | return 0
49 | else:
50 | return 1
51 |
52 | if __name__ == '__main__':
53 | import inspect
54 | if len(sys.argv) < 2:
55 | print "Usage:"
56 | for k, v in sorted(globals().items(), key=lambda item: item[0]):
57 | if inspect.isfunction(v) and k[0] != "_":
58 | args, __, __, defaults = inspect.getargspec(v)
59 | if defaults:
60 | print sys.argv[0], k, str(args[:-len(defaults)])[1:-1].replace(",", ""), \
61 | str(["%s=%s" % (a, b) for a, b in zip(
62 | args[-len(defaults):], defaults)])[1:-1].replace(",", "")
63 | else:
64 | print sys.argv[0], k, str(v.func_code.co_varnames[:v.func_code.co_argcount])[1:-1].replace(",", "")
65 | sys.exit(-1)
66 | else:
67 | func = eval(sys.argv[1])
68 | args = sys.argv[2:]
69 | try:
70 | r = func(*args)
71 | except Exception, e:
72 | print "Usage:"
73 | print "\t", "python %s" % sys.argv[1], str(func.func_code.co_varnames[:func.func_code.co_argcount])[1:-1].replace(",", "")
74 | if func.func_doc:
75 | print "\n".join(["\t\t" + line.strip() for line in func.func_doc.strip().split("\n")])
76 | print e
77 | r = -1
78 | import traceback
79 | traceback.print_exc()
80 | if isinstance(r, int):
81 | sys.exit(r)
82 |
--------------------------------------------------------------------------------
/template_service/install/install.sh:
--------------------------------------------------------------------------------
1 | mkdir -p /etc/zabbix/zabbix_agentd.d/
2 | cp conf/service.conf /etc/zabbix/zabbix_agentd.d/
3 | mkdir -p /usr/lib/zabbix/externalscripts/
4 | cp conf/service.py /usr/lib/zabbix/externalscripts/
5 | chmod 777 /usr/lib/zabbix/externalscripts/service.py
6 | if [[ ! -f "/etc/sudoers.d/zabbix" ]]
7 | then
8 | echo 'zabbix ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/zabbix
9 | fi
10 |
11 | # UnsafeUserParameters=1
12 | CHECK=`grep "^Include=/etc/zabbix/zabbix_agentd.d/" /etc/zabbix/zabbix_agentd.conf|wc -l`
13 | if [[ "w$CHECK" == "w0" ]]
14 | then
15 | echo 'Include=/etc/zabbix/zabbix_agentd.d/' >> /etc/zabbix/zabbix_agentd.conf
16 | fi
17 |
18 | # UnsafeUserParameters=1
19 | CHECK=`grep "^UnsafeUserParameters=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
20 | if [[ "w$CHECK" == "w0" ]]
21 | then
22 | sed -ri '/UnsafeUserParameters=/a UnsafeUserParameters=1' /etc/zabbix/zabbix_agentd.conf
23 | fi
24 |
25 | # Timeout=10
26 | CHECK=`grep "^Timeout=3" /etc/zabbix/zabbix_agentd.conf|wc -l`
27 | if [[ "w$CHECK" == "w0" ]]
28 | then
29 | sed -ri '/Timeout=3/a Timeout=10' /etc/zabbix/zabbix_agentd.conf
30 | fi
31 |
32 | # AllowRoot=1
33 | CHECK=`grep "^AllowRoot=1" /etc/zabbix/zabbix_agentd.conf|wc -l`
34 | if [[ "w$CHECK" == "w0" ]]
35 | then
36 | sed -ri '/AllowRoot=0/a AllowRoot=1' /etc/zabbix/zabbix_agentd.conf
37 | fi
38 |
--------------------------------------------------------------------------------
/template_service/templates/service.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 3.0
4 | 2018-01-24T05:59:37Z
5 |
6 |
7 | Templates
8 |
9 |
10 |
11 |
12 | service
13 | service
14 |
15 |
16 |
17 | Templates
18 |
19 |
20 |
21 |
22 | service
23 |
24 |
25 |
26 |
27 |
28 | service Discovery
29 | 7
30 |
31 |
32 | service.discovery
33 | 30
34 | 0
35 |
36 |
37 |
38 | 0
39 | 0
40 |
41 | 0
42 |
43 |
44 |
45 |
46 | 0
47 |
48 |
49 |
50 |
51 |
52 |
53 | 0
54 |
55 |
56 |
57 | {#SERVER_NAME}
58 |
59 | 8
60 | A
61 |
62 |
63 |
64 | 5
65 |
66 |
67 |
68 | server $1 status
69 | 7
70 |
71 | 0
72 |
73 | service.[{#SERVER_NAME}]
74 | 60
75 | 7
76 | 365
77 | 0
78 | 3
79 |
80 |
81 | 0
82 |
83 |
84 | 0
85 | 0
86 |
87 | 0
88 |
89 | 1
90 |
91 |
92 |
93 | 0
94 | 0
95 |
96 |
97 |
98 |
99 |
100 |
101 | 0
102 |
103 |
104 | service
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | {service:service.[{#SERVER_NAME}].last(#3)}<>0
115 | service Check [{#SERVER_NAME}]
116 |
117 | 0
118 | 4
119 |
120 | 0
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------