Initial release
This commit is contained in:
		
							
								
								
									
										75
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,5 +1,72 @@ | ||||
| # zabbix-go | ||||
| zabbix | ||||
| ====== | ||||
|  | ||||
| This Go library implements the Zabbix 2.0 JRPC API | ||||
|  | ||||
| Based on https://github.com/adubkov/zabbix | ||||
| This Go library implements the Zabbix 2.0 API. The Zabbix API is a JSONRPC | ||||
| based API, although it is not compatable with Go's builtin JSONRPC libraries. | ||||
| So we implement that JSONRPC, and provide data types that mimic Zabbbix's | ||||
| return values. | ||||
|  | ||||
| Based on https://github.com/adubkov/zabbix | ||||
|  | ||||
| Connecting to the API | ||||
| ===================== | ||||
|  | ||||
| ```go | ||||
| func main() { | ||||
|     api, err := zabbix.NewAPI("http://zabbix.yourhost.net/api_jsonrpc.php", "User", "Password") | ||||
|     if err != nil { | ||||
|         fmt.Println(err) | ||||
|         return | ||||
|     } | ||||
|  | ||||
|     versionresult, err := api.Version() | ||||
|     if err != nil { | ||||
|         fmt.Println(err) | ||||
|     } | ||||
|  | ||||
|     fmt.Println(versionresult) | ||||
|  | ||||
|     _, err = api.Login() | ||||
|     if err != nil { | ||||
|         fmt.Println(err) | ||||
|         return | ||||
|     } | ||||
|     fmt.Println("Connected to API") | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Making a call | ||||
| ============= | ||||
|  | ||||
| I typically wrap the actual API call to hide the messy details. If the | ||||
| response has an Error field, and the code is greater than 0, the API | ||||
| will return that Error. Then my wrapper function return a ZabbixError | ||||
| to the caller. | ||||
|  | ||||
| ```go | ||||
| // Find and return a single host object by name | ||||
| func GetHost(api *zabbix.API, host string) (zabbix.ZabbixHost, error) { | ||||
|     params := make(map[string]interface{}, 0) | ||||
|     filter := make(map[string]string, 0) | ||||
|     filter["host"] = host | ||||
|     params["filter"] = filter | ||||
|     params["output"] = "extend" | ||||
|     params["select_groups"] = "extend" | ||||
|     params["templated_hosts"] = 1 | ||||
|     ret, err := api.Host("get", params) | ||||
|  | ||||
|     // This happens if there was an RPC error | ||||
|     if err != nil { | ||||
|         return nil, err | ||||
|     } | ||||
|  | ||||
|     // If our call was successful | ||||
|     if len(ret) > 0 { | ||||
|         return ret[0], err | ||||
|     } | ||||
|  | ||||
|     // This will be the case if the RPC call was successful, but | ||||
|     // Zabbix had an issue with the data we passed. | ||||
|     return nil, &zabbix.ZabbixError{0,"","Host not found"} | ||||
| } | ||||
| ``` | ||||
|   | ||||
							
								
								
									
										287
									
								
								zabbix.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								zabbix.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,287 @@ | ||||
| package zabbix | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/tls" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| /** | ||||
| Zabbix and Go's RPC implementations don't play with each other.. at all. | ||||
| So I've re-created the wheel at bit. | ||||
| */ | ||||
| type JsonRPCResponse struct { | ||||
| 	Jsonrpc string      `json:"jsonrpc"` | ||||
| 	Error   ZabbixError `json:"error"` | ||||
| 	Result  interface{} `json:"result"` | ||||
| 	Id      int         `json:"id"` | ||||
| } | ||||
|  | ||||
| type JsonRPCRequest struct { | ||||
| 	Jsonrpc string      `json:"jsonrpc"` | ||||
| 	Method  string      `json:"method"` | ||||
| 	Params  interface{} `json:"params"` | ||||
|  | ||||
| 	// Zabbix 2.0: | ||||
| 	// The "user.login" method must be called without the "auth" parameter | ||||
| 	Auth string `json:"auth,omitempty"` | ||||
| 	Id   int    `json:"id"` | ||||
| } | ||||
|  | ||||
| type ZabbixError struct { | ||||
| 	Code    int    `json:"code"` | ||||
| 	Message string `json:"message"` | ||||
| 	Data    string `json:"data"` | ||||
| } | ||||
|  | ||||
| func (z *ZabbixError) Error() string { | ||||
| 	return z.Data | ||||
| } | ||||
|  | ||||
| type ZabbixHost map[string]interface{} | ||||
| type ZabbixGraph map[string]interface{} | ||||
| type ZabbixGraphItem map[string]interface{} | ||||
| type ZabbixHistoryItem struct { | ||||
| 	Clock  string `json:"clock"` | ||||
| 	Value  string `json:"value"` | ||||
| 	Itemid string `json:"itemid"` | ||||
| } | ||||
|  | ||||
| type ZabbixTemplate map[string]interface{} | ||||
| type ZabbixHostGroup map[string]interface{} | ||||
|  | ||||
| type API struct { | ||||
| 	url    string | ||||
| 	user   string | ||||
| 	passwd string | ||||
| 	id     int | ||||
| 	auth   string | ||||
| } | ||||
|  | ||||
| func NewAPI(server, user, passwd string) (*API, error) { | ||||
| 	return &API{server, user, passwd, 0, ""}, nil | ||||
| } | ||||
|  | ||||
| func (api *API) GetAuth() string { | ||||
| 	return api.auth | ||||
| } | ||||
|  | ||||
| /** | ||||
| Each request establishes its own connection to the server. This makes it easy | ||||
| to keep request/responses in order without doing any concurrency | ||||
| */ | ||||
|  | ||||
| func (api *API) ZabbixRequest(method string, data interface{}) (JsonRPCResponse, error) { | ||||
| 	// Setup our JSONRPC Request data | ||||
| 	id := api.id | ||||
| 	api.id = api.id + 1 | ||||
| 	jsonobj := JsonRPCRequest{"2.0", method, data, api.auth, id} | ||||
| 	encoded, err := json.Marshal(jsonobj) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return JsonRPCResponse{}, err | ||||
| 	} | ||||
| 	// Setup our HTTP request | ||||
| 	client := &http.Client{ | ||||
| 		Transport: &http.Transport{ | ||||
| 			MaxIdleConnsPerHost:   10, | ||||
| 			ResponseHeaderTimeout: 60 * time.Second, | ||||
| 			DialContext:           (&net.Dialer{Timeout: time.Second}).DialContext, | ||||
| 			TLSClientConfig: &tls.Config{ | ||||
| 				MaxVersion:         tls.VersionTLS11, | ||||
| 				InsecureSkipVerify: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	request, err := http.NewRequest("POST", api.url, bytes.NewBuffer(encoded)) | ||||
| 	if err != nil { | ||||
| 		return JsonRPCResponse{}, err | ||||
| 	} | ||||
| 	request.Header.Add("Content-Type", "application/json-rpc") | ||||
| 	if api.auth != "" { | ||||
| 		// XXX Not required in practice, check spec | ||||
| 		//request.SetBasicAuth(api.user, api.passwd) | ||||
| 		//request.Header.Add("Authorization", api.auth) | ||||
| 	} | ||||
|  | ||||
| 	// Execute the request | ||||
| 	response, err := client.Do(request) | ||||
| 	if err != nil { | ||||
| 		return JsonRPCResponse{}, err | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	We can't rely on response.ContentLength because it will | ||||
| 	be set at -1 for large responses that are chunked. So | ||||
| 	we treat each API response as streamed data. | ||||
| 	*/ | ||||
| 	var result JsonRPCResponse | ||||
| 	var buf bytes.Buffer | ||||
|  | ||||
| 	_, err = io.Copy(&buf, response.Body) | ||||
| 	if err != nil { | ||||
| 		return JsonRPCResponse{}, err | ||||
| 	} | ||||
|  | ||||
| 	json.Unmarshal(buf.Bytes(), &result) | ||||
|  | ||||
| 	response.Body.Close() | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| func (api *API) Login() (bool, error) { | ||||
| 	params := make(map[string]string, 0) | ||||
| 	params["user"] = api.user | ||||
| 	params["password"] = api.passwd | ||||
|  | ||||
| 	response, err := api.ZabbixRequest("user.login", params) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %s\n", err) | ||||
| 		return false, err | ||||
| 	} | ||||
|  | ||||
| 	if response.Error.Code != 0 { | ||||
| 		return false, &response.Error | ||||
| 	} | ||||
|  | ||||
| 	api.auth = response.Result.(string) | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func (api *API) Version() (string, error) { | ||||
| 	response, err := api.ZabbixRequest("APIInfo.version", make(map[string]string, 0)) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	if response.Error.Code != 0 { | ||||
| 		return "", &response.Error | ||||
| 	} | ||||
|  | ||||
| 	return response.Result.(string), nil | ||||
| } | ||||
|  | ||||
| /** | ||||
| Interface to the user.* calls | ||||
| */ | ||||
| func (api *API) User(method string, data interface{}) ([]interface{}, error) { | ||||
| 	response, err := api.ZabbixRequest("user."+method, data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if response.Error.Code != 0 { | ||||
| 		return nil, &response.Error | ||||
| 	} | ||||
|  | ||||
| 	return response.Result.([]interface{}), nil | ||||
| } | ||||
|  | ||||
| /** | ||||
| Interface to the host.* calls | ||||
| */ | ||||
| func (api *API) Host(method string, data interface{}) ([]ZabbixHost, error) { | ||||
| 	response, err := api.ZabbixRequest("host."+method, data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if response.Error.Code != 0 { | ||||
| 		return nil, &response.Error | ||||
| 	} | ||||
|  | ||||
| 	// XXX uhg... there has got to be a better way to convert the response | ||||
| 	// to the type I want to return | ||||
| 	res, err := json.Marshal(response.Result) | ||||
| 	var ret []ZabbixHost | ||||
| 	err = json.Unmarshal(res, &ret) | ||||
| 	return ret, nil | ||||
| } | ||||
|  | ||||
| /** | ||||
| Interface to the graph.* calls | ||||
| */ | ||||
| func (api *API) Graph(method string, data interface{}) ([]ZabbixGraph, error) { | ||||
| 	response, err := api.ZabbixRequest("graph."+method, data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if response.Error.Code != 0 { | ||||
| 		return nil, &response.Error | ||||
| 	} | ||||
|  | ||||
| 	// XXX uhg... there has got to be a better way to convert the response | ||||
| 	// to the type I want to return | ||||
| 	res, err := json.Marshal(response.Result) | ||||
| 	var ret []ZabbixGraph | ||||
| 	err = json.Unmarshal(res, &ret) | ||||
| 	return ret, nil | ||||
| } | ||||
|  | ||||
| /** | ||||
| Interface to the history.* calls | ||||
| */ | ||||
| func (api *API) History(method string, data interface{}) ([]ZabbixHistoryItem, error) { | ||||
| 	response, err := api.ZabbixRequest("history."+method, data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if response.Error.Code != 0 { | ||||
| 		return nil, &response.Error | ||||
| 	} | ||||
|  | ||||
| 	// XXX uhg... there has got to be a better way to convert the response | ||||
| 	// to the type I want to return | ||||
| 	res, err := json.Marshal(response.Result) | ||||
| 	var ret []ZabbixHistoryItem | ||||
| 	err = json.Unmarshal(res, &ret) | ||||
| 	return ret, nil | ||||
| } | ||||
|  | ||||
| /** | ||||
| Interface to the template.* calls | ||||
| */ | ||||
| func (api *API) Template(method string, data interface{}) ([]ZabbixTemplate, error) { | ||||
| 	response, err := api.ZabbixRequest("template."+method, data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if response.Error.Code != 0 { | ||||
| 		return nil, &response.Error | ||||
| 	} | ||||
|  | ||||
| 	// XXX uhg... there has got to be a better way to convert the response | ||||
| 	// to the type I want to return | ||||
| 	res, err := json.Marshal(response.Result) | ||||
| 	var ret []ZabbixTemplate | ||||
| 	err = json.Unmarshal(res, &ret) | ||||
| 	return ret, nil | ||||
| } | ||||
|  | ||||
| /** | ||||
| Interface to the hostgroup.* calls | ||||
| */ | ||||
| func (api *API) HostGroup(method string, data interface{}) ([]ZabbixHostGroup, error) { | ||||
| 	response, err := api.ZabbixRequest("hostgroup."+method, data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if response.Error.Code != 0 { | ||||
| 		return nil, &response.Error | ||||
| 	} | ||||
|  | ||||
| 	res, err := json.Marshal(response.Result) | ||||
| 	var ret []ZabbixHostGroup | ||||
| 	err = json.Unmarshal(res, &ret) | ||||
| 	return ret, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 svkalinin
					svkalinin