/** * Copyright (C) 2012-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.google; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.log4j.Logger; import org.dasein.cloud.CloudErrorType; import org.dasein.cloud.CloudException; import org.dasein.cloud.InternalException; import org.dasein.cloud.ProviderContext; import org.dasein.cloud.dc.DataCenter; import org.dasein.cloud.dc.DataCenterCapabilities; import org.dasein.cloud.dc.DataCenterServices; import org.dasein.cloud.dc.Folder; import org.dasein.cloud.dc.Region; import org.dasein.cloud.dc.ResourcePool; import org.dasein.cloud.dc.StoragePool; import org.dasein.cloud.util.APITrace; import org.dasein.cloud.util.Cache; import org.dasein.cloud.util.CacheLevel; import org.dasein.util.uom.time.Hour; import org.dasein.util.uom.time.TimePeriod; import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.services.compute.Compute; import com.google.api.services.compute.model.RegionList; import com.google.api.services.compute.model.Zone; import com.google.api.services.compute.model.ZoneList; /** * Implementation of GCE Regions and Zones * @author Drew Lyall * @version 2014.03 initial version * @since 2014.03 */ public class DataCenters implements DataCenterServices { static private final Logger logger = Google.getLogger(DataCenters.class); private static HashMap<String, String> zone2Region = new HashMap<String, String>(); private Google provider; DataCenters(@Nonnull Google provider) { this.provider = provider; } private transient volatile GoogleDataCenterCapabilities capabilities; @Nonnull @Override public DataCenterCapabilities getCapabilities() throws InternalException, CloudException { if( capabilities == null ) { capabilities = new GoogleDataCenterCapabilities(provider); } return capabilities; } @Override public @Nullable DataCenter getDataCenter(@Nonnull String dataCenterId) throws InternalException, CloudException { Compute gce = provider.getGoogleCompute(); try{ Zone dataCenter = gce.zones().get(provider.getContext().getAccountNumber(), dataCenterId).execute(); return toDataCenter(dataCenter); } catch (IOException ex) { logger.error(ex.getMessage()); if (ex.getClass() == GoogleJsonResponseException.class) { GoogleJsonResponseException gjre = (GoogleJsonResponseException)ex; throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(), gjre.getDetails().getMessage()); } else throw new CloudException("An error occurred retrieving the dataCenter: " + dataCenterId + ": " + ex.getMessage()); } } @Override public @Nonnull String getProviderTermForDataCenter(@Nonnull Locale locale) { return "zone"; } @Override public @Nonnull String getProviderTermForRegion(@Nonnull Locale locale) { return "region"; } @Override public @Nullable Region getRegion(@Nonnull String providerRegionId) throws InternalException, CloudException { Compute gce = provider.getGoogleCompute(); try{ com.google.api.services.compute.model.Region r = gce.regions().get(provider.getContext().getAccountNumber(), providerRegionId).execute(); return toRegion(r); } catch (IOException ex) { logger.error(ex.getMessage()); if (ex.getClass() == GoogleJsonResponseException.class) { GoogleJsonResponseException gjre = (GoogleJsonResponseException)ex; throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(), gjre.getDetails().getMessage()); } else throw new CloudException("An error occurred retrieving the region: " + providerRegionId + ": " + ex.getMessage()); } } @Override public @Nonnull Collection<DataCenter> listDataCenters(@Nonnull String providerRegionId) throws InternalException, CloudException { APITrace.begin(provider, "listDataCenters"); try { ProviderContext ctx = provider.getContext(); if( ctx == null ) { throw new NoContextException(); } Collection<DataCenter> dataCenters; Cache<DataCenter> cache = null; String originalRegionId = ctx.getRegionId(); if(providerRegionId.equals(originalRegionId)) { cache = Cache.getInstance(provider, "datacenters", DataCenter.class, CacheLevel.REGION_ACCOUNT, new TimePeriod<Hour>(10, TimePeriod.HOUR)); dataCenters = (Collection<DataCenter>)cache.get(ctx); if(dataCenters != null){ return dataCenters; } } dataCenters = new ArrayList<DataCenter>(); Compute gce = provider.getGoogleCompute(); Compute.Zones.List gceDataCenters = null; try{ ZoneList zoneList = gce.zones().list(ctx.getAccountNumber()).execute(); if (null != zoneList) { List<Zone> dataCenterList = zoneList.getItems(); for (int i=0; i < dataCenterList.size(); i++) { Zone current = dataCenterList.get(i); String region = current.getRegion().substring(current.getRegion().lastIndexOf("/") + 1); if (region.equals(providerRegionId)) { dataCenters.add(toDataCenter(current, (null != current.getDeprecated()))); } zone2Region.put(current.getName(), region); } } } catch (IOException ex) { logger.error("Failed to listDataCenters: " + ex.getMessage()); if (ex.getClass() == GoogleJsonResponseException.class) { GoogleJsonResponseException gjre = (GoogleJsonResponseException)ex; throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(), gjre.getDetails().getMessage()); } else throw new CloudException(CloudErrorType.COMMUNICATION, gceDataCenters.getLastStatusCode(), gceDataCenters.getLastStatusMessage(), "An error occurred while listing DataCenters"); } if (cache != null) { cache.put(ctx, dataCenters); } return dataCenters; } finally { APITrace.end(); } } @Override public Collection<Region> listRegions() throws InternalException, CloudException { APITrace.begin(provider, "listRegions"); try { ProviderContext ctx = provider.getContext(); if( ctx == null ) { throw new NoContextException(); } Cache<Region> cache = Cache.getInstance(provider, "regions", Region.class, CacheLevel.CLOUD_ACCOUNT, new TimePeriod<Hour>(10, TimePeriod.HOUR)); Collection<Region> regions = (Collection<Region>)cache.get(ctx); if( regions != null ) { return regions; } regions = new ArrayList<Region>(); Compute gce = provider.getGoogleCompute(); Compute.Regions.List gceRegions = null; try { gceRegions = gce.regions().list(ctx.getAccountNumber()); RegionList regionList = gceRegions.execute(); if ((null != regionList) && (null != regionList.getItems())) { List<com.google.api.services.compute.model.Region> regionListItems = regionList.getItems(); for(int i=0;i<regionListItems.size();i++){ com.google.api.services.compute.model.Region current = regionListItems.get(i); regions.add(toRegion(current)); } } } catch (IOException ex) { logger.error("Failed to listRegions: " + ex.getMessage()); if (ex.getClass() == GoogleJsonResponseException.class) { GoogleJsonResponseException gjre = (GoogleJsonResponseException)ex; throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(), gjre.getDetails().getMessage()); } else throw new CloudException(CloudErrorType.COMMUNICATION, gceRegions.getLastStatusCode(), gceRegions.getLastStatusMessage(), "An error occurred while listing regions"); } cache.put(ctx, regions); return regions; } finally { APITrace.end(); } } public @Nonnull String getRegionFromZone(@Nonnull String zoneName) throws CloudException, InternalException{ if(zoneName.contains("zones/"))zoneName = zoneName.replace("zones/", ""); if(zone2Region == null || !zone2Region.containsKey(zoneName)){ for(Region r : listRegions()){ listDataCenters(r.getProviderRegionId()); } } return zone2Region.get(zoneName); } private Region toRegion(com.google.api.services.compute.model.Region googleRegion){ Region region = new Region(); region.setName(googleRegion.getName()); //region.setProviderRegionId(googleRegion.getId() + ""); - GCE uses name as IDs region.setProviderRegionId(googleRegion.getName()); region.setActive(true); region.setAvailable(true); if( googleRegion.getName().startsWith("eu") ) { region.setJurisdiction("EU"); } else region.setJurisdiction("US"); return region; } private DataCenter toDataCenter(Zone zone) { return toDataCenter(zone, false); } private DataCenter toDataCenter(Zone zone, Boolean deprecated){ DataCenter dc = new DataCenter(); dc.setActive(true); if (deprecated) { dc.setAvailable(false); } else { if (zone.getStatus().equals("UP")) { dc.setAvailable(true); }else { dc.setAvailable(false); } } //dc.setProviderDataCenterId(zone.getId() + ""); - GCE uses name as IDs dc.setProviderDataCenterId(zone.getName()); dc.setRegionId(zone.getRegion().substring(zone.getRegion().lastIndexOf("/") + 1)); dc.setName(zone.getName()); return dc; } @Override public Collection<ResourcePool> listResourcePools(String providerDataCenterId) throws InternalException, CloudException { return Collections.emptyList(); } @Override public ResourcePool getResourcePool(String providerResourcePoolId) throws InternalException, CloudException { return null; } @Override public Collection<StoragePool> listStoragePools() throws InternalException, CloudException { return Collections.emptyList(); } @Nonnull @Override public StoragePool getStoragePool(String providerStoragePoolId) throws InternalException, CloudException { return null; } @Override public Collection<Folder> listVMFolders() throws InternalException, CloudException { return Collections.emptyList(); } @Override public Folder getVMFolder( String providerVMFolderId ) throws InternalException, CloudException { return null; } }