Package org.apache.whirr.service

Source Code of org.apache.whirr.service.Key

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.whirr.service;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.ForwardingObject;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.MapMaker;
import com.google.inject.Module;

import java.util.Map;
import java.util.Properties;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationConverter;
import org.apache.commons.lang.StringUtils;
import org.apache.whirr.ClusterSpec;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.Utils;
import org.jclouds.domain.Credentials;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.providers.Providers;
import org.jclouds.rest.RestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_AMI_QUERY;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMI_QUERY;
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION;

/**
* A convenience class for building jclouds {@link ComputeServiceContext} objects.
*/
// singleton enum pattern
public enum ComputeCache implements Function<ClusterSpec, ComputeServiceContext> {
  
  INSTANCE;
 
  private static final Logger LOG = LoggerFactory.getLogger(ComputeCache.class);

  @Override
  public ComputeServiceContext apply(ClusterSpec arg0) {
    return cache.get(new Key(arg0));
  }
 
  // this should prevent recreating the same compute context twice
  @VisibleForTesting
  final Map<Key, ComputeServiceContext> cache = new MapMaker().makeComputingMap(
      new Function<Key, ComputeServiceContext>(){
        private final ComputeServiceContextFactory factory =  new ComputeServiceContextFactory();
              
        @Override
        public ComputeServiceContext apply(Key arg0) {
          LOG.debug("creating new ComputeServiceContext {}", arg0);
          ComputeServiceContext context = new IgnoreCloseComputeServiceContext(factory.createContext(
            arg0.provider, arg0.identity, arg0.credential,
            ImmutableSet.<Module>of(), arg0.overrides));
          LOG.debug("created new ComputeServiceContext {}", context);
          return context;
        }
   
    }
  );
  
  private static class IgnoreCloseComputeServiceContext
    extends ForwardingObject implements ComputeServiceContext {

    private final ComputeServiceContext context;

    public IgnoreCloseComputeServiceContext(final ComputeServiceContext context) {
      this.context = context;
      Runtime.getRuntime().addShutdownHook(new Thread() {
         @Override
         public void run() {
           LOG.debug("closing ComputeServiceContext {}", context);
           context.close();
         }
       });
    }

    @Override
    protected ComputeServiceContext delegate() {
       return context;
    }

    @Override
    public ComputeService getComputeService() {
      return delegate().getComputeService();
    }

    @Override
    public <S, A> RestContext<S, A> getProviderSpecificContext() {
      return delegate().getProviderSpecificContext();
    }

    @Override
    public Map<String, Credentials> getCredentialStore() {
      return delegate().getCredentialStore();
    }

    @Override
    public Map<String, Credentials> credentialStore() {
      return delegate().credentialStore();
    }

    @Override
    public Utils getUtils() {
      return delegate().getUtils();
    }

    @Override
    public Utils utils() {
      return delegate().utils();
    }

    @Override
    public void close() {
      /* Do nothing. The instance is closed by the builder */
    }

  }

  /**
   * All APIs that are independently configurable.
   * @see <a href="http://code.google.com/p/jclouds/issues/detail?id=657" />
   */
  public static final Iterable<String> COMPUTE_APIS = ImmutableSet.of(
      "stub", "nova", "vcloud", "elasticstack",
      "eucalyptus", "deltacloud", "byon"
  );

  /**
   *  jclouds providers and apis that can be used in ComputeServiceContextFactory
   */
  public static final Iterable<String> COMPUTE_KEYS = Iterables.concat(
      Iterables.transform(Providers.allCompute(), new Function<ProviderMetadata, String>() {

        @Override
        public String apply(ProviderMetadata input) {
          return input.getId();
        }

      }), COMPUTE_APIS);

  /**
   * configurable properties, scoped to a provider.
   */
  public static final Iterable<String> PROVIDER_PROPERTIES = ImmutableSet.of(
    "endpoint", "api", "apiversion", "iso3166-codes");

  /**
   * Key class for the compute context cache
   */
  private static class Key {
    private String provider;
    private String identity;
    private String credential;

    private final String key;
    private final Properties overrides;

    public Key(ClusterSpec spec) {
      provider = spec.getProvider();
      identity = spec.getIdentity();
      credential = spec.getCredential();

      key = String.format("%s-%s-%s", provider, identity, credential);
      Configuration jcloudsConfig = spec.getConfigurationForKeysWithPrefix("jclouds");
     
      // jclouds configuration for providers are not prefixed with jclouds.
      for (String key : COMPUTE_KEYS) {
        for (String property : PROVIDER_PROPERTIES) {
          String prefixedProperty = "jclouds." + key + "." + property;

          if (jcloudsConfig.containsKey(prefixedProperty)) {
            jcloudsConfig.setProperty(key + "." + property,
                jcloudsConfig.getProperty(prefixedProperty));
          }
        }
      }
      overrides = ConfigurationConverter.getProperties(jcloudsConfig);

      if ("aws-ec2".equals(spec.getProvider()) && spec.getImageId() != null) {
        enableAWSEC2LazyImageFetching(spec);
      }

      if ("stub".equals(spec.getProvider())) {
        overrides.setProperty("jclouds.modules",
          SLF4JLoggingModule.class.getName() + ",org.apache.whirr.service.DryRunModule"
        );
      }
    }

    /**
     * AWS EC2 specific optimisation to avoid running queries across
     * all regiosn when the image-id is know from the property file
     *
     * @param spec
     */
    private void enableAWSEC2LazyImageFetching(ClusterSpec spec) {
      overrides.setProperty(PROPERTY_EC2_AMI_QUERY, "");
      overrides.setProperty(PROPERTY_EC2_CC_AMI_QUERY, "");

      String[] parts = StringUtils.split(spec.getImageId(), '/');
      checkArgument(parts.length == 2, "Expected to find image-id = region/ami-id");

      overrides.setProperty(PROPERTY_REGION, parts[0]);
    }

    @Override
    public boolean equals(Object that) {
      if (that instanceof Key) {
        return Objects.equal(this.key, ((Key)that).key)
          && Objects.equal(overrides, ((Key)that).overrides);
      }
      return false;
    }

    @Override
    public int hashCode() {
      return Objects.hashCode(key, overrides);
    }
   
    @Override
    public String toString() {
      return Objects.toStringHelper(this)
        .add("provider", provider)
        .add("identity", identity)
        .add("overrides", overrides)
        .toString();
    }
  }

}
TOP

Related Classes of org.apache.whirr.service.Key

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.