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.network.resource.wrapper;
  
  import static com.cloud.network.resource.NiciraNvpResource.NAME_MAX_LEN;
  import static com.cloud.network.resource.NiciraNvpResource.NUM_RETRIES;
  
  import java.util.ArrayList;
  import java.util.List;
  
  
  import com.cloud.agent.api.Answer;
  import com.cloud.agent.api.CreateLogicalRouterAnswer;
  import com.cloud.agent.api.CreateLogicalRouterCommand;
  import com.cloud.network.nicira.L3GatewayAttachment;
  import com.cloud.network.nicira.LogicalRouter;
  import com.cloud.network.nicira.LogicalRouterPort;
  import com.cloud.network.nicira.LogicalSwitchPort;
  import com.cloud.network.nicira.Match;
  import com.cloud.network.nicira.NiciraNvpApi;
  import com.cloud.network.nicira.NiciraNvpApiException;
  import com.cloud.network.nicira.NiciraNvpTag;
  import com.cloud.network.nicira.PatchAttachment;
  import com.cloud.network.nicira.RouterNextHop;
  import com.cloud.network.nicira.SingleDefaultRouteImplicitRoutingConfig;
  import com.cloud.network.nicira.SourceNatRule;
  import com.cloud.network.resource.NiciraNvpResource;
  import com.cloud.network.utils.CommandRetryUtility;
  import com.cloud.resource.CommandWrapper;
  import com.cloud.resource.ResourceWrapper;
  
  @ResourceWrapper(handles =  CreateLogicalRouterCommand.class)
  public final class NiciraNvpCreateLogicalRouterCommandWrapper extends CommandWrapper<CreateLogicalRouterCommand, Answer, NiciraNvpResource> {
  
  
      @Override
      public Answer execute(final CreateLogicalRouterCommand command, final NiciraNvpResource niciraNvpResource) {
          final String routerName = command.getName();
          final String gatewayServiceUuid = command.getGatewayServiceUuid();
          final String logicalSwitchUuid = command.getLogicalSwitchUuid();
  
          final List<NiciraNvpTag> tags = new ArrayList<NiciraNvpTag>();
          tags.add(new NiciraNvpTag("cs_account", command.getOwnerName()));
  
          final String publicNetworkNextHopIp = command.getPublicNextHop();
          final String publicNetworkIpAddress = command.getPublicIpCidr();
          final String internalNetworkAddress = command.getInternalIpCidr();
  
          logger.debug("Creating a logical router with external ip " + publicNetworkIpAddress + " and internal ip " + internalNetworkAddress + "on gateway service " +
                  gatewayServiceUuid);
  
          final NiciraNvpApi niciraNvpApi = niciraNvpResource.getNiciraNvpApi();
  
          try {
              // Create the Router
              LogicalRouter lrc = new LogicalRouter();
              lrc.setDisplayName(niciraNvpResource.truncate(routerName, NAME_MAX_LEN));
              lrc.setTags(tags);
              lrc.setRoutingConfig(new SingleDefaultRouteImplicitRoutingConfig(new RouterNextHop(publicNetworkNextHopIp)));
              lrc = niciraNvpApi.createLogicalRouter(lrc);
  
              // store the switchport for rollback
              LogicalSwitchPort lsp = null;
  
              try {
                  // Create the outside port for the router
                  LogicalRouterPort lrpo = new LogicalRouterPort();
                  lrpo.setAdminStatusEnabled(true);
                  lrpo.setDisplayName(niciraNvpResource.truncate(routerName + "-outside-port", NAME_MAX_LEN));
                  lrpo.setTags(tags);
                  final List<String> outsideIpAddresses = new ArrayList<String>();
                  outsideIpAddresses.add(publicNetworkIpAddress);
                  lrpo.setIpAddresses(outsideIpAddresses);
                  lrpo = niciraNvpApi.createLogicalRouterPort(lrc.getUuid(), lrpo);
  
                  // Attach the outside port to the gateway service on the correct VLAN
                  final L3GatewayAttachment attachment = new L3GatewayAttachment(gatewayServiceUuid);
                  if (command.getVlanId() != 0) {
                      attachment.setVlanId(command.getVlanId());
                  }
                  niciraNvpApi.updateLogicalRouterPortAttachment(lrc.getUuid(), lrpo.getUuid(), attachment);
  
                  // Create the inside port for the router
                  LogicalRouterPort lrpi = new LogicalRouterPort();
                  lrpi.setAdminStatusEnabled(true);
                  lrpi.setDisplayName(niciraNvpResource.truncate(routerName + "-inside-port", NAME_MAX_LEN));
                  lrpi.setTags(tags);
                  final List<String> insideIpAddresses = new ArrayList<String>();
                  insideIpAddresses.add(internalNetworkAddress);
                  lrpi.setIpAddresses(insideIpAddresses);
                  lrpi = niciraNvpApi.createLogicalRouterPort(lrc.getUuid(), lrpi);
  
                  // Create the inside port on the lswitch
                  lsp = new LogicalSwitchPort(niciraNvpResource.truncate(routerName + "-inside-port", NAME_MAX_LEN), tags, true);
                  lsp = niciraNvpApi.createLogicalSwitchPort(logicalSwitchUuid, lsp);
  
                  // Attach the inside router port to the lswitch port with a PatchAttachment
                  niciraNvpApi.updateLogicalRouterPortAttachment(lrc.getUuid(), lrpi.getUuid(), new PatchAttachment(lsp.getUuid()));
  
                  // Attach the inside lswitch port to the router with a PatchAttachment
                  niciraNvpApi.updateLogicalSwitchPortAttachment(logicalSwitchUuid, lsp.getUuid(), new PatchAttachment(lrpi.getUuid()));
  
                  // Setup the source nat rule
                  final SourceNatRule snr = new SourceNatRule();
                  snr.setToSourceIpAddressMin(publicNetworkIpAddress.split("/")[0]);
                  snr.setToSourceIpAddressMax(publicNetworkIpAddress.split("/")[0]);
                  final Match match = new Match();
                  match.setSourceIpAddresses(internalNetworkAddress);
                  snr.setMatch(match);
                  snr.setOrder(200);
                  niciraNvpApi.createLogicalRouterNatRule(lrc.getUuid(), snr);
              } catch (final NiciraNvpApiException e) {
                  // We need to destroy the router if we already created it
                  // this will also take care of any router ports and rules
                  try {
                      niciraNvpApi.deleteLogicalRouter(lrc.getUuid());
                      if (lsp != null) {
                          niciraNvpApi.deleteLogicalSwitchPort(logicalSwitchUuid, lsp.getUuid());
                      }
                  } catch (final NiciraNvpApiException ex) {
                  }
  
                  throw e;
              }
  
              return new CreateLogicalRouterAnswer(command, true, "Logical Router created (uuid " + lrc.getUuid() + ")", lrc.getUuid());
          } catch (final NiciraNvpApiException e) {
              final CommandRetryUtility retryUtility = niciraNvpResource.getRetryUtility();
              retryUtility.addRetry(command, NUM_RETRIES);
              return retryUtility.retry(command, CreateLogicalRouterAnswer.class, e);
          }
      }
  }
  