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 org.apache.cloudstack.network.contrail.model;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.List;
  
  import org.apache.commons.lang3.StringUtils;
  
  import com.cloud.network.Networks;
  
  import net.juniper.contrail.api.types.NetworkPolicy;
  import net.juniper.contrail.api.types.PolicyEntriesType;
  import net.juniper.contrail.api.types.PolicyEntriesType.PolicyRuleType;
  import net.juniper.contrail.api.types.Project;
  import net.juniper.contrail.api.ApiConnector;
  import org.apache.cloudstack.network.contrail.management.ContrailManager;
  
  import com.cloud.exception.InternalErrorException;
  import com.cloud.network.dao.NetworkVO;
  import com.cloud.network.vpc.NetworkACLItem;
  import com.cloud.network.vpc.NetworkACLItem.Action;
  import com.cloud.utils.db.SearchBuilder;
  import com.cloud.utils.db.SearchCriteria;
  import com.cloud.utils.db.SearchCriteria.Op;
  import com.cloud.utils.exception.CloudRuntimeException;
  
  public class NetworkPolicyModel extends ModelObjectBase {
  
      private String _uuid;
      private String _fqName;
      private String _name;
      private Project _project;
      private NetworkPolicy _policy;
      PolicyEntriesType _policyMap;
  
      public NetworkPolicyModel(String uuid, String name) {
          _uuid = uuid;
          _name = name;
      }
  
       public String getQualifiedName() {
          return _fqName;
      }
  
      public String getName() {
          return _name;
      }
  
      public NetworkVO cidrToNetwork(ModelController controller, String cidr) {
          SearchBuilder<NetworkVO> searchBuilder = controller.getNetworkDao().createSearchBuilder();
          searchBuilder.and("trafficType", searchBuilder.entity().getTrafficType(), Op.EQ);
          searchBuilder.and("cidr", searchBuilder.entity().getCidr(), Op.EQ);
          searchBuilder.and("networkOfferingId", searchBuilder.entity().getNetworkOfferingId(), Op.EQ);
  
          SearchCriteria<NetworkVO> sc = searchBuilder.create();
  
          sc.setParameters("networkOfferingId", controller.getManager().getVpcRouterOffering().getId());
          sc.setParameters("cidr", cidr);
          sc.setParameters("trafficType", Networks.TrafficType.Guest);
  
          List<NetworkVO> dbNets = controller.getNetworkDao().search(sc, null);
          if (dbNets == null || dbNets.size() == 0) {
              return null;
          }
          if (dbNets.size() > 1) {
              logger.warn("more than one network found with cidr: " + cidr);
          }
          return dbNets.get(0);
      }
  
      public void build(ModelController controller, List<? extends NetworkACLItem> rules) throws Exception {
          String projectName = null;
          if (_project != null) {
              _fqName = StringUtils.join(_project.getQualifiedName(), ':') + ":" + _name;
              projectName = StringUtils.join(_project.getQualifiedName(), ':');
          } else {
              _fqName = ContrailManager.VNC_ROOT_DOMAIN + ":" + ContrailManager.VNC_DEFAULT_PROJECT + ":" + _name;
              projectName = ContrailManager.VNC_ROOT_DOMAIN + ":" + ContrailManager.VNC_DEFAULT_PROJECT;
          }
  
          PolicyEntriesType policyMap = new PolicyEntriesType();
  
          for (NetworkACLItem rule:rules) {
              if (rule.getState() != NetworkACLItem.State.Active &&
                   rule.getState() != NetworkACLItem.State.Add)  {
                   continue;
              }
  
              String action = null;
              if (rule.getAction() == Action.Allow) {
                  action = "pass";
              } else if (rule.getAction() == Action.Deny) {
                  action = "deny";
              }
              List<String> cidrList = rule.getSourceCidrList();
              String protocol = rule.getProtocol();
              if (protocol == null || protocol.equalsIgnoreCase("ALL") || protocol.isEmpty()) {
                  protocol = "any";
              } else {
                  protocol = protocol.toLowerCase();
              }
  
              Integer portStart = rule.getSourcePortStart();
              Integer portEnd = rule.getSourcePortEnd();
              if (portStart == null) {
                  portStart = 0;
              }
              if (portEnd == null) {
                  portEnd = 65535;
              }
  
              List<PolicyRuleType.AddressType> srcList = new ArrayList<PolicyRuleType.AddressType>();
              List<PolicyRuleType.AddressType> dstList = new ArrayList<PolicyRuleType.AddressType>();
  
              List<PolicyRuleType.PortType> srcPorts = new ArrayList<PolicyRuleType.PortType>();
              List<PolicyRuleType.PortType> dstPorts = new ArrayList<PolicyRuleType.PortType>();
  
              if (rule.getTrafficType() == NetworkACLItem.TrafficType.Egress){
                  for (String cidr: cidrList) {
                      NetworkVO net = cidrToNetwork(controller, cidr);
                      /*String[] maskInfo = StringUtils.splitByWholeSeparator(cidr, "/");
                      SubnetType subnet = new SubnetType();
                      subnet.setIpPrefix(maskInfo[0]);
                      subnet.setIpPrefixLen(Integer.parseInt(maskInfo[1]));
                      */
                      String netName = projectName + ":" + controller.getManager().getCanonicalName(net);
                      dstList.add(new PolicyRuleType.AddressType(null, netName, null));
                  }
                  dstPorts.add(new PolicyRuleType.PortType(portStart, portEnd));
                  srcList.add(new PolicyRuleType.AddressType(null, "local", null));
                  srcPorts.add(new PolicyRuleType.PortType(0, 65535));
              } else {
                  for (String cidr: cidrList) {
                      NetworkVO net = cidrToNetwork(controller, cidr);
                      String netName = projectName + ":" + controller.getManager().getCanonicalName(net);
                      srcList.add(new PolicyRuleType.AddressType(null, netName, null));
                  }
                  dstPorts.add(new PolicyRuleType.PortType(portStart, portEnd));
  
                  dstList.add(new PolicyRuleType.AddressType(null, "local", null));
                  srcPorts.add(new PolicyRuleType.PortType(0, 65535));
              }
  
              PolicyRuleType vnRule = new PolicyRuleType(
                      new PolicyRuleType.SequenceType(1, 0), rule.getUuid(), "<>", protocol,
                      srcList, srcPorts, null, dstList, dstPorts,
                      new PolicyRuleType.ActionListType(action, null, null, null));
              policyMap.addPolicyRule(vnRule);
          }
          _policyMap = policyMap;
      }
  
      /* for service instance policy */
      public void build(ModelController modelController, String leftVn, String rightVn, String gatewayName,
              List<String> siList, String action) {
          if (_project != null) {
              _fqName = StringUtils.join(_project.getQualifiedName(), ':') + ":" + _name;
          } else {
              _fqName = ContrailManager.VNC_ROOT_DOMAIN + ":" + ContrailManager.VNC_DEFAULT_PROJECT + ":" + _name;
          }
  
          PolicyEntriesType policyMap = new PolicyEntriesType();
          List<PolicyRuleType.AddressType> srcList = new ArrayList<PolicyRuleType.AddressType>();
          srcList.add(new PolicyRuleType.AddressType(null, leftVn, null));
          List<PolicyRuleType.AddressType> dstList = new ArrayList<PolicyRuleType.AddressType>();
          dstList.add(new PolicyRuleType.AddressType(null, rightVn, null));
  
          List<PolicyRuleType.PortType> portAny = new ArrayList<PolicyRuleType.PortType>();
          portAny.add(new PolicyRuleType.PortType(0, 65535));
  
          PolicyRuleType rule = new PolicyRuleType(
                  new PolicyRuleType.SequenceType(1, 0),  null, "<>", "any",
                  srcList, portAny, null, dstList, portAny,
                  new PolicyRuleType.ActionListType(action, gatewayName, siList, null));
          policyMap.addPolicyRule(rule);
          _policyMap = policyMap;
      }
  
      public boolean hasPolicyRules() {
          if (_policyMap != null && _policyMap.getPolicyRule() != null && _policyMap.getPolicyRule().size() > 0) {
              return true;
          }
          return false;
      }
  
      @Override
      public int compareTo(ModelObject o) {
          NetworkPolicyModel other;
          try {
              other = (NetworkPolicyModel) o;
          } catch (ClassCastException ex) {
              String clsname = o.getClass().getName();
              return NetworkPolicyModel.class.getName().compareTo(clsname);
          }
          return _uuid.compareTo(other._uuid);
      }
  
      @Override
      public void delete(ModelController controller) throws IOException {
          ApiConnector api = controller.getApiAccessor();
          if (_policy != null) {
              api.delete(_policy);
              _policy = null;
          }
      }
  
      @Override
      public void destroy(ModelController controller) throws IOException {
      }
  
      public String getUuid() {
          return _uuid;
      }
  
      @Override
      public void update(ModelController controller) throws InternalErrorException, IOException {
          ApiConnector api = controller.getApiAccessor();
          if (_project == null) {
              logger.debug("Project is null for the policy: " + _name);
              throw new IOException("Project is null for the policy: " + _name);
          }
  
          NetworkPolicy policy = _policy;
  
          if (policy == null) {
              try {
                  String policyId = api.findByName(NetworkPolicy.class, _project, _name);
                  if (policyId != null) {
                      policy = _policy = (NetworkPolicy) api.findById(NetworkPolicy.class, policyId);
                  }
                  if (policy == null) {
                      policy = new NetworkPolicy();
                      policy.setUuid(_uuid);
                      policy.setName(_name);
                      policy.setParent(_project);
                  }
              } catch (IOException ex) {
                  logger.warn("network-policy read", ex);
                  return;
              }
          }
  
          policy.setEntries(_policyMap);
          if (_policy == null) {
              try {
                  api.create(policy);
              } catch (Exception ex) {
                  logger.debug("network policy create", ex);
                  throw new CloudRuntimeException("Failed to create network policy", ex);
              }
              _policy = policy;
          } else {
              try {
                  api.update(policy);
              } catch (IOException ex) {
                  logger.warn("network policy update", ex);
                  throw new CloudRuntimeException("Unable to update network policy", ex);
              }
          }
          for (ModelObject successor: successors()) {
              successor.update(controller);
          }
      }
  
      @Override
      public boolean verify(ModelController controller) {
          return false;
      }
  
      @Override
      public boolean compare(ModelController controller, ModelObject current) {
          return true;
      }
  
      public void setProperties(ModelController controller, List<? extends NetworkACLItem> rules) {
  
      }
  
      public void setProject(Project project) {
          _project = project;
      }
  
      public NetworkPolicy getPolicy() {
          return _policy;
      }
  }
  