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.
  package com.cloud.test;
  
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Vector;
  
  import com.cloud.network.Networks.TrafficType;
  import com.cloud.utils.component.ComponentContext;
  import com.cloud.utils.db.DB;
  import com.cloud.utils.db.TransactionLegacy;
  import com.cloud.utils.net.NetUtils;
  
  public class PodZoneConfig {
  
      public static void main(String[] args) {
          PodZoneConfig config = ComponentContext.inject(PodZoneConfig.class);
          //config.run(args);
          System.exit(0);
      }
  
      public void savePod(boolean printOutput, long id, String name, long dcId, String gateway, String cidr, int vlanStart, int vlanEnd) {
          // Check that the cidr was valid
          if (!IPRangeConfig.validCIDR(cidr))
              printError("Please enter a valid CIDR for pod: " + name);
  
          // Get the individual cidrAddress and cidrSize values
          String[] cidrPair = cidr.split("\\/");
          String cidrAddress = cidrPair[0];
          String cidrSize = cidrPair[1];
  
          String sql = null;
          if (id != -1)
              sql =
                  "INSERT INTO `cloud`.`host_pod_ref` (id, name, data_center_id, gateway, cidr_address, cidr_size) " + "VALUES ('" + id + "','" + name + "','" + dcId +
                      "','" + gateway + "','" + cidrAddress + "','" + cidrSize + "')";
          else
              sql =
                  "INSERT INTO `cloud`.`host_pod_ref` (name, data_center_id, gateway, cidr_address, cidr_size) " + "VALUES ('" + name + "','" + dcId + "','" + gateway +
                      "','" + cidrAddress + "','" + cidrSize + "')";
  
          DatabaseConfig.saveSQL(sql, "Failed to save pod due to exception. Please contact Cloud Support.");
  
          if (printOutput)
              System.out.println("Successfully saved pod.");
      }
  
      public void checkAllPodCidrSubnets() {
          Vector<Long> allZoneIDs = getAllZoneIDs();
          for (Long dcId : allZoneIDs) {
              HashMap<Long, Vector<Object>> currentPodCidrSubnets = getCurrentPodCidrSubnets(dcId.longValue());
              String result = checkPodCidrSubnets(dcId.longValue(), currentPodCidrSubnets);
              if (!result.equals("success"))
                  printError(result);
          }
      }
  
      private String checkPodCidrSubnets(long dcId, HashMap<Long, Vector<Object>> currentPodCidrSubnets) {
  
  //        DataCenterDao _dcDao = null;
  //        final ComponentLocator locator = ComponentLocator.getLocator("management-server");
  
  //        _dcDao = locator.getDao(DataCenterDao.class);
          // For each pod, return an error if any of the following is true:
          // 1. The pod's CIDR subnet conflicts with the guest network subnet
          // 2. The pod's CIDR subnet conflicts with the CIDR subnet of any other pod
  
          String zoneName = PodZoneConfig.getZoneName(dcId);
  
          //get the guest network cidr and guest netmask from the zone
  //        DataCenterVO dcVo = _dcDao.findById(dcId);
  
          String guestNetworkCidr = IPRangeConfig.getGuestNetworkCidr(dcId);
  
          if (guestNetworkCidr == null || guestNetworkCidr.isEmpty())
              return "Please specify a valid guest cidr";
          String[] cidrTuple = guestNetworkCidr.split("\\/");
  
          String guestIpNetwork = NetUtils.getIpRangeStartIpFromCidr(cidrTuple[0], Long.parseLong(cidrTuple[1]));
          long guestCidrSize = Long.parseLong(cidrTuple[1]);
  
          // Iterate through all pods in this zone
          for (Long podId : currentPodCidrSubnets.keySet()) {
              String podName;
              if (podId.longValue() == -1)
                  podName = "newPod";
              else
                  podName = PodZoneConfig.getPodName(podId.longValue(), dcId);
  
              Vector<Object> cidrPair = currentPodCidrSubnets.get(podId);
              String cidrAddress = (String)cidrPair.get(0);
              long cidrSize = ((Long)cidrPair.get(1)).longValue();
  
              long cidrSizeToUse = -1;
              if (cidrSize < guestCidrSize)
                  cidrSizeToUse = cidrSize;
              else
                  cidrSizeToUse = guestCidrSize;
  
              String cidrSubnet = NetUtils.getCidrSubNet(cidrAddress, cidrSizeToUse);
              String guestSubnet = NetUtils.getCidrSubNet(guestIpNetwork, cidrSizeToUse);
  
              // Check that cidrSubnet does not equal guestSubnet
              if (cidrSubnet.equals(guestSubnet)) {
                  if (podName.equals("newPod")) {
                      return "The subnet of the pod you are adding conflicts with the subnet of the Guest IP Network. Please specify a different CIDR.";
                  } else {
                      return "Warning: The subnet of pod " + podName + " in zone " + zoneName +
                          " conflicts with the subnet of the Guest IP Network. Please change either the pod's CIDR or the Guest IP Network's subnet, and re-run install-vmops-management.";
                  }
              }
  
              // Iterate through the rest of the pods
              for (Long otherPodId : currentPodCidrSubnets.keySet()) {
                  if (podId.equals(otherPodId))
                      continue;
  
                  // Check that cidrSubnet does not equal otherCidrSubnet
                  Vector<Object> otherCidrPair = currentPodCidrSubnets.get(otherPodId);
                  String otherCidrAddress = (String)otherCidrPair.get(0);
                  long otherCidrSize = ((Long)otherCidrPair.get(1)).longValue();
  
                  if (cidrSize < otherCidrSize)
                      cidrSizeToUse = cidrSize;
                  else
                      cidrSizeToUse = otherCidrSize;
  
                  cidrSubnet = NetUtils.getCidrSubNet(cidrAddress, cidrSizeToUse);
                  String otherCidrSubnet = NetUtils.getCidrSubNet(otherCidrAddress, cidrSizeToUse);
  
                  if (cidrSubnet.equals(otherCidrSubnet)) {
                      String otherPodName = PodZoneConfig.getPodName(otherPodId.longValue(), dcId);
                      if (podName.equals("newPod")) {
                          return "The subnet of the pod you are adding conflicts with the subnet of pod " + otherPodName + " in zone " + zoneName +
                              ". Please specify a different CIDR.";
                      } else {
                          return "Warning: The pods " + podName + " and " + otherPodName + " in zone " + zoneName +
                              " have conflicting CIDR subnets. Please change the CIDR of one of these pods.";
                      }
                  }
              }
          }
  
          return "success";
      }
  
      @DB
      protected HashMap<Long, Vector<Object>> getCurrentPodCidrSubnets(long dcId) {
          HashMap<Long, Vector<Object>> currentPodCidrSubnets = new HashMap<Long, Vector<Object>>();
  
          String selectSql = "SELECT id, cidr_address, cidr_size FROM host_pod_ref WHERE data_center_id=" + dcId;
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(selectSql);
              ResultSet rs = stmt.executeQuery();
              while (rs.next()) {
                  Long podId = rs.getLong("id");
                  String cidrAddress = rs.getString("cidr_address");
                  long cidrSize = rs.getLong("cidr_size");
                  Vector<Object> cidrPair = new Vector<Object>();
                  cidrPair.add(0, cidrAddress);
                  cidrPair.add(1, new Long(cidrSize));
                  currentPodCidrSubnets.put(podId, cidrPair);
              }
          } catch (SQLException ex) {
              System.out.println(ex.getMessage());
              printError("There was an issue with reading currently saved pod CIDR subnets. Please contact Cloud Support.");
              return null;
          }
  
          return currentPodCidrSubnets;
      }
  
      public void deletePod(String name, long dcId) {
          String sql = "DELETE FROM `cloud`.`host_pod_ref` WHERE name=\"" + name + "\" AND data_center_id=\"" + dcId + "\"";
          DatabaseConfig.saveSQL(sql, "Failed to delete pod due to exception. Please contact Cloud Support.");
      }
  
      public long getVlanDbId(String zone, String vlanId) {
          long zoneId = getZoneId(zone);
  
          return DatabaseConfig.getDatabaseValueLong("SELECT * FROM `cloud`.`vlan` WHERE data_center_id=\"" + zoneId + "\" AND vlan_id =\"" + vlanId + "\"", "id",
              "Unable to start DB connection to read vlan DB id. Please contact Cloud Support.");
      }
  
      public List<String> modifyVlan(String zone, boolean add, String vlanId, String vlanGateway, String vlanNetmask, String pod, String vlanType, String ipRange,
          long networkId, long physicalNetworkId) {
          // Check if the zone is valid
          long zoneId = getZoneId(zone);
          if (zoneId == -1)
              return genReturnList("false", "Please specify a valid zone.");
  
          //check if physical network is valid
          long physicalNetworkDbId = checkPhysicalNetwork(physicalNetworkId);
          if (physicalNetworkId == -1)
              return genReturnList("false", "Please specify a valid physical network.");
  
          Long podId = pod != null ? getPodId(pod, zone) : null;
          if (podId != null && podId == -1)
              return genReturnList("false", "Please specify a valid pod.");
  
          if (add) {
  
              // Make sure the gateway is valid
              if (!NetUtils.isValidIp4(vlanGateway))
                  return genReturnList("false", "Please specify a valid gateway.");
  
              // Make sure the netmask is valid
              if (!NetUtils.isValidIp4(vlanNetmask))
                  return genReturnList("false", "Please specify a valid netmask.");
  
              // Check if a vlan with the same vlanId already exists in the specified zone
              if (getVlanDbId(zone, vlanId) != -1)
                  return genReturnList("false", "A VLAN with the specified VLAN ID already exists in zone " + zone + ".");
  
              /*
              // Check if another vlan in the same zone has the same subnet
              String newVlanSubnet = NetUtils.getSubNet(vlanGateway, vlanNetmask);
              List<VlanVO> vlans = _vlanDao.findByZone(zoneId);
              for (VlanVO vlan : vlans) {
                  String currentVlanSubnet = NetUtils.getSubNet(vlan.getVlanGateway(), vlan.getVlanNetmask());
                  if (newVlanSubnet.equals(currentVlanSubnet))
                      return genReturnList("false", "The VLAN with ID " + vlan.getVlanId() + " in zone " + zone + " has the same subnet. Please specify a different gateway/netmask.");
              }
               */
  
              // Everything was fine, so persist the VLAN
              saveVlan(zoneId, podId, vlanId, vlanGateway, vlanNetmask, vlanType, ipRange, networkId, physicalNetworkDbId);
              if (podId != null) {
                  long vlanDbId = getVlanDbId(zone, vlanId);
                  String sql = "INSERT INTO `cloud`.`pod_vlan_map` (pod_id, vlan_db_id) " + "VALUES (?,?)";
                  String errorMsg =  "Failed to save pod_vlan_map due to exception vlanDbId=" + vlanDbId + ", podId=" + podId + ". Please contact Cloud Support.";
                  TransactionLegacy txn = TransactionLegacy.open("saveSQL");
                  try ( PreparedStatement stmt = txn.prepareAutoCloseStatement(sql); ) {
                          stmt.setString(1, podId.toString());
                          stmt.setString(2, String.valueOf(vlanDbId));
                          stmt.executeUpdate();
                      } catch (SQLException ex) {
                          System.out.println("SQL Exception: " + ex.getMessage());
                          printError(errorMsg);
                      }
              }
  
              return genReturnList("true", "Successfully added VLAN.");
  
          } else {
              return genReturnList("false", "That operation is not supported.");
          }
  
          /*
          else {
  
              // Check if a VLAN actually exists in the specified zone
              long vlanDbId = getVlanDbId(zone, vlanId);
              if (vlanDbId == -1)
                  return genReturnList("false", "A VLAN with ID " + vlanId + " does not exist in zone " + zone);
  
              // Check if there are any public IPs that are in the specified vlan.
              List<IPAddressVO> ips = _publicIpAddressDao.listByVlanDbId(vlanDbId);
              if (ips.size() != 0)
                  return genReturnList("false", "Please delete all IP addresses that are in VLAN " + vlanId + " before deleting the VLAN.");
  
              // Delete the vlan
              _vlanDao.delete(vlanDbId);
  
              return genReturnList("true", "Successfully deleted VLAN.");
          }
           */
      }
  
      @DB
      public void saveZone(boolean printOutput, long id, String name, String dns1, String dns2, String dns3, String dns4, String guestNetworkCidr, String networkType) {
  
          if (printOutput)
              System.out.println("Saving zone, please wait...");
  
          String columns = null;
          String values = null;
  
          if (id != -1) {
              columns = "(id, name";
              values = "('" + id + "','" + name + "'";
          } else {
              columns = "(name";
              values = "('" + name + "'";
          }
  
          if (dns1 != null) {
              columns += ", dns1";
              values += ",'" + dns1 + "'";
          }
  
          if (dns2 != null) {
              columns += ", dns2";
              values += ",'" + dns2 + "'";
          }
  
          if (dns3 != null) {
              columns += ", internal_dns1";
              values += ",'" + dns3 + "'";
          }
  
          if (dns4 != null) {
              columns += ", internal_dns2";
              values += ",'" + dns4 + "'";
          }
  
          if (guestNetworkCidr != null) {
              columns += ", guest_network_cidr";
              values += ",'" + guestNetworkCidr + "'";
          }
  
          if (networkType != null) {
              columns += ", networktype";
              values += ",'" + networkType + "'";
          }
  
          columns += ", uuid";
          values += ", UUID()";
  
          columns += ")";
          values += ")";
  
          String sql = "INSERT INTO `cloud`.`data_center` " + columns + " VALUES " + values;
  
          DatabaseConfig.saveSQL(sql, "Failed to save zone due to exception. Please contact Cloud Support.");
  
          if (printOutput)
              System.out.println("Successfully saved zone.");
      }
  
      @DB
      public void savePhysicalNetwork(boolean printOutput, long id, long dcId, int vnetStart, int vnetEnd) {
  
          if (printOutput)
              System.out.println("Saving physical network, please wait...");
  
          String columns = null;
          String values = null;
  
          columns = "(id ";
          values = "('" + id + "'";
  
          columns += ", name ";
          values += ",'physical network'";
  
          columns += ", data_center_id ";
          values += ",'" + dcId + "'";
  
          //save vnet information
          columns += ", vnet";
          values += ",'" + vnetStart + "-" + vnetEnd + "'";
  
          columns += ", state";
          values += ", 'Enabled'";
  
          columns += ", uuid";
          values += ", UUID()";
  
          columns += ")";
          values += ")";
  
          String sql = "INSERT INTO `cloud`.`physical_network` " + columns + " VALUES " + values;
  
          DatabaseConfig.saveSQL(sql, "Failed to save physical network due to exception. Please contact Cloud Support.");
  
          // Hardcode the vnet range to be the full range
          int begin = 0x64;
          int end = 64000;
  
          // If vnet arguments were passed in, use them
          if (vnetStart != -1 && vnetEnd != -1) {
              begin = vnetStart;
              end = vnetEnd;
          }
  
          String insertVnet = "INSERT INTO `cloud`.`op_dc_vnet_alloc` (vnet, data_center_id, physical_network_id) VALUES ( ?, ?, ?)";
  
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertVnet);
              for (int i = begin; i <= end; i++) {
                  stmt.setString(1, Integer.toString(i));
                  stmt.setLong(2, dcId);
                  stmt.setLong(3, id);
                  stmt.addBatch();
              }
              stmt.executeBatch();
          } catch (SQLException ex) {
              printError("Error creating vnet for the physical network. Please contact Cloud Support.");
          }
  
          //add default traffic types
  
          //get default Xen network labels
          String defaultXenPrivateNetworkLabel = getDefaultXenNetworkLabel(TrafficType.Management);
          String defaultXenPublicNetworkLabel = getDefaultXenNetworkLabel(TrafficType.Public);
          String defaultXenStorageNetworkLabel = getDefaultXenNetworkLabel(TrafficType.Storage);
          String defaultXenGuestNetworkLabel = getDefaultXenNetworkLabel(TrafficType.Guest);
  
          String insertTraficType = "INSERT INTO `cloud`.`physical_network_traffic_types` " + "(physical_network_id, traffic_type, xenserver_network_label) VALUES ( ?, ?, ?)";
  
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(insertTraficType);
              for (TrafficType traffic : TrafficType.values()) {
                  if (traffic.equals(TrafficType.Control) || traffic.equals(TrafficType.Vpn) || traffic.equals(TrafficType.None)) {
                      continue;
                  }
                  stmt.setLong(1, id);
                  stmt.setString(2, traffic.toString());
                  if (traffic.equals(TrafficType.Public)) {
                      stmt.setString(3, defaultXenPublicNetworkLabel);
                  } else if (traffic.equals(TrafficType.Management)) {
                      stmt.setString(3, defaultXenPrivateNetworkLabel);
                  } else if (traffic.equals(TrafficType.Storage)) {
                      stmt.setString(3, defaultXenStorageNetworkLabel);
                  } else if (traffic.equals(TrafficType.Guest)) {
                      stmt.setString(3, defaultXenGuestNetworkLabel);
                  }
  
                  stmt.addBatch();
              }
              stmt.executeBatch();
          } catch (SQLException ex) {
              printError("Error adding default traffic types for the physical network. Please contact Cloud Support.");
          }
  
          if (printOutput)
              System.out.println("Successfully saved physical network.");
      }
  
      private String getDefaultXenNetworkLabel(TrafficType trafficType) {
          String xenLabel = null;
          String configName = null;
          switch (trafficType) {
              case Public:
                  configName = "xenserver.public.network.device";
                  break;
              case Guest:
                  configName = "xenserver.guest.network.device";
                  break;
              case Storage:
                  configName = "xenserver.storage.network.device1";
                  break;
              case Management:
                  configName = "xenserver.private.network.device";
                  break;
          }
  
          if (configName != null) {
              xenLabel = getConfiguredValue(configName);
          }
          return xenLabel;
      }
  
      public static String getConfiguredValue(String configName) {
          return DatabaseConfig.getDatabaseValueString("SELECT value FROM `cloud`.`configuration` where name = \"" + configName + "\"", "value",
              "Unable to start DB connection to read configuration. Please contact Cloud Support.");
      }
  
      public void deleteZone(String name) {
          String sql = "DELETE FROM `cloud`.`data_center` WHERE name=\"" + name + "\"";
          DatabaseConfig.saveSQL(sql, "Failed to delete zone due to exception. Please contact Cloud Support.");
      }
  
      public void saveVlan(long zoneId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String vlanType, String ipRange, long networkId,
          long physicalNetworkId) {
          String sql =
              "INSERT INTO `cloud`.`vlan` (vlan_id, vlan_gateway, vlan_netmask, data_center_id, vlan_type, ip4_range, network_id, physical_network_id) " + "VALUES ('" +
                  vlanId + "','" + vlanGateway + "','" + vlanNetmask + "','" + zoneId + "','" + vlanType + "','" + ipRange + "','" + networkId + "','" + physicalNetworkId +
                  "')";
          DatabaseConfig.saveSQL(sql, "Failed to save vlan due to exception. Please contact Cloud Support.");
      }
  
      public static long getPodId(String pod, String zone) {
          long dcId = getZoneId(zone);
          String selectSql = "SELECT * FROM `cloud`.`host_pod_ref` WHERE name = \"" + pod + "\" AND data_center_id = \"" + dcId + "\"";
          String errorMsg = "Could not read pod ID fro mdatabase. Please contact Cloud Support.";
          return DatabaseConfig.getDatabaseValueLong(selectSql, "id", errorMsg);
      }
  
      public static long getPodId(String pod, long dcId) {
          String selectSql = "SELECT * FROM `cloud`.`host_pod_ref` WHERE name = \"" + pod + "\" AND data_center_id = \"" + dcId + "\"";
          String errorMsg = "Could not read pod ID fro mdatabase. Please contact Cloud Support.";
          return DatabaseConfig.getDatabaseValueLong(selectSql, "id", errorMsg);
      }
  
      public static long getZoneId(String zone) {
          String selectSql = "SELECT * FROM `cloud`.`data_center` WHERE name = \"" + zone + "\"";
          String errorMsg = "Could not read zone ID from database. Please contact Cloud Support.";
          return DatabaseConfig.getDatabaseValueLong(selectSql, "id", errorMsg);
      }
  
      public static long checkPhysicalNetwork(long physicalNetworkId) {
          String selectSql = "SELECT * FROM `cloud`.`physical_network` WHERE id = \"" + physicalNetworkId + "\"";
          String errorMsg = "Could not read physicalNetwork ID from database. Please contact Cloud Support.";
          return DatabaseConfig.getDatabaseValueLong(selectSql, "id", errorMsg);
      }
  
      @DB
      public Vector<Long> getAllZoneIDs() {
          Vector<Long> allZoneIDs = new Vector<Long>();
  
          String selectSql = "SELECT id FROM data_center";
          TransactionLegacy txn = TransactionLegacy.currentTxn();
          try {
              PreparedStatement stmt = txn.prepareAutoCloseStatement(selectSql);
              ResultSet rs = stmt.executeQuery();
              while (rs.next()) {
                  Long dcId = rs.getLong("id");
                  allZoneIDs.add(dcId);
              }
          } catch (SQLException ex) {
              System.out.println(ex.getMessage());
              printError("There was an issue with reading zone IDs. Please contact Cloud Support.");
              return null;
          }
  
          return allZoneIDs;
      }
  
      public static boolean validPod(String pod, String zone) {
          return (getPodId(pod, zone) != -1);
      }
  
      public static boolean validZone(String zone) {
          return (getZoneId(zone) != -1);
      }
  
      public static String getPodName(long podId, long dcId) {
          return DatabaseConfig.getDatabaseValueString("SELECT * FROM `cloud`.`host_pod_ref` WHERE id=" + podId + " AND data_center_id=" + dcId, "name",
              "Unable to start DB connection to read pod name. Please contact Cloud Support.");
      }
  
      public static String getZoneName(long dcId) {
          return DatabaseConfig.getDatabaseValueString("SELECT * FROM `cloud`.`data_center` WHERE id=" + dcId, "name",
              "Unable to start DB connection to read zone name. Please contact Cloud Support.");
      }
  
      private static void printError(String message) {
          DatabaseConfig.printError(message);
      }
  
      private List<String> genReturnList(String success, String message) {
          List<String> returnList = new ArrayList<String>();
          returnList.add(0, success);
          returnList.add(1, message);
          return returnList;
      }
  
  }
  