├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── action.go ├── action_json.go ├── action_test.go ├── alert.go ├── alert_json.go ├── alert_test.go ├── bool.go ├── cache.go ├── client_builder.go ├── client_builder_test.go ├── debug.go ├── doc.go ├── error.go ├── event.go ├── event_json.go ├── event_test.go ├── file_cache.go ├── get_parameters.go ├── go.mod ├── go.sum ├── history.go ├── history_json.go ├── host.go ├── host_interface.go ├── host_json.go ├── host_macro.go ├── hostgroup.go ├── hostgroup_json.go ├── hostgroups_test.go ├── hosts_test.go ├── item.go ├── item_json.go ├── maintenance.go ├── maintenance_json.go ├── request.go ├── response.go ├── select_query.go ├── session.go ├── session_test.go ├── time.go ├── trigger.go ├── trigger_json.go ├── usermacro.go └── usermacros_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | # Goland files 27 | .idea/* 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build 2 | 3 | build: 4 | go build -x 5 | 6 | test: 7 | go test -v 8 | 9 | docker-run: 10 | docker run \ 11 | -d \ 12 | --name zabbix-db \ 13 | --env="MARIADB_USER=zabbix" \ 14 | --env="MARIADB_PASS=zabbix" \ 15 | million12/mariadb || : 16 | sleep 5 17 | docker run \ 18 | -d \ 19 | --name zabbix \ 20 | --env="DB_ADDRESS=zabbix-db" \ 21 | --env="DB_USER=zabbix" \ 22 | --env="DB_PASS=zabbix" \ 23 | --link=zabbix-db:zabbix-db \ 24 | -p 8080:80 \ 25 | zabbix/zabbix-server-2.4 || : 26 | 27 | docker-clean: 28 | docker rm -f zabbix-db zabbix 29 | 30 | .PHONY: all build test docker-run docker-clean 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-zabbix 2 | 3 | Go bindings for the Zabbix API 4 | 5 | [![go report card](https://goreportcard.com/badge/github.com/cavaliercoder/go-zabbix "go report card")](https://goreportcard.com/report/github.com/cavaliercoder/go-zabbix) 6 | [![GPL license](https://img.shields.io/badge/license-GPL-brightgreen.svg)](https://opensource.org/licenses/gpl-license) 7 | [![GoDoc](https://godoc.org/github.com/cavaliercoder/go-zabbix?status.svg)](https://godoc.org/github.com/cavaliercoder/go-zabbix) 8 | 9 | ## Overview 10 | 11 | This project provides bindings to interoperate between programs written in Go 12 | language and the Zabbix monitoring API. 13 | 14 | A number of Zabbix API bindings already exist for Go with varying levels of 15 | maturity. This project aims to provide an alternative implementation which is 16 | stable, fast, and allows for loose typing (using types such as`interface{}` or 17 | `map[string]interface{}`) as well as strong types (such as `Host` or `Event`). 18 | 19 | The package aims to have comprehensive coverage of Zabbix API methods from v1.8 20 | through to v3.0 without introducing limitations to the native API methods. 21 | 22 | ## Getting started 23 | 24 | ```go 25 | package main 26 | 27 | import ( 28 | "crypto/tls" 29 | "fmt" 30 | "log" 31 | "net/http" 32 | 33 | "github.com/cavaliercoder/go-zabbix" 34 | ) 35 | 36 | func main() { 37 | // Default approach - without session caching 38 | session, err := zabbix.NewSession("http://zabbix/api_jsonrpc.php", "Admin", "zabbix") 39 | if err != nil { 40 | panic(err) 41 | } 42 | 43 | version, err := session.GetVersion() 44 | 45 | if err != nil { 46 | panic(err) 47 | } 48 | 49 | fmt.Printf("Connected to Zabbix API v%s", version) 50 | 51 | // Use session builder with caching. 52 | // You can use own cache by implementing SessionAbstractCache interface 53 | // Optionally an http.Client can be passed to the builder, allowing to skip TLS verification, 54 | // pass proxy settings, etc. 55 | 56 | client := &http.Client{ 57 | Transport: &http.Transport{ 58 | TLSClientConfig: &tls.Config{ 59 | InsecureSkipVerify: true 60 | } 61 | } 62 | } 63 | 64 | cache := zabbix.NewSessionFileCache().SetFilePath("./zabbix_session") 65 | session, err := zabbix.CreateClient("http://zabbix/api_jsonrpc.php"). 66 | WithCache(cache). 67 | WithHTTPClient(client). 68 | WithCredentials("Admin", "zabbix"). 69 | Connect() 70 | if err != nil { 71 | log.Fatalf("%v\n", err) 72 | } 73 | 74 | version, err := session.GetVersion() 75 | 76 | if err != nil { 77 | log.Fatalf("%v\n", err) 78 | } 79 | 80 | fmt.Printf("Connected to Zabbix API v%s", version) 81 | } 82 | ``` 83 | 84 | ## License 85 | 86 | Released under the [GNU GPL License](https://github.com/cavaliercoder/go-zabbix/blob/master/LICENSE) 87 | -------------------------------------------------------------------------------- /action.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const ( 8 | // ActionEvalTypeAndOr indicated that an Action will evaluate its conditions 9 | // using AND/OR bitwise logic. 10 | ActionEvalTypeAndOr = iota 11 | 12 | // ActionEvalTypeAnd indicated that an Action will evaluate its conditions 13 | // using AND bitwise logic. 14 | ActionEvalTypeAnd 15 | 16 | // ActionEvalTypeOr indicated that an Action will evaluate its conditions 17 | // using OR bitwise logic. 18 | ActionEvalTypeOr 19 | ) 20 | 21 | // Action represents a Zabbix Action returned from the Zabbix API. 22 | // 23 | // See: https://www.zabbix.com/documentation/2.2/manual/config/notifications/action 24 | type Action struct { 25 | // ActionID is the unique ID of the Action. 26 | ActionID string 27 | 28 | // StepDuration is the interval in seconds between each operation step. 29 | StepDuration int 30 | 31 | // EvaluationType determines the bitwise logic used to evaluate the Actions 32 | // conditions. 33 | // 34 | // EvaluationType must be one of the ActionEvalType constants. 35 | // 36 | // EvaluationType is only supported up to Zabbix v2.2. 37 | EvaluationType int 38 | 39 | // EventType is the type of Events that this Action will handle. 40 | // 41 | // Source must be one of the EventSource constants. 42 | EventType int 43 | 44 | // Name is the name of the Action. 45 | Name string 46 | 47 | // ProblemMessageBody is the message body text to be submitted for this 48 | // Action. 49 | ProblemMessageBody string 50 | 51 | // ProblemMessageSubject is the short summary text to be submitted for this 52 | // Action. 53 | ProblemMessageSubject string 54 | 55 | // RecoveryMessageBody is the message body text to be submitted for this 56 | // Action. 57 | RecoveryMessageBody string 58 | 59 | // RecoveryMessageSubject is the short summary text to be submitted for this 60 | // Action. 61 | RecoveryMessageSubject string 62 | 63 | // RecoveryMessageEnabled determines whether recovery messages will be 64 | // submitted for the Action when the source problem is resolved. 65 | RecoveryMessageEnabled bool 66 | 67 | // Enabled determines whether the Action is enabled or disabled. 68 | Enabled bool 69 | 70 | // Conditions are the conditions which must be met for this Action to 71 | // execute. 72 | Conditions []ActionCondition 73 | 74 | // Operations are the operations which will be exectuted for this Action. 75 | Operations []ActionOperation 76 | } 77 | 78 | // ActionCondition is action condition 79 | type ActionCondition struct{} 80 | 81 | // ActionOperation is action operation 82 | type ActionOperation struct{} 83 | 84 | // ActionGetParams is query params for action.get call 85 | type ActionGetParams struct { 86 | GetParameters 87 | } 88 | 89 | // GetActions queries the Zabbix API for Actions matching the given search 90 | // parameters. 91 | // 92 | // ErrNotFound is returned if the search result set is empty. 93 | // An error is returned if a transport, parsing or API error occurs. 94 | func (c *Session) GetActions(params ActionGetParams) ([]Action, error) { 95 | actions := make([]jAction, 0) 96 | err := c.Get("action.get", params, &actions) 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | if len(actions) == 0 { 102 | return nil, ErrNotFound 103 | } 104 | 105 | // map JSON Actions to Go Actions 106 | out := make([]Action, len(actions)) 107 | for i, jaction := range actions { 108 | action, err := jaction.Action() 109 | if err != nil { 110 | return nil, fmt.Errorf("Error mapping Action %d in response: %v", i, err) 111 | } 112 | 113 | out[i] = *action 114 | } 115 | 116 | return out, nil 117 | } 118 | -------------------------------------------------------------------------------- /action_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | // jAction is a private map for the Zabbix API Action object. 9 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference/action/object 10 | type jAction struct { 11 | ActionID string `json:"actionid"` 12 | EscPeriod string `json:"esc_period"` 13 | EvalType string `json:"evaltype"` 14 | EventSource string `json:"eventsource"` 15 | Name string `json:"name"` 16 | DefLongData string `json:"def_longdata"` 17 | DefShortData string `json:"def_shortdata"` 18 | RLongData string `json:"r_longdata"` 19 | RShortData string `json:"r_shortdata"` 20 | RecoveryMsg string `json:"recovery_msg"` 21 | Status string `json:"status"` 22 | } 23 | 24 | // Action returns a native Go Action struct mapped from the given JSON Action 25 | // data. 26 | func (c *jAction) Action() (*Action, error) { 27 | var err error 28 | 29 | action := &Action{} 30 | action.ActionID = c.ActionID 31 | action.Name = c.Name 32 | action.ProblemMessageSubject = c.DefShortData 33 | action.ProblemMessageBody = c.DefLongData 34 | action.RecoveryMessageSubject = c.RShortData 35 | action.RecoveryMessageBody = c.RShortData 36 | action.RecoveryMessageEnabled = (c.RecoveryMsg == "1") 37 | action.Enabled = (c.Status == "0") 38 | 39 | action.StepDuration, err = strconv.Atoi(c.EscPeriod) 40 | if err != nil { 41 | return nil, fmt.Errorf("Error parsing Action Step Duration: %v", err) 42 | } 43 | 44 | if c.EvalType != "" { // removed in v2.4 45 | action.EvaluationType, err = strconv.Atoi(c.EvalType) 46 | if err != nil { 47 | return nil, fmt.Errorf("Error parsing Action Evaluation Type: %v", err) 48 | } 49 | } 50 | 51 | action.EventType, err = strconv.Atoi(c.EventSource) 52 | if err != nil { 53 | return nil, fmt.Errorf("Error parsing Action Event Type: %v", err) 54 | } 55 | 56 | return action, nil 57 | } 58 | -------------------------------------------------------------------------------- /action_test.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestActions(t *testing.T) { 8 | session := GetTestSession(t) 9 | 10 | params := ActionGetParams{} 11 | 12 | actions, err := session.GetActions(params) 13 | if err != nil { 14 | t.Fatalf("Error getting actions: %v", err) 15 | } 16 | 17 | if len(actions) == 0 { 18 | t.Fatal("No actions found") 19 | } 20 | 21 | for i, action := range actions { 22 | if action.ActionID == "" { 23 | t.Fatalf("Action %d has no Action ID", i) 24 | } 25 | 26 | if action.Name == "" { 27 | t.Fatalf("Action %d has no name", i) 28 | } 29 | 30 | if action.EventType == EventSourceTrigger && action.ProblemMessageSubject == "" { 31 | t.Fatalf("Action %d has no problem message subject", i) 32 | } 33 | } 34 | 35 | t.Logf("Validated %d Actions", len(actions)) 36 | } 37 | -------------------------------------------------------------------------------- /alert.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | const ( 9 | // AlertTypeMessage indicates that an Alert is a notification message. 10 | AlertTypeMessage = iota 11 | 12 | // AlertTypeRemoteCommand indicates that an Alert is a remote command call. 13 | AlertTypeRemoteCommand 14 | ) 15 | 16 | const ( 17 | // AlertMessageStatusNotSent indicates that an Alert of type 18 | // AlertTypeMessage has not been sent yet. 19 | AlertMessageStatusNotSent = iota 20 | 21 | // AlertMessageStatusSent indicates that an Alert of type AlertTypeMessage 22 | // has been sent successfully. 23 | AlertMessageStatusSent 24 | 25 | // AlertMessageStatusFailed indicates that an Alert of type AlertTypeMessage 26 | // failed to send. 27 | AlertMessageStatusFailed 28 | ) 29 | 30 | const ( 31 | // AlertCommandStatusRun indicates that an Alert of type 32 | // AlertTypeRemoteCommand has been run. 33 | AlertCommandStatusRun = 1 + iota 34 | 35 | // AlertCommandStatusAgentUnavailable indicates that an Alert of type 36 | // AlertTypeRemoteCommand failed to run as the Zabbix Agent was unavailable. 37 | AlertCommandStatusAgentUnavailable 38 | ) 39 | 40 | // Alert represents a Zabbix Alert returned from the Zabbix API. 41 | // 42 | // See: https://www.zabbix.com/documentation/2.2/manual/config/notifications 43 | type Alert struct { 44 | // AlertID is the unique ID of the Alert. 45 | AlertID string 46 | 47 | // ActionID is the unique ID of the Action that generated this Alert. 48 | ActionID string 49 | 50 | // AlertType is the type of the Alert. 51 | // AlertType must be one of the AlertType constants. 52 | AlertType int 53 | 54 | // Timestamp is the UTC timestamp at which the Alert was generated. 55 | Timestamp time.Time 56 | 57 | // ErrorText is the error message if there was a problem sending a message 58 | // or running a remote command. 59 | ErrorText string 60 | 61 | // EscalationStep is the escalation step during which the Alert was 62 | // generated. 63 | EscalationStep int 64 | 65 | // EventID is the unique ID of the Event that triggered this Action that 66 | // generated this Alert. 67 | EventID string 68 | 69 | // MediaTypeID is the unique ID of the Media Type that was used to send this 70 | // Alert if the AlertType is AlertTypeMessage. 71 | MediaTypeID string 72 | 73 | // Message is the Alert message body if AlertType is AlertTypeMessage. 74 | Message string 75 | 76 | // RetryCount is the number of times Zabbix tried to send a message. 77 | RetryCount int 78 | 79 | // Recipient is the end point address of a message if AlertType is 80 | // AlertTypeMessage. 81 | Recipient string 82 | 83 | // Status indicates the outcome of executing the Alert. 84 | // 85 | // If AlertType is AlertTypeMessage, Status must be one of the 86 | // AlertMessageStatus constants. 87 | // 88 | // If AlertType is AlertTypeRemoteCommand, Status must be one of the 89 | // AlertCommandStatus constants. 90 | Status int 91 | 92 | // Subject is the Alert message subject if AlertType is AlertTypeMessage. 93 | Subject string 94 | 95 | // UserID is the unique ID of the User the Alert message was sent to. 96 | UserID string 97 | 98 | // Hosts is an array of Hosts that triggered this Alert. 99 | // 100 | // Hosts is only populated if AlertGetParams.SelectHosts is given in the 101 | // query parameters that returned this Alert. 102 | Hosts []Host 103 | } 104 | 105 | // AlertGetParams is query params for alert.get call 106 | type AlertGetParams struct { 107 | GetParameters 108 | 109 | // SelectHosts causes all Hosts which triggered the Alert to be attached in 110 | // the search results. 111 | SelectHosts SelectQuery `json:"selectHosts,omitempty"` 112 | 113 | // SelectMediaTypes causes the Media Types used for the Alert to be attached 114 | // in the search results. 115 | SelectMediaTypes SelectQuery `json:"selectMediatypes,omitempty"` 116 | 117 | // SelectUsers causes all Users to which the Alert was addressed to be 118 | // attached in the search results. 119 | SelectUsers SelectQuery `json:"selectUsers,omitempty"` 120 | } 121 | 122 | // GetAlerts queries the Zabbix API for Alerts matching the given search 123 | // parameters. 124 | // 125 | // ErrNotFound is returned if the search result set is empty. 126 | // An error is returned if a transport, parsing or API error occurs. 127 | func (c *Session) GetAlerts(params AlertGetParams) ([]Alert, error) { 128 | alerts := make([]jAlert, 0) 129 | err := c.Get("alert.get", params, &alerts) 130 | if err != nil { 131 | return nil, err 132 | } 133 | 134 | if len(alerts) == 0 { 135 | return nil, ErrNotFound 136 | } 137 | 138 | // map JSON Alerts to Go Alerts 139 | out := make([]Alert, len(alerts)) 140 | for i, jalert := range alerts { 141 | alert, err := jalert.Alert() 142 | if err != nil { 143 | return nil, fmt.Errorf("Error mapping Alert %d in response: %v", i, err) 144 | } 145 | 146 | out[i] = *alert 147 | } 148 | 149 | return out, nil 150 | } 151 | -------------------------------------------------------------------------------- /alert_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // jAlert is a private map for the Zabbix API Alert object. 8 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference/alert/object 9 | type jAlert struct { 10 | AlertID string `json:"alertid"` 11 | ActionID string `json:"actionid"` 12 | AlertType int `json:"alerttype,string"` 13 | Clock int64 `json:"clock,string"` 14 | Error string `json:"error"` 15 | EscStep int `json:"esc_step,string"` 16 | EventID string `json:"eventid"` 17 | MediaTypeID string `json:"mediatypeid"` 18 | Message string `json:"message"` 19 | Retries int `json:"retries,string"` 20 | SendTo string `json:"sendto"` 21 | Status int `json:"status,string"` 22 | Subject string `json:"subject"` 23 | UserID string `json:"userid"` 24 | Hosts jHosts `json:"hosts"` 25 | } 26 | 27 | // Alert returns a native Go Alert struct mapped from the given JSON Alert data. 28 | func (c *jAlert) Alert() (*Alert, error) { 29 | var err error 30 | 31 | alert := &Alert{} 32 | alert.AlertID = c.AlertID 33 | alert.ActionID = c.ActionID 34 | alert.AlertType = c.AlertType 35 | alert.Timestamp = time.Unix(c.Clock, 0) 36 | alert.ErrorText = c.Error 37 | alert.EscalationStep = c.EscStep 38 | alert.EventID = c.EventID 39 | alert.MediaTypeID = c.MediaTypeID 40 | alert.Message = c.Message 41 | alert.RetryCount = c.Retries 42 | alert.Recipient = c.SendTo 43 | alert.Status = c.Status 44 | alert.Subject = c.Subject 45 | alert.UserID = c.UserID 46 | 47 | // map Hosts 48 | alert.Hosts, err = c.Hosts.Hosts() 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | return alert, nil 54 | } 55 | -------------------------------------------------------------------------------- /alert_test.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestAlerts(t *testing.T) { 8 | session := GetTestSession(t) 9 | 10 | params := AlertGetParams{ 11 | SelectHosts: SelectExtendedOutput, 12 | } 13 | 14 | alerts, err := session.GetAlerts(params) 15 | if err != nil { 16 | t.Fatalf("Error getting alerts: %v", err) 17 | } 18 | 19 | if len(alerts) == 0 { 20 | t.Fatal("No alerts found") 21 | } 22 | 23 | for i, alert := range alerts { 24 | if alert.AlertID == "" { 25 | t.Fatalf("Alert %d has no Alert ID", i) 26 | } 27 | } 28 | 29 | t.Logf("Validated %d Alerts", len(alerts)) 30 | } 31 | -------------------------------------------------------------------------------- /bool.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type ZBXBoolean bool 9 | 10 | func (bit *ZBXBoolean) UnmarshalJSON(data []byte) error { 11 | asString := string(data) 12 | if asString == "1" || asString == "true" { 13 | *bit = true 14 | } else if asString == "0" || asString == "false" { 15 | *bit = false 16 | } else { 17 | return errors.New(fmt.Sprintf("Boolean unmarshal error: invalid input %s", asString)) 18 | } 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /cache.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // SessionAbstractCache represents abstract Zabbix session cache backend 8 | type SessionAbstractCache interface { 9 | // SetSessionLifetime sets lifetime of cached Zabbix session 10 | SetSessionLifetime(d time.Duration) 11 | 12 | // SaveSession saves session to a cache 13 | SaveSession(session *Session) error 14 | 15 | // HasSession checks if any valid Zabbix session has been cached and available 16 | HasSession() bool 17 | 18 | // GetSession returns cached Zabbix session 19 | GetSession() (*Session, error) 20 | 21 | // Flush removes cached session 22 | Flush() error 23 | } 24 | -------------------------------------------------------------------------------- /client_builder.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import "net/http" 4 | 5 | // ClientBuilder is Zabbix API client builder 6 | type ClientBuilder struct { 7 | cache SessionAbstractCache 8 | hasCache bool 9 | url string 10 | credentials map[string]string 11 | client *http.Client 12 | } 13 | 14 | // WithCache sets cache for Zabbix sessions 15 | func (builder *ClientBuilder) WithCache(cache SessionAbstractCache) *ClientBuilder { 16 | builder.cache = cache 17 | builder.hasCache = true 18 | 19 | return builder 20 | } 21 | 22 | // WithCredentials sets auth credentials for Zabbix API 23 | func (builder *ClientBuilder) WithCredentials(username string, password string) *ClientBuilder { 24 | builder.credentials["username"] = username 25 | builder.credentials["password"] = password 26 | 27 | return builder 28 | } 29 | 30 | // WithHTTPClient sets the HTTP client to use to connect to the Zabbix API 31 | func (builder *ClientBuilder) WithHTTPClient(client *http.Client) *ClientBuilder { 32 | builder.client = client 33 | 34 | return builder 35 | } 36 | 37 | // Connect creates Zabbix API client and connects to the API server 38 | // or provides a cached server if any cache was specified 39 | func (builder *ClientBuilder) Connect() (session *Session, err error) { 40 | // Check if any cache was defined and if it has a valid cached session 41 | if builder.hasCache && builder.cache.HasSession() { 42 | if session, err = builder.cache.GetSession(); err == nil { 43 | session.client = builder.client 44 | return session, nil 45 | } 46 | } 47 | 48 | // Otherwise - login to a Zabbix server 49 | session = &Session{URL: builder.url, client: builder.client} 50 | err = session.login(builder.credentials["username"], builder.credentials["password"]) 51 | 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | // Try to cache session if any cache used 57 | if builder.hasCache { 58 | return session, builder.cache.SaveSession(session) 59 | } 60 | 61 | return session, err 62 | } 63 | 64 | // CreateClient creates a Zabbix API client builder 65 | func CreateClient(apiEndpoint string) *ClientBuilder { 66 | return &ClientBuilder{ 67 | url: apiEndpoint, 68 | credentials: make(map[string]string), 69 | client: &http.Client{}, 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /client_builder_test.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "testing" 7 | ) 8 | 9 | const ( 10 | fakeURL = "http://localhost/api_jsonrpc.php" 11 | fakeToken = "0424bd59b807674191e7d77572075f33" 12 | fakeAPIVersion = "2.0" 13 | ) 14 | 15 | func prepareTemporaryDir(t *testing.T) (dir string, success bool) { 16 | tempDir, err := ioutil.TempDir("", "zabbix-session-test") 17 | 18 | if err != nil { 19 | t.Fatalf("cannot create a temporary dir for session cache: %v", err) 20 | return "", false 21 | } 22 | 23 | t.Logf("used %s directory as temporary dir", tempDir) 24 | 25 | return tempDir, true 26 | } 27 | 28 | func getTestFileCache(baseDir string) SessionAbstractCache { 29 | sessionFilePath := baseDir + "/" + ".zabbix_session" 30 | return NewSessionFileCache().SetFilePath(sessionFilePath) 31 | } 32 | 33 | func TestSessionCache(t *testing.T) { 34 | // Create a fake session for r/w test 35 | fakeSession := &Session{ 36 | URL: fakeURL, 37 | Token: fakeToken, 38 | APIVersion: fakeAPIVersion, 39 | } 40 | 41 | tempDir, success := prepareTemporaryDir(t) 42 | 43 | if !success { 44 | return 45 | } 46 | 47 | cache := getTestFileCache(tempDir) 48 | 49 | if err := cache.SaveSession(fakeSession); err != nil { 50 | t.Errorf("failed to save mock session - %v", err) 51 | return 52 | } 53 | 54 | if !cache.HasSession() { 55 | t.Errorf("session was saved but not detected again by cache") 56 | return 57 | } 58 | 59 | // Try to get a cached session 60 | cachedSession, err := cache.GetSession() 61 | 62 | if err != nil { 63 | t.Error(err) 64 | return 65 | } 66 | 67 | // Check session integrity 68 | if err := compareSessionWithMock(cachedSession); err != nil { 69 | t.Error(err) 70 | } 71 | 72 | testClientBuilder(t, cache) 73 | 74 | if err := cache.Flush(); err != nil { 75 | t.Error("failed to remove a cached session file") 76 | } 77 | } 78 | 79 | func compareSessionWithMock(session *Session) error { 80 | if session.URL != fakeURL { 81 | return fmt.Errorf("Session URL '%s' is not equal to '%s'", session.URL, fakeURL) 82 | } 83 | 84 | if session.Token != fakeToken { 85 | return fmt.Errorf("Session token '%s' is not equal to '%s'", session.Token, fakeToken) 86 | } 87 | 88 | if session.APIVersion != fakeAPIVersion { 89 | return fmt.Errorf("Session version '%s' is not equal to '%s'", session.APIVersion, fakeAPIVersion) 90 | } 91 | 92 | return nil 93 | } 94 | 95 | // should started by TestSessionCache 96 | func testClientBuilder(t *testing.T, cache SessionAbstractCache) { 97 | username, password, url := GetTestCredentials() 98 | 99 | if !cache.HasSession() { 100 | t.Errorf("ManualTestClientBuilder test requires a cached session, run TestSessionCache before running this test case") 101 | return 102 | } 103 | 104 | // Try to build a session using the session builder 105 | client, err := CreateClient(url).WithCache(cache).WithCredentials(username, password).Connect() 106 | 107 | if err != nil { 108 | t.Errorf("failed to create a session using cache - %s", err) 109 | return 110 | } 111 | 112 | if err := compareSessionWithMock(client); err != nil { 113 | t.Error(err) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /debug.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // debug caches the value of environment variable ZBX_DEBUG from program start. 9 | var debug bool = (os.Getenv("ZBX_DEBUG") == "1") 10 | 11 | // dprintf prints formatted debug message to STDERR if the ZBX_DEBUG environment 12 | // variable is set to "1". 13 | func dprintf(format string, a ...interface{}) { 14 | if debug { 15 | fmt.Fprintf(os.Stderr, format, a...) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package zabbix provides bindings to interoperate between programs written in Go 3 | language and the Zabbix monitoring API. 4 | 5 | A number of Zabbix API bindings already exist for Go with varying levels of 6 | maturity. This project aims to provide an alternative implementation which is 7 | stable, fast, and allows for loose typing (using types such as interface{} or 8 | map[string]interface{}) as well as strong types (such as zabbix.Host or 9 | zabbix.Event). 10 | 11 | The package aims to have comprehensive coverage of Zabbix API methods from v1.8 12 | through to v3.0 without introducing limitations to the native API methods. 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "github.com/cavaliercoder/go-zabbix" 19 | ) 20 | 21 | func main() { 22 | // Default approach - without session caching 23 | session, err := zabbix.NewSession("http://zabbix/api_jsonrpc.php", "Admin", "zabbix") 24 | if err != nil { 25 | panic(err) 26 | } 27 | fmt.Printf("Connected to Zabbix API v%s", session.GetVersion()) 28 | 29 | // Use session builder with caching. 30 | // You can use own cache by implementing SessionAbstractCache interface 31 | // Optionally an http.Client can be passed to the builder, allowing to skip TLS verification, 32 | // pass proxy settings, etc. 33 | 34 | client := &http.Client{ 35 | Transport: &http.Transport{ 36 | TLSClientConfig: &tls.Config{ 37 | InsecureSkipVerify: true 38 | } 39 | } 40 | } 41 | cache := zabbix.NewSessionFileCache().SetFilePath("./zabbix_session") 42 | session, err := zabbix.CreateClient("http://zabbix/api_jsonrpc.php"). 43 | WithCache(cache). 44 | WithHTTPClient(client). 45 | WithCredentials("Admin", "zabbix"). 46 | Connect() 47 | 48 | 49 | fmt.Printf("Connected to Zabbix API v%s", session.GetVersion()) 50 | } 51 | 52 | For more information see: https://github.com/cavaliercoder/go-zabbix 53 | 54 | */ 55 | package zabbix 56 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // APIError represents a Zabbix API error. 8 | type APIError struct { 9 | // Code is the Zabbix API error code. 10 | Code int `json:"code"` 11 | 12 | // Message is a short error summary. 13 | Message string `json:"message"` 14 | 15 | // Data is a detailed error message. 16 | Data string `json:"data"` 17 | } 18 | 19 | // Error returns the string representation of an APIError. 20 | func (e *APIError) Error() string { 21 | return fmt.Sprintf("%s (%d)", e.Message, e.Code) 22 | } 23 | -------------------------------------------------------------------------------- /event.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | const ( 9 | // EventSourceTrigger indicates that an Event was created by a Trigger. 10 | EventSourceTrigger = iota 11 | 12 | // EventSourceDiscoveryRule indicates than an Event was created by a 13 | // Discovery Rule. 14 | EventSourceDiscoveryRule 15 | 16 | // EventSourceAutoRegistration indicates that an Event was created by an 17 | // active Host registration rule. 18 | EventSourceAutoRegistration 19 | 20 | // EventSourceInternal indicates that an Event was created by an Internal 21 | // Event. 22 | EventSourceInternal 23 | ) 24 | 25 | const ( 26 | // EventObjectTypeTrigger indicates that an Event with Source type 27 | // EventSourceTrigger or EventSourceInternal is related to a Trigger. 28 | EventObjectTypeTrigger = iota 29 | 30 | // EventObjectTypeDiscoveredHost indicates that an Event with Source type 31 | // EventSourceDiscoveryRule is related to a discovered Host. 32 | EventObjectTypeDiscoveredHost 33 | 34 | // EventObjectTypeDiscoveredService indicates that an Event with Source type 35 | // EventSourceDiscoveryRule is related to a discovered Service. 36 | EventObjectTypeDiscoveredService 37 | 38 | // EventObjectTypeAutoRegisteredHost indicates that an Event with Source 39 | // type EventSourceAutoRegistration is related to an auto-registered Host. 40 | EventObjectTypeAutoRegisteredHost 41 | 42 | // EventObjectTypeItem indicates that an Event with Source type 43 | // EventSourceInternal is related to an Item. 44 | EventObjectTypeItem 45 | 46 | // EventObjectTypeLLDRule indicates that an Event with Source type 47 | // EventSourceInternal is related to a low-level Discovery Rule. 48 | EventObjectTypeLLDRule 49 | ) 50 | 51 | const ( 52 | // TriggerEventValueOK indicates that the Object related to an Event with 53 | // Source type EventSourceTrigger is in an "OK" state. 54 | TriggerEventValueOK = iota 55 | 56 | // TriggerEventValueProblem indicates that the Object related to an Event with 57 | // Source type EventSourceTrigger is in a "Problem" state. 58 | TriggerEventValueProblem 59 | ) 60 | 61 | const ( 62 | // DiscoveryEventValueUp indicates that the Host or Service related to an 63 | // Event with Source type EventSourceDiscoveryRule is in an "Up" state. 64 | DiscoveryEventValueUp = iota 65 | 66 | // DiscoveryEventValueDown indicates that the Host or Service related to an 67 | // Event with Source type EventSourceDiscoveryRule is in a "Down" state. 68 | DiscoveryEventValueDown 69 | 70 | // DiscoveryEventValueDiscovered indicates that the Host or Service related 71 | // to an Event with Source type EventSourceDiscoveryRule is in a 72 | // "Discovered" state. 73 | DiscoveryEventValueDiscovered 74 | 75 | // DiscoveryEventValueLost indicates that the Host or Service related to an 76 | // Event with Source type EventSourceDiscoveryRule is in a "Lost" state. 77 | DiscoveryEventValueLost 78 | ) 79 | 80 | const ( 81 | // InternalEventValueNormal indicates that the Object related to an Event 82 | // with Source type EventSourceInternal is in a "Normal" state. 83 | InternalEventValueNormal = iota 84 | 85 | // InternalEventValueNotSupported indicates that the Object related to an 86 | // Event with Source type EventSourceInternal is in an "Unknown" or 87 | // "Not supported" state. 88 | InternalEventValueNotSupported 89 | ) 90 | 91 | // Event represents a Zabbix Event returned from the Zabbix API. Events are 92 | // readonly as they may only be created by the Zabbix server. 93 | // 94 | // See: https://www.zabbix.com/documentation/2.2/manual/config/events 95 | type Event struct { 96 | // EventID is the ID of the Event. 97 | EventID string 98 | 99 | // Acknowledged indicates if the Event has been acknowledged by an operator. 100 | Acknowledged bool 101 | 102 | // Timestamp is the UTC timestamp at which the Event occurred. 103 | Timestamp time.Time 104 | 105 | // Source is the type of the Event source. 106 | // 107 | // Source must be one of the EventSource constants. 108 | Source int 109 | 110 | // ObjectType is the type of the Object that is related to the Event. 111 | // ObjectType must be one of the EventObjectType constants. 112 | ObjectType int 113 | 114 | // ObjectID is the unique identifier of the Object that caused this Event. 115 | ObjectID int 116 | 117 | // Value is the state of the related Object. 118 | // 119 | // Value must be one of the EventValue constants, according to the Event's 120 | // Source type. 121 | Value int 122 | 123 | // ValueChanges indicates if the state of the related Object has changed 124 | // since the previous Event. 125 | ValueChanged bool 126 | 127 | // Hosts is an array of Host which contained the Object which created this 128 | // Event. 129 | // 130 | // Hosts is only populated if EventGetParams.SelectHosts is given in the 131 | // query parameters that returned this Event and the Event Source is one of 132 | // EventSourceTrigger or EventSourceDiscoveryRule. 133 | Hosts []Host 134 | } 135 | 136 | // EventGetParams is query params for event.get call 137 | type EventGetParams struct { 138 | GetParameters 139 | 140 | // EventIDs filters search results to Events that matched the given Event 141 | // IDs. 142 | EventIDs []string `json:"eventids,omitempty"` 143 | 144 | // GroupIDs filters search results to events for hosts that are members of 145 | // the given Group IDs. 146 | GroupIDs []string `json:"groupids,omitempty"` 147 | 148 | // HostIDs filters search results to events for hosts that matched the given 149 | // Host IDs. 150 | HostIDs []string `json:"hostids,omitempty"` 151 | 152 | // ObjectIDs filters search results to events for Objects that matched 153 | // the given Object IDs. 154 | ObjectIDs []string `json:"objectids,omitempty"` 155 | 156 | // ObjectType filters search results to events created by the given Object 157 | // Type. Must be one of the EventObjectType constants. 158 | // 159 | // Default: EventObjectTypeTrigger 160 | ObjectType int `json:"object"` 161 | 162 | // AcknowledgedOnly filters search results to event which have been 163 | // acknowledged. 164 | AcknowledgedOnly bool `json:"acknowledged"` 165 | 166 | // MinEventID filters search results to Events with an ID greater or equal 167 | // to the given ID. 168 | MinEventID string `json:"eventid_from,omitempty"` 169 | 170 | // MaxEventID filters search results to Events with an ID lesser or equal 171 | // to the given ID. 172 | MaxEventID string `json:"eventid_till,omitempty"` 173 | 174 | // MinTime filters search results to Events with a timestamp lesser than or 175 | // equal to the given timestamp. 176 | MinTime int64 `json:"time_from,omitempty"` 177 | 178 | // MaxTime filters search results to Events with a timestamp greater than or 179 | // equal to the given timestamp. 180 | MaxTime int64 `json:"time_till,omitempty"` 181 | 182 | // Value filters search results to Events with the given values. Each value 183 | // must be one of the EventValue constants for the given ObjectType. 184 | Value []int `json:"value,omitempty"` 185 | 186 | // SelectHosts causes all Hosts which contain the object that caused each 187 | // Event to be attached in the search results. 188 | SelectHosts SelectQuery `json:"selectHosts,omitempty"` 189 | 190 | // SelectRelatedObject causes the object which caused each Event to be 191 | // attached in the search results. 192 | SelectRelatedObject SelectQuery `json:"selectRelatedObject,omitempty"` 193 | 194 | // SelectAlerts causes Alerts generated by each Event to be attached in the 195 | // search results. 196 | SelectAlerts SelectQuery `json:"select_alerts,omitempty"` 197 | 198 | // SelectAcknowledgements causes Acknowledgments for each Event to be 199 | // attached in the search results in reverse chronological order. 200 | SelectAcknowledgements SelectQuery `json:"select_acknowledges,omitempty"` 201 | } 202 | 203 | // GetEvents queries the Zabbix API for Events matching the given search 204 | // parameters. 205 | // 206 | // ErrEventNotFound is returned if the search result set is empty. 207 | // An error is returned if a transport, parsing or API error occurs. 208 | func (c *Session) GetEvents(params EventGetParams) ([]Event, error) { 209 | events := make([]jEvent, 0) 210 | err := c.Get("event.get", params, &events) 211 | if err != nil { 212 | return nil, err 213 | } 214 | 215 | if len(events) == 0 { 216 | return nil, ErrNotFound 217 | } 218 | 219 | // map JSON Events to Go Events 220 | out := make([]Event, len(events)) 221 | for i, jevent := range events { 222 | event, err := jevent.Event() 223 | if err != nil { 224 | return nil, fmt.Errorf("Error mapping Event %d in response: %v", i, err) 225 | } 226 | 227 | out[i] = *event 228 | } 229 | 230 | return out, nil 231 | } 232 | -------------------------------------------------------------------------------- /event_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | // jEvent is a private map for the Zabbix API Event object. 10 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference/event/object 11 | type jEvent struct { 12 | EventID string `json:"eventid"` 13 | Acknowledged string `json:"acknowledged"` 14 | Clock string `json:"clock"` 15 | Nanoseconds string `json:"ns"` 16 | ObjectType string `json:"object"` 17 | ObjectID string `json:"objectid"` 18 | Source string `json:"source"` 19 | Value string `json:"value"` 20 | ValueChanged string `json:"value_changed"` 21 | Hosts jHosts `json:"hosts"` 22 | } 23 | 24 | // Event returns a native Go Event struct mapped from the given JSON Event data. 25 | func (c *jEvent) Event() (*Event, error) { 26 | event := &Event{} 27 | event.EventID = c.EventID 28 | event.Acknowledged = (c.Acknowledged == "1") 29 | 30 | // parse timestamp 31 | sec, err := strconv.ParseInt(c.Clock, 10, 64) 32 | if err != nil { 33 | return nil, fmt.Errorf("Error parsing Event timestamp: %v", err) 34 | } 35 | 36 | nsec, err := strconv.ParseInt(c.Nanoseconds, 10, 64) 37 | if err != nil { 38 | return nil, fmt.Errorf("Error parsing Event timestamp nanoseconds: %v", err) 39 | } 40 | 41 | event.Timestamp = time.Unix(sec, nsec) 42 | 43 | event.ObjectType, err = strconv.Atoi(c.ObjectType) 44 | if err != nil { 45 | return nil, fmt.Errorf("Error parsing Event Object Type: %v", err) 46 | } 47 | 48 | event.ObjectID, err = strconv.Atoi(c.ObjectID) 49 | if err != nil { 50 | return nil, fmt.Errorf("Error parsing Event Object ID: %v", err) 51 | } 52 | 53 | event.Source, err = strconv.Atoi(c.Source) 54 | if err != nil { 55 | return nil, fmt.Errorf("Error parsing Event Source: %v", err) 56 | } 57 | 58 | event.Value, err = strconv.Atoi(c.Value) 59 | if err != nil { 60 | return nil, fmt.Errorf("Error parsing Event Source: %v", err) 61 | } 62 | 63 | event.ValueChanged = (c.ValueChanged == "1") 64 | 65 | // map hosts 66 | event.Hosts, err = c.Hosts.Hosts() 67 | if err != nil { 68 | return nil, err 69 | } 70 | 71 | return event, nil 72 | } 73 | -------------------------------------------------------------------------------- /event_test.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestEvents(t *testing.T) { 8 | session := GetTestSession(t) 9 | 10 | params := EventGetParams{ 11 | SelectAcknowledgements: SelectExtendedOutput, 12 | SelectAlerts: SelectExtendedOutput, 13 | SelectHosts: SelectExtendedOutput, 14 | SelectRelatedObject: SelectExtendedOutput, 15 | } 16 | 17 | events, err := session.GetEvents(params) 18 | if err != nil { 19 | t.Fatalf("Error getting events: %v", err) 20 | } 21 | 22 | if len(events) == 0 { 23 | t.Fatal("No events found") 24 | } 25 | 26 | for i, event := range events { 27 | if event.EventID == "" { 28 | t.Fatalf("Event %d has no Event ID", i) 29 | } 30 | 31 | if event.Timestamp.IsZero() { 32 | t.Fatalf("Event %d has no timestamp", i) 33 | } 34 | } 35 | 36 | t.Logf("Validated %d Events", len(events)) 37 | } 38 | -------------------------------------------------------------------------------- /file_cache.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "time" 9 | ) 10 | 11 | /* 12 | cachedSessionData represents a model of cached session. 13 | 14 | Example: 15 | { 16 | "createdAt": 1530056885, 17 | "session": { 18 | "url": "...", 19 | "token": "...", 20 | "apiVersion": "..." 21 | } 22 | } 23 | */ 24 | type cachedSessionContainer struct { 25 | CreatedAt int64 `json:"createdAt"` 26 | Session `json:"session"` 27 | } 28 | 29 | // SessionFileCache is Zabbix session filesystem cache. 30 | type SessionFileCache struct { 31 | filePath string 32 | sessionLifeTime time.Duration 33 | filePermissions uint32 34 | } 35 | 36 | // SetFilePath sets Zabbix session cache file path. Default value is "./zabbix_session" 37 | func (c *SessionFileCache) SetFilePath(filePath string) *SessionFileCache { 38 | c.filePath = filePath 39 | return c 40 | } 41 | 42 | // SetFilePermissions sets permissions for a session file. Default value is 0655. 43 | func (c *SessionFileCache) SetFilePermissions(permissions uint32) *SessionFileCache { 44 | c.filePermissions = permissions 45 | return c 46 | } 47 | 48 | // SetSessionLifetime sets lifetime in seconds of cached Zabbix session. Default value is 4 hours. 49 | func (c *SessionFileCache) SetSessionLifetime(d time.Duration) { 50 | c.sessionLifeTime = d 51 | } 52 | 53 | // SaveSession saves session to a cache 54 | func (c *SessionFileCache) SaveSession(session *Session) error { 55 | sessionContainer := cachedSessionContainer{ 56 | CreatedAt: time.Now().Unix(), 57 | Session: *session, 58 | } 59 | 60 | serialized, err := json.Marshal(sessionContainer) 61 | 62 | if err != nil { 63 | return err 64 | } 65 | 66 | return ioutil.WriteFile(c.filePath, []byte(serialized), os.FileMode(c.filePermissions)) 67 | } 68 | 69 | // GetSession returns cached Zabbix session 70 | func (c *SessionFileCache) GetSession() (*Session, error) { 71 | contents, err := ioutil.ReadFile(c.filePath) 72 | 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | var sessionContainer cachedSessionContainer 78 | 79 | if err := json.Unmarshal(contents, &sessionContainer); err != nil { 80 | return nil, err 81 | } 82 | 83 | // Check if session is expired 84 | if !c.checkSessionLifeTime(&sessionContainer) { 85 | // Delete the session file and throw an error if TTL is expired 86 | os.Remove(c.filePath) 87 | return nil, fmt.Errorf("cached session lifetime expired") 88 | } 89 | 90 | return &sessionContainer.Session, err 91 | } 92 | 93 | // checkSessionLifeTime checks if session is still actual 94 | func (c *SessionFileCache) checkSessionLifeTime(sessionContainer *cachedSessionContainer) bool { 95 | now := time.Now().Unix() 96 | createdAt := sessionContainer.CreatedAt 97 | timeDiff := now - createdAt 98 | 99 | // Check session TTL by time diff 100 | isExpired := timeDiff > int64(c.sessionLifeTime) 101 | 102 | return !isExpired 103 | } 104 | 105 | // HasSession checks if any valid Zabbix session has been cached and available 106 | func (c *SessionFileCache) HasSession() bool { 107 | _, err := os.Stat(c.filePath) 108 | 109 | return err == nil 110 | } 111 | 112 | // Flush removes a cached session 113 | func (c *SessionFileCache) Flush() error { 114 | return os.Remove(c.filePath) 115 | } 116 | 117 | // NewSessionFileCache creates a new instance of session file system cache 118 | func NewSessionFileCache() *SessionFileCache { 119 | return &SessionFileCache{ 120 | filePath: "./zabbix_session", 121 | sessionLifeTime: 14400, // Default TTL is 4 hours 122 | filePermissions: 0600, 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /get_parameters.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | const ( 4 | // SortOrderAscending is a valid value for GetParameters.SortOrder and 5 | // causes an API query to return all results sorted in ascending order by 6 | // the fields specified in GetParmeters.SortField. 7 | SortOrderAscending = "ASC" 8 | 9 | // SortOrderDescending is a valid value for GetParameters.SortOrder and 10 | // causes an API query to return all results sorted in descending order by 11 | // the fields specified in GetParmeters.SortField. 12 | SortOrderDescending = "DESC" 13 | ) 14 | 15 | // GetParameters represents the common parameters for all API Get methods. 16 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference_commentary#common_get_method_parameters 17 | type GetParameters struct { 18 | // CountOutput indicates whether an API call should return the number of 19 | // records in the result instead of the actual data. 20 | CountOutput bool `json:"countOutput,omitempty"` 21 | 22 | // EditableOnly indicates whether an API call should only return results 23 | // that the user has write permissions to. 24 | EditableOnly bool `json:"editable,omitempty"` 25 | 26 | // ExcludeSearch indicates whether an API call should only return result 27 | // that do not match the given Search parameter. 28 | ExcludeSearch bool `json:"excludeSearch,omitempty"` 29 | 30 | // Filter causes an API query to return only results that exactly match the 31 | // given filter where map keys are the API fields to query and map values 32 | // are an exact value (or array of values) that must match each key field. 33 | // 34 | // Not valid for text fields. 35 | Filter map[string]interface{} `json:"filter,omitempty"` 36 | 37 | // ResultLimit limits the number of records returned by an API query. 38 | ResultLimit int `json:"limit,omitempty"` 39 | 40 | // NodeIDs causes an API query to return only the result that belong to the 41 | // given Zabbix nodes. 42 | NodeIDs []string `json:"nodeids,omitempty"` 43 | 44 | // OutputFields causes an API query to return only the given fields for each 45 | // result. 46 | // 47 | // Default: SelectExtendedOutput 48 | OutputFields SelectQuery `json:"output,omitempty"` 49 | 50 | // PreserveKeys causes an API query to return all results using the IDs of 51 | // each result as a key in the JSON response. 52 | // This parameter is deliberately not implemented as the the current 53 | // implementation of JSON decoding expects an array of objects, not an 54 | // associative array. 55 | // PreserveKeys bool `json:"preservekeys,omitempty"` 56 | 57 | // TextSearch causes an API query to return only results that match the 58 | // given wilcard search where the map keys are the desired field names and 59 | // the map values are the search expression. 60 | // 61 | // Only string and text fields are supported. 62 | TextSearch map[string]string `json:"search,omitempty"` 63 | 64 | // TextSearchByStart causes an API query to return only results that match 65 | // the search parameters given in TextSearch where each given field starts 66 | // with the given search expressions. 67 | // 68 | // By default, TextSearch will return results that match a search expression 69 | // anywhere in a field's value; not just the start. 70 | TextSearchByStart bool `json:"startSearch,omitempty"` 71 | 72 | // SearchByAny currently has an unknown affect (TODO). According to the 73 | // Zabbix API documentation: If set to true return results that match any of 74 | // the criteria given in the filter or search parameter instead of all of 75 | // them. 76 | SearchByAny bool `json:"searchByAny,omitempty"` 77 | 78 | // EnableTextSearchWildcards enables the use of "*" as a wildcard character 79 | // in the given TextSearch search criteria. 80 | EnableTextSearchWildcards bool `json:"searchWildcardsEnabled,omitempty"` 81 | 82 | // Return only hosts that have inventory data matching the given wildcard search. 83 | // This parameter is affected by the same additional parameters as search. 84 | SearchInventory map[string]string `json:"searchInventory,omitempty"` 85 | 86 | // SortField causes an API query to return all results sorted by the given 87 | // field names. 88 | SortField []string `json:"sortfield,omitempty"` 89 | 90 | // SortOrder causes an API query to return all results sorted in the given 91 | // order if SortField is defined. 92 | // 93 | // Must be one of SortOrderAscending or SortOrderDescending. 94 | SortOrder string `json:"sortorder,omitempty"` 95 | } 96 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cavaliercoder/go-zabbix 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zabbix-tools/go-zabbix/93725c39d6394d3f9784fa4bce8893ae0d44f44e/go.sum -------------------------------------------------------------------------------- /history.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // History represents a Zabbix History returned from the Zabbix API. 8 | // 9 | // See: https://www.zabbix.com/documentation/4.0/manual/api/reference/history/object 10 | type History struct { 11 | // Clock is the time when that value was received. 12 | Clock int 13 | 14 | // ItemID is the ID of the related item. 15 | ItemID int 16 | 17 | // Ns is the nanoseconds when the value was received. 18 | Ns int 19 | 20 | // Value is the received value. 21 | // Possible types: 0 - float; 1 - character; 2 - log; 3 - int; 4 - text; 22 | Value string 23 | 24 | // LogEventID is the Windows event log entry ID. 25 | LogEventID int 26 | 27 | // Severity is the Windows event log entry level. 28 | Severity int 29 | 30 | // Source is the Windows event log entry source. 31 | Source string 32 | 33 | // Timestamp is the Windows event log entry time. 34 | Timestamp string 35 | } 36 | 37 | type HistoryGetParams struct { 38 | GetParameters 39 | 40 | // History object types to return 41 | // Possible values: 0 - numeric float, 1 - character, 2 - log, 42 | // 3 - numeric signed, 4, text 43 | // Default: 3 44 | History int `json:"history"` 45 | 46 | // HistoryIDs filters search results to histories with the given History ID's. 47 | HistoryIDs []string `json:"historyids,omitempty"` 48 | 49 | // ItemIDs filters search results to histories belong to the hosts 50 | // of the given Item ID's. 51 | ItemIDs []string `json:"itemids,omitempty"` 52 | 53 | // Return only values that have been received after or at the given time. 54 | TimeFrom float64 `json:"time_from,omitempty"` 55 | 56 | // Return only values that have been received before or at the given time. 57 | TimeTill float64 `json:"time_till,omitempty"` 58 | } 59 | 60 | // GetHistories queries the Zabbix API for Histories matching the given search 61 | // parameters. 62 | // 63 | // ErrEventNotFound is returned if the search result set is empty. 64 | // An error is returned if a transport, parsing or API error occurs. 65 | func (c *Session) GetHistories(params HistoryGetParams) ([]History, error) { 66 | histories := make([]jHistory, 0) 67 | err := c.Get("history.get", params, &histories) 68 | if err != nil { 69 | return nil, err 70 | } 71 | if len(histories) == 0 { 72 | return nil, ErrNotFound 73 | } 74 | // map JSON Events to Go Events 75 | out := make([]History, len(histories)) 76 | for i, jhistory := range histories { 77 | history, err := jhistory.History() 78 | if err != nil { 79 | return nil, fmt.Errorf("Error mapping History %d in response: %v", i, err) 80 | } 81 | out[i] = *history 82 | } 83 | 84 | return out, nil 85 | } 86 | -------------------------------------------------------------------------------- /history_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | // jHistory is a private map for the Zabbix API History object. 9 | // See: https://www.zabbix.com/documentation/4.0/manual/api/reference/history/get 10 | type jHistory struct { 11 | ItemID string `json:"itemid"` 12 | Clock string `json:"clock"` 13 | Ns string `json:"ns"` 14 | Value string `json:"value"` 15 | LogEventID string `json:"logeventid,omitempty"` 16 | Severity string `json:"severity,omitempty"` 17 | Source string `json:"source,omitempty"` 18 | Timestamp string `json:"timestamp,omitempty"` 19 | } 20 | 21 | // History returns a native Go History struct mapped from the given JSON History data. 22 | func (c *jHistory) History() (*History, error) { 23 | var err error 24 | history := &History{} 25 | 26 | history.Clock, err = strconv.Atoi(c.Clock) 27 | if err != nil { 28 | return nil, fmt.Errorf("Error parsing History Clock: %v", err) 29 | } 30 | 31 | history.ItemID, err = strconv.Atoi(c.ItemID) 32 | if err != nil { 33 | return nil, fmt.Errorf("Error parsing History ItemID: %v", err) 34 | } 35 | 36 | history.Ns, err = strconv.Atoi(c.Ns) 37 | if err != nil { 38 | return nil, fmt.Errorf("Error parsing History Ns: %v", err) 39 | } 40 | 41 | history.Value = c.Value 42 | 43 | if c.LogEventID != "" { 44 | history.LogEventID, err = strconv.Atoi(c.LogEventID) 45 | if err != nil { 46 | return nil, fmt.Errorf("Error parsing History LogEventID: %v", err) 47 | } 48 | } 49 | 50 | if c.Severity != "" { 51 | history.LogEventID, err = strconv.Atoi(c.Severity) 52 | if err != nil { 53 | return nil, fmt.Errorf("Error parsing History Severity: %v", err) 54 | } 55 | } 56 | 57 | history.Source = c.Source 58 | 59 | history.Timestamp = c.Timestamp 60 | 61 | return history, err 62 | } 63 | 64 | // jHistories is a slice of jHistory structs. 65 | type jHistories []jHistory 66 | 67 | // Histories returns a native Go slice of Histories mapped from the given JSON HISTORIES 68 | // data. 69 | func (c jHistories) Histories() ([]History, error) { 70 | if c != nil { 71 | histories := make([]History, len(c)) 72 | for i, jhistory := range c { 73 | history, err := jhistory.History() 74 | if err != nil { 75 | return nil, fmt.Errorf("Error unmarshalling History %d in JSON data: %v", i, err) 76 | } 77 | histories[i] = *history 78 | } 79 | 80 | return histories, nil 81 | } 82 | 83 | return nil, nil 84 | } 85 | -------------------------------------------------------------------------------- /host.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | const ( 4 | // HostSourceDefault indicates that a Host was created in the normal way. 5 | HostSourceDefault = 0 6 | 7 | // HostSourceDiscovery indicates that a Host was created by Host discovery. 8 | HostSourceDiscovery = 4 9 | 10 | // HostAvailabilityUnknown Unknown availability of host, never has come online 11 | HostAvailabilityUnknown = 0 12 | 13 | // HostAvailabilityAvailable Host is available 14 | HostAvailabilityAvailable = 1 15 | 16 | // HostAvailabilityUnavailable Host is NOT available 17 | HostAvailabilityUnavailable = 2 18 | 19 | // HostInventoryModeDisabled Host inventory in disabled 20 | HostInventoryModeDisabled = -1 21 | 22 | // HostInventoryModeManual Host inventory is managed manually 23 | HostInventoryModeManual = 0 24 | 25 | // HostInventoryModeAutomatic Host inventory is managed automatically 26 | HostInventoryModeAutomatic = 1 27 | 28 | // HostTLSConnectUnencryped connect unencrypted to or from host 29 | HostTLSConnectUnencryped = 1 30 | 31 | // HostTLSConnectPSK connect with PSK to or from host 32 | HostTLSConnectPSK = 2 33 | 34 | // HostTLSConnectCertificate connect with certificate to or from host 35 | HostTLSConnectCertificate = 4 36 | 37 | // HostStatusMonitored Host is monitored 38 | HostStatusMonitored = 0 39 | 40 | // HostStatusUnmonitored Host is not monitored 41 | HostStatusUnmonitored = 1 42 | ) 43 | 44 | // Host represents a Zabbix Host returned from the Zabbix API. 45 | // 46 | // See: https://www.zabbix.com/documentation/2.2/manual/config/hosts 47 | type Host struct { 48 | // HostID is the unique ID of the Host. 49 | HostID string `json:"hostid"` 50 | 51 | // Hostname is the technical name of the Host. 52 | Hostname string `json:"host"` 53 | 54 | // DisplayName is the visible name of the Host. 55 | DisplayName string `json:"name,omitempty"` 56 | 57 | // Source is the origin of the Host and must be one of the HostSource 58 | // constants. 59 | Source int `json:"flags,string,omitempty"` 60 | 61 | // Macros contains all Host Macros assigned to the Host. 62 | Macros []HostMacro `json:"macros,omitempty"` 63 | 64 | // Groups contains all Host Groups assigned to the Host. 65 | Groups []Hostgroup `json:"groups,omitempty"` 66 | 67 | MaintenanceStatus string `json:"maintenance_status"` 68 | MaintenanceID string `json:"maintenanceid"` 69 | MaintenanceType string `json:"maintenance_type"` 70 | MaintenanceFrom string `json:"maintenance_from"` 71 | 72 | // Status of the host 73 | Status int `json:"status,string"` 74 | 75 | // Availbility of host 76 | // *NOTE*: this field was removed in Zabbix 5.4 77 | // See: https://support.zabbix.com/browse/ZBXNEXT-6311 78 | Available int `json:"available,string,omitempty"` 79 | 80 | // Description of host 81 | Description string `json:"description"` 82 | 83 | // Inventory mode 84 | InventoryMode int `json:"inventory_mode"` 85 | 86 | // HostID of the proxy managing this host 87 | ProxyHostID string `json:"proxy_hostid"` 88 | 89 | // How should we connect to host 90 | TLSConnect int `json:"tls_connect,string"` 91 | 92 | // What type of connections we accept from host 93 | TLSAccept int `json:"tls_accept,string"` 94 | 95 | TLSIssuer string `json:"tls_issuer"` 96 | TLSSubject string `json:"tls_subject"` 97 | TLSPSKIdentity string `json:"tls_psk_identity"` 98 | TLSPSK string `json:"tls_psk"` 99 | } 100 | 101 | // HostGetParams represent the parameters for a `host.get` API call. 102 | // 103 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference/host/get#parameters 104 | type HostGetParams struct { 105 | GetParameters 106 | 107 | // GroupIDs filters search results to hosts that are members of the given 108 | // Group IDs. 109 | GroupIDs []string `json:"groupids,omitempty"` 110 | 111 | // ApplicationIDs filters search results to hosts that have items in the 112 | // given Application IDs. 113 | ApplicationIDs []string `json:"applicationids,omitempty"` 114 | 115 | // DiscoveredServiceIDs filters search results to hosts that are related to 116 | // the given discovered service IDs. 117 | DiscoveredServiceIDs []string `json:"dserviceids,omitempty"` 118 | 119 | // GraphIDs filters search results to hosts that have the given graph IDs. 120 | GraphIDs []string `json:"graphids,omitempty"` 121 | 122 | // HostIDs filters search results to hosts that matched the given Host IDs. 123 | HostIDs []string `json:"hostids,omitempty"` 124 | 125 | // WebCheckIDs filters search results to hosts with the given Web Check IDs. 126 | WebCheckIDs []string `json:"httptestids,omitempty"` 127 | 128 | // InterfaceIDs filters search results to hosts that use the given Interface 129 | // IDs. 130 | InterfaceIDs []string `json:"interfaceids,omitempty"` 131 | 132 | // ItemIDs filters search results to hosts with the given Item IDs. 133 | ItemIDs []string `json:"itemids,omitempty"` 134 | 135 | // MaintenanceIDs filters search results to hosts that are affected by the 136 | // given Maintenance IDs 137 | MaintenanceIDs []string `json:"maintenanceids,omitempty"` 138 | 139 | // MonitoredOnly filters search results to return only monitored hosts. 140 | MonitoredOnly bool `json:"monitored_hosts,omitempty"` 141 | 142 | // ProxyOnly filters search results to hosts which are Zabbix proxies. 143 | ProxiesOnly bool `json:"proxy_host,omitempty"` 144 | 145 | // ProxyIDs filters search results to hosts monitored by the given Proxy 146 | // IDs. 147 | ProxyIDs []string `json:"proxyids,omitempty"` 148 | 149 | // IncludeTemplates extends search results to include Templates. 150 | IncludeTemplates bool `json:"templated_hosts,omitempty"` 151 | 152 | // SelectGroups causes the Host Groups that each Host belongs to to be 153 | // attached in the search results. 154 | SelectGroups SelectQuery `json:"selectGroups,omitempty"` 155 | 156 | // SelectApplications causes the Applications from each Host to be attached 157 | // in the search results. 158 | SelectApplications SelectQuery `json:"selectApplications,omitempty"` 159 | 160 | // SelectDiscoveries causes the Low-Level Discoveries from each Host to be 161 | // attached in the search results. 162 | SelectDiscoveries SelectQuery `json:"selectDiscoveries,omitempty"` 163 | 164 | // SelectDiscoveryRule causes the Low-Level Discovery Rule that created each 165 | // Host to be attached in the search results. 166 | SelectDiscoveryRule SelectQuery `json:"selectDiscoveryRule,omitempty"` 167 | 168 | // SelectGraphs causes the Graphs from each Host to be attached in the 169 | // search results. 170 | SelectGraphs SelectQuery `json:"selectGraphs,omitempty"` 171 | 172 | SelectHostDiscovery SelectQuery `json:"selectHostDiscovery,omitempty"` 173 | 174 | SelectWebScenarios SelectQuery `json:"selectHttpTests,omitempty"` 175 | 176 | SelectInterfaces SelectQuery `json:"selectInterfaces,omitempty"` 177 | 178 | SelectInventory SelectQuery `json:"selectInventory,omitempty"` 179 | 180 | SelectItems SelectQuery `json:"selectItems,omitempty"` 181 | 182 | SelectMacros SelectQuery `json:"selectMacros,omitempty"` 183 | 184 | SelectParentTemplates SelectQuery `json:"selectParentTemplates,omitempty"` 185 | SelectScreens SelectQuery `json:"selectScreens,omitempty"` 186 | SelectTriggers SelectQuery `json:"selectTriggers,omitempty"` 187 | } 188 | 189 | // GetHosts queries the Zabbix API for Hosts matching the given search 190 | // parameters. 191 | // 192 | // ErrEventNotFound is returned if the search result set is empty. 193 | // An error is returned if a transport, parsing or API error occurs. 194 | func (c *Session) GetHosts(params HostGetParams) ([]Host, error) { 195 | hosts := make([]Host, 0) 196 | err := c.Get("host.get", params, &hosts) 197 | if err != nil { 198 | return nil, err 199 | } 200 | 201 | if len(hosts) == 0 { 202 | return nil, ErrNotFound 203 | } 204 | 205 | return hosts, nil 206 | } 207 | -------------------------------------------------------------------------------- /host_interface.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | const ( 4 | // HostInterfaceAvailabilityUnknown Unknown availability of host, never has come online 5 | HostInterfaceAvailabilityUnknown = 0 6 | // HostInterfaceAvailabilityAvailable Host is available 7 | HostInterfaceAvailabilityAvailable = 1 8 | // HostInterfaceAvailabilityUnavailable Host is NOT available 9 | HostInterfaceAvailabilityUnavailable = 2 10 | 11 | // HostInterfaceTypeAgent Host interface type agent 12 | HostInterfaceTypeAgent = 1 13 | // HostInterfaceTypeSNMP Host interface type SNMP 14 | HostInterfaceTypeSNMP = 2 15 | // HostInterfaceTypeIPMI Host interface type IPMI 16 | HostInterfaceTypeIPMI = 3 17 | // HostInterfaceTypeJMX Host interface type JMX 18 | HostInterfaceTypeJMX = 4 19 | ) 20 | 21 | // HostInterface This class is designed to work with host interfaces. 22 | // 23 | // See https://www.zabbix.com/documentation/current/manual/api/reference/hostinterface/object#host_interface 24 | type HostInterface struct { 25 | // (readonly) ID of the interface. 26 | InterfaceID string `json:"interfaceid"` 27 | 28 | // (readonly) Availability of host interface. 29 | Available int `json:"available,string,omitempty"` 30 | 31 | // DNS name used by the interface. 32 | DNS string `json:"dns"` 33 | 34 | // IP address used by the interface. 35 | IP string `json:"ip"` 36 | 37 | // (readonly) Error text if host interface is unavailable. 38 | Error string `json:"error,omitempty"` 39 | 40 | // (readonly) Time when host interface became unavailable. 41 | ErrorsFrom *UnixTimestamp `json:"errors_from,string,omitempty"` 42 | 43 | // ID of the host the interface belongs to. 44 | HostID string `json:"hostid"` 45 | 46 | // Whether the interface is used as default on the host. Only one interface of some type can be set as default on a host. 47 | Main ZBXBoolean `json:"main,string"` 48 | 49 | // Interface type. 50 | Type int `json:"type,string"` 51 | 52 | // Whether the connection should be made via IP. 53 | UseIP ZBXBoolean `json:"useip,string"` 54 | } 55 | 56 | type HostInterfaceGetParams struct { 57 | GetParameters 58 | 59 | // Return only host interfaces used by the given hosts. 60 | HostIDs []string `json:"hostids,omitempty"` 61 | 62 | // Return only host interfaces with the given IDs. 63 | InterfaceIDs []string `json:"interfaceids,omitempty"` 64 | 65 | // Return only host interfaces used by the given items. 66 | ItemIDs []string `json:"itemids,omitempty"` 67 | 68 | // Return only host interfaces used by items in the given triggers. 69 | TriggerIDs []string `json:"triggerids,omitempty"` 70 | } 71 | 72 | // GetHostInterfaces queries the Zabbix API for Hosts interfaces matching the given search 73 | // parameters. 74 | // 75 | // ErrEventNotFound is returned if the search result set is empty. 76 | // An error is returned if a transport, parsing or API error occurs. 77 | func (c *Session) GetHostInterfaces(params HostInterfaceGetParams) ([]HostInterface, error) { 78 | hostInterfaces := make([]HostInterface, 0) 79 | err := c.Get("hostinterface.get", params, &hostInterfaces) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | if len(hostInterfaces) == 0 { 85 | return nil, ErrNotFound 86 | } 87 | 88 | return hostInterfaces, nil 89 | } 90 | -------------------------------------------------------------------------------- /host_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | //"strconv" 6 | ) 7 | 8 | // jHost is a private map for the Zabbix API Host object. 9 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference/host/object 10 | type jHost struct { 11 | HostID string `json:"hostid"` 12 | Hostname string `json:"host"` 13 | Flags int `json:"flags,string,omitempty"` 14 | Name string `json:"name,omitempty"` 15 | Macros []HostMacro `json:"macros,omitempty"` 16 | Groups []Hostgroup `json:"groups,omitempty"` 17 | } 18 | 19 | // Host returns a native Go Host struct mapped from the given JSON Host data. 20 | func (c *jHost) Host() (*Host, error) { 21 | //var err error 22 | 23 | host := &Host{} 24 | host.HostID = c.HostID 25 | host.Hostname = c.Hostname 26 | host.DisplayName = c.Name 27 | host.Macros = c.Macros 28 | host.Groups = c.Groups 29 | /* 30 | host.Source, err = strconv.Atoi(c.Flags) 31 | if err != nil { 32 | return nil, fmt.Errorf("Error parsing Host Flags: %v", err) 33 | } 34 | */ 35 | host.Source = c.Flags 36 | return host, nil 37 | } 38 | 39 | // jHosts is a slice of jHost structs. 40 | type jHosts []jHost 41 | 42 | // Hosts returns a native Go slice of Hosts mapped from the given JSON Hosts 43 | // data. 44 | func (c jHosts) Hosts() ([]Host, error) { 45 | if c != nil { 46 | hosts := make([]Host, len(c)) 47 | for i, jhost := range c { 48 | host, err := jhost.Host() 49 | if err != nil { 50 | return nil, fmt.Errorf("Error unmarshalling Host %d in JSON data: %v", i, err) 51 | } 52 | 53 | hosts[i] = *host 54 | } 55 | 56 | return hosts, nil 57 | } 58 | 59 | return nil, nil 60 | } 61 | -------------------------------------------------------------------------------- /host_macro.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | // HostMacro represents a Zabbix Host Macro returned from the Zabbix API. 4 | type HostMacro struct { 5 | // HostMacroID is the unique ID of the Host Macro. 6 | HostMacroID string `json:"hostmacroid"` 7 | 8 | // HostID is the ID of the Host which owns this Macro. 9 | HostID string `json:"hostid"` 10 | 11 | // Macro is the name of the Macro (e.g. '{HOST.MACRO}'). 12 | Macro string `json:"macro"` 13 | 14 | // Value is the value of the Macro. 15 | Value string `json:"value"` 16 | } 17 | -------------------------------------------------------------------------------- /hostgroup.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const ( 8 | // HostgroupSourcePlain indicates that a Hostgroup was created in the normal way. 9 | HostgroupSourcePlain = 0 10 | 11 | // HostgroupSourceDiscovery indicates that a Hostgroup was created by Host discovery. 12 | HostgroupSourceDiscovery = 4 13 | 14 | // HostgroupInternalNo indicates that a Hostgroup is used not internally by the system. 15 | HostgroupInternalNo = 0 16 | 17 | // HostgroupInternalYes indicates that a Hostgroup is used internally by the system. 18 | HostgroupInternalYes = 1 19 | ) 20 | 21 | // Hostgroup represents a Zabbix Hostgroup Object returned from the Zabbix API (see zabbix documentation). 22 | type Hostgroup struct { 23 | GroupID string `json:"groupid"` 24 | Name string `json:"name"` 25 | Flags string `json:"flags"` 26 | Internal string `json:"internal"` 27 | Hosts []Host `json:"hosts,omitempty"` 28 | } 29 | 30 | // HostgroupGetParams represent the parameters for a `hostgroup.get` API call (see zabbix documentation). 31 | type HostgroupGetParams struct { 32 | GetParameters 33 | 34 | // Return only host groups that contain hosts or templates with the given graphs 35 | GraphIDs []string `json:"graphids,omitempty"` 36 | 37 | // Return only host groups with the given host group IDs 38 | GroupIDs []string `json:"groupids,omitempty"` 39 | 40 | // Return only host groups that contain the given hosts 41 | HostIDs []string `json:"hostids,omitempty"` 42 | 43 | // Return only host groups that are affected by the given maintenances 44 | MaintenanceIDs []string `json:"maintenanceids,omitempty"` 45 | 46 | // Return only host groups that contain monitored hosts 47 | MonitoredHosts int `json:"monitored_hosts,omitempty"` 48 | 49 | // Return only host groups that contain hosts 50 | RealHosts int `json:"real_hosts,omitempty"` 51 | 52 | // Return only host groups that contain templates 53 | TemplatedHosts int `json:"templated_hosts,omitempty"` 54 | 55 | // Return only host groups that contain the given templates 56 | TemplateIDs []string `json:"templateids,omitempty"` 57 | 58 | // Return only host groups that contain hosts or templates with the given triggers 59 | TriggerIDs []string `json:"triggerids,omitempty"` 60 | 61 | // Return only host groups that contain hosts with applications 62 | WithApplications int `json:"with_applications,omitempty"` 63 | 64 | // Return only host groups that contain hosts with graphs 65 | WithGraphs int `json:"with_graphs,omitempty"` 66 | 67 | // Return only host groups that contain hosts or templates 68 | WithHostsAndTemplates int `json:"with_hosts_and_templates,omitempty"` 69 | 70 | // Return only host groups that contain hosts with web checks 71 | WithHttptests int `json:"with_httptests,omitempty"` 72 | 73 | // Return only host groups that contain hosts or templates with items 74 | WithItems int `json:"with_items,omitempty"` 75 | 76 | // Return only host groups that contain hosts with enabled web checks 77 | WithMonitoredHttptests int `json:"with_monitored_httptests,omitempty"` 78 | 79 | // Return only host groups that contain hosts or templates with enabled items 80 | WithMonitoredItems int `json:"with_monitored_items,omitempty"` 81 | 82 | // Return only host groups that contain hosts with enabled triggers 83 | WithMonitoredTriggers int `json:"with_monitored_triggers,omitempty"` 84 | 85 | // Return only host groups that contain hosts with numeric items 86 | WithSimpleGraphItems int `json:"with_simple_graph_items,omitempty"` 87 | 88 | // Return only host groups that contain hosts with triggers 89 | WithTriggers int `json:"with_triggers,omitempty"` 90 | 91 | // Return the LLD rule that created the host group in the discoveryRule property 92 | SelectDiscoveryRule SelectQuery `json:"selectDiscoveryRule,omitempty"` 93 | 94 | // Return the host group discovery object in the groupDiscovery property 95 | SelectGroupDiscovery SelectQuery `json:"selectGroupDiscovery,omitempty"` 96 | 97 | // Return the hosts that belong to the host group in the hosts property 98 | SelectHosts SelectQuery `json:"selectHosts,omitempty"` 99 | 100 | // Return the templates that belong to the host group in the templates property 101 | SelectTemplates SelectQuery `json:"selectTemplates,omitempty"` 102 | 103 | // Limits the number of records returned by subselects 104 | LimitSelects int `json:"limitSelects,omitempty"` 105 | 106 | // Return only host groups that contain the given templates 107 | Sortfield []string `json:"sortfield,omitempty"` 108 | } 109 | 110 | // GetHostgroups queries the Zabbix API for Hostgroups matching the given search 111 | // parameters. 112 | // 113 | // ErrEventNotFound is returned if the search result set is empty. 114 | // An error is returned if a transport, parsing or API error occurs. 115 | func (c *Session) GetHostgroups(params HostgroupGetParams) ([]Hostgroup, error) { 116 | hostgroups := make([]jHostgroup, 0) 117 | err := c.Get("hostgroup.get", params, &hostgroups) 118 | if err != nil { 119 | return nil, err 120 | } 121 | 122 | if len(hostgroups) == 0 { 123 | return nil, ErrNotFound 124 | } 125 | 126 | // map JSON Events to Go Events 127 | out := make([]Hostgroup, len(hostgroups)) 128 | for i, jhostgroup := range hostgroups { 129 | hostgroup, err := jhostgroup.Hostgroup() 130 | if err != nil { 131 | return nil, fmt.Errorf("Error mapping Hostgroup %d in response: %v", i, err) 132 | } 133 | 134 | out[i] = *hostgroup 135 | } 136 | 137 | return out, nil 138 | } 139 | -------------------------------------------------------------------------------- /hostgroup_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // jHostgroup is a private map for the Hostgroup Zabbix API object (see zabbix documentation). 8 | type jHostgroup struct { 9 | GroupID string `json:"groupid"` 10 | Name string `json:"name"` 11 | Flags string `json:"flags"` 12 | Internal string `json:"internal"` 13 | Hosts jHosts `json:"hosts,omitempty"` 14 | } 15 | 16 | // Hostgroup returns a native Go Hostgroup struct mapped from the given JSON Hostgroup data. 17 | func (c *jHostgroup) Hostgroup() (*Hostgroup, error) { 18 | hostgroup := &Hostgroup{} 19 | hostgroup.GroupID = c.GroupID 20 | hostgroup.Name = c.Name 21 | hostgroup.Flags = c.Flags 22 | hostgroup.Internal = c.Internal 23 | 24 | if len(c.Hosts) > 0 { 25 | if hosts, err := c.Hosts.Hosts(); err == nil { 26 | hostgroup.Hosts = hosts 27 | } 28 | 29 | } 30 | 31 | return hostgroup, nil 32 | } 33 | 34 | // jHostgroups is a slice of jHostgroup structs. 35 | type jHostgroups []jHostgroup 36 | 37 | // Hostgroups returns a native Go slice of Hostgroups mapped from the given JSON Hostgroups 38 | // data. 39 | func (c jHostgroups) Hostgroups() ([]Hostgroup, error) { 40 | if c != nil { 41 | hosts := make([]Hostgroup, len(c)) 42 | for i, jhost := range c { 43 | host, err := jhost.Hostgroup() 44 | if err != nil { 45 | return nil, fmt.Errorf("Error unmarshalling Hostgroup %d in JSON data: %v", i, err) 46 | } 47 | 48 | hosts[i] = *host 49 | } 50 | 51 | return hosts, nil 52 | } 53 | 54 | return nil, nil 55 | } 56 | -------------------------------------------------------------------------------- /hostgroups_test.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestHostgroups(t *testing.T) { 8 | session := GetTestSession(t) 9 | 10 | params := HostgroupGetParams{} 11 | 12 | hostgroups, err := session.GetHostgroups(params) 13 | if err != nil { 14 | t.Fatalf("Error getting Hostgroups: %v", err) 15 | } 16 | 17 | if len(hostgroups) == 0 { 18 | t.Fatal("No Hostgroups found") 19 | } 20 | 21 | for i, hostgroup := range hostgroups { 22 | if hostgroup.GroupID == "" { 23 | t.Fatalf("Hostgroup %d returned in response body has no Group ID", i) 24 | } 25 | } 26 | 27 | t.Logf("Validated %d Hostgroups", len(hostgroups)) 28 | } 29 | -------------------------------------------------------------------------------- /hosts_test.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestHosts(t *testing.T) { 8 | session := GetTestSession(t) 9 | 10 | params := HostGetParams{ 11 | IncludeTemplates: true, 12 | SelectGroups: SelectExtendedOutput, 13 | SelectApplications: SelectExtendedOutput, 14 | SelectDiscoveries: SelectExtendedOutput, 15 | SelectDiscoveryRule: SelectExtendedOutput, 16 | SelectGraphs: SelectExtendedOutput, 17 | SelectHostDiscovery: SelectExtendedOutput, 18 | SelectWebScenarios: SelectExtendedOutput, 19 | SelectInterfaces: SelectExtendedOutput, 20 | SelectInventory: SelectExtendedOutput, 21 | SelectItems: SelectExtendedOutput, 22 | SelectMacros: SelectExtendedOutput, 23 | SelectParentTemplates: SelectExtendedOutput, 24 | SelectScreens: SelectExtendedOutput, 25 | SelectTriggers: SelectExtendedOutput, 26 | } 27 | 28 | hosts, err := session.GetHosts(params) 29 | if err != nil { 30 | t.Fatalf("Error getting Hosts: %v", err) 31 | } 32 | 33 | if len(hosts) == 0 { 34 | t.Fatal("No Hosts found") 35 | } 36 | 37 | for i, host := range hosts { 38 | if host.HostID == "" { 39 | t.Fatalf("Host %d returned in response body has no Host ID", i) 40 | } 41 | } 42 | 43 | t.Logf("Validated %d Hosts", len(hosts)) 44 | } 45 | -------------------------------------------------------------------------------- /item.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Item represents a Zabbix Item returned from the Zabbix API. 8 | // 9 | // See: https://www.zabbix.com/documentation/4.0/manual/api/reference/item/object 10 | type Item struct { 11 | // HostID is the unique ID of the Host. 12 | HostID int 13 | 14 | // ItemID is the unique ID of the Item. 15 | ItemID int 16 | 17 | // Itemname is the technical name of the Item. 18 | ItemName string 19 | 20 | // ItemDescr is the description of the Item. 21 | ItemDescr string 22 | 23 | // LastClock is the last Item epoh time. 24 | LastClock int 25 | 26 | // LastValue is the last value of the Item. 27 | LastValue string 28 | 29 | // LastValueType is the type of LastValue 30 | // 0 - float; 1 - text; 3 - int; 31 | LastValueType int 32 | } 33 | 34 | type ItemTagFilter struct { 35 | Tag string `json:"tag"` 36 | Value string `json:"value"` 37 | Operator int `json:"operator"` 38 | } 39 | 40 | type ItemGetParams struct { 41 | GetParameters 42 | 43 | // ItemIDs filters search results to items with the given Item ID's. 44 | ItemIDs []string `json:"itemids,omitempty"` 45 | 46 | // GroupIDs filters search results to items belong to the hosts 47 | // of the given Group ID's. 48 | GroupIDs []string `json:"groupids,omitempty"` 49 | 50 | // TemplateIDs filters search results to items belong to the 51 | // given templates of the given Template ID's. 52 | TemplateIDs []string `json:"templateids,omitempty"` 53 | 54 | // HostIDs filters search results to items belong to the 55 | // given Host ID's. 56 | HostIDs []string `json:"hostids,omitempty"` 57 | 58 | // ProxyIDs filters search results to items that are 59 | // monitored by the given Proxy ID's. 60 | ProxyIDs []string `json:"proxyids,omitempty"` 61 | 62 | // InterfaceIDs filters search results to items that use 63 | // the given host Interface ID's. 64 | InterfaceIDs []string `json:"interfaceids,omitempty"` 65 | 66 | // GraphIDs filters search results to items that are used 67 | // in the given graph ID's. 68 | GraphIDs []string `json:"graphids,omitempty"` 69 | 70 | // TriggerIDs filters search results to items that are used 71 | // in the given Trigger ID's. 72 | TriggerIDs []string `json:"triggerids,omitempty"` 73 | 74 | // ApplicationIDs filters search results to items that 75 | // belong to the given Applications ID's. 76 | ApplicationIDs []string `json:"applicationids,omitempty"` 77 | 78 | // WebItems flag includes web items in the result. 79 | WebItems bool `json:"webitems,omitempty"` 80 | 81 | // Inherited flag return only items inherited from a template 82 | // if set to 'true'. 83 | Inherited bool `json:"inherited,omitempty"` 84 | 85 | // Templated flag return only items that belong to templates 86 | // if set to 'true'. 87 | Templated bool `json:"templated,omitempty"` 88 | 89 | // Monitored flag return only enabled items that belong to 90 | // monitored hosts if set to 'true'. 91 | Monitored bool `json:"monitored,omitempty"` 92 | 93 | // Group filters search results to items belong to a group 94 | // with the given name. 95 | Group string `json:"group,omitempty"` 96 | 97 | // Host filters search results to items that belong to a host 98 | // with the given name. 99 | Host string `json:"host,omitempty"` 100 | 101 | // Application filters search results to items that belong to 102 | // an application with the given name. 103 | Application string `json:"application,omitempty"` 104 | 105 | // WithTriggers flag return only items that are used in triggers 106 | WithTriggers bool `json:"with_triggers,omitempty"` 107 | 108 | // Filter by tags 109 | Tags []ItemTagFilter `json:"tags,omitempty"` 110 | } 111 | 112 | // GetItems queries the Zabbix API for Items matching the given search 113 | // parameters. 114 | // 115 | // ErrEventNotFound is returned if the search result set is empty. 116 | // An error is returned if a transport, parsing or API error occurs. 117 | func (c *Session) GetItems(params ItemGetParams) ([]Item, error) { 118 | items := make([]jItem, 0) 119 | err := c.Get("item.get", params, &items) 120 | if err != nil { 121 | return nil, err 122 | } 123 | if len(items) == 0 { 124 | return nil, ErrNotFound 125 | } 126 | // map JSON Events to Go Events 127 | out := make([]Item, len(items)) 128 | for i, jitem := range items { 129 | item, err := jitem.Item() 130 | if err != nil { 131 | return nil, fmt.Errorf("Error mapping Item %d in response: %v", i, err) 132 | } 133 | out[i] = *item 134 | } 135 | 136 | return out, nil 137 | } 138 | -------------------------------------------------------------------------------- /item_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | // jItem is a private map for the Zabbix API Host object. 9 | // See: https://www.zabbix.com/documentation/4.0/manual/api/reference/item/get 10 | type jItem struct { 11 | HostID string `json:"hostid,omitempty"` 12 | ItemID string `json:"itemid"` 13 | ItemName string `json:"name"` 14 | ItemDescr string `json:"description,omitempty"` 15 | LastClock string `json:"lastclock,omitempty"` 16 | LastValue string `json:"lastvalue,omitempty"` 17 | LastValueType string `json:"value_type"` 18 | } 19 | 20 | // Item returns a native Go Item struct mapped from the given JSON Item data. 21 | func (c *jItem) Item() (*Item, error) { 22 | var err error 23 | item := &Item{} 24 | item.HostID, err = strconv.Atoi(c.HostID) 25 | if err != nil { 26 | return nil, fmt.Errorf("Error parsing Host ID: %v", err) 27 | } 28 | item.ItemID, err = strconv.Atoi(c.ItemID) 29 | if err != nil { 30 | return nil, fmt.Errorf("Error parsing Item ID: %v", err) 31 | } 32 | item.ItemName = c.ItemName 33 | item.ItemDescr = c.ItemDescr 34 | 35 | item.LastClock, err = strconv.Atoi(c.LastClock) 36 | if err != nil { 37 | return nil, fmt.Errorf("Error parsing Item LastClock: %v", err) 38 | } 39 | item.LastValue = c.LastValue 40 | 41 | item.LastValueType, err = strconv.Atoi(c.LastValueType) 42 | if err != nil { 43 | return nil, fmt.Errorf("Error parsing Item LastValueType: %v", err) 44 | } 45 | return item, err 46 | } 47 | 48 | // jItems is a slice of jItems structs. 49 | type jItems []jItem 50 | 51 | // Items returns a native Go slice of Items mapped from the given JSON ITEMS 52 | // data. 53 | func (c jItems) Items() ([]Item, error) { 54 | if c != nil { 55 | items := make([]Item, len(c)) 56 | for i, jitem := range c { 57 | item, err := jitem.Item() 58 | if err != nil { 59 | return nil, fmt.Errorf("Error unmarshalling Item %d in JSON data: %v", i, err) 60 | } 61 | items[i] = *item 62 | } 63 | 64 | return items, nil 65 | } 66 | 67 | return nil, nil 68 | } 69 | -------------------------------------------------------------------------------- /maintenance.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | type MaintenanceType int 11 | type TagsEvaltype int 12 | 13 | var ErrMaintenanceHostNotFound = errors.New("Failed to find ID by host name") 14 | 15 | const ( 16 | withDataCollection MaintenanceType = iota 17 | withoutDataCollection 18 | 19 | and TagsEvaltype = iota * 2 20 | or 21 | 22 | Once int = iota 23 | EveryDay 24 | EveryWeek 25 | EveryMonth 26 | ) 27 | 28 | type Maintenance struct { 29 | MaintenanceID string 30 | Name string 31 | ActiveSince time.Time 32 | ActiveTill time.Time 33 | Description string 34 | // Service period in hours 35 | ServicePeriod int 36 | Type MaintenanceType 37 | ActionEvalTypeAndOr TagsEvaltype 38 | } 39 | 40 | type MaintenanceGetParams struct { 41 | GetParameters 42 | 43 | // Sort the result by the given properties. 44 | // Possible values are: maintenanceid, name and maintenance_type. 45 | SortField []string `json:"sortfield,omitempty"` 46 | 47 | // Return the maintenance's time periods in the timeperiods property. 48 | SelectTimeperiods SelectQuery `json:"selectTimeperiods,omitempty"` 49 | 50 | // Return hosts assigned to the maintenance in the hosts property. 51 | SelectHosts SelectQuery `json:"selectHosts,omitempty"` 52 | 53 | // Return host groups assigned to the maintenance in the groups property. 54 | SelectGroups SelectQuery `json:"selectGroups,omitempty"` 55 | 56 | // Return only maintenances with the given IDs. 57 | Maintenanceids []string `json:"maintenanceids,omitempty"` 58 | 59 | // Return only maintenances that are assigned to the given hosts. 60 | Hostids []string `json:"hostids,omitempty"` 61 | 62 | // Return only maintenances that are assigned to the given host groups. 63 | Groupids []string `json:"groupids,omitempty"` 64 | } 65 | 66 | type MaintenanceCreateParams struct { 67 | JMaintenance 68 | 69 | Groupids []string `json:"groupids,omitempty"` 70 | // Hosts name 71 | HostNames []string `json:"-"` 72 | HostIDs []string `json:"hostids"` 73 | Timeperiods []Timeperiods `json:"timeperiods"` 74 | Tags []string `json:"tags,omitempty"` 75 | } 76 | 77 | type MaintenanceCreateResponse struct { 78 | IDs []string `json:"maintenanceids"` 79 | } 80 | 81 | // GetMaintenance queries the Zabbix API for Maintenance matching the given search 82 | // parameters. 83 | func (s *Session) GetMaintenance(params *MaintenanceGetParams) ([]Maintenance, error) { 84 | jmaintenance := make([]JMaintenance, 0) 85 | err := s.Get("maintenance.get", params, &jmaintenance) 86 | if err != nil { 87 | return nil, err 88 | } 89 | 90 | if len(jmaintenance) == 0 { 91 | return nil, ErrNotFound 92 | } 93 | 94 | out := make([]Maintenance, len(jmaintenance)) 95 | for i, jaction := range jmaintenance { 96 | maintenance, err := jaction.Maintenance() 97 | if err != nil { 98 | return nil, fmt.Errorf("Error mapping Maintenance %d in response: %v", i, err) 99 | } 100 | 101 | out[i] = *maintenance 102 | } 103 | 104 | return out, nil 105 | } 106 | 107 | func (s *Session) CreateMaintenance(params *MaintenanceCreateParams) (response MaintenanceCreateResponse, err error) { 108 | if err = params.FillHostIDs(s); err != nil { 109 | return 110 | } 111 | 112 | err = s.Get("maintenance.create", params, &response) 113 | return 114 | } 115 | 116 | func (m *Maintenance) Delete(session *Session) error { 117 | ID := []string{m.MaintenanceID} 118 | response := make(map[string]interface{}) 119 | if err := session.Get("maintenance.delete", ID, &response); err != nil { 120 | return err 121 | } 122 | return nil 123 | } 124 | 125 | func (m *MaintenanceCreateParams) FillHostIDs(session *Session) error { 126 | hosts, err := session.GetHosts(HostGetParams{}) 127 | if err != nil { 128 | return err 129 | } 130 | 131 | err = ErrMaintenanceHostNotFound 132 | for _, name := range m.HostNames { 133 | for _, host := range hosts { 134 | if strings.ToUpper(strings.Trim(host.Hostname, " ")) == strings.ToUpper(strings.Trim(name, " ")) { 135 | m.HostIDs = append(m.HostIDs, host.HostID) 136 | 137 | err = nil 138 | } 139 | } 140 | } 141 | 142 | return err 143 | } 144 | 145 | func (c *MaintenanceCreateParams) FillFields(Object *Maintenance) *MaintenanceCreateParams { 146 | c.ActiveSince = Object.ActiveSince.Unix() 147 | c.ActiveTill = Object.ActiveSince.Add(time.Hour * time.Duration(Object.ServicePeriod)).Unix() 148 | c.Description = Object.Description 149 | c.MaintenanceID = Object.MaintenanceID 150 | c.Name = Object.Name 151 | c.TagsEvaltype = int(Object.Type) 152 | c.MaintenanceType = int(Object.ActionEvalTypeAndOr) 153 | 154 | return c 155 | } 156 | -------------------------------------------------------------------------------- /maintenance_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // JMaintenance is a private map for the Zabbix API Maintenance object. 9 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference/maintenance/object 10 | type JMaintenance struct { 11 | MaintenanceID string `json:"maintenanceid"` 12 | Name string `json:"name"` 13 | ActiveSince int64 `json:"active_since,string"` 14 | ActiveTill int64 `json:"active_till,string"` 15 | Description string `json:"description"` 16 | MaintenanceType int `json:"maintenance_type,string"` 17 | TagsEvaltype int `json:"tags_evaltype,string"` 18 | } 19 | 20 | // Timeperiods is a private map for the Zabbix API Maintenance object. 21 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference/maintenance/object 22 | type Timeperiods struct { 23 | TimeperiodType int `json:"timeperiod_type,int"` 24 | Every int `json:"every,string"` 25 | Dayofweek int `json:"dayofweek,string"` 26 | StartTime int `json:"start_time,string"` 27 | Period int `json:"period,string"` 28 | } 29 | 30 | // Maintenance returns a native Go Maintenance struct mapped from the given JSON Maintenance 31 | // data. 32 | func (c *JMaintenance) Maintenance() (result *Maintenance, err error) { 33 | defer func() { 34 | if e := recover(); e != nil { 35 | err = fmt.Errorf("%v", e) 36 | } 37 | }() 38 | 39 | maintenance := &Maintenance{ 40 | ActionEvalTypeAndOr: TagsEvaltype(c.MaintenanceType), 41 | Type: MaintenanceType(c.TagsEvaltype), 42 | ActiveSince: time.Unix(c.ActiveSince, 0), 43 | ActiveTill: time.Unix(c.ActiveTill, 0), 44 | Description: c.Description, 45 | MaintenanceID: c.MaintenanceID, 46 | Name: c.Name, 47 | } 48 | 49 | return maintenance, nil 50 | } 51 | -------------------------------------------------------------------------------- /request.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "sync/atomic" 5 | ) 6 | 7 | // A Request represents a JSON-RPC request to be sent by a client. 8 | // 9 | // This struct maps to the JSON request body described in the Zabbix API 10 | // documentation: 11 | // https://www.zabbix.com/documentation/2.2/manual/api#authentication. 12 | type Request struct { 13 | // JSONRPCVersion is the version string of the Zabbix API. This should 14 | // always be set to "2.0". 15 | JSONRPCVersion string `json:"jsonrpc"` 16 | 17 | // Method is the name of the Zabbix API method to be called. 18 | Method string `json:"method"` 19 | 20 | // Params is the request's body. 21 | Params interface{} `json:"params"` 22 | 23 | // RequestID is an abitrary identifier for the Request which is returned in 24 | // the corresponding API Response to assist with multi-threaded 25 | // applications. This value is automatically incremented for each new 26 | // Request by NewRequest. 27 | RequestID uint64 `json:"id"` 28 | 29 | // AuthToken is the Request's authentication token. When used in a Session, 30 | // this value is overwritten by the Session. 31 | AuthToken string `json:"auth,omitempty"` 32 | } 33 | 34 | // requestId is a global counter used to assign each APi request a unique ID. 35 | var requestID uint64 36 | 37 | // NewRequest returns a new Request given an API method name, and optional 38 | // request body parameters. 39 | func NewRequest(method string, params interface{}) *Request { 40 | if params == nil { 41 | params = map[string]string{} 42 | } 43 | return &Request{ 44 | JSONRPCVersion: "2.0", 45 | Method: method, 46 | Params: params, 47 | RequestID: atomic.AddUint64(&requestID, 1), 48 | AuthToken: "", // set by session 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /response.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | // Response represents the response from a JSON-RPC API request. 9 | // 10 | // This struct maps to the JSON response body described in the Zabbix API 11 | // documentation: 12 | // https://www.zabbix.com/documentation/2.2/manual/api#authentication. 13 | type Response struct { 14 | // HTTP status code of the API response e.g. 200 15 | StatusCode int `json:"-"` 16 | 17 | // JSONRPCVersion is the version string of the Zabbix API. This should 18 | // always be set to "2.0". 19 | JSONRPCVersion string `json:"jsonrpc"` 20 | 21 | // Body represents the response body as an array of bytes. 22 | // 23 | // The Body may be decoded later into a struct with Bind or json.Unmarshal. 24 | Body json.RawMessage `json:"result"` 25 | 26 | // RequestID is an abitrary identifier which matches the RequestID set in 27 | // the corresponding API Request. 28 | RequestID int `json:"id"` 29 | 30 | // Error is populated with error information if the JSON-RPC request 31 | // succeeded but there was an API error. 32 | // 33 | // This struct maps to the JSON response body described in the Zabbix API 34 | // documentation: 35 | // https://www.zabbix.com/documentation/2.2/manual/api#error_handling. 36 | Error APIError `json:"error"` 37 | } 38 | 39 | // Err returns an error if the Response includes any error information returned 40 | // from the Zabbix API. 41 | func (c *Response) Err() error { 42 | if c.Error.Code != 0 { 43 | return fmt.Errorf("HTTP %d %s (%d)\n%s", c.StatusCode, c.Error.Message, c.Error.Code, c.Error.Data) 44 | } 45 | 46 | return nil 47 | } 48 | 49 | // Bind unmarshals the JSON body of the Response into the given interface. 50 | func (c *Response) Bind(v interface{}) error { 51 | err := json.Unmarshal(c.Body, v) 52 | if err != nil { 53 | return fmt.Errorf("Error decoding JSON response body: %v", err) 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /select_query.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | // SelectQuery represents the query data type for a Zabbix API call. 4 | // Wherever a SelectQuery is required, one of SelectFields, SelectExtendedOutput 5 | // or SelectCount should be given. 6 | // 7 | // See: https://www.zabbix.com/documentation/2.2/manual/api/reference_commentary#data_types 8 | type SelectQuery interface{} 9 | 10 | // SelectFields may be given as a SelectQuery in search parameters where each 11 | // member string is the name of a JSON field which should be returned for each 12 | // search result. 13 | // 14 | // For example, for a Host search query: 15 | // 16 | // query := SelectFields{ "hostid", "host", "name" } 17 | // 18 | type SelectFields []string 19 | 20 | const ( 21 | // SelectExtendedOutput may be given as a SelectQuery in search parameters 22 | // to return all available feilds for all objects in the search results. 23 | SelectExtendedOutput = "extend" 24 | 25 | // SelectCount may be given as a SelectQuery for supported search parameters 26 | // to return only the number of available search results, instead of the 27 | // search result details. 28 | SelectCount = "count" 29 | ) 30 | -------------------------------------------------------------------------------- /session.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "io/ioutil" 9 | "net/http" 10 | ) 11 | 12 | // ErrNotFound describes an empty result set for an API call. 13 | var ErrNotFound = errors.New("No results were found matching the given search parameters") 14 | 15 | // A Session is an authenticated Zabbix JSON-RPC API client. It must be 16 | // initialized and connected with NewSession. 17 | type Session struct { 18 | // URL of the Zabbix JSON-RPC API (ending in `/api_jsonrpc.php`). 19 | URL string `json:"url"` 20 | 21 | // Token is the cached authentication token returned by `user.login` and 22 | // used to authenticate all API calls in this Session. 23 | Token string `json:"token"` 24 | 25 | // ApiVersion is the software version string of the connected Zabbix API. 26 | APIVersion string `json:"apiVersion"` 27 | 28 | client *http.Client 29 | } 30 | 31 | // NewSession returns a new Session given an API connection URL and an API 32 | // username and password. 33 | // 34 | // An error is returned if there was an HTTP protocol error, the API credentials 35 | // are incorrect or if the API version is indeterminable. 36 | // 37 | // The authentication token returned by the Zabbix API server is cached to 38 | // authenticate all subsequent requests in this Session. 39 | func NewSession(url string, username string, password string) (session *Session, err error) { 40 | // create session 41 | session = &Session{URL: url} 42 | err = session.login(username, password) 43 | return 44 | } 45 | 46 | func (c *Session) login(username, password string) error { 47 | // get Zabbix API version 48 | _, err := c.GetVersion() 49 | if err != nil { 50 | return fmt.Errorf("Failed to retrieve Zabbix API version: %v", err) 51 | } 52 | 53 | // login to API 54 | params := map[string]string{ 55 | "user": username, 56 | "password": password, 57 | } 58 | 59 | res, err := c.Do(NewRequest("user.login", params)) 60 | if err != nil { 61 | return fmt.Errorf("Error logging in to Zabbix API: %v", err) 62 | } 63 | 64 | err = res.Bind(&c.Token) 65 | if err != nil { 66 | return fmt.Errorf("Error failed to decode Zabbix login response: %v", err) 67 | } 68 | 69 | return nil 70 | } 71 | 72 | // GetVersion returns the software version string of the connected Zabbix API. 73 | func (c *Session) GetVersion() (string, error) { 74 | if c.APIVersion == "" { 75 | // get Zabbix API version 76 | res, err := c.Do(NewRequest("apiinfo.version", nil)) 77 | if err != nil { 78 | return "", err 79 | } 80 | 81 | err = res.Bind(&c.APIVersion) 82 | if err != nil { 83 | return "", err 84 | } 85 | } 86 | return c.APIVersion, nil 87 | } 88 | 89 | // AuthToken returns the authentication token used by this session to 90 | // authentication all API calls. 91 | func (c *Session) AuthToken() string { 92 | return c.Token 93 | } 94 | 95 | // Do sends a JSON-RPC request and returns an API Response, using connection 96 | // configuration defined in the parent Session. 97 | // 98 | // An error is returned if there was an HTTP protocol error, a non-200 response 99 | // is received, or if an error code is set is the JSON response body. 100 | // 101 | // When err is nil, resp always contains a non-nil resp.Body. 102 | // 103 | // Generally Get or a wrapper function will be used instead of Do. 104 | func (c *Session) Do(req *Request) (resp *Response, err error) { 105 | // configure request 106 | req.AuthToken = c.Token 107 | 108 | // encode request as json 109 | b, err := json.Marshal(req) 110 | if err != nil { 111 | return 112 | } 113 | 114 | dprintf("Call [%s:%d]: %s\n", req.Method, req.RequestID, b) 115 | 116 | // create HTTP request 117 | r, err := http.NewRequest("POST", c.URL, bytes.NewReader(b)) 118 | if err != nil { 119 | return 120 | } 121 | r.ContentLength = int64(len(b)) 122 | r.Header.Add("Content-Type", "application/json-rpc") 123 | 124 | // send request 125 | client := c.client 126 | if client == nil { 127 | client = http.DefaultClient 128 | } 129 | res, err := client.Do(r) 130 | if err != nil { 131 | return 132 | } 133 | 134 | defer res.Body.Close() 135 | 136 | // read response body 137 | b, err = ioutil.ReadAll(res.Body) 138 | if err != nil { 139 | return nil, fmt.Errorf("Error reading response: %v", err) 140 | } 141 | 142 | dprintf("Response [%s:%d]: %s\n", req.Method, req.RequestID, b) 143 | 144 | // map HTTP response to Response struct 145 | resp = &Response{ 146 | StatusCode: res.StatusCode, 147 | } 148 | 149 | // unmarshal response body 150 | err = json.Unmarshal(b, &resp) 151 | if err != nil { 152 | return nil, fmt.Errorf("Error decoding JSON response body: %v", err) 153 | } 154 | 155 | // check for API errors 156 | if err = resp.Err(); err != nil { 157 | return 158 | } 159 | 160 | return 161 | } 162 | 163 | // Get calls the given Zabbix API method with the given query parameters and 164 | // unmarshals the JSON response body into the given interface. 165 | // 166 | // An error is return if a transport, marshalling or API error happened. 167 | func (c *Session) Get(method string, params interface{}, v interface{}) error { 168 | req := NewRequest(method, params) 169 | resp, err := c.Do(req) 170 | if err != nil { 171 | return err 172 | } 173 | 174 | err = resp.Bind(v) 175 | if err != nil { 176 | return err 177 | } 178 | 179 | return nil 180 | } 181 | -------------------------------------------------------------------------------- /session_test.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | var session *Session 9 | 10 | func GetTestCredentials() (username string, password string, url string) { 11 | url = os.Getenv("ZBX_URL") 12 | if url == "" { 13 | url = "http://localhost:8080/api_jsonrpc.php" 14 | } 15 | 16 | username = os.Getenv("ZBX_USERNAME") 17 | if username == "" { 18 | username = "Admin" 19 | } 20 | 21 | password = os.Getenv("ZBX_PASSWORD") 22 | if password == "" { 23 | password = "zabbix" 24 | } 25 | 26 | return username, password, url 27 | } 28 | 29 | func GetTestSession(t *testing.T) *Session { 30 | var err error 31 | if session == nil { 32 | username, password, url := GetTestCredentials() 33 | 34 | session, err = NewSession(url, username, password) 35 | if err != nil { 36 | t.Fatalf("Error creating a session: %v", err) 37 | } 38 | } 39 | 40 | return session 41 | } 42 | 43 | func TestSession(t *testing.T) { 44 | s := GetTestSession(t) 45 | 46 | v, err := s.GetVersion() 47 | if err != nil || v == "" { 48 | t.Errorf("No API version found for session") 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /time.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | type UnixTimestamp struct { 11 | *time.Time 12 | } 13 | 14 | func (t UnixTimestamp) MarshalJSON() ([]byte, error) { 15 | stamp := fmt.Sprintf("\"%s\"", t.Unix()) 16 | return []byte(stamp), nil 17 | } 18 | 19 | func (t *UnixTimestamp) UnmarshalJSON(data []byte) (err error) { 20 | var unixString string 21 | err = json.Unmarshal(data, &unixString) 22 | if err != nil { 23 | return 24 | } 25 | 26 | unix, err := strconv.ParseInt(unixString, 10, 64) 27 | 28 | // Fractional seconds are handled implicitly by Parse. 29 | tt := time.Unix(unix, 0) 30 | *t = UnixTimestamp{&tt} 31 | 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /trigger.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const ( 8 | // TriggerAlarmStateOK means a normal trigger state. Called FALSE in older Zabbix versions. 9 | TriggerAlarmStateOK = iota 10 | 11 | // TriggerAlarmStateProblem normally means that something happened. 12 | TriggerAlarmStateProblem 13 | ) 14 | 15 | const ( 16 | // TriggerStateNormal means normal trigger state 17 | TriggerStateNormal = iota 18 | 19 | // TriggerStateUnknown means unknown trigger state 20 | TriggerStateUnknown 21 | ) 22 | 23 | const ( 24 | // TriggerSeverityNotClassified is Not classified severity 25 | TriggerSeverityNotClassified = iota 26 | 27 | // TriggerSeverityInformation is Information severity 28 | TriggerSeverityInformation 29 | 30 | // TriggerSeverityWarning is Warning severity 31 | TriggerSeverityWarning 32 | 33 | // TriggerSeverityAverage is Average severity 34 | TriggerSeverityAverage 35 | 36 | // TriggerSeverityHigh is High severity 37 | TriggerSeverityHigh 38 | 39 | // TriggerSeverityDisaster is Disaster severity 40 | TriggerSeverityDisaster 41 | ) 42 | 43 | // Trigger represents a Zabbix Trigger returned from the Zabbix API. 44 | // 45 | // See: https://www.zabbix.com/documentation/3.4/manual/config/triggers 46 | type Trigger struct { 47 | // TriggerID is the ID of the Trigger. 48 | TriggerID string 49 | 50 | // AlarmState shows whether the trigger is in OK or problem state. 51 | // 52 | // AlarmState must be one of the TriggerAlarmState constants. 53 | AlarmState int 54 | 55 | // Description is the name of the trigger. 56 | Description string 57 | 58 | // Enabled shows whether the trigger is enabled or disabled. 59 | Enabled bool 60 | 61 | // Expression is the trigger expression 62 | Expression string 63 | 64 | // Hosts is an array of Hosts that the trigger belongs. 65 | // 66 | // Hosts is only populated if TriggerGetParams.SelectHosts is given in the 67 | // query parameters that returned this Trigger. 68 | Hosts []Host 69 | 70 | // Groups is an array of Hostgroups that the trigger belongs. 71 | // 72 | // Groups is only populated if TriggerGetParams.SelectGroups is given in the 73 | // query parameters that returned this Trigger. 74 | Groups []Hostgroup 75 | 76 | // LastChange is the time when the trigger last changed its state. 77 | LastChange int 78 | 79 | // Severity of the trigger. 80 | // 81 | // Severity must be one of the TriggerSeverity constants. 82 | Severity int 83 | 84 | // State of the trigger. 85 | // 86 | // State must be one of the TriggerState constants. 87 | State int 88 | 89 | // Tags is an array of trigger tags 90 | // 91 | // Tags is only populated if TriggerGetParams.SelectTags is given in the 92 | // query parameters that returned this Trigger. 93 | Tags []TriggerTag 94 | 95 | // LastEvent is the latest event for the trigger 96 | // 97 | // LastEvent is only populated if TriggerGetParams.SelectLastEvent is set 98 | LastEvent *Event 99 | 100 | // URL is a link to the trigger graph in Zabbix 101 | URL string 102 | } 103 | 104 | // TriggerTag is trigger tag 105 | type TriggerTag struct { 106 | Name string 107 | Value string 108 | } 109 | 110 | // TriggerGetParams is params for trigger.get query 111 | type TriggerGetParams struct { 112 | GetParameters 113 | 114 | // TriggerIDs filters search results to Triggers that matched the given Trigger 115 | // IDs. 116 | TriggerIDs []string `json:"triggerids,omitempty"` 117 | 118 | // GroupIDs filters search results to triggers for hosts that are members of 119 | // the given Group IDs. 120 | GroupIDs []string `json:"groupids,omitempty"` 121 | 122 | TemplateIDs []string `json:"templateids,omitempty"` 123 | 124 | // HostIDs filters search results to triggers for hosts that matched the given 125 | // Host IDs. 126 | HostIDs []string `json:"hostids,omitempty"` 127 | 128 | ItemIDs []string `json:"itemids,omitempty"` 129 | 130 | ApplicationIDs []string `json:"applicationids,omitempty"` 131 | 132 | Functions []string `json:"functions,omitempty"` 133 | 134 | Group string `json:"group,omitempty"` 135 | 136 | Host string `json:"host,omitempty"` 137 | 138 | // InheritedOnly filters search results to triggers which have been 139 | // inherited from a template. 140 | InheritedOnly bool `json:"inherited,omitempty"` 141 | 142 | TemplatedOnly bool `json:"templated,omitempty"` 143 | 144 | MonitoredOnly bool `json:"monitored,omitempty"` 145 | 146 | ActiveOnly bool `json:"active,omitempty"` 147 | 148 | MaintenanceOnly bool `json:"maintenance,omitempty"` 149 | 150 | WithUnacknowledgedEventsOnly bool `json:"withUnacknowledgedEvents,omitempty"` 151 | 152 | WithAcknowledgedEventsOnly bool `json:"withAcknowledgedEvents,omitempty"` 153 | 154 | WithLastEventUnacknowledgedOnly bool `json:"withLastEventUnacknowledged,omitempty"` 155 | 156 | SkipDependent bool `json:"skipDependent,omitempty"` 157 | 158 | // LastChangeSince timestamp `json:"lastChangeSince,omitempty"` 159 | 160 | // LastChangeTill timestamp `json:"lastChangeTill,omitempty"` 161 | 162 | RecentProblemOnly bool `json:"only_true,omitempty"` 163 | 164 | MinSeverity int `json:"min_severity,omitempty"` 165 | 166 | ExpandComment bool `json:"expandComment,omitempty"` 167 | 168 | ExpandDescription bool `json:"expandDescription,omitempty"` 169 | 170 | ExpandExpression bool `json:"expandExpression,omitempty"` 171 | 172 | // SelectGroups causes all Hostgroups which contain the object that caused each 173 | // Trigger to be attached in the search results. 174 | SelectGroups SelectQuery `json:"selectGroups,omitempty"` 175 | 176 | // SelectHosts causes all Hosts which contain the object that caused each 177 | // Trigger to be attached in the search results. 178 | SelectHosts SelectQuery `json:"selectHosts,omitempty"` 179 | 180 | SelectItems SelectQuery `json:"selectItems,omitempty"` 181 | 182 | SelectFunctions SelectQuery `json:"selectFunctions,omitempty"` 183 | 184 | SelectDependencies SelectQuery `json:"selectDependencies,omitempty"` 185 | 186 | SelectDiscoveryRule SelectQuery `json:"selectDiscoveryRule,omitempty"` 187 | 188 | SelectLastEvent SelectQuery `json:"selectLastEvent,omitempty"` 189 | 190 | SelectTags SelectQuery `json:"selectTags,omitempty"` 191 | } 192 | 193 | // GetTriggers queries the Zabbix API for Triggers matching the given search 194 | // parameters. 195 | // 196 | // ErrTriggerNotFound is returned if the search result set is empty. 197 | // An error is returned if a transport, parsing or API error occurs. 198 | func (c *Session) GetTriggers(params TriggerGetParams) ([]Trigger, error) { 199 | triggers := make([]jTrigger, 0) 200 | err := c.Get("trigger.get", params, &triggers) 201 | if err != nil { 202 | return nil, err 203 | } 204 | 205 | if len(triggers) == 0 { 206 | return nil, ErrNotFound 207 | } 208 | 209 | // map JSON Triggers to Go Triggers 210 | out := make([]Trigger, len(triggers)) 211 | for i, jtrigger := range triggers { 212 | trigger, err := jtrigger.Trigger() 213 | if err != nil { 214 | return nil, fmt.Errorf("Error mapping Trigger %d in response: %v", i, err) 215 | } 216 | 217 | out[i] = *trigger 218 | } 219 | 220 | return out, nil 221 | } 222 | -------------------------------------------------------------------------------- /trigger_json.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import "fmt" 4 | 5 | // jTrigger is a private map for the Zabbix API Trigger object. 6 | // See: https://www.zabbix.com/documentation/3.4/manual/api/reference/trigger/object 7 | type jTrigger struct { 8 | TriggerID string `json:"triggerid"` 9 | AlarmState int `json:"value,string"` 10 | Description string `json:"description"` 11 | Enabled string `json:"status"` 12 | Expression string `json:"expression"` 13 | Groups jHostgroups `json:"groups"` 14 | Hosts jHosts `json:"hosts"` 15 | LastChange int `json:"lastchange,string"` 16 | Severity int `json:"priority,string"` 17 | State int `json:"state,string"` 18 | Tags jTriggerTags `json:"tags"` 19 | LastEvent *jEvent `json:"lastEvent"` 20 | URL string `json:"url"` 21 | } 22 | 23 | type jTriggerTag struct { 24 | Name string `json:"tag"` 25 | Value string `json:"value"` 26 | } 27 | 28 | func (c *jTriggerTag) Tag() (*TriggerTag, error) { 29 | tag := &TriggerTag{} 30 | tag.Name = c.Name 31 | tag.Value = c.Value 32 | return tag, nil 33 | } 34 | 35 | type jTriggerTags []jTriggerTag 36 | 37 | func (c jTriggerTags) Tags() ([]TriggerTag, error) { 38 | if c != nil { 39 | tags := make([]TriggerTag, len(c)) 40 | for i, jTriggerTag := range c { 41 | tag, err := jTriggerTag.Tag() 42 | if err != nil { 43 | return nil, fmt.Errorf("Error unmarshalling Trigger Tag %d in JSON data: %v", i, err) 44 | } 45 | 46 | tags[i] = *tag 47 | } 48 | 49 | return tags, nil 50 | } 51 | 52 | return nil, nil 53 | } 54 | 55 | // Trigger returns a native Go Trigger struct mapped from the given JSON Trigger data. 56 | func (c *jTrigger) Trigger() (*Trigger, error) { 57 | var err error 58 | trigger := &Trigger{} 59 | trigger.TriggerID = c.TriggerID 60 | trigger.AlarmState = c.AlarmState 61 | trigger.Enabled = (c.Enabled == "1") 62 | trigger.Description = c.Description 63 | trigger.Expression = c.Expression 64 | trigger.URL = c.URL 65 | 66 | if c.LastEvent != nil { 67 | trigger.LastEvent, err = c.LastEvent.Event() 68 | if err != nil { 69 | return nil, err 70 | } 71 | } 72 | 73 | // map groups 74 | trigger.Groups, err = c.Groups.Hostgroups() 75 | if err != nil { 76 | return nil, err 77 | } 78 | 79 | // map hosts 80 | trigger.Hosts, err = c.Hosts.Hosts() 81 | if err != nil { 82 | return nil, err 83 | } 84 | 85 | trigger.LastChange = c.LastChange 86 | trigger.Severity = c.Severity 87 | trigger.State = c.State 88 | 89 | // map tags 90 | trigger.Tags, err = c.Tags.Tags() 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | return trigger, nil 96 | } 97 | -------------------------------------------------------------------------------- /usermacro.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | // UserMacroResponse represent usermacro action response body 4 | type UserMacroResponse struct { 5 | HostMacroIDs []string `json:"hostmacroids"` 6 | } 7 | 8 | // UserMacroGetParams represent the parameters for a `usermacro.get` API call (see zabbix documentation). 9 | type UserMacroGetParams struct { 10 | GetParameters 11 | 12 | // Return global macros instead of host macros. 13 | GlobalMacro bool `json:"globalmacro,omitempty"` 14 | 15 | // Return only global macros with the given IDs. 16 | GlobalMacroIDs []string `json:"globalmacroids,omitempty"` 17 | 18 | // Return only host macros that belong to hosts or templates from the given host groups. 19 | GroupIDs []string `json:"groupids,omitempty"` 20 | 21 | // Return only macros that belong to the given hosts or templates. 22 | HostIDs []string `json:"hostids,omitempty"` 23 | 24 | // Return only host macros with the given IDs. 25 | HostMacroIDs []string `json:"hostmacroids,omitempty"` 26 | 27 | // Return only host macros that belong to the given templates. (Zabbix 2.x only) 28 | TemplateIDs []string `json:"templateids,omitempty"` 29 | 30 | // TODO: add selectGroups, selectHosts and selectTemplates queries 31 | } 32 | 33 | // GetUserMacro queries the Zabbix API for user macros matching the given search 34 | // parameters. 35 | // 36 | // ErrEventNotFound is returned if the search result set is empty. 37 | // An error is returned if a transport, parsing or API error occurs. 38 | func (c *Session) GetUserMacro(params UserMacroGetParams) ([]HostMacro, error) { 39 | macros := make([]HostMacro, 0) 40 | 41 | if err := c.Get("usermacro.get", params, ¯os); err != nil { 42 | return nil, err 43 | } 44 | 45 | if len(macros) == 0 { 46 | return nil, ErrNotFound 47 | } 48 | 49 | return macros, nil 50 | } 51 | 52 | // CreateUserMacros creates a single or multiple new user macros. 53 | // Returns a list of macro id(s) of created macro(s). 54 | // 55 | // Zabbix API docs: https://www.zabbix.com/documentation/3.0/manual/config/macros/usermacros 56 | func (c *Session) CreateUserMacros(macros ...HostMacro) (hostMacroIds []string, err error) { 57 | var body UserMacroResponse 58 | 59 | if err := c.Get("usermacro.create", macros, &body); err != nil { 60 | return nil, err 61 | } 62 | 63 | if (body.HostMacroIDs == nil) || (len(body.HostMacroIDs) == 0) { 64 | return nil, ErrNotFound 65 | } 66 | 67 | return body.HostMacroIDs, nil 68 | } 69 | 70 | // DeleteUserMacros method allows to delete host user macros. 71 | // Returns a list of deleted macro id(s). 72 | // 73 | // Zabbix API docs: https://www.zabbix.com/documentation/2.2/manual/api/reference/usermacro/delete 74 | func (c *Session) DeleteUserMacros(hostMacroIDs ...string) (hostMacroIds []string, err error) { 75 | var body UserMacroResponse 76 | 77 | if err := c.Get("usermacro.delete", hostMacroIds, &body); err != nil { 78 | return nil, err 79 | } 80 | 81 | if (body.HostMacroIDs == nil) || (len(body.HostMacroIDs) == 0) { 82 | return nil, ErrNotFound 83 | } 84 | 85 | return body.HostMacroIDs, nil 86 | } 87 | 88 | // UpdateUserMacros method allows to update host user macros. 89 | // Returns a list of updated macro id(s). 90 | // 91 | // Zabbix API docs: https://www.zabbix.com/documentation/2.2/manual/api/reference/usermacro/update 92 | func (c *Session) UpdateUserMacros(macros ...HostMacro) (hostMacroIds []string, err error) { 93 | var body UserMacroResponse 94 | 95 | if err := c.Get("usermacro.update", hostMacroIds, &body); err != nil { 96 | return nil, err 97 | } 98 | 99 | if (body.HostMacroIDs == nil) || (len(body.HostMacroIDs) == 0) { 100 | return nil, ErrNotFound 101 | } 102 | 103 | return body.HostMacroIDs, nil 104 | } 105 | -------------------------------------------------------------------------------- /usermacros_test.go: -------------------------------------------------------------------------------- 1 | package zabbix 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestUserMacros(t *testing.T) { 8 | session := GetTestSession(t) 9 | 10 | params := UserMacroGetParams{} 11 | 12 | macros, err := session.GetUserMacro(params) 13 | 14 | if err != nil { 15 | t.Fatalf("Error getting user macros: %v", err) 16 | } 17 | 18 | if len(macros) == 0 { 19 | t.Fatal("No usermacro found") 20 | } 21 | 22 | for i, macro := range macros { 23 | if macro.HostID == "" { 24 | t.Fatalf("User macro %d returned in response body has no Host ID", i) 25 | } 26 | } 27 | 28 | t.Logf("Validated %d user macros", len(macros)) 29 | } 30 | --------------------------------------------------------------------------------