public class WalrusProperties {
  private static Logger LOG = Logger.getLogger(WalrusProperties.class);

  public static final String SERVICE_NAME = "Walrus";
  public static String NAME = "Walrus";
  public static final String DB_NAME = "eucalyptus_walrus";
  public static final String VIRTUAL_SUBDOMAIN = "I_R_Bukkit";
  public static final long G = 1024 * 1024 * 1024;
  public static final long M = 1024 * 1024;
  public static final long K = 1024;
  public static String WALRUS_SUBDOMAIN = "walrus";

  public static final String bucketRootDirectory = BaseDirectory.VAR.toString() + "/bukkits";
  public static int MAX_BUCKETS_PER_ACCOUNT = 5;
  public static long MAX_BUCKET_SIZE = 5 * G;
  public static long IMAGE_CACHE_SIZE = 30 * G;
  public static String WALRUS_URL;
  public static int MAX_TOTAL_SNAPSHOT_SIZE = 50;
  public static int MAX_KEYS = 1000;

  public static int IO_CHUNK_SIZE = 102400;
  public static boolean shouldEnforceUsageLimits = true;
  public static boolean trackUsageStatistics = false;
  public static boolean enableTorrents = false;
  public static boolean enableVirtualHosting = true;
  public static long CACHE_PROGRESS_TIMEOUT = 600000L; // ten minutes
  public static long IMAGE_CACHE_RETRY_TIMEOUT = 1000L;
  public static int IMAGE_CACHE_RETRY_LIMIT = 3;
  public static long MAX_INLINE_DATA_SIZE = 10 * M;
  public static final String walrusServicePath = "/services/Walrus";
  public static int WALRUS_PORT = 8773;
  public static final String NAMESPACE_VERSION = "2006-03-01";
  public static final String CONTENT_LEN = "Content-Length";
  public static final String CONTENT_TYPE = "Content-Type";
  public static final String CONTENT_DISPOSITION = "Content-Disposition";
  public static final String CONTENT_MD5 = "Content-MD5";
  public static final String MULTIFORM_DATA_TYPE = "multipart/form-data";

  public static final String URL_PROPERTY = "euca.walrus.url";
  public static final String WALRUS_HOST_PROPERTY = "euca.walrus.host";
  public static final String USAGE_LIMITS_PROPERTY = "euca.walrus.usageLimits";
  public static final String WALRUS_OPERATION = "WalrusOperation";
  public static final String AMZ_META_HEADER_PREFIX = "x-amz-meta-";
  public static final String STREAMING_HTTP_GET = "STREAMING_HTTP_GET";
  public static final String STREAMING_HTTP_PUT = "STREAMING_HTTP_PUT";
  public static final String AMZ_ACL = "x-amz-acl";

  public static final String ALL_USERS_GROUP = "http://acs.amazonaws.com/groups/global/AllUsers";
  public static final String AUTHENTICATED_USERS_GROUP =
      "http://acs.amazonaws.com/groups/global/AuthenticatedUsers";
  public static final String LOGGING_GROUP = "http://acs.amazonaws.com/groups/s3/LogDelivery";

  public static final String IGNORE_PREFIX = "x-ignore-";
  public static final String COPY_SOURCE = "x-amz-copy-source";
  public static final String METADATA_DIRECTIVE = "x-amz-metadata-directive";
  public static final String ADMIN = "admin";

  public static final String X_AMZ_VERSION_ID = "x-amz-version-id";
  public static final String NULL_VERSION_ID = "null";

  public static final String X_AMZ_SECURITY_TOKEN = "x-amz-security-token";

  public static final String TRACKER_BINARY = "bttrack";
  public static final String TORRENT_CREATOR_BINARY = "btmakemetafile";
  public static final String TORRENT_CLIENT_BINARY = "btdownloadheadless";
  public static String TRACKER_DIR = BaseDirectory.VAR.toString() + "/bt";
  public static String TRACKER_URL = "http://localhost:6969/announce";
  public static String TRACKER_PORT = "6969";
  public static final String EUCA_ROOT_WRAPPER =
      BaseDirectory.LIBEXEC.toString() + "/euca_rootwrap";
  public static final String EUCA_MOUNT_WRAPPER =
      BaseDirectory.LIBEXEC.toString() + "/euca_mountwrap";
  public static final String EUCA_USER = System.getProperty("euca.user");
  public static final Integer DEFAULT_INITIAL_CAPACITY = 10; // 10 GB initial total capacity.

  // 15 minutes
  public static final long EXPIRATION_LIMIT = 900000;

  static {
    Groovyness.loadConfig("walrusprops.groovy");
  }

  public enum CannedACL {
    private_only {
      public String toString() {
        return "private";
      }
    },
    public_read {
      public String toString() {
        return "public-read";
      }
    },
    public_read_write {
      public String toString() {
        return "public-read-write";
      }
    },
    authenticated_read {
      public String toString() {
        return "authenticated-read";
      }
    },
    bucket_owner_read {
      public String toString() {
        return "bucket-owner-read";
      }
    },
    bucket_owner_full_control {
      public String toString() {
        return "bucket-owner-full-control";
      }
    },
    log_delivery_write {
      public String toString() {
        return "log-delivery-write";
      }
    },
    aws_exec_read {
      public String toString() {
        return "aws-exec-read";
      }
    }
  }

  public enum Permission {
    READ,
    WRITE,
    READ_ACP,
    WRITE_ACP,
    FULL_CONTROL
  }

  public enum VersioningStatus {
    Enabled,
    Disabled,
    Suspended
  }

