/*
 * ******************************************************
 * Copyright 2016-2019 VMware, Inc.  All Rights Reserved.
 * ******************************************************
 */

package com.vmware.vsan.samples;

import java.util.Map;

import com.vmware.common.annotations.Action;
import com.vmware.common.annotations.Option;
import com.vmware.common.annotations.Sample;
import com.vmware.connection.ConnectedVimServiceBase;
import com.vmware.vim25.AboutInfo;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.ServiceContent;
import com.vmware.vsan.connection.VsanHealthConnection;
import com.vmware.vsan.sdk.InvalidStateFaultMsg;
import com.vmware.vsan.sdk.NotFoundFaultMsg;
import com.vmware.vsan.sdk.NotSupportedFaultMsg;
import com.vmware.vsan.sdk.RuntimeFaultFaultMsg;
import com.vmware.vsan.sdk.VimVsanReconfigSpec;
import com.vmware.vsan.sdk.VsanFaultFaultMsg;
import com.vmware.vsan.sdk.VsanIscsiLUNSpec;
import com.vmware.vsan.sdk.VsanIscsiTargetServiceDefaultConfigSpec;
import com.vmware.vsan.sdk.VsanIscsiTargetServiceSpec;
import com.vmware.vsan.sdk.VsanIscsiTargetSpec;
import com.vmware.vsan.sdk.VsanhealthPortType;
import com.vmware.vsan.util.VsanUtil;

/**
 * <pre>
 * VsanIscsiSample
 *
 * This file includes sample codes for vCenter vSAN iSCSI API accessing.
 *
 * To provide an example of vSAN iSCSI API access, it shows how to enable vSAN
 * iSCSI service, create targets and LUNs, together with disable iSCSI service.
 *
 * <b>Parameters:</b>
 * url          [required] : url of the web service
 * username     [required] : username for the authentication
 * password     [required] : password for the authentication
 * clustername  [required] : vCenter cluster name using in cluster health query API
 *
 * <b>Command Line:</b>
 * run.bat com.vmware.vsan.samples.VsanIscsiSample --url [webserviceurl]
 *       --username [username] --password [password] --clustername [name]
 * </pre>
 */

@Sample(
      name = "VsanIscsiSample",
      description = "This samples vSAN iSCSI API accessing from vCenter")
public class VsanIscsiSample extends ConnectedVimServiceBase {
   private String clusterName;

   @Option(
      name = "clustername",
      required = true,
      description = "The target vCenter cluster name"
   )
   public void setClusterName(String name) {
      this.clusterName = name;
   }

   /**
    * Get the vCenter cluster instance from the cluster name.
    * It will try to search the cluster under this vCenter
    * datacenters and return the first vCenter cluster matching
    * the give name
    *
    * @param serviceContent
    * @return The vCenter cluster instance. Return null if not found
    */
   private ManagedObjectReference getClusterFromName(
      ServiceContent serviceContent) {
      try {
         Map<String, ManagedObjectReference> clusters =
            getMOREFs.inContainerByType(serviceContent.getRootFolder(),
            "ClusterComputeResource");

         for (String cname : clusters.keySet()) {
            if (cname.equals(clusterName)) {
               return clusters.get(cname);
            }
         }
      } catch(Exception e) {
         System.err.println("Failed to get cluster name" + clusterName);
      }
      return null;
   }

   private void waitForVsanTask(
         com.vmware.vsan.sdk.ManagedObjectReference vsanTask, String ops) {
      ManagedObjectReference vcTask = VsanUtil.ConvertToVcMoRef(vsanTask);

      Boolean status = VsanUtil.WaitForTasks(this.waitForValues, vcTask);
      if (status) {
         System.out.println(ops + " task completed with status: success");
      } else {
         System.out.println(ops + " task completed with status: failure");
      }
   }

