@Test public void prepareSnapshot_BasicTest() throws Exception { final String volId = "testsnap"; final String rezPrefix = "fooprefix"; final String rezSuffix = "foosuffix"; final Integer snapSz = new Integer(5); SANInfo sanInfo = new SANInfo(StorageProperties.NAME, "foohost", "foouser", "foopassword"); sanInfo.setResourcePrefix(rezPrefix); sanInfo.setResourceSuffix(rezSuffix); try (TransactionResource tran = Entities.transactionFor(SANInfo.class)) { Entities.persist(sanInfo); tran.commit(); } StorageProperties.SC_INITIATOR_IQN = "sc-foo-iqn"; final SANProvider sanProvider = context.mock(SANProvider.class); context.checking(new Expectations() { { oneOf(sanProvider).createSnapshotHolder(rezPrefix + volId + rezSuffix, snapSz * 1024l); will(returnValue("foo-iqn")); oneOf(sanProvider).exportResource(rezPrefix + volId + rezSuffix, "sc-foo-iqn", "foo-iqn"); will(returnValue(new String("1"))); oneOf(sanProvider).connectTarget("foo-iqn", "1"); will(returnValue(new StorageResource(volId, "foopath", StorageResource.Type.FILE) { @Override public Long getSize() throws Exception { return null; } @Override public InputStream getInputStream() throws Exception { return null; } @Override public OutputStream getOutputStream() throws Exception { return null; } @Override public Boolean isDownloadSynchronous() { return Boolean.TRUE; } })); } }); SANManager test = new SANManager(sanProvider); test.prepSnapshotForDownload(volId, snapSz.intValue(), snapSz.intValue() * 1024l); try (TransactionResource tran = Entities.transactionFor(SANVolumeInfo.class)) { List<SANVolumeInfo> results = Entities.query(new SANVolumeInfo()); assertTrue("expected one SANVolumeInfo to exist", results != null && results.size() == 1); } }
public StorageResourceWithCallback prepSnapshotForDownload(final String snapshotId, int sizeExpected, long actualSizeInMB) throws EucalyptusCloudException { try { lookup(snapshotId); LOG.debug("Found existing database record for " + snapshotId + ". Will use that lun and record."); return null; } catch (NoSuchRecordException e) { LOG.debug( "Backend database record for " + snapshotId + " not found. Setting up holder on backend to hold the snapshot content downloaded from OSG"); } String sanSnapshotId = resourceIdOnSan(snapshotId); String iqn = null; try { LOG.info("Creating " + sanSnapshotId + " of size " + actualSizeInMB + " MB on backend"); iqn = connectionManager.createSnapshotHolder(sanSnapshotId, actualSizeInMB); } catch (EucalyptusCloudException e) { LOG.warn("Failed to create backend resource for " + snapshotId); iqn = null; } if (iqn != null) { try { String scIqn = StorageProperties.getStorageIqn(); if (scIqn == null) { throw new EucalyptusCloudException("Could not get the SC's initiator IQN, found null."); } String lun = null; try { LOG.info("Exporting " + sanSnapshotId + " on backend to Storage Controller host IQN " + scIqn); lun = connectionManager.exportResource(sanSnapshotId, scIqn, iqn); } catch (EucalyptusCloudException attEx) { LOG.warn("Failed to export " + sanSnapshotId + " on backend to Storage Controller", attEx); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to error exporting " + sanSnapshotId + " on backend to Storage Controller", attEx); } if (lun == null) { LOG.warn("Invalid value found for LUN upon exporting " + sanSnapshotId + " on backend"); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to invalid value for LUN upon exporting " + sanSnapshotId + " on backend"); } SANVolumeInfo snapInfo = new SANVolumeInfo(snapshotId, iqn + ',' + lun, sizeExpected).withSanVolumeId(sanSnapshotId); try { Transactions.save(snapInfo); } catch (TransactionException e) { LOG.warn("Failed to update database record with IQN and LUN post creation for " + snapshotId); throw new EucalyptusCloudException("Failed to update database entity with IQN and LUN post creation for " + snapshotId, e); } StorageResource storageResource = null; try { LOG.info("Connecting " + sanSnapshotId + " on backend to Storage Controller for transfer"); storageResource = connectionManager.connectTarget(iqn, lun); storageResource.setId(snapshotId); } catch (Exception connEx) { LOG.warn("Failed to connect " + sanSnapshotId + " on backend to Storage Controller. Detaching and cleaning up", connEx); try { LOG.info("Unexporting " + sanSnapshotId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanSnapshotId, scIqn); } catch (EucalyptusCloudException detEx) { LOG.debug("Could not unexport " + sanSnapshotId + " during cleanup of failed connection"); } throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to an error connecting " + sanSnapshotId + " on backend to Storage Controller", connEx); } return new StorageResourceWithCallback(storageResource, new Function<StorageResource, String>() { @Override public String apply(StorageResource arg0) { try { LOG.debug("Executing callback for prepareSnapshotForDownload() with " + snapshotId); SANVolumeInfo snapInfo = null; String iqnAndLun = null; String sanVolumeId = null; try { snapInfo = lookup(snapshotId); iqnAndLun = snapInfo.getIqn(); sanVolumeId = snapInfo.getSanVolumeId(); } catch (NoSuchRecordException e) { LOG.debug("Skipping finish up for " + snapshotId); return null; } if (iqnAndLun != null && iqnAndLun.contains(",")) { String[] parts = iqnAndLun.split(","); if (parts.length == 2) { try { LOG.info("Disconnecting " + sanVolumeId + " on backend from Storage Controller"); connectionManager.disconnectTarget(sanVolumeId, parts[0], parts[1]); } catch (Exception e) { LOG.warn("Failed to disconnect iscsi session between " + sanVolumeId + " and SC", e); } } else { LOG.warn("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format. Expected iqn to contain one ',' but got: " + iqnAndLun); throw new EucalyptusCloudException("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format"); } String scIqn = StorageProperties.getStorageIqn(); try { LOG.info("Unexporting " + sanVolumeId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanVolumeId, scIqn); } catch (Exception e) { LOG.warn("Could not unexport " + sanVolumeId + " on backend from Storage Controller"); } try (TransactionResource tran = Entities.transactionFor(SANVolumeInfo.class)) { SANVolumeInfo existingSnap = Entities.uniqueResult(snapInfo); existingSnap.setIqn(parts[0]); Entities.merge(existingSnap); tran.commit(); } catch (Exception e) { LOG.warn("Failed to update IQN after disconnecting " + snapshotId + " from Storage Controller", e); } } else { LOG.debug("Skipping disconnect and unexport operations for " + sanVolumeId); } try { LOG.info("Waiting for " + sanVolumeId + " to complete on backend"); connectionManager.waitAndComplete(sanVolumeId, iqnAndLun); } catch (EucalyptusCloudException e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw e; } catch (Exception e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw new EucalyptusCloudException("Failed during wait for " + sanVolumeId + " to complete on backend", e); } } catch (Exception e) { Exceptions.toException("", e); } return null; } }); } catch (EucalyptusCloudException e) { LOG.debug("Deleting " + sanSnapshotId + " on backend"); if (!connectionManager.deleteVolume(sanSnapshotId, iqn)) { LOG.debug("Failed to delete backend resource " + snapshotId); } throw e; } } return null; }
SANManager implements LogicalStorageManager { public StorageResourceWithCallback prepSnapshotForDownload(final String snapshotId, int sizeExpected, long actualSizeInMB) throws EucalyptusCloudException { try { lookup(snapshotId); LOG.debug("Found existing database record for " + snapshotId + ". Will use that lun and record."); return null; } catch (NoSuchRecordException e) { LOG.debug( "Backend database record for " + snapshotId + " not found. Setting up holder on backend to hold the snapshot content downloaded from OSG"); } String sanSnapshotId = resourceIdOnSan(snapshotId); String iqn = null; try { LOG.info("Creating " + sanSnapshotId + " of size " + actualSizeInMB + " MB on backend"); iqn = connectionManager.createSnapshotHolder(sanSnapshotId, actualSizeInMB); } catch (EucalyptusCloudException e) { LOG.warn("Failed to create backend resource for " + snapshotId); iqn = null; } if (iqn != null) { try { String scIqn = StorageProperties.getStorageIqn(); if (scIqn == null) { throw new EucalyptusCloudException("Could not get the SC's initiator IQN, found null."); } String lun = null; try { LOG.info("Exporting " + sanSnapshotId + " on backend to Storage Controller host IQN " + scIqn); lun = connectionManager.exportResource(sanSnapshotId, scIqn, iqn); } catch (EucalyptusCloudException attEx) { LOG.warn("Failed to export " + sanSnapshotId + " on backend to Storage Controller", attEx); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to error exporting " + sanSnapshotId + " on backend to Storage Controller", attEx); } if (lun == null) { LOG.warn("Invalid value found for LUN upon exporting " + sanSnapshotId + " on backend"); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to invalid value for LUN upon exporting " + sanSnapshotId + " on backend"); } SANVolumeInfo snapInfo = new SANVolumeInfo(snapshotId, iqn + ',' + lun, sizeExpected).withSanVolumeId(sanSnapshotId); try { Transactions.save(snapInfo); } catch (TransactionException e) { LOG.warn("Failed to update database record with IQN and LUN post creation for " + snapshotId); throw new EucalyptusCloudException("Failed to update database entity with IQN and LUN post creation for " + snapshotId, e); } StorageResource storageResource = null; try { LOG.info("Connecting " + sanSnapshotId + " on backend to Storage Controller for transfer"); storageResource = connectionManager.connectTarget(iqn, lun); storageResource.setId(snapshotId); } catch (Exception connEx) { LOG.warn("Failed to connect " + sanSnapshotId + " on backend to Storage Controller. Detaching and cleaning up", connEx); try { LOG.info("Unexporting " + sanSnapshotId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanSnapshotId, scIqn); } catch (EucalyptusCloudException detEx) { LOG.debug("Could not unexport " + sanSnapshotId + " during cleanup of failed connection"); } throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to an error connecting " + sanSnapshotId + " on backend to Storage Controller", connEx); } return new StorageResourceWithCallback(storageResource, new Function<StorageResource, String>() { @Override public String apply(StorageResource arg0) { try { LOG.debug("Executing callback for prepareSnapshotForDownload() with " + snapshotId); SANVolumeInfo snapInfo = null; String iqnAndLun = null; String sanVolumeId = null; try { snapInfo = lookup(snapshotId); iqnAndLun = snapInfo.getIqn(); sanVolumeId = snapInfo.getSanVolumeId(); } catch (NoSuchRecordException e) { LOG.debug("Skipping finish up for " + snapshotId); return null; } if (iqnAndLun != null && iqnAndLun.contains(",")) { String[] parts = iqnAndLun.split(","); if (parts.length == 2) { try { LOG.info("Disconnecting " + sanVolumeId + " on backend from Storage Controller"); connectionManager.disconnectTarget(sanVolumeId, parts[0], parts[1]); } catch (Exception e) { LOG.warn("Failed to disconnect iscsi session between " + sanVolumeId + " and SC", e); } } else { LOG.warn("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format. Expected iqn to contain one ',' but got: " + iqnAndLun); throw new EucalyptusCloudException("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format"); } String scIqn = StorageProperties.getStorageIqn(); try { LOG.info("Unexporting " + sanVolumeId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanVolumeId, scIqn); } catch (Exception e) { LOG.warn("Could not unexport " + sanVolumeId + " on backend from Storage Controller"); } try (TransactionResource tran = Entities.transactionFor(SANVolumeInfo.class)) { SANVolumeInfo existingSnap = Entities.uniqueResult(snapInfo); existingSnap.setIqn(parts[0]); Entities.merge(existingSnap); tran.commit(); } catch (Exception e) { LOG.warn("Failed to update IQN after disconnecting " + snapshotId + " from Storage Controller", e); } } else { LOG.debug("Skipping disconnect and unexport operations for " + sanVolumeId); } try { LOG.info("Waiting for " + sanVolumeId + " to complete on backend"); connectionManager.waitAndComplete(sanVolumeId, iqnAndLun); } catch (EucalyptusCloudException e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw e; } catch (Exception e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw new EucalyptusCloudException("Failed during wait for " + sanVolumeId + " to complete on backend", e); } } catch (Exception e) { Exceptions.toException("", e); } return null; } }); } catch (EucalyptusCloudException e) { LOG.debug("Deleting " + sanSnapshotId + " on backend"); if (!connectionManager.deleteVolume(sanSnapshotId, iqn)) { LOG.debug("Failed to delete backend resource " + snapshotId); } throw e; } } return null; } }
SANManager implements LogicalStorageManager { public StorageResourceWithCallback prepSnapshotForDownload(final String snapshotId, int sizeExpected, long actualSizeInMB) throws EucalyptusCloudException { try { lookup(snapshotId); LOG.debug("Found existing database record for " + snapshotId + ". Will use that lun and record."); return null; } catch (NoSuchRecordException e) { LOG.debug( "Backend database record for " + snapshotId + " not found. Setting up holder on backend to hold the snapshot content downloaded from OSG"); } String sanSnapshotId = resourceIdOnSan(snapshotId); String iqn = null; try { LOG.info("Creating " + sanSnapshotId + " of size " + actualSizeInMB + " MB on backend"); iqn = connectionManager.createSnapshotHolder(sanSnapshotId, actualSizeInMB); } catch (EucalyptusCloudException e) { LOG.warn("Failed to create backend resource for " + snapshotId); iqn = null; } if (iqn != null) { try { String scIqn = StorageProperties.getStorageIqn(); if (scIqn == null) { throw new EucalyptusCloudException("Could not get the SC's initiator IQN, found null."); } String lun = null; try { LOG.info("Exporting " + sanSnapshotId + " on backend to Storage Controller host IQN " + scIqn); lun = connectionManager.exportResource(sanSnapshotId, scIqn, iqn); } catch (EucalyptusCloudException attEx) { LOG.warn("Failed to export " + sanSnapshotId + " on backend to Storage Controller", attEx); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to error exporting " + sanSnapshotId + " on backend to Storage Controller", attEx); } if (lun == null) { LOG.warn("Invalid value found for LUN upon exporting " + sanSnapshotId + " on backend"); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to invalid value for LUN upon exporting " + sanSnapshotId + " on backend"); } SANVolumeInfo snapInfo = new SANVolumeInfo(snapshotId, iqn + ',' + lun, sizeExpected).withSanVolumeId(sanSnapshotId); try { Transactions.save(snapInfo); } catch (TransactionException e) { LOG.warn("Failed to update database record with IQN and LUN post creation for " + snapshotId); throw new EucalyptusCloudException("Failed to update database entity with IQN and LUN post creation for " + snapshotId, e); } StorageResource storageResource = null; try { LOG.info("Connecting " + sanSnapshotId + " on backend to Storage Controller for transfer"); storageResource = connectionManager.connectTarget(iqn, lun); storageResource.setId(snapshotId); } catch (Exception connEx) { LOG.warn("Failed to connect " + sanSnapshotId + " on backend to Storage Controller. Detaching and cleaning up", connEx); try { LOG.info("Unexporting " + sanSnapshotId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanSnapshotId, scIqn); } catch (EucalyptusCloudException detEx) { LOG.debug("Could not unexport " + sanSnapshotId + " during cleanup of failed connection"); } throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to an error connecting " + sanSnapshotId + " on backend to Storage Controller", connEx); } return new StorageResourceWithCallback(storageResource, new Function<StorageResource, String>() { @Override public String apply(StorageResource arg0) { try { LOG.debug("Executing callback for prepareSnapshotForDownload() with " + snapshotId); SANVolumeInfo snapInfo = null; String iqnAndLun = null; String sanVolumeId = null; try { snapInfo = lookup(snapshotId); iqnAndLun = snapInfo.getIqn(); sanVolumeId = snapInfo.getSanVolumeId(); } catch (NoSuchRecordException e) { LOG.debug("Skipping finish up for " + snapshotId); return null; } if (iqnAndLun != null && iqnAndLun.contains(",")) { String[] parts = iqnAndLun.split(","); if (parts.length == 2) { try { LOG.info("Disconnecting " + sanVolumeId + " on backend from Storage Controller"); connectionManager.disconnectTarget(sanVolumeId, parts[0], parts[1]); } catch (Exception e) { LOG.warn("Failed to disconnect iscsi session between " + sanVolumeId + " and SC", e); } } else { LOG.warn("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format. Expected iqn to contain one ',' but got: " + iqnAndLun); throw new EucalyptusCloudException("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format"); } String scIqn = StorageProperties.getStorageIqn(); try { LOG.info("Unexporting " + sanVolumeId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanVolumeId, scIqn); } catch (Exception e) { LOG.warn("Could not unexport " + sanVolumeId + " on backend from Storage Controller"); } try (TransactionResource tran = Entities.transactionFor(SANVolumeInfo.class)) { SANVolumeInfo existingSnap = Entities.uniqueResult(snapInfo); existingSnap.setIqn(parts[0]); Entities.merge(existingSnap); tran.commit(); } catch (Exception e) { LOG.warn("Failed to update IQN after disconnecting " + snapshotId + " from Storage Controller", e); } } else { LOG.debug("Skipping disconnect and unexport operations for " + sanVolumeId); } try { LOG.info("Waiting for " + sanVolumeId + " to complete on backend"); connectionManager.waitAndComplete(sanVolumeId, iqnAndLun); } catch (EucalyptusCloudException e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw e; } catch (Exception e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw new EucalyptusCloudException("Failed during wait for " + sanVolumeId + " to complete on backend", e); } } catch (Exception e) { Exceptions.toException("", e); } return null; } }); } catch (EucalyptusCloudException e) { LOG.debug("Deleting " + sanSnapshotId + " on backend"); if (!connectionManager.deleteVolume(sanSnapshotId, iqn)) { LOG.debug("Failed to delete backend resource " + snapshotId); } throw e; } } return null; } SANManager();   SANManager(SANProvider connectionManager); }
SANManager implements LogicalStorageManager { public StorageResourceWithCallback prepSnapshotForDownload(final String snapshotId, int sizeExpected, long actualSizeInMB) throws EucalyptusCloudException { try { lookup(snapshotId); LOG.debug("Found existing database record for " + snapshotId + ". Will use that lun and record."); return null; } catch (NoSuchRecordException e) { LOG.debug( "Backend database record for " + snapshotId + " not found. Setting up holder on backend to hold the snapshot content downloaded from OSG"); } String sanSnapshotId = resourceIdOnSan(snapshotId); String iqn = null; try { LOG.info("Creating " + sanSnapshotId + " of size " + actualSizeInMB + " MB on backend"); iqn = connectionManager.createSnapshotHolder(sanSnapshotId, actualSizeInMB); } catch (EucalyptusCloudException e) { LOG.warn("Failed to create backend resource for " + snapshotId); iqn = null; } if (iqn != null) { try { String scIqn = StorageProperties.getStorageIqn(); if (scIqn == null) { throw new EucalyptusCloudException("Could not get the SC's initiator IQN, found null."); } String lun = null; try { LOG.info("Exporting " + sanSnapshotId + " on backend to Storage Controller host IQN " + scIqn); lun = connectionManager.exportResource(sanSnapshotId, scIqn, iqn); } catch (EucalyptusCloudException attEx) { LOG.warn("Failed to export " + sanSnapshotId + " on backend to Storage Controller", attEx); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to error exporting " + sanSnapshotId + " on backend to Storage Controller", attEx); } if (lun == null) { LOG.warn("Invalid value found for LUN upon exporting " + sanSnapshotId + " on backend"); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to invalid value for LUN upon exporting " + sanSnapshotId + " on backend"); } SANVolumeInfo snapInfo = new SANVolumeInfo(snapshotId, iqn + ',' + lun, sizeExpected).withSanVolumeId(sanSnapshotId); try { Transactions.save(snapInfo); } catch (TransactionException e) { LOG.warn("Failed to update database record with IQN and LUN post creation for " + snapshotId); throw new EucalyptusCloudException("Failed to update database entity with IQN and LUN post creation for " + snapshotId, e); } StorageResource storageResource = null; try { LOG.info("Connecting " + sanSnapshotId + " on backend to Storage Controller for transfer"); storageResource = connectionManager.connectTarget(iqn, lun); storageResource.setId(snapshotId); } catch (Exception connEx) { LOG.warn("Failed to connect " + sanSnapshotId + " on backend to Storage Controller. Detaching and cleaning up", connEx); try { LOG.info("Unexporting " + sanSnapshotId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanSnapshotId, scIqn); } catch (EucalyptusCloudException detEx) { LOG.debug("Could not unexport " + sanSnapshotId + " during cleanup of failed connection"); } throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to an error connecting " + sanSnapshotId + " on backend to Storage Controller", connEx); } return new StorageResourceWithCallback(storageResource, new Function<StorageResource, String>() { @Override public String apply(StorageResource arg0) { try { LOG.debug("Executing callback for prepareSnapshotForDownload() with " + snapshotId); SANVolumeInfo snapInfo = null; String iqnAndLun = null; String sanVolumeId = null; try { snapInfo = lookup(snapshotId); iqnAndLun = snapInfo.getIqn(); sanVolumeId = snapInfo.getSanVolumeId(); } catch (NoSuchRecordException e) { LOG.debug("Skipping finish up for " + snapshotId); return null; } if (iqnAndLun != null && iqnAndLun.contains(",")) { String[] parts = iqnAndLun.split(","); if (parts.length == 2) { try { LOG.info("Disconnecting " + sanVolumeId + " on backend from Storage Controller"); connectionManager.disconnectTarget(sanVolumeId, parts[0], parts[1]); } catch (Exception e) { LOG.warn("Failed to disconnect iscsi session between " + sanVolumeId + " and SC", e); } } else { LOG.warn("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format. Expected iqn to contain one ',' but got: " + iqnAndLun); throw new EucalyptusCloudException("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format"); } String scIqn = StorageProperties.getStorageIqn(); try { LOG.info("Unexporting " + sanVolumeId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanVolumeId, scIqn); } catch (Exception e) { LOG.warn("Could not unexport " + sanVolumeId + " on backend from Storage Controller"); } try (TransactionResource tran = Entities.transactionFor(SANVolumeInfo.class)) { SANVolumeInfo existingSnap = Entities.uniqueResult(snapInfo); existingSnap.setIqn(parts[0]); Entities.merge(existingSnap); tran.commit(); } catch (Exception e) { LOG.warn("Failed to update IQN after disconnecting " + snapshotId + " from Storage Controller", e); } } else { LOG.debug("Skipping disconnect and unexport operations for " + sanVolumeId); } try { LOG.info("Waiting for " + sanVolumeId + " to complete on backend"); connectionManager.waitAndComplete(sanVolumeId, iqnAndLun); } catch (EucalyptusCloudException e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw e; } catch (Exception e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw new EucalyptusCloudException("Failed during wait for " + sanVolumeId + " to complete on backend", e); } } catch (Exception e) { Exceptions.toException("", e); } return null; } }); } catch (EucalyptusCloudException e) { LOG.debug("Deleting " + sanSnapshotId + " on backend"); if (!connectionManager.deleteVolume(sanSnapshotId, iqn)) { LOG.debug("Failed to delete backend resource " + snapshotId); } throw e; } } return null; } SANManager();   SANManager(SANProvider connectionManager); static LogicalStorageManager getInstance(); void addSnapshot(String snapshotId); void checkPreconditions(); @Override void cleanSnapshot(String snapshotId, String snapshotPointId); void cleanVolume(String volumeId); void configure(); StorageResource createSnapshot(String volumeId, String snapshotId, String snapshotPointId, Boolean shouldTransferSnapshots); void createSnapshot(String volumeId, String snapshotId, String snapshotPointId); void createVolume(String volumeId, int size); int createVolume(String volumeId, String snapshotId, int size); void cloneVolume(String volumeId, String parentVolumeId); @Override void deleteSnapshot(String snapshotId, String snapshotPointId); void deleteVolume(String volumeId); int getSnapshotSize(String snapshotId); String getVolumeConnectionString(String volumeId); void initialize(); void loadSnapshots(List<String> snapshotSet, List<String> snapshotFileNames); List<String> prepareForTransfer(String snapshotId); void reload(); void startupChecks(); void finishVolume(String snapshotId); StorageResourceWithCallback prepSnapshotForDownload(final String snapshotId, int sizeExpected, long actualSizeInMB); ArrayList<ComponentProperty> getStorageProps(); void setStorageProps(ArrayList<ComponentProperty> storageProps); String getStorageRootDirectory(); String getVolumePath(String volumeId); void importVolume(String volumeId, String volumePath, int size); String getSnapshotPath(String snapshotId); void importSnapshot(String snapshotId, String volumeId, String snapPath, int size); String exportVolume(String volumeId, String nodeIqn); void unexportVolumeFromAll(String volumeId); void unexportVolume(String volumeId, String nodeIqn); void checkReady(); void stop(); void disable(); void enable(); boolean getFromBackend(String snapshotId, int size); void checkVolume(String volumeId); List<CheckerTask> getCheckers(); String createSnapshotPoint(String parentVolumeId, String volumeId); void deleteSnapshotPoint(String parentVolumeId, String volumeId, String snapshotPointId); @Override boolean supportsIncrementalSnapshots(); @Override StorageResourceWithCallback prepIncrementalSnapshotForUpload(String volumeId, String snapshotId, String snapPointId, String prevSnapshotId,
      String prevSnapPointId); @Override StorageResource prepSnapshotForUpload(String volumeId, String snapshotId, String snapPointId); @Override StorageResourceWithCallback prepSnapshotBaseForRestore(final String snapshotId, final int size, final String snapshotPointId); @Override void restoreSnapshotDelta(String currentSnapId, String prevSnapId, String baseId, StorageResource sr); @Override void completeSnapshotRestorationFromDeltas(String snapshotId); @Override T executeCallback(Function<F, T> callback, F input); }
SANManager implements LogicalStorageManager { public StorageResourceWithCallback prepSnapshotForDownload(final String snapshotId, int sizeExpected, long actualSizeInMB) throws EucalyptusCloudException { try { lookup(snapshotId); LOG.debug("Found existing database record for " + snapshotId + ". Will use that lun and record."); return null; } catch (NoSuchRecordException e) { LOG.debug( "Backend database record for " + snapshotId + " not found. Setting up holder on backend to hold the snapshot content downloaded from OSG"); } String sanSnapshotId = resourceIdOnSan(snapshotId); String iqn = null; try { LOG.info("Creating " + sanSnapshotId + " of size " + actualSizeInMB + " MB on backend"); iqn = connectionManager.createSnapshotHolder(sanSnapshotId, actualSizeInMB); } catch (EucalyptusCloudException e) { LOG.warn("Failed to create backend resource for " + snapshotId); iqn = null; } if (iqn != null) { try { String scIqn = StorageProperties.getStorageIqn(); if (scIqn == null) { throw new EucalyptusCloudException("Could not get the SC's initiator IQN, found null."); } String lun = null; try { LOG.info("Exporting " + sanSnapshotId + " on backend to Storage Controller host IQN " + scIqn); lun = connectionManager.exportResource(sanSnapshotId, scIqn, iqn); } catch (EucalyptusCloudException attEx) { LOG.warn("Failed to export " + sanSnapshotId + " on backend to Storage Controller", attEx); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to error exporting " + sanSnapshotId + " on backend to Storage Controller", attEx); } if (lun == null) { LOG.warn("Invalid value found for LUN upon exporting " + sanSnapshotId + " on backend"); throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to invalid value for LUN upon exporting " + sanSnapshotId + " on backend"); } SANVolumeInfo snapInfo = new SANVolumeInfo(snapshotId, iqn + ',' + lun, sizeExpected).withSanVolumeId(sanSnapshotId); try { Transactions.save(snapInfo); } catch (TransactionException e) { LOG.warn("Failed to update database record with IQN and LUN post creation for " + snapshotId); throw new EucalyptusCloudException("Failed to update database entity with IQN and LUN post creation for " + snapshotId, e); } StorageResource storageResource = null; try { LOG.info("Connecting " + sanSnapshotId + " on backend to Storage Controller for transfer"); storageResource = connectionManager.connectTarget(iqn, lun); storageResource.setId(snapshotId); } catch (Exception connEx) { LOG.warn("Failed to connect " + sanSnapshotId + " on backend to Storage Controller. Detaching and cleaning up", connEx); try { LOG.info("Unexporting " + sanSnapshotId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanSnapshotId, scIqn); } catch (EucalyptusCloudException detEx) { LOG.debug("Could not unexport " + sanSnapshotId + " during cleanup of failed connection"); } throw new EucalyptusCloudException( "Failed to create " + snapshotId + " due to an error connecting " + sanSnapshotId + " on backend to Storage Controller", connEx); } return new StorageResourceWithCallback(storageResource, new Function<StorageResource, String>() { @Override public String apply(StorageResource arg0) { try { LOG.debug("Executing callback for prepareSnapshotForDownload() with " + snapshotId); SANVolumeInfo snapInfo = null; String iqnAndLun = null; String sanVolumeId = null; try { snapInfo = lookup(snapshotId); iqnAndLun = snapInfo.getIqn(); sanVolumeId = snapInfo.getSanVolumeId(); } catch (NoSuchRecordException e) { LOG.debug("Skipping finish up for " + snapshotId); return null; } if (iqnAndLun != null && iqnAndLun.contains(",")) { String[] parts = iqnAndLun.split(","); if (parts.length == 2) { try { LOG.info("Disconnecting " + sanVolumeId + " on backend from Storage Controller"); connectionManager.disconnectTarget(sanVolumeId, parts[0], parts[1]); } catch (Exception e) { LOG.warn("Failed to disconnect iscsi session between " + sanVolumeId + " and SC", e); } } else { LOG.warn("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format. Expected iqn to contain one ',' but got: " + iqnAndLun); throw new EucalyptusCloudException("Unable to disconnect " + sanVolumeId + " from Storage Controller due to invalid iqn format"); } String scIqn = StorageProperties.getStorageIqn(); try { LOG.info("Unexporting " + sanVolumeId + " on backend from Storage Controller host IQN " + scIqn); connectionManager.unexportResource(sanVolumeId, scIqn); } catch (Exception e) { LOG.warn("Could not unexport " + sanVolumeId + " on backend from Storage Controller"); } try (TransactionResource tran = Entities.transactionFor(SANVolumeInfo.class)) { SANVolumeInfo existingSnap = Entities.uniqueResult(snapInfo); existingSnap.setIqn(parts[0]); Entities.merge(existingSnap); tran.commit(); } catch (Exception e) { LOG.warn("Failed to update IQN after disconnecting " + snapshotId + " from Storage Controller", e); } } else { LOG.debug("Skipping disconnect and unexport operations for " + sanVolumeId); } try { LOG.info("Waiting for " + sanVolumeId + " to complete on backend"); connectionManager.waitAndComplete(sanVolumeId, iqnAndLun); } catch (EucalyptusCloudException e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw e; } catch (Exception e) { LOG.warn("Failed during wait for " + sanVolumeId + " to complete on backend", e); throw new EucalyptusCloudException("Failed during wait for " + sanVolumeId + " to complete on backend", e); } } catch (Exception e) { Exceptions.toException("", e); } return null; } }); } catch (EucalyptusCloudException e) { LOG.debug("Deleting " + sanSnapshotId + " on backend"); if (!connectionManager.deleteVolume(sanSnapshotId, iqn)) { LOG.debug("Failed to delete backend resource " + snapshotId); } throw e; } } return null; } SANManager();   SANManager(SANProvider connectionManager); static LogicalStorageManager getInstance(); void addSnapshot(String snapshotId); void checkPreconditions(); @Override void cleanSnapshot(String snapshotId, String snapshotPointId); void cleanVolume(String volumeId); void configure(); StorageResource createSnapshot(String volumeId, String snapshotId, String snapshotPointId, Boolean shouldTransferSnapshots); void createSnapshot(String volumeId, String snapshotId, String snapshotPointId); void createVolume(String volumeId, int size); int createVolume(String volumeId, String snapshotId, int size); void cloneVolume(String volumeId, String parentVolumeId); @Override void deleteSnapshot(String snapshotId, String snapshotPointId); void deleteVolume(String volumeId); int getSnapshotSize(String snapshotId); String getVolumeConnectionString(String volumeId); void initialize(); void loadSnapshots(List<String> snapshotSet, List<String> snapshotFileNames); List<String> prepareForTransfer(String snapshotId); void reload(); void startupChecks(); void finishVolume(String snapshotId); StorageResourceWithCallback prepSnapshotForDownload(final String snapshotId, int sizeExpected, long actualSizeInMB); ArrayList<ComponentProperty> getStorageProps(); void setStorageProps(ArrayList<ComponentProperty> storageProps); String getStorageRootDirectory(); String getVolumePath(String volumeId); void importVolume(String volumeId, String volumePath, int size); String getSnapshotPath(String snapshotId); void importSnapshot(String snapshotId, String volumeId, String snapPath, int size); String exportVolume(String volumeId, String nodeIqn); void unexportVolumeFromAll(String volumeId); void unexportVolume(String volumeId, String nodeIqn); void checkReady(); void stop(); void disable(); void enable(); boolean getFromBackend(String snapshotId, int size); void checkVolume(String volumeId); List<CheckerTask> getCheckers(); String createSnapshotPoint(String parentVolumeId, String volumeId); void deleteSnapshotPoint(String parentVolumeId, String volumeId, String snapshotPointId); @Override boolean supportsIncrementalSnapshots(); @Override StorageResourceWithCallback prepIncrementalSnapshotForUpload(String volumeId, String snapshotId, String snapPointId, String prevSnapshotId,
      String prevSnapPointId); @Override StorageResource prepSnapshotForUpload(String volumeId, String snapshotId, String snapPointId); @Override StorageResourceWithCallback prepSnapshotBaseForRestore(final String snapshotId, final int size, final String snapshotPointId); @Override void restoreSnapshotDelta(String currentSnapId, String prevSnapId, String baseId, StorageResource sr); @Override void completeSnapshotRestorationFromDeltas(String snapshotId); @Override T executeCallback(Function<F, T> callback, F input);  }