/* * Copyright 2014 by SCSK Corporation. * * This file is part of PrimeCloud Controller(TM). * * PrimeCloud Controller(TM) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * PrimeCloud Controller(TM) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PrimeCloud Controller(TM). If not, see <http://www.gnu.org/licenses/>. */ package jp.primecloud.auto.zabbix; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import jp.primecloud.auto.exception.AutoException; import jp.primecloud.auto.zabbix.model.ResponseError; import net.sf.json.JSON; import net.sf.json.JSONObject; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * <p> * ZabbixのAPIにアクセスするためのAccessorクラスです。 * </p> * */ public class ZabbixAccessor { private Log log = LogFactory.getLog(getClass()); private static ZabbixAccessor zAccessor = new ZabbixAccessor(); protected static List<String> ignoreAuthMethods; protected HttpClient httpClient; protected String apiUrl; protected String username; protected String password; private String auth; private int id; private String apiVersion; static { ignoreAuthMethods = new ArrayList<String>(); ignoreAuthMethods.add("apiinfo.version"); ignoreAuthMethods.add("user.login"); } private ZabbixAccessor(){} public static ZabbixAccessor getInstance(HttpClient httpClient, String apiUrl, String username, String password) { zAccessor.init(httpClient, apiUrl, username, password); return zAccessor; } public void init(HttpClient httpClient, String apiUrl, String username, String password) { //設定されていなければ設定する if (this.httpClient == null){ this.httpClient = httpClient; } if (this.apiUrl == null){ this.apiUrl = apiUrl; } if (this.username == null){ this.username = username; } if (this.password == null) { this.password = password; } } public synchronized Object execute(String method, JSON params) { // authが空の場合、認証する if (!ignoreAuthMethods.contains(method) && StringUtils.isEmpty(auth)) { authenticate(); } Map<String, Object> request = new HashMap<String, Object>(); request.put("jsonrpc", "2.0"); request.put("method", method); request.put("params", params == null ? Collections.EMPTY_MAP : params); request.put("id", ++id); if (!ignoreAuthMethods.contains(method)) { request.put("auth", auth == null ? "" : auth); } String jsonRequest = JSONObject.fromObject(request).toString(); if (log.isDebugEnabled()) { // パスワードのマスク化 String str = jsonRequest; if (str.contains("password")) { str = str.replaceAll("\"password\":\".*?\"", "\"password\":\"--------\""); } if (str.contains("passwd")) { str = str.replaceAll("\"passwd\":\".*?\"", "\"passwd\":\"--------\""); } log.debug(str); } String jsonResponse = post(jsonRequest); if (log.isDebugEnabled()) { log.debug(jsonResponse); } JSONObject response = JSONObject.fromObject(jsonResponse); if (response.containsKey("error")) { ResponseError error = (ResponseError) JSONObject.toBean(response.getJSONObject("error"), ResponseError.class); // 認証されていない場合、再度認証して実行する if ("Not authorized".equals(error.getData())) { auth = ""; return execute(method, params); } // エラー発生時 AutoException exception = new AutoException("EZABBIX-000001", method); exception.addDetailInfo("params=" + params); exception.addDetailInfo("error=" + ReflectionToStringBuilder.toString(error, ToStringStyle.SHORT_PREFIX_STYLE)); throw exception; } return response.get("result"); } protected void authenticate() { JSONObject params = new JSONObject(); params.put("user", username); params.put("password", password); Object result = execute("user.login", params); auth = (String) result; } protected String post(String jsonRequest) { PostMethod postMethod = new PostMethod(apiUrl); postMethod.setRequestHeader("Content-Type", "application/json-rpc"); postMethod.setRequestEntity(new ByteArrayRequestEntity(jsonRequest.getBytes())); int status; try { status = httpClient.executeMethod(postMethod); } catch (HttpException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } if (status < 200 || status >= 300) { String body; try { body = postMethod.getResponseBodyAsString(); } catch (Exception ignore) { body = ""; } throw new RuntimeException("Reponse Error: status=" + status + ", body=" + body); } String jsonResponse; try { jsonResponse = postMethod.getResponseBodyAsString(); } catch (IOException e) { throw new RuntimeException(e); } return jsonResponse; } /** * API実行対象のZabbix Serverのバージョンと指定したバージョンを比較します。<br/> * 指定したバージョンと同じであれば0、指定したバージョンより後であれば0より大きい値、指定したバージョンより前であれば0より小さい値を返します。 * * @param zabbixVersion Zabbixバージョン * @return */ public int checkVersion(String zabbixVersion) { if (apiVersion == null) { apiVersion = (String) this.execute("apiinfo.version", null); } return compareVersion(apiVersion, zabbixVersion); } protected int compareVersion(String apiVersion, String zabbixVersion) { int version1; { String[] array = apiVersion.split("\\."); version1 = Integer.parseInt(array[0]) * 1000 * 1000; version1 += Integer.parseInt(array[1]) * 1000; version1 += (array.length == 3) ? Integer.parseInt(array[2]) : 0; } int version2; { String[] array = zabbixVersion.split("\\."); version2 = Integer.parseInt(array[0]) * 1000 * 1000; version2 += Integer.parseInt(array[1]) * 1000; version2 += (array.length == 3) ? Integer.parseInt(array[2]) : 0; if (version2 <= 1008000) { version2 = 1000000; } else if (version2 == 1008001) { version2 = 1001000; } else if (version2 == 1008002) { version2 = 1002000; } else if (version2 < 2000000) { version2 = 1003000; } else if (version2 <= 2000003) { version2 = 1004000; } } return version1 - version2; } }