| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| package com.cloud.network.resource; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.net.URLEncoder; |
| import java.text.DateFormat; |
| import java.text.SimpleDateFormat; |
| import java.util.Date; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| |
| import javax.naming.ConfigurationException; |
| |
| import org.apache.log4j.Logger; |
| |
| import com.cloud.agent.IAgentControl; |
| import com.cloud.agent.api.Answer; |
| import com.cloud.agent.api.Command; |
| import com.cloud.agent.api.DirectNetworkUsageAnswer; |
| import com.cloud.agent.api.DirectNetworkUsageCommand; |
| import com.cloud.agent.api.MaintainAnswer; |
| import com.cloud.agent.api.MaintainCommand; |
| import com.cloud.agent.api.PingCommand; |
| import com.cloud.agent.api.ReadyAnswer; |
| import com.cloud.agent.api.ReadyCommand; |
| import com.cloud.agent.api.RecurringNetworkUsageAnswer; |
| import com.cloud.agent.api.RecurringNetworkUsageCommand; |
| import com.cloud.agent.api.StartupCommand; |
| import com.cloud.agent.api.StartupTrafficMonitorCommand; |
| import com.cloud.host.Host; |
| import com.cloud.resource.ServerResource; |
| import com.cloud.utils.exception.ExecutionException; |
| import java.net.HttpURLConnection; |
| |
| public class TrafficSentinelResource implements ServerResource { |
| |
| private String _name; |
| private String _zoneId; |
| private String _ip; |
| private String _guid; |
| private String _url; |
| private String _inclZones; |
| private String _exclZones; |
| |
| private static final Logger s_logger = Logger.getLogger(TrafficSentinelResource.class); |
| |
| @Override |
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { |
| try { |
| |
| _name = name; |
| |
| _zoneId = (String)params.get("zone"); |
| if (_zoneId == null) { |
| throw new ConfigurationException("Unable to find zone"); |
| } |
| |
| _ip = (String)params.get("ipaddress"); |
| if (_ip == null) { |
| throw new ConfigurationException("Unable to find IP"); |
| } |
| |
| _guid = (String)params.get("guid"); |
| if (_guid == null) { |
| throw new ConfigurationException("Unable to find the guid"); |
| } |
| |
| _url = (String)params.get("url"); |
| if (_url == null) { |
| throw new ConfigurationException("Unable to find url"); |
| } |
| |
| _inclZones = (String)params.get("inclZones"); |
| _exclZones = (String)params.get("exclZones"); |
| |
| return true; |
| } catch (Exception e) { |
| throw new ConfigurationException(e.getMessage()); |
| } |
| |
| } |
| |
| @Override |
| public StartupCommand[] initialize() { |
| StartupTrafficMonitorCommand cmd = new StartupTrafficMonitorCommand(); |
| cmd.setName(_name); |
| cmd.setDataCenter(_zoneId); |
| cmd.setPod(""); |
| cmd.setPrivateIpAddress(_ip); |
| cmd.setStorageIpAddress(""); |
| cmd.setVersion(TrafficSentinelResource.class.getPackage().getImplementationVersion()); |
| cmd.setGuid(_guid); |
| return new StartupCommand[] {cmd}; |
| } |
| |
| @Override |
| public Host.Type getType() { |
| return Host.Type.TrafficMonitor; |
| } |
| |
| @Override |
| public String getName() { |
| return _name; |
| } |
| |
| @Override |
| public PingCommand getCurrentStatus(final long id) { |
| return new PingCommand(Host.Type.TrafficMonitor, id); |
| } |
| |
| @Override |
| public boolean start() { |
| return true; |
| } |
| |
| @Override |
| public boolean stop() { |
| return true; |
| } |
| |
| @Override |
| public void disconnected() { |
| return; |
| } |
| |
| @Override |
| public IAgentControl getAgentControl() { |
| return null; |
| } |
| |
| @Override |
| public void setAgentControl(IAgentControl agentControl) { |
| return; |
| } |
| |
| @Override |
| public Answer executeRequest(Command cmd) { |
| if (cmd instanceof ReadyCommand) { |
| return execute((ReadyCommand)cmd); |
| } else if (cmd instanceof MaintainCommand) { |
| return execute((MaintainCommand)cmd); |
| } else if (cmd instanceof DirectNetworkUsageCommand) { |
| return execute((DirectNetworkUsageCommand)cmd); |
| } else if (cmd instanceof RecurringNetworkUsageCommand) { |
| return execute((RecurringNetworkUsageCommand)cmd); |
| } else { |
| return Answer.createUnsupportedCommandAnswer(cmd); |
| } |
| } |
| |
| private Answer execute(ReadyCommand cmd) { |
| return new ReadyAnswer(cmd); |
| } |
| |
| private synchronized RecurringNetworkUsageAnswer execute(RecurringNetworkUsageCommand cmd) { |
| return new RecurringNetworkUsageAnswer(cmd); |
| } |
| |
| private synchronized DirectNetworkUsageAnswer execute(DirectNetworkUsageCommand cmd) { |
| try { |
| return getPublicIpBytesSentAndReceived(cmd); |
| } catch (ExecutionException e) { |
| return new DirectNetworkUsageAnswer(cmd, e); |
| } |
| } |
| |
| private Answer execute(MaintainCommand cmd) { |
| return new MaintainAnswer(cmd); |
| } |
| |
| private DirectNetworkUsageAnswer getPublicIpBytesSentAndReceived(DirectNetworkUsageCommand cmd) throws ExecutionException { |
| DirectNetworkUsageAnswer answer = new DirectNetworkUsageAnswer(cmd); |
| |
| try { |
| //Direct Network Usage |
| URL trafficSentinel; |
| //Use Global include/exclude zones if there are no per TS zones |
| if (_inclZones == null) { |
| _inclZones = cmd.getIncludeZones(); |
| } |
| |
| if (_exclZones == null) { |
| _exclZones = cmd.getExcludeZones(); |
| } |
| |
| BufferedReader in = null; |
| OutputStream os = null; |
| try { |
| //Query traffic Sentinel using POST method. 3 parts to the connection call and subsequent writing. |
| |
| //Part 1 - Connect to the URL of the traffic sentinel's instance. |
| trafficSentinel = new URL(_url + "/inmsf/Query"); |
| String postData = "script="+URLEncoder.encode(getScript(cmd.getPublicIps(), cmd.getStart(), cmd.getEnd()), "UTF-8")+"&authenticate=basic&resultFormat=txt"; |
| HttpURLConnection con = (HttpURLConnection) trafficSentinel.openConnection(); |
| con.setRequestMethod("POST"); |
| con.setRequestProperty("Content-Length", String.valueOf(postData.length())); |
| con.setDoOutput(true); |
| |
| //Part 2 - Write Data |
| os = con.getOutputStream(); |
| os.write(postData.getBytes("UTF-8")); |
| |
| //Part 3 - Read response of the request |
| in = new BufferedReader(new InputStreamReader(con.getInputStream())); |
| String inputLine; |
| |
| while ((inputLine = in.readLine()) != null) { |
| //Parse the script output |
| StringTokenizer st = new StringTokenizer(inputLine, ","); |
| if (st.countTokens() == 3) { |
| String publicIp = st.nextToken(); |
| Long bytesSent = new Long(st.nextToken()); |
| Long bytesRcvd = new Long(st.nextToken()); |
| long[] bytesSentAndReceived = new long[2]; |
| bytesSentAndReceived[0] = bytesSent; |
| bytesSentAndReceived[1] = bytesRcvd; |
| answer.put(publicIp, bytesSentAndReceived); |
| } |
| } |
| } catch (MalformedURLException e1) { |
| s_logger.info("Invalid Traffic Sentinel URL", e1); |
| throw new ExecutionException(e1.getMessage()); |
| } catch (IOException e) { |
| s_logger.debug("Error in direct network usage accounting", e); |
| throw new ExecutionException(e.getMessage()); |
| } finally { |
| if (os != null) { |
| os.close(); |
| } |
| if (in != null) { |
| in.close(); |
| } |
| } |
| } catch (Exception e) { |
| s_logger.debug(e); |
| throw new ExecutionException(e.getMessage()); |
| } |
| return answer; |
| } |
| |
| private String getScript(List<String> ips, Date start, Date end) { |
| String IpAddresses = ""; |
| for (int i = 0; i < ips.size(); i++) { |
| IpAddresses += ips.get(i); |
| if (i != (ips.size() - 1)) { |
| // Append comma for all Ips except the last Ip |
| IpAddresses += ","; |
| } |
| } |
| String destZoneCondition = ""; |
| if (_inclZones != null && !_inclZones.isEmpty()) { |
| destZoneCondition = " & destinationzone = " + _inclZones; |
| } |
| if (_exclZones != null && !_exclZones.isEmpty()) { |
| destZoneCondition += " & destinationzone != " + _exclZones; |
| } |
| |
| String srcZoneCondition = ""; |
| if (_inclZones != null && !_inclZones.isEmpty()) { |
| srcZoneCondition = " & sourcezone = " + _inclZones; |
| } |
| if (_exclZones != null && !_exclZones.isEmpty()) { |
| srcZoneCondition += " & sourcezone != " + _exclZones; |
| } |
| |
| String startDate = getDateString(start); |
| String endtDate = getDateString(end); |
| StringBuffer sb = new StringBuffer(); |
| sb.append("var q = Query.topN(\"historytrmx\","); |
| sb.append(" \"ipsource,bytes\","); |
| sb.append(" \"ipsource = " + IpAddresses + destZoneCondition + "\","); |
| sb.append(" \"" + startDate + ", " + endtDate + "\","); |
| sb.append(" \"bytes\","); |
| sb.append(" 100000);"); |
| sb.append("var totalsSent = {};"); |
| sb.append("var t = q.run("); |
| sb.append(" function(row,table) {"); |
| sb.append(" if(row[0]) { "); |
| sb.append(" totalsSent[row[0]] = row[1];"); |
| sb.append(" }"); |
| sb.append(" });"); |
| sb.append("var q = Query.topN(\"historytrmx\","); |
| sb.append(" \"ipdestination,bytes\","); |
| sb.append(" \"ipdestination = " + IpAddresses + srcZoneCondition + "\","); |
| sb.append(" \"" + startDate + ", " + endtDate + "\","); |
| sb.append(" \"bytes\","); |
| sb.append(" 100000);"); |
| sb.append("var totalsRcvd = {};"); |
| sb.append("var t = q.run("); |
| sb.append(" function(row,table) {"); |
| sb.append(" if(row[0]) {"); |
| sb.append(" totalsRcvd[row[0]] = row[1];"); |
| sb.append(" }"); |
| sb.append(" });"); |
| sb.append("for (var addr in totalsSent) {"); |
| sb.append(" var TS = 0;"); |
| sb.append(" var TR = 0;"); |
| sb.append(" if(totalsSent[addr]) TS = totalsSent[addr];"); |
| sb.append(" if(totalsRcvd[addr]) TR = totalsRcvd[addr];"); |
| sb.append(" println(addr + \",\" + TS + \",\" + TR);"); |
| sb.append("}"); |
| return sb.toString(); |
| } |
| |
| private String getDateString(Date date) { |
| DateFormat dfDate = new SimpleDateFormat("yyyyMMdd HH:mm:ss"); |
| return dfDate.format(date); |
| } |
| |
| @Override |
| public void setName(String name) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public void setConfigParams(Map<String, Object> params) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public Map<String, Object> getConfigParams() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public int getRunLevel() { |
| // TODO Auto-generated method stub |
| return 0; |
| } |
| |
| @Override |
| public void setRunLevel(int level) { |
| // TODO Auto-generated method stub |
| |
| } |
| } |