content: // 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.
  //
  // Automatically generated by addcopyright.py at 01/29/2013
  // Apache License, Version 2.0 (the "License"); you may not use this
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  //
  // Automatically generated by addcopyright.py at 04/03/2012
  
  package com.cloud.baremetal.networkservice;
  
  import com.cloud.agent.api.SecurityGroupRuleAnswer;
  import com.cloud.agent.api.SecurityGroupRulesCmd;
  import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto;
  import com.cloud.baremetal.networkservice.schema.SecurityGroupRule;
  import com.cloud.baremetal.networkservice.schema.SecurityGroupVmRuleSet;
  import com.cloud.utils.Pair;
  import com.cloud.utils.exception.CloudRuntimeException;
  import org.apache.commons.httpclient.HttpClient;
  import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
  import org.apache.commons.httpclient.methods.PostMethod;
  import org.apache.commons.httpclient.methods.StringRequestEntity;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.LogManager;
  
  import javax.xml.bind.JAXBContext;
  import javax.xml.bind.Marshaller;
  import java.io.StringWriter;
  import java.net.SocketTimeoutException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.concurrent.TimeUnit;
  
  public class SecurityGroupHttpClient {
      protected Logger logger = LogManager.getLogger(getClass());
      private static final String ARG_NAME = "args";
      private static final String COMMAND = "command";
      private JAXBContext context;
      private int port;
      private static HttpClient httpClient;
      static {
          MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager();
          httpClient = new HttpClient(connman);
          httpClient.setConnectionTimeout(5000);
      }
  
      private enum OpConstant {
          setRules, echo,
      }
  
      public SecurityGroupHttpClient() {
          try {
              context = JAXBContext.newInstance(SecurityGroupRule.class, SecurityGroupVmRuleSet.class);
              port = 9988;
          } catch (Exception e) {
              throw new CloudRuntimeException(
                      "Unable to create JAXBContext for security group", e);
          }
      }
  
      private List<SecurityGroupRule> generateRules(final List<IpPortAndProto> ipps) {
          List<SecurityGroupRule> rules = new ArrayList<SecurityGroupRule>(
                  ipps.size());
          for (SecurityGroupRulesCmd.IpPortAndProto ipp : ipps) {
              SecurityGroupRule r = new SecurityGroupRule();
              r.setProtocol(ipp.getProto());
              r.setStartPort(ipp.getStartPort());
              r.setEndPort(ipp.getEndPort());
              for (String cidr : ipp.getAllowedCidrs()) {
                  r.getIp().add(cidr);
              }
              rules.add(r);
          }
          return rules;
      }
  
      public HashMap<String, Pair<Long, Long>> sync(String vmName, Long vmId, String agentIp) {
          HashMap<String, Pair<Long, Long>> states = new HashMap<String, Pair<Long, Long>>();
          PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort()));
          try {
              post.addRequestHeader("command", "sync");
              if (httpClient.executeMethod(post) != 200) {
                  logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString()));
              } else {
                  String res = post.getResponseBodyAsString();
                  // res = ';'.join([vmName, vmId, seqno])
                  String[] rulelogs = res.split(",");
                  if (rulelogs.length != 6) {
                      logger.debug(String.format("host[%s] returns invalid security group sync document[%s], reset rules", agentIp, res));
                      states.put(vmName, new Pair<Long, Long>(vmId, -1L));
                      return states;
                  }
                  Pair<Long, Long> p = new Pair<Long, Long>(Long.valueOf(rulelogs[1]), Long.valueOf(rulelogs[5]));
                  states.put(rulelogs[0], p);
                  return states;
              }
          } catch (SocketTimeoutException se) {
              logger.warn(String.format("unable to sync security group rules on host[%s], %s", agentIp, se.getMessage()));
          } catch (Exception e) {
              logger.warn(String.format("unable to sync security group rules on host[%s]", agentIp), e);
          } finally {
              if (post != null) {
                  post.releaseConnection();
              }
          }
          return states;
      }
  
  
      public boolean echo(String agentIp, long l, long m) {
          boolean ret = false;
          int count = 1;
          while (true) {
              try {
                  Thread.sleep(m);
                  count++;
              } catch (InterruptedException e1) {
                  logger.warn("", e1);
                  break;
              }
              PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort()));
              try {
                  post.addRequestHeader("command", "echo");
                  if (httpClient.executeMethod(post) != 200) {
                      logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString()));
                  } else {
                      ret = true;
                  }
                  break;
              } catch (Exception e) {
                  if (count*m >= l) {
                      logger.debug(String.format("ping security group agent on vm[%s] timeout after %s minutes, starting vm failed, count=%s", agentIp, TimeUnit.MILLISECONDS.toSeconds(l), count));
                      break;
                  } else {
                      logger.debug(String.format("Having pinged security group agent on vm[%s] %s times, continue to wait...", agentIp, count));
                  }
              } finally {
                  if (post != null) {
                      post.releaseConnection();
                  }
              }
          }
          return ret;
      }
  
      public SecurityGroupRuleAnswer call(String agentIp, SecurityGroupRulesCmd cmd) {
          PostMethod post = new PostMethod(String.format(
                  "http://%s:%s", agentIp, getPort()));
          try {
              SecurityGroupVmRuleSet rset = new SecurityGroupVmRuleSet();
              rset.getEgressRules().addAll(generateRules(cmd.getEgressRuleSet()));
              rset.getIngressRules().addAll(
                      generateRules(cmd.getIngressRuleSet()));
              rset.setVmName(cmd.getVmName());
              rset.setVmIp(cmd.getGuestIp());
              rset.setVmMac(cmd.getGuestMac());
              rset.setVmId(cmd.getVmId());
              rset.setSignature(cmd.getSignature());
              rset.setSequenceNumber(cmd.getSeqNum());
              Marshaller marshaller = context.createMarshaller();
              StringWriter writer = new StringWriter();
              marshaller.marshal(rset, writer);
              String xmlContents = writer.toString();
              logger.debug(xmlContents);
  
              post.addRequestHeader("command", "set_rules");
              StringRequestEntity entity = new StringRequestEntity(xmlContents);
              post.setRequestEntity(entity);
              if (httpClient.executeMethod(post) != 200) {
                  return new SecurityGroupRuleAnswer(cmd, false,
                          post.getResponseBodyAsString());
              } else {
                  return new SecurityGroupRuleAnswer(cmd);
              }
          } catch (Exception e) {
              return new SecurityGroupRuleAnswer(cmd, false, e.getMessage());
          } finally {
              if (post != null) {
                  post.releaseConnection();
              }
          }
      }
  
      public int getPort() {
          return port;
      }
  
      public void setPort(int port) {
          this.port = port;
      }
  }
  