   /**
    * This method demonstrates how to enable vSAN iSCSI Target service,
    * create a target and the associated LUN, and disables the service through
    * the vSAN iSCSI service on vCenter.
    *
    * @throws RuntimeFaultFaultMsg
    * @throws InvalidPropertyFaultMsg
    * @throws NotFoundFaultMsg
    * @throws NotSupportedFaultMsg
    * @throws VsanFaultFaultMsg
    * @throws com.vmware.pbm.RuntimeFaultFaultMsg
    * @throws InvalidArgumentFaultMsg
    * @throws InvalidStateFaultMsg
    * @throws com.vmware.vsan.sdk.RuntimeFaultFaultMsg
    */
   @Action
   public void main()
         throws RuntimeFaultFaultMsg, NotFoundFaultMsg, NotSupportedFaultMsg,
         VsanFaultFaultMsg, InvalidStateFaultMsg, RuntimeFaultFaultMsg {
      VsanHealthConnection connection = (VsanHealthConnection)super.connection;
      AboutInfo aboutInfo = serviceContent.getAbout();
      String apiVersion = aboutInfo.getApiVersion();
      // Here is an example of how to access vCenter side vSAN Health Service API.
      ManagedObjectReference cluster =
         getClusterFromName(serviceContent);
      if (cluster == null) {
         System.out.println("Cannot find vCenter cluster " + clusterName);
         return;
      }

      // Construct the VSAN iSCSI service spec and enable iSCIS service;
      VsanIscsiTargetServiceDefaultConfigSpec vsanConfigSpec = new
            VsanIscsiTargetServiceDefaultConfigSpec();
      vsanConfigSpec.setNetworkInterface("vmk0");
      vsanConfigSpec.setPort(2300);

      VsanIscsiTargetServiceSpec enableSpec = new VsanIscsiTargetServiceSpec();
      enableSpec.setDefaultConfig(vsanConfigSpec);
      enableSpec.setEnabled(true);

      VimVsanReconfigSpec reconfigSpec = new VimVsanReconfigSpec();
      reconfigSpec.setIscsiSpec(enableSpec);
      reconfigSpec.setModify(true);
      VsanhealthPortType healthPort = connection.getVsanHealthPort();
      com.vmware.vsan.sdk.ManagedObjectReference vsanTask =
            healthPort.vsanClusterReconfig(
                  connection.getVsanVcClusterConfigServiceInstanceReference(),
                  VsanUtil.ConvertToHealthMoRef(cluster), reconfigSpec);

      waitForVsanTask(vsanTask, "Enable vSAN iSCSI target service");

      // Create a iSCSI target and the associated LUN
      String targetAlias = "sampleTarget2";
      VsanIscsiTargetSpec targetSpec = new VsanIscsiTargetSpec();
      targetSpec.setAlias(targetAlias);
      targetSpec.setIqn("iqn.2015-08.com.vmware:vit.target2");
      vsanTask = healthPort.vsanVitAddIscsiTarget(
            connection.getVsanVcIscsiTargetServiceInstanceReference(),
            VsanUtil.ConvertToHealthMoRef(cluster), targetSpec);

      waitForVsanTask(vsanTask, "Create vSAN iSCSI target");

      int lunSize = 1 * 1024 * 1024 * 1024;
      VsanIscsiLUNSpec lunSpec = new VsanIscsiLUNSpec();
      lunSpec.setLunId(0);
      lunSpec.setLunSize(lunSize);
      vsanTask = healthPort.vsanVitAddIscsiLUN(
            connection.getVsanVcIscsiTargetServiceInstanceReference(),
            VsanUtil.ConvertToHealthMoRef(cluster), targetAlias, lunSpec);

      waitForVsanTask(vsanTask, "Create vSAN iSCSI LUN");

     // Remove iSCSI target and the associated LUN
      vsanTask = healthPort.vsanVitRemoveIscsiLUN(
            connection.getVsanVcIscsiTargetServiceInstanceReference(),
            VsanUtil.ConvertToHealthMoRef(cluster), targetAlias, 0);
      waitForVsanTask(vsanTask, "Remove vSAN iSCSI LUN");

      vsanTask = healthPort.vsanVitRemoveIscsiTarget(
            connection.getVsanVcIscsiTargetServiceInstanceReference(),
            VsanUtil.ConvertToHealthMoRef(cluster), targetAlias);
      waitForVsanTask(vsanTask, "Remove vSAN iSCSI target");

      // Construct the vSAN iSCSI service spec and disable iSCIS service;
      VsanIscsiTargetServiceSpec disableSpec = new VsanIscsiTargetServiceSpec();
      disableSpec.setEnabled(false);

      reconfigSpec = new VimVsanReconfigSpec();
      reconfigSpec.setIscsiSpec(disableSpec);
      reconfigSpec.setModify(true);
      vsanTask = healthPort.vsanClusterReconfig(
            connection.getVsanVcClusterConfigServiceInstanceReference(),
            VsanUtil.ConvertToHealthMoRef(cluster), reconfigSpec);

      waitForVsanTask(vsanTask, "Disable vSAN iSCSI target service");
   }
}
