/* * Copyright (c) 2012-2015 iWave Software LLC * All Rights Reserved */ package com.emc.sa.service.vmware.file.tasks; import static com.iwave.ext.vmware.VMwareUtils.isAlreadyExists; import static com.iwave.ext.vmware.VMwareUtils.isPermissionDenied; import static com.iwave.ext.vmware.VMwareUtils.isPlatformConfigFault; import com.emc.sa.engine.ExecutionTask; import com.iwave.ext.vmware.HostStorageAPI; import com.iwave.ext.vmware.VMWareException; import com.iwave.ext.vmware.VMwareUtils; import com.vmware.vim25.AlreadyExists; import com.vmware.vim25.MethodFault; import com.vmware.vim25.mo.Datastore; import com.vmware.vim25.mo.HostSystem; /** * Create an NFS Datastore in VCenter */ public class CreateNfsDatastore extends ExecutionTask<Datastore> { private static final int CREATE_RETRIES = 34; private final HostStorageAPI hostStorageAPI; private final HostSystem host; private final String datastoreName; private final String fileserver; private final String mountPath; public CreateNfsDatastore(HostSystem host, String fileserver, String mountPath, String datastoreName) { this.host = host; this.hostStorageAPI = new HostStorageAPI(this.host); this.datastoreName = datastoreName; this.fileserver = fileserver; this.mountPath = mountPath; provideDetailArgs(datastoreName, host.getName(), fileserver, mountPath); } @Override public Datastore executeTask() throws Exception { debug("Executing: %s", getDetail()); long starttime = System.nanoTime(); try { return createNfsDatastore(); } catch (VMWareException e) { throw handleException(fileserver + mountPath, e); } finally { info("elapsed time: %d seconds", (System.nanoTime() - starttime) / 1000 / 1000 / 1000); } } private Datastore createNfsDatastore() { RuntimeException lastException = new RuntimeException("Unable to create NFS Datastore."); for (int retry = 1; retry <= CREATE_RETRIES + 1; retry++) { info("Attempt #%d to create the NFS Datastore...", retry); try { return hostStorageAPI.createNfsDatastore(datastoreName, fileserver, mountPath); } catch (VMWareException e) { lastException = e; handleCreationAttemptException(retry, e); } } info("Retries exhausted."); throw lastException; } private void handleCreationAttemptException(int retry, VMWareException e) { String errorMessage = e.getMessage(); // if this is a platform config fault we can get some more info about its actual message if (isPlatformConfigFault(e)) { errorMessage = "Fault Message: " + getFaultMessage(e); } info(e, "Attempt #%d to create the NFS Datastore failed. %d retries remaining. [%s]", retry, CREATE_RETRIES - retry + 1, errorMessage); // if the error is the 'permission denied' error, we want to try again // any other error will be viewed as a show-stopper if (isPermissionDenied(e)) { delayRetry(retry); } else { throw e; } } /** * dalays the current thread. Logs any errors. * The delay is 1000 millis * the given multiplier. * Used within a loop, the iterator index can be used to give * progressively longer delays. */ private void delayRetry(int multiplier) { debug("Sleeping before next retry..."); try { Thread.sleep(1000 * multiplier); } catch (InterruptedException e) { warn(e, "Thread sleeping failed.\nContinuing with the next retry."); } } /** * An attempt was made to create the Datastore on a particular * file server interface and it failed. If it's an error we * were expecting might have occurred, we can throw a new * exception with some more relevant information. * Otherwise we need to raise this as a legitimate exception. */ private Exception handleException(String mountPath, Exception e) { if (isPlatformConfigFault(e)) { return handleKnownException(e, getFaultMessage(e)); } else if (isAlreadyExists(e)) { final String datastore = ((AlreadyExists) e.getCause()).getName(); return handleKnownException(e, getMessage("CreateNfsDatastore.exception.exportMapped", datastore, getFaultMessage(e))); } else { return e; } } private RuntimeException handleKnownException(Exception e, String detailMessage, String... args) { final String errorMessage = getMessage("CreateNfsDatastore.exception.boiler", mountPath, String.format(detailMessage, (Object[]) args)); error(e, errorMessage); return stateException(errorMessage, e); } private String getFaultMessage(Exception e) { if (e.getCause() instanceof MethodFault) { return VMwareUtils.getFaultMessage((MethodFault) e.getCause()); } else { return null; } } }