  public enum Headers {
    Bucket,
    Key,
    RandomKey,
    VolumeId,
    S3UploadPolicy,
    S3UploadPolicySignature
  }

  public enum ExtendedGetHeaders {
    IfModifiedSince,
    IfUnmodifiedSince,
    IfMatch,
    IfNoneMatch,
    Range
  }

  public enum ExtendedHeaderDateTypes {
    IfModifiedSince,
    IfUnmodifiedSince,
    CopySourceIfModifiedSince,
    CopySourceIfUnmodifiedSince;

    public static boolean contains(String value) {
      for (ExtendedHeaderDateTypes type : values()) {
        if (type.toString().equals(value)) {
          return true;
        }
      }
      return false;
    }
  }

  public enum ExtendedHeaderRangeTypes {
    ByteRangeStart,
    ByteRangeEnd
  }

  public enum WalrusInternalOperations {
    GetDecryptedImage,
    ValidateImage
  }

  public enum GetOptionalParameters {
    IsCompressed
  }

  public enum StorageOperations {
    StoreSnapshot,
    DeleteWalrusSnapshot,
    GetWalrusSnapshot,
    GetWalrusSnapshotSize
  }

  public enum InfoOperations {
    GetSnapshotInfo
  }

  public enum StorageParameters {
    SnapshotVgName,
    SnapshotLvName
  }

  public enum FormField {
    FormUploadPolicyData,
    AWSAccessKeyId,
    key,
    bucket,
    acl,
    policy,
    redirect,
    success_action_redirect,
    success_action_status,
    signature,
    file
  }

  public enum IgnoredFields {
    AWSAccessKeyId,
    signature,
    file,
    policy,
    submit
  }

  public enum PolicyHeaders {
    expiration,
    conditions
  }

  public enum CopyHeaders {
    CopySourceIfMatch,
    CopySourceIfNoneMatch,
    CopySourceIfUnmodifiedSince,
    CopySourceIfModifiedSince
  }

  public enum SubResource {
    // Per the S3 Dev guide, these must be included in the canonicalized resource:
    // acl, lifecycle, location, logging, notification, partNumber, policy, requestPayment, torrent,
    // uploadId, uploads, versionId, versioning, versions and website
    acl,
    location,
    logging,
    torrent,
    versioning,
    versions,
    versionId
  }

  public enum HTTPVerb {
    GET,
    PUT,
    DELETE,
    POST,
    HEAD;
  }

  public enum ServiceParameter {}

  public enum BucketParameter {
    acl,
    location,
    prefix,
    maxkeys,
    delimiter,
    marker,
    torrent,
    logging,
    versioning,
    versions,
    versionidmarker,
    keymarker;
  }

  public enum ObjectParameter {
    acl,
    torrent,
    versionId;
  }

  public enum RequiredQueryParams {
    Date
  }

  public enum RequiredSOAPTags {
    AWSAccessKeyId,
    Timestamp,
    Signature
  }

  /*
   * Simply determines if the userId is a member of the groupId, very simplistic only for ALL_USERS and AUTHENTICATED_USERS, not arbitrary groups.
   * Arbitrary groups are not yet supported in Walrus bucket policies/IAM policies.
   */
  public static boolean isUserMember(String userId, String groupId) {
    if (groupId == null) {
      return false;
    }

    if (groupId.equals(WalrusProperties.ALL_USERS_GROUP)) {
      return true;
    }

    if (groupId.equals(WalrusProperties.AUTHENTICATED_USERS_GROUP)
        && userId != null
        && !"".equals(userId)
        && !userId.equals(Principals.nobodyUser().getUserId())) {
      return true;
    }

    return false;
  }

  public static String getTrackerUrl() {
    try {
      String walrusUrl = SystemConfiguration.getWalrusUrl();
      TRACKER_URL = "http://" + new URI(walrusUrl).getHost() + ":" + TRACKER_PORT + "/announce";
    } catch (EucalyptusCloudException e) {
      LOG.error(e);
    } catch (URISyntaxException e) {
      LOG.error(e);
    }
    return TRACKER_URL;
  }

  public static InetAddress getWalrusAddress() throws EucalyptusCloudException {
    if (Topology.isEnabled(Walrus.class)) {
      return Topology.lookup(Walrus.class).getInetAddress();
    } else {
      throw new EucalyptusCloudException("Walrus not ENABLED");
    }
  }
}
public class StorageProperties {

  private static Logger LOG = Logger.getLogger(StorageProperties.class);

  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 = 100;
  public static final int MAX_VOLUME_SIZE = 15;
  public static int TRANSFER_CHUNK_SIZE = 8192;
  public static final boolean zeroFillVolumes = false;
  public static final long timeoutInMillis = 10000;

  public static boolean enableSnapshots = false;
  public static boolean enableStorage = false;
  public static boolean shouldEnforceUsageLimits = true;
  public static String STORE_PREFIX = "iqn.2009-06.com.eucalyptus.";
  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:::*/*\""
          + "}"
          + "]}";

  public static final Integer DELETED_VOLUME_EXPIRATION_TIME = 24; // hours

  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.info("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;
    }
  }

  public enum Status {
    creating,
    available,
    pending,
    completed,
    failed,
    error,
    deleting,
    deleted
  }

  public enum StorageParameters {
    EucaSignature,
    EucaSnapSize,
    EucaCert,
    EucaEffectiveUserId
  }

  public static <T> EntityWrapper<T> getEntityWrapper() {
    return (EntityWrapper<T>) EntityWrapper.get(VolumeInfo.class);
  }
}