/************************************************************************* * Copyright 2009-2015 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. * * This file may incorporate work covered under the following copyright * and permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, * with or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE * THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL, * COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE, * AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, * SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, * WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, * REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO * IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT * NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS. ************************************************************************/ package com.eucalyptus.blockstorage.upgrade; import static com.eucalyptus.upgrade.Upgrades.Version.v4_1_1; import java.util.Map; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.eucalyptus.blockstorage.Storage; import com.eucalyptus.blockstorage.config.StorageControllerConfiguration; import com.eucalyptus.blockstorage.entities.VolumeExportRecord; import com.eucalyptus.entities.Transactions; import com.eucalyptus.upgrade.Upgrades.EntityUpgrade; import com.eucalyptus.util.Callback; import com.eucalyptus.util.Exceptions; import com.google.common.base.Predicate; import com.google.common.collect.Maps; /** * Upgrade code for modifying elements of VolumeExportRecord rows from 4.0.2 format to 4.1.0 format. This upgrade logic should technically reside in * block-storage-common package along with VolumeExportRecord.java but a new class has been created here since the code refers to * StorageControllerConfiguration which is accessible only from the block-storage package * * @author Swathi Gangisetty */ public class VolumeExportRecord411Upgrade { @EntityUpgrade(entities = {VolumeExportRecord.class}, since = v4_1_1, value = Storage.class) public static enum UpdateConnectionStringPrefix implements Predicate<Class> { INSTANCE; private static final Logger LOG = Logger.getLogger(UpdateConnectionStringPrefix.class); @Override public boolean apply(@Nullable Class arg0) { LOG.info("Entity upgrade for VolumeExportRecord entities - modifying connection_string field"); final Map<String, String> clusterEbsBackendMap = Maps.newHashMap(); // populate partition name and ebs backend map, use StorageControllerConfiguration entity try { LOG.info("Gathering EBS backends for all Storage Controllers in the cloud"); Transactions.each(new StorageControllerConfiguration(), new Callback<StorageControllerConfiguration>() { @Override public void fire(StorageControllerConfiguration input) { clusterEbsBackendMap.put(input.getPartition(), input.getBlockStorageManager()); } }); } catch (Exception e) { LOG.warn("Failed to lookup Storage Controller Configuration. Insufficient information for updating VolumeExportRecord", e); Exceptions.toUndeclared("Failed to lookup Storage Controller Configuration. Insufficient information for updating VolumeExportRecord", e); } // tag the protocol and provider name as prefix to connection string if its not already there try { LOG.info("Iterating through all VolumeExportRecords in the cloud"); Transactions.each(new VolumeExportRecord(), new Callback<VolumeExportRecord>() { @Override public void fire(VolumeExportRecord input) { try { if (input.getIsActive() != null && input.getIsActive()) { // check if export record is active String ebsBackend = null; String connectionString = input.getConnectionString(); LOG.debug("VolumeExportRecord connection_string under scrutiny: " + connectionString); // Look for ebs backend in the map using partition name of the export record as key if ((ebsBackend = clusterEbsBackendMap.get(input.getVolume().getScName())) != null) { String prefix = new String(); switch (ebsBackend) { case "das": case "overlay": if (connectionString.startsWith("iscsi,tgt,")) { LOG.debug("Connection string already has the correct prefix. Skipping connection string update"); return; } else { prefix = "iscsi,tgt,"; break; } case "equallogic": if (connectionString.startsWith("iscsi,equallogic,")) { LOG.debug("Connection string already has the correct prefix. Skipping connection string update"); return; } else { prefix = "iscsi,equallogic,"; break; } case "emc-vnx": if (connectionString.startsWith("iscsi,emc-vnx,")) { LOG.debug("Connection string already has the correct prefix. Skipping connection string update"); return; } else { prefix = "iscsi,emc-vnx,"; break; } case "emc-vnx-flare31": if (connectionString.startsWith("iscsi,emc-vnx-flare31,")) { LOG.debug("Connection string already has the correct prefix. Skipping connection string update"); return; } else { prefix = "iscsi,emc-vnx-flare31,"; break; } case "netapp": if (connectionString.startsWith("iscsi,netapp,")) { LOG.debug("Connection string already has the correct prefix. Skipping connection string update"); return; } else { prefix = "iscsi,netapp,"; break; } case "(netapp-nextgen)": if (connectionString.startsWith("iscsi,netapp-nextgen,")) { LOG.debug("Connection string already has the correct prefix. Skipping connection string update"); return; } else { prefix = "iscsi,netapp-nextgen,"; break; } case "ceph-rbd": if (connectionString.startsWith("rbd,ceph,")) { LOG.debug("Connection string already has the correct prefix. Skipping connection string update"); return; } else { prefix = "rbd,ceph,"; break; } default: LOG.warn("Unknown block storage manager: " + ebsBackend + ". Skipping connection string update"); return; } if (StringUtils.isNotBlank(prefix)) { String newConnectionString = prefix + connectionString; LOG.debug("Modifying VolumeExportRecord connection_string to: " + newConnectionString); input.setConnectionString(newConnectionString); return; } else { LOG.warn("Unable to construct a valid prefix. Skipping connection string update"); return; } } else { LOG.warn("No EBS backend found in cloud for SC " + input.getVolume().getScName() + ". Skipping connection string update"); return; } } else { LOG.debug("Export record is invalidated. Skipping prefix check of connection string"); return; } } catch (Exception e) { LOG.warn("Failed to process VolumeExportRecord", e); return; } } }); } catch (Exception e) { LOG.warn("Failed to perform entity upgrade for VolumeExportRecord entities", e); Exceptions.toUndeclared("Failed to perform entity upgrade for VolumeExportRecord entities", e); } return true; } } }