/************************************************************************* * (c) Copyright 2017 Hewlett Packard Enterprise Development Company LP * * 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/. * * 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.util; import java.util.NoSuchElementException; import java.util.regex.Pattern; import org.apache.log4j.Logger; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Restrictions; import com.eucalyptus.blockstorage.Storage; import com.eucalyptus.component.Components; import com.eucalyptus.component.ServiceConfiguration; import com.eucalyptus.component.ServiceUris; import com.eucalyptus.component.Topology; import com.eucalyptus.objectstorage.ObjectStorage; import com.eucalyptus.system.BaseDirectory; import com.google.common.collect.ImmutableSet; import edu.ucsb.eucalyptus.util.ConfigParser; import edu.ucsb.eucalyptus.util.StreamConsumer; public class StorageProperties { private static Logger LOG = Logger.getLogger(StorageProperties.class); /* * Threshold after which the SC will cleanup the failed volume record by deleting it. This value ensures that the SC can send the volume state to * the CLC possibly multiple times so that a single missed message will not cause the CLC to hit its much longer timeout for volume state (2 hrs). */ public static final long FAILED_STATE_CLEANUP_THRESHOLD_MS = 10 * 60 * 1000l; // 10 minutes public static final String storageRootDirectory = BaseDirectory.VAR.getChildPath("volumes"); public static final long GB = 1024 * 1024 * 1024; public static final long MB = 1024 * 1024; public static final long KB = 1024; public static final String iface = "eth0"; public static final int MAX_TOTAL_VOLUME_SIZE = 500; public static final int MAX_VOLUME_SIZE = 100; public static int TRANSFER_CHUNK_SIZE = 8192; public static final String zeroFillVolumesTxt = "false"; public static final boolean zeroFillVolumes = Boolean.valueOf( zeroFillVolumesTxt ); public static final long timeoutInMillis = 10000; public static boolean enableSnapshots = false; public static boolean enableStorage = false; public static boolean shouldEnforceUsageLimits = true; public static final String DEFAULT_STORE_PREFIX = "iqn.2009-06.com.eucalyptus."; public static String STORE_PREFIX = DEFAULT_STORE_PREFIX; public static String WALRUS_URL = "http://localhost:8773/services/objectstorage"; public static String NAME = "unregistered"; public static String STORAGE_HOST = "127.0.0.1"; public static final String ISCSI_INITIATOR_NAME_CONF = "/etc/iscsi/initiatorname.iscsi"; public static String SC_INITIATOR_IQN = null; public static final String EUCA_ROOT_WRAPPER = BaseDirectory.LIBEXEC.toString() + "/euca_rootwrap"; public static final String blockSize = "1M"; public static String DAS_DEVICE = "/dev/blockdev"; public static final String TOKEN_PREFIX = "sc://"; // Used to indicate a token should be resolved to an SC public static final String SNAPSHOT_BUCKET_PREFIX = "snapshots-"; public static final String EBS_ROLE_NAME = "EBSUpload"; public static final String S3_BUCKET_ACCESS_POLICY_NAME = "S3EBSBucketAccess"; public static final String S3_OBJECT_ACCESS_POLICY_NAME = "S3EBSObjectAccess"; public static final String DEFAULT_ASSUME_ROLE_POLICY = "{\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"s3.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"; public static final String S3_SNAPSHOT_BUCKET_ACCESS_POLICY = "{\"Statement\":[" + "{" + "\"Effect\":\"Allow\"," + "\"Action\": [\"s3:*\"]," + "\"Resource\": \"arn:aws:s3:::*\"" + "}" + "]}"; public static final String S3_SNAPSHOT_OBJECT_ACCESS_POLICY = "{\"Statement\":[" + "{" + "\"Effect\":\"Allow\"," + "\"Action\": [\"s3:*\"]," + "\"Resource\": \"arn:aws:s3:::*/*\"" + "}" + "]}"; /** * <p> * Perl connection script returns xml output for libvirt usage. Use this pattern for parsing the block device name from the output. * </p> * * Example output from perl script: * * <pre> * {@code * <disk type='block'> * <driver cache='none' name='qemu'/> * <source dev='/dev/disk/by-id/dm-uuid-mpath-3600a098037542d68732b447869397146'/> * <target bus='virtio' dev='vdb'/> <serial>vol-5062e8f1-dev-sdb</serial> </disk> * } * </pre> * * Use this regex pattern for parsing the block device string /dev/disk/by-id/dm-uuid-mpath-3600a098037542d68732b447869397146 */ public static final Pattern PARSE_BLOCK_DEVICE = Pattern.compile("source.* dev='([^']*)'"); public static final ImmutableSet<String> DELTA_GENERATION_STATE_EXCLUSION = ImmutableSet.of(StorageProperties.Status.failed.toString(), StorageProperties.Status.deleting.toString(), StorageProperties.Status.deletedfromebs.toString(), StorageProperties.Status.deleted.toString()); public static final ImmutableSet<String> DELTA_RESTORATION_STATE_EXCLUSION = ImmutableSet.of(StorageProperties.Status.failed.toString(), StorageProperties.Status.deleted.toString()); public static final Criterion SNAPSHOT_DELTA_GENERATION_CRITERION = Restrictions.not(Restrictions.in("status", DELTA_GENERATION_STATE_EXCLUSION)); public static final Criterion SNAPSHOT_DELTA_RESTORATION_CRITERION = Restrictions.not(Restrictions.in("status", DELTA_RESTORATION_STATE_EXCLUSION)); public static String formatVolumeAttachmentTokenForTransfer(String token, String volumeId) { return TOKEN_PREFIX + volumeId + "," + token; } private static String getSCIqn() { try { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec(new String[] {StorageProperties.EUCA_ROOT_WRAPPER, "cat", ISCSI_INITIATOR_NAME_CONF}); StreamConsumer error = new StreamConsumer(proc.getErrorStream()); ConfigParser output = new ConfigParser(proc.getInputStream()); error.start(); output.start(); output.join(); error.join(); if (output.getValues() != null && output.getValues().containsKey("InitiatorName")) { return output.getValues().get("InitiatorName"); } } catch (Exception t) { LOG.error("Failed to get local SC's initiator iqn from " + ISCSI_INITIATOR_NAME_CONF, t); } return null; } public static String getStorageIqn() { if (SC_INITIATOR_IQN == null) { SC_INITIATOR_IQN = getSCIqn(); } return SC_INITIATOR_IQN; } public static void updateName() { try { StorageProperties.NAME = Components.lookup(Storage.class).getLocalServiceConfiguration().getPartition(); } catch (NoSuchElementException ex) { LOG.error(ex, ex); LOG.error("Failed to configure Storage Controller NAME."); throw ex; } } public static void updateStorageHost() { try { STORAGE_HOST = Components.lookup(Storage.class).getLocalServiceConfiguration().getHostName(); } catch (NoSuchElementException ex) { LOG.error(ex, ex); LOG.error("Failed to configure Storage Controller HOST (given the name " + StorageProperties.NAME + "."); } } public static void updateStorageHost(String hostName) { STORAGE_HOST = hostName; } public static void updateWalrusUrl() { try { ServiceConfiguration walrusConfig = Topology.lookup(ObjectStorage.class); WALRUS_URL = ServiceUris.remote(walrusConfig).toASCIIString(); StorageProperties.enableSnapshots = true; LOG.debug("Setting WALRUS_URL to: " + WALRUS_URL); } catch (Exception e) { LOG.warn("Could not obtain walrus information. Snapshot functionality may be unavailable. Have you registered ObjectStorage?"); StorageProperties.enableSnapshots = false; } } //TODO: Split this enum which is overloaded, used by snapshots and volumes, and // use AWS's states for compatibility where possible. see: // http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/ec2/model/SnapshotState.html // http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/ec2/model/VolumeState.html // Snapshots: // "pending" == AWS "Pending" \_ Are these two any different in Euca? // "creating" == AWS "Pending" / // "available" == AWS "Completed" // "failed" == AWS "Error" // "delet*" are Euca-specific // Volumes: // "creating" == AWS "Creating" // "available" == AWS "Available" // "failed" == AWS "Error" // "deleting" == AWS "Deleting" // "deleted" == AWS "Deleted" // "pending" and "deletedfromebs" not used for volumes public enum Status { creating, available, pending, failed, deleting, deleted, deletedfromebs } public enum StorageParameters { EucaSignature, EucaSnapSize, EucaCert, EucaEffectiveUserId } }