/** * Copyright (C) 2009-2015 Dell, Inc * See annotations for authorship information * * ==================================================================== * Licensed 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.dasein.cloud.joyent; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; import java.util.TimeZone; import org.apache.log4j.Logger; import org.dasein.cloud.*; import org.dasein.cloud.joyent.compute.JoyentComputeServices; import org.dasein.cloud.joyent.storage.MantaStorageServices; import org.dasein.cloud.storage.StorageServices; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SmartDataCenter extends AbstractCloud { static private @Nonnull String getLastItem(@Nonnull String name) { int idx = name.lastIndexOf('.'); if( idx < 0 ) { return name; } else if( idx == (name.length()-1) ) { return ""; } return name.substring(idx+1); } static public @Nonnull Logger getLogger(@Nonnull Class<?> cls, @Nonnull String type) { String pkg = getLastItem(cls.getPackage().getName()); if( pkg.equals("joyent") ) { pkg = ""; } else { pkg = pkg + "."; } return Logger.getLogger("dasein.cloud.joyent." + type + "." + pkg + getLastItem(cls.getName())); } public SmartDataCenter() { } @Override public @Nonnull synchronized StorageServices getStorageServices() { return new MantaStorageServices(this); } @Override public @Nonnull JoyentComputeServices getComputeServices() { return new JoyentComputeServices(this); } public static final String DSN_SSH_KEY = "sshKey"; public static final String DSN_SSH_KEY_PASSWORD = "sshKeyPassword"; @Override public @Nonnull ContextRequirements getContextRequirements() { return new ContextRequirements( new ContextRequirements.Field(DSN_SSH_KEY, "Private SSH Key stored in Joyent", ContextRequirements.FieldType.KEYPAIR, ContextRequirements.Field.ACCESS_KEYS, true), new ContextRequirements.Field(DSN_SSH_KEY_PASSWORD, "Password of ssh key uploaded to Joyent", ContextRequirements.FieldType.PASSWORD, ContextRequirements.Field.ACCESS_KEYS, false), new ContextRequirements.Field("storageUrl", "Manta Storage URL", ContextRequirements.FieldType.TEXT, false), new ContextRequirements.Field("proxyHost", "Proxy host", ContextRequirements.FieldType.TEXT, false), new ContextRequirements.Field("proxyPort", "Proxy port", ContextRequirements.FieldType.TEXT, false) ); } @Override public @Nonnull String getCloudName() { return "Joyent Cloud"; } @Override public @Nonnull JoyentDataCenter getDataCenterServices() { return new JoyentDataCenter(this); } static private final HashMap<String,Map<String,String>> endpointCache = new HashMap<String,Map<String,String>>(); public @Nonnull String getEndpoint() throws CloudException, InternalException { ProviderContext ctx = getContext(); if( ctx == null ) { throw new CloudException("No context has been established for this request"); } String e = ctx.getCloud().getEndpoint(); if( e == null ) { e = "https://us-west-1.api.joyentcloud.com"; } String[] parts = e.split(","); if( parts == null || parts.length < 1 ) { parts = new String[] { e }; } String r = ctx.getRegionId(); if( r == null ) { return parts[0]; } if( endpointCache.containsKey(e) ) { Map<String,String> cache = endpointCache.get(e); if( cache != null && cache.containsKey(r) ) { String endpoint = cache.get(r); if( endpoint != null ) { return endpoint; } } } JoyentMethod method = new JoyentMethod(this); String json = method.doGetJson(parts[0], "datacenters"); try { JSONObject ob = new JSONObject(json); JSONArray ids = ob.names(); for( int i=0; i<ids.length(); i++ ) { String regionId = ids.getString(i); if( regionId.equals(r) && ob.has(regionId) ) { String endpoint = ob.getString(regionId); Map<String,String> cache; if( endpointCache.containsKey(e) ) { cache = endpointCache.get(e); } else { cache = new HashMap<String,String>(); endpointCache.put(e, cache); } cache.put(r, endpoint); return endpoint; } } throw new CloudException("No endpoint exists for " + r); } catch( JSONException ex ) { throw new CloudException(ex); } } @Override public @Nonnull String getProviderName() { return "Joyent"; } public @Nonnegative long parseTimestamp(String time) throws CloudException { if( time == null ) { return 0L; } int idx = time.lastIndexOf('+'); if (idx < 0) { idx = time.lastIndexOf('Z'); if (idx < 0) { throw new CloudException("Could not parse timestamp: " + time); } time = time.substring(0,idx); } else { time = time.substring(0,idx); } SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); fmt.setTimeZone(TimeZone.getTimeZone("GMT")); if( time.length() > 0 ) { try { return fmt.parse(time).getTime(); } catch( ParseException e ) { fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); try { return fmt.parse(time).getTime(); } catch (ParseException e2) { throw new CloudException("Could not parse timestamp: " + time, e2); } } } return 0L; } @Override public @Nullable String testContext() { Logger logger = getLogger(SmartDataCenter.class, "std"); if( logger.isTraceEnabled() ) { logger.trace("enter - " + SmartDataCenter.class.getName() + ".textContext()"); } try { try { ProviderContext ctx = getContext(); if( ctx == null ) { return null; } String pk = ctx.getAccountNumber(); JoyentMethod method = new JoyentMethod(this); try { method.doGetJson(getEndpoint(), "datacenters"); return pk; } catch( CloudException e ) { if( e.getErrorType().equals(CloudErrorType.AUTHENTICATION) ) { return null; } logger.warn("Cloud error testing Joyent context: " + e.getMessage(), e); } return null; } catch( Throwable t ) { logger.warn("Failed to test Joyent connection context: " + t.getMessage(), t); return null; } } finally { if( logger.isTraceEnabled() ) { logger.trace("exit - " + SmartDataCenter.class.getName() + ".testContext()"); } } } }