Repository: jclouds-labs Updated Branches: refs/heads/master 5bd2a80fa -> f38f80453
[JCLOUDS-1430] - add region and zone API Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/f38f8045 Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/f38f8045 Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/f38f8045 Branch: refs/heads/master Commit: f38f804537c2c7a3b76ba355ab113475ef862fc1 Parents: 5bd2a80 Author: andreaturli <[email protected]> Authored: Tue Jul 3 14:47:43 2018 +0200 Committer: andreaturli <[email protected]> Committed: Fri Jul 6 13:41:24 2018 +0200 ---------------------------------------------------------------------- .../aliyun/ecs/ECSComputeServiceApi.java | 4 + .../ecs/ECSComputeServiceProviderMetadata.java | 2 +- .../org/jclouds/aliyun/ecs/domain/Region.java | 36 ++ .../jclouds/aliyun/ecs/domain/ResourceInfo.java | 66 +++ .../org/jclouds/aliyun/ecs/domain/Zone.java | 71 +++ .../aliyun/ecs/features/RegionAndZoneApi.java | 58 +++ .../ecs/compute/features/ImageApiMockTest.java | 28 +- .../features/RegionAndZoneApiLiveTest.java | 62 +++ .../features/RegionAndZoneApiMockTest.java | 68 +++ .../BaseECSComputeServiceApiMockTest.java | 27 +- aliyun-ecs/src/test/resources/regions.json | 79 +++ aliyun-ecs/src/test/resources/zones.json | 477 +++++++++++++++++++ 12 files changed, 949 insertions(+), 29 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceApi.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceApi.java b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceApi.java index 268d773..140b098 100644 --- a/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceApi.java +++ b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceApi.java @@ -17,6 +17,7 @@ package org.jclouds.aliyun.ecs; import org.jclouds.aliyun.ecs.features.ImageApi; +import org.jclouds.aliyun.ecs.features.RegionAndZoneApi; import org.jclouds.rest.annotations.Delegate; import java.io.Closeable; @@ -26,4 +27,7 @@ public interface ECSComputeServiceApi extends Closeable { @Delegate ImageApi imageApi(); + @Delegate + RegionAndZoneApi regionAndZoneApi(); + } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceProviderMetadata.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceProviderMetadata.java b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceProviderMetadata.java index 61b4df9..fbd7206 100644 --- a/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceProviderMetadata.java +++ b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/ECSComputeServiceProviderMetadata.java @@ -57,7 +57,7 @@ public class ECSComputeServiceProviderMetadata extends BaseProviderMetadata { .homepage(URI.create("https://www.alibabacloud.com")) .console(URI.create("https://ecs.console.aliyun.com")) .endpoint("https://ecs.aliyuncs.com") - .iso3166Codes("US-CA", "US-VA", "DE", "JP", "ID-JK", "SG", "IN", "AU-NSW", "MY", "CN-HE", "CN-SH", "CN-ZJ", "CN-GD", "HK", "AE-DU") // TODO + .iso3166Codes("US-CA", "US-VA", "DE", "JP", "ID-JK", "SG", "IN", "AU-NSW", "MY", "CN-HE", "CN-SH", "CN-ZJ", "CN-GD", "HK", "AE-DU") .defaultProperties(ECSServiceApiMetadata.defaultProperties()); } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/Region.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/Region.java b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/Region.java new file mode 100644 index 0000000..ce2f6b7 --- /dev/null +++ b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/Region.java @@ -0,0 +1,36 @@ +/* + * 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.jclouds.aliyun.ecs.domain; + +import com.google.auto.value.AutoValue; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class Region { + + Region() {} + + @SerializedNames({ "RegionId", "LocalName" }) + public static Region create(String regionId, String localName) { + return new AutoValue_Region(regionId, localName); + } + + public abstract String regionId(); + + public abstract String localName(); + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/ResourceInfo.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/ResourceInfo.java b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/ResourceInfo.java new file mode 100644 index 0000000..ea4bbc3 --- /dev/null +++ b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/ResourceInfo.java @@ -0,0 +1,66 @@ +/* + * 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.jclouds.aliyun.ecs.domain; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; +import org.jclouds.json.SerializedNames; + +import java.util.List; +import java.util.Map; + +@AutoValue +public abstract class ResourceInfo { + + ResourceInfo() { + } + + @SerializedNames( + { "IoOptimized", "SystemDiskCategories", "InstanceTypes", "InstanceTypeFamilies", "DataDiskCategories", + "InstanceGenerations", "NetworkTypes" }) + public static ResourceInfo create(boolean ioOptimized, Map<String, List<String>> systemDiskCategories, + Map<String, List<String>> instanceTypes, Map<String, List<String>> instanceTypeFamilies, + Map<String, List<String>> dataDiskCategories, Map<String, List<String>> instanceGenerations, + Map<String, List<String>> networkTypes) { + return new AutoValue_ResourceInfo(ioOptimized, systemDiskCategories == null ? + ImmutableMap.<String, List<String>>of() : + ImmutableMap.copyOf(systemDiskCategories), + instanceTypes == null ? ImmutableMap.<String, List<String>>of() : ImmutableMap.copyOf(instanceTypes), + instanceTypeFamilies == null ? + ImmutableMap.<String, List<String>>of() : + ImmutableMap.copyOf(instanceTypeFamilies), dataDiskCategories == null ? + ImmutableMap.<String, List<String>>of() : + ImmutableMap.copyOf(dataDiskCategories), instanceGenerations == null ? + ImmutableMap.<String, List<String>>of() : + ImmutableMap.copyOf(instanceGenerations), + networkTypes == null ? ImmutableMap.<String, List<String>>of() : ImmutableMap.copyOf(networkTypes)); + } + + public abstract boolean ioOptimized(); + + public abstract Map<String, List<String>> systemDiskCategories(); + + public abstract Map<String, List<String>> instanceTypes(); + + public abstract Map<String, List<String>> instanceTypeFamilies(); + + public abstract Map<String, List<String>> dataDiskCategories(); + + public abstract Map<String, List<String>> instanceGenerations(); + + public abstract Map<String, List<String>> networkTypes(); +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/Zone.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/Zone.java b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/Zone.java new file mode 100644 index 0000000..87709e2 --- /dev/null +++ b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/domain/Zone.java @@ -0,0 +1,71 @@ +/* + * 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.jclouds.aliyun.ecs.domain; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; +import org.jclouds.json.SerializedNames; + +import java.util.List; +import java.util.Map; + +@AutoValue +public abstract class Zone { + + Zone() {} + + @SerializedNames({ "ZoneId", "LocalName", "DedicatedHostGenerations", "AvailableResourceCreation", + "AvailableDedicatedHostTypes", "AvailableResources", "AvailableInstanceTypes", + "AvailableVolumeCategories", "AvailableDiskCategories" }) + public static Zone create(String zoneId, String localName, + Map<String, List<Object>> dedicatedHostGenerations, // FIXME neither doc nor example showed the type in the list + Map<String, List<String>> availableResourceCreation, + Map<String, List<String>> availableDedicatedHostTypes, + Map<String, List<ResourceInfo>> availableResources, + Map<String, List<String>> availableInstanceTypes, + Map<String, List<String>> availableVolumeCategories, + Map<String, List<String>> availableDiskCategories) { + return new AutoValue_Zone(zoneId, localName, + dedicatedHostGenerations == null ? ImmutableMap.<String, List<Object>>of() : ImmutableMap.copyOf(dedicatedHostGenerations), + availableResourceCreation == null ? ImmutableMap.<String, List<String>>of() : ImmutableMap.copyOf(availableResourceCreation), + availableDedicatedHostTypes == null ? ImmutableMap.<String, List<String>>of() : ImmutableMap.copyOf(availableDedicatedHostTypes), + availableResources == null ? ImmutableMap.<String, List<ResourceInfo>>of() : ImmutableMap.copyOf(availableResources), + availableInstanceTypes == null ? ImmutableMap.<String, List<String>>of() : ImmutableMap.copyOf(availableInstanceTypes), + availableVolumeCategories == null ? ImmutableMap.<String, List<String>>of() : ImmutableMap.copyOf(availableVolumeCategories), + availableDiskCategories == null ? ImmutableMap.<String, List<String>>of() : ImmutableMap.copyOf(availableDiskCategories) + ); + } + + public abstract String zoneId(); + + public abstract String localName(); + + public abstract Map<String, List<Object>> dedicatedHostGenerations(); + + public abstract Map<String, List<String>> availableResourceCreation(); + + public abstract Map<String, List<String>> availableDedicatedHostTypes(); + + public abstract Map<String, List<ResourceInfo>> availableResources(); + + public abstract Map<String, List<String>> availableInstanceTypes(); + + public abstract Map<String, List<String>> availableVolumeCategories(); + + public abstract Map<String, List<String>> availableDiskCategories(); + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/features/RegionAndZoneApi.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/features/RegionAndZoneApi.java b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/features/RegionAndZoneApi.java new file mode 100644 index 0000000..8216ab0 --- /dev/null +++ b/aliyun-ecs/src/main/java/org/jclouds/aliyun/ecs/features/RegionAndZoneApi.java @@ -0,0 +1,58 @@ +/* + * 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.jclouds.aliyun.ecs.features; + +import org.jclouds.Constants; +import org.jclouds.Fallbacks; +import org.jclouds.aliyun.ecs.domain.Region; +import org.jclouds.aliyun.ecs.domain.Zone; +import org.jclouds.aliyun.ecs.filters.FormSign; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.QueryParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.util.List; + +/** + * https://www.alibabacloud.com/help/doc-detail/25609.htm?spm=a2c63.p38356.a1.4.7dd43c1aeoTmzO + */ +@Consumes(MediaType.APPLICATION_JSON) +@RequestFilters(FormSign.class) +@QueryParams(keys = { "Version", "Format", "SignatureVersion", "ServiceCode", "SignatureMethod" }, + values = {"{" + Constants.PROPERTY_API_VERSION + "}", "JSON", "1.0", "ecs", "HMAC-SHA1"}) +public interface RegionAndZoneApi { + + @Named("region:list") + @GET + @SelectJson("Region") + @QueryParams(keys = "Action", values = "DescribeRegions") + @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class) + List<Region> describeRegions(); + + @Named("zone:list") + @GET + @SelectJson("Zone") + @QueryParams(keys = "Action", values = "DescribeZones") + @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class) + List<Zone> describeZones(@QueryParam("RegionId") String region); +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java index a29c067..b333e6d 100644 --- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java +++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java @@ -16,16 +16,17 @@ */ package org.jclouds.aliyun.ecs.compute.features; +import com.google.common.collect.ImmutableMap; import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest; import org.jclouds.aliyun.ecs.domain.Image; import org.jclouds.aliyun.ecs.domain.Regions; -import org.jclouds.aliyun.ecs.domain.options.ListImagesOptions; -import org.jclouds.aliyun.ecs.domain.options.PaginationOptions; import org.jclouds.collect.IterableWithMarker; import org.testng.annotations.Test; import static com.google.common.collect.Iterables.isEmpty; import static com.google.common.collect.Iterables.size; +import static org.jclouds.aliyun.ecs.domain.options.ListImagesOptions.Builder.paginationOptions; +import static org.jclouds.aliyun.ecs.domain.options.PaginationOptions.Builder.pageNumber; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -36,13 +37,12 @@ public class ImageApiMockTest extends BaseECSComputeServiceApiMockTest { server.enqueue(jsonResponse("/images-first.json")); server.enqueue(jsonResponse("/images-second.json")); server.enqueue(jsonResponse("/images-last.json")); - Iterable<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName()).concat(); assertEquals(size(images), 28); // Force the PagedIterable to advance assertEquals(server.getRequestCount(), 3); - assertSent(server, "GET", "DescribeImages"); - assertSent(server, "GET", "DescribeImages", 2); - assertSent(server, "GET", "DescribeImages", 3); + assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName())); + assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 2); + assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 3); } public void testListImagesReturns404() { @@ -54,26 +54,18 @@ public class ImageApiMockTest extends BaseECSComputeServiceApiMockTest { public void testListImagesWithOptions() throws InterruptedException { server.enqueue(jsonResponse("/images-first.json")); - - IterableWithMarker<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName(), ListImagesOptions.Builder - .paginationOptions(PaginationOptions.Builder.pageNumber(1))); - + IterableWithMarker<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName(), paginationOptions(pageNumber(1))); assertEquals(size(images), 10); assertEquals(server.getRequestCount(), 1); - - assertSent(server, "GET", "DescribeImages", 1); + assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 1); } public void testListImagesWithOptionsReturns404() throws InterruptedException { server.enqueue(response404()); - - IterableWithMarker<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName(), ListImagesOptions.Builder - .paginationOptions(PaginationOptions.Builder.pageNumber(2))); - + IterableWithMarker<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName(), paginationOptions(pageNumber(2))); assertTrue(isEmpty(images)); - assertEquals(server.getRequestCount(), 1); - assertSent(server, "GET", "DescribeImages", 2); + assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 2); } } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiLiveTest.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiLiveTest.java new file mode 100644 index 0000000..91239a1 --- /dev/null +++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiLiveTest.java @@ -0,0 +1,62 @@ +/* + * 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.jclouds.aliyun.ecs.compute.features; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiLiveTest; +import org.jclouds.aliyun.ecs.domain.Region; +import org.jclouds.aliyun.ecs.domain.Zone; +import org.jclouds.aliyun.ecs.features.RegionAndZoneApi; +import org.testng.annotations.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +import static org.testng.Assert.assertTrue; +import static org.testng.util.Strings.isNullOrEmpty; + +@Test(groups = "live", testName = "RegionAndZoneApiLiveTest") +public class RegionAndZoneApiLiveTest extends BaseECSComputeServiceApiLiveTest { + + public void testListRegions() { + final AtomicInteger found = new AtomicInteger(0); + assertTrue(Iterables.all(api().describeRegions(), new Predicate<Region>() { + @Override + public boolean apply(Region input) { + found.incrementAndGet(); + return !isNullOrEmpty(input.regionId()); + } + }), "All regions must have the 'id' field populated"); + assertTrue(found.get() > 0, "Expected some region to be returned"); + } + + public void testListZones() { + final AtomicInteger found = new AtomicInteger(0); + assertTrue(Iterables.all(api().describeZones("eu-central-1"), new Predicate<Zone>() { + @Override + public boolean apply(Zone input) { + found.incrementAndGet(); + return !isNullOrEmpty(input.zoneId()); + } + }), "All zones must have the 'id' field populated"); + assertTrue(found.get() > 0, "Expected some zone to be returned"); + } + + private RegionAndZoneApi api() { + return api.regionAndZoneApi(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java new file mode 100644 index 0000000..291d1b0 --- /dev/null +++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java @@ -0,0 +1,68 @@ +/* + * 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.jclouds.aliyun.ecs.compute.features; + +import com.google.common.collect.ImmutableMap; +import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest; +import org.jclouds.aliyun.ecs.domain.Region; +import org.jclouds.aliyun.ecs.domain.Regions; +import org.jclouds.aliyun.ecs.domain.Zone; +import org.testng.annotations.Test; + +import java.util.List; + +import static com.google.common.collect.Iterables.isEmpty; +import static com.google.common.collect.Iterables.size; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +@Test(groups = "unit", testName = "RegionAndZoneApiMockTest", singleThreaded = true) +public class RegionAndZoneApiMockTest extends BaseECSComputeServiceApiMockTest { + + public void testListRegions() throws InterruptedException { + server.enqueue(jsonResponse("/regions.json")); + List<Region> regions = api.regionAndZoneApi().describeRegions(); + assertEquals(size(regions), 18); + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", "DescribeRegions"); + } + + public void testListRegionsReturns404() throws InterruptedException { + server.enqueue(response404()); + List<Region> regions = api.regionAndZoneApi().describeRegions(); + assertTrue(isEmpty(regions)); + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", "DescribeRegions"); + } + + public void testListZones() throws InterruptedException { + server.enqueue(jsonResponse("/zones.json")); + List<Zone> zones = api.regionAndZoneApi().describeZones(Regions.EU_CENTRAL_1.getName()); + assertEquals(size(zones), 2); + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", "DescribeZones", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName())); + } + + public void testListZonesReturns404() throws InterruptedException { + server.enqueue(response404()); + List<Zone> zones = api.regionAndZoneApi().describeZones(Regions.EU_CENTRAL_1.getName()); + assertTrue(isEmpty(zones)); + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", "DescribeZones", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName())); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/internal/BaseECSComputeServiceApiMockTest.java ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/internal/BaseECSComputeServiceApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/internal/BaseECSComputeServiceApiMockTest.java index 5845339..1b27556 100644 --- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/internal/BaseECSComputeServiceApiMockTest.java +++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/internal/BaseECSComputeServiceApiMockTest.java @@ -19,6 +19,7 @@ package org.jclouds.aliyun.ecs.compute.internal; import com.google.common.base.Charsets; import com.google.common.base.Splitter; import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; import com.google.inject.Module; @@ -42,6 +43,7 @@ import java.util.Set; import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService; import static org.jclouds.Constants.PROPERTY_MAX_RETRIES; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; public class BaseECSComputeServiceApiMockTest { @@ -97,20 +99,25 @@ public class BaseECSComputeServiceApiMockTest { } protected RecordedRequest assertSent(MockWebServer server, String method, String action) throws InterruptedException { - RecordedRequest request = server.takeRequest(); - assertEquals(request.getMethod(), method); - Map<String, String> queryParameters = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(request.getPath()); - assertEquals(queryParameters.get("Action"), action); - assertEquals(request.getHeader("Accept"), "application/json"); - return request; + return assertSent(server, method, action, ImmutableMap.<String, String>of(), null); } - protected RecordedRequest assertSent(MockWebServer server, String method, String action, Integer page) throws InterruptedException { + protected RecordedRequest assertSent(MockWebServer server, String method, String action, Map<String, String> queryParameters) throws InterruptedException { + return assertSent(server, method, action, queryParameters, null); + } + + protected RecordedRequest assertSent(MockWebServer server, String method, String action, Map<String, String> queryParameters, Integer page) throws InterruptedException { RecordedRequest request = server.takeRequest(); assertEquals(request.getMethod(), method); - Map<String, String> queryParameters = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(request.getPath()); - assertEquals(queryParameters.get("Action"), action); - assertEquals(Integer.valueOf(queryParameters.get("pageNumber")), page); + Map<String, String> requestQueryParameters = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(request.getPath()); + assertEquals(requestQueryParameters.get("Action"), action); + + for (Map.Entry<String, String> keyAndValue : queryParameters.entrySet()) { + assertTrue(requestQueryParameters.containsKey(keyAndValue.getKey())); + assertTrue(requestQueryParameters.containsValue(keyAndValue.getValue())); + assertEquals(requestQueryParameters.get(keyAndValue.getKey()), keyAndValue.getValue()); + } + if (page != null) assertEquals(Integer.valueOf(requestQueryParameters.get("pageNumber")), page); assertEquals(request.getHeader("Accept"), "application/json"); return request; } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/test/resources/regions.json ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/test/resources/regions.json b/aliyun-ecs/src/test/resources/regions.json new file mode 100644 index 0000000..734e35c --- /dev/null +++ b/aliyun-ecs/src/test/resources/regions.json @@ -0,0 +1,79 @@ +{ + "RequestId": "A3EF3FCC-020E-4056-9C20-DD9902227CD6", + "Regions": { + "Region": [ + { + "RegionId": "cn-qingdao", + "LocalName": "[0xe5][0x8d][0x8e][0xe5][0x8c][0x97] 1" + }, + { + "RegionId": "cn-beijing", + "LocalName": "[0xe5][0x8d][0x8e][0xe5][0x8c][0x97] 2" + }, + { + "RegionId": "cn-zhangjiakou", + "LocalName": "[0xe5][0x8d][0x8e][0xe5][0x8c][0x97] 3" + }, + { + "RegionId": "cn-huhehaote", + "LocalName": "[0xe5][0x8d][0x8e][0xe5][0x8c][0x97] 5" + }, + { + "RegionId": "cn-hangzhou", + "LocalName": "[0xe5][0x8d][0x8e][0xe4][0xb8][0x9c] 1" + }, + { + "RegionId": "cn-shanghai", + "LocalName": "[0xe5][0x8d][0x8e][0xe4][0xb8][0x9c] 2" + }, + { + "RegionId": "cn-shenzhen", + "LocalName": "[0xe5][0x8d][0x8e][0xe5][0x8d][0x97] 1" + }, + { + "RegionId": "cn-hongkong", + "LocalName": "[0xe9][0xa6][0x99][0xe6][0xb8][0xaf]" + }, + { + "RegionId": "ap-northeast-1", + "LocalName": "[0xe4][0xba][0x9a][0xe5][0xa4][0xaa][0xe4][0xb8][0x9c][0xe5][0x8c][0x97] 1 ([0xe4][0xb8][0x9c][0xe4][0xba][0xac])" + }, + { + "RegionId": "ap-southeast-1", + "LocalName": "[0xe4][0xba][0x9a][0xe5][0xa4][0xaa][0xe4][0xb8][0x9c][0xe5][0x8d][0x97] 1 ([0xe6][0x96][0xb0][0xe5][0x8a][0xa0][0xe5][0x9d][0xa1])" + }, + { + "RegionId": "ap-southeast-2", + "LocalName": "[0xe4][0xba][0x9a][0xe5][0xa4][0xaa][0xe4][0xb8][0x9c][0xe5][0x8d][0x97] 2 ([0xe6][0x82][0x89][0xe5][0xb0][0xbc])" + }, + { + "RegionId": "ap-southeast-3", + "LocalName": "[0xe4][0xba][0x9a][0xe5][0xa4][0xaa][0xe4][0xb8][0x9c][0xe5][0x8d][0x97] 3 ([0xe5][0x90][0x89][0xe9][0x9a][0x86][0xe5][0x9d][0xa1])" + }, + { + "RegionId": "ap-southeast-5", + "LocalName": "[0xe4][0xba][0x9a][0xe5][0xa4][0xaa][0xe4][0xb8][0x9c][0xe5][0x8d][0x97] 5 ([0xe9][0x9b][0x85][0xe5][0x8a][0xa0][0xe8][0xbe][0xbe])" + }, + { + "RegionId": "ap-south-1", + "LocalName": "[0xe4][0xba][0x9a][0xe5][0xa4][0xaa][0xe5][0x8d][0x97][0xe9][0x83][0xa8] 1 ([0xe5][0xad][0x9f][0xe4][0xb9][0xb0])" + }, + { + "RegionId": "us-east-1", + "LocalName": "[0xe7][0xbe][0x8e][0xe5][0x9b][0xbd][0xe4][0xb8][0x9c][0xe9][0x83][0xa8] 1 ([0xe5][0xbc][0x97][0xe5][0x90][0x89][0xe5][0xb0][0xbc][0xe4][0xba][0x9a])" + }, + { + "RegionId": "us-west-1", + "LocalName": "[0xe7][0xbe][0x8e][0xe5][0x9b][0xbd][0xe8][0xa5][0xbf][0xe9][0x83][0xa8] 1 ([0xe7][0xa1][0x85][0xe8][0xb0][0xb7])" + }, + { + "RegionId": "me-east-1", + "LocalName": "[0xe4][0xb8][0xad][0xe4][0xb8][0x9c][0xe4][0xb8][0x9c][0xe9][0x83][0xa8] 1 ([0xe8][0xbf][0xaa][0xe6][0x8b][0x9c])" + }, + { + "RegionId": "eu-central-1", + "LocalName": "[0xe6][0xac][0xa7][0xe6][0xb4][0xb2][0xe4][0xb8][0xad][0xe9][0x83][0xa8] 1 ([0xe6][0xb3][0x95][0xe5][0x85][0xb0][0xe5][0x85][0x8b][0xe7][0xa6][0x8f])" + } + ] + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f38f8045/aliyun-ecs/src/test/resources/zones.json ---------------------------------------------------------------------- diff --git a/aliyun-ecs/src/test/resources/zones.json b/aliyun-ecs/src/test/resources/zones.json new file mode 100644 index 0000000..a76baa8 --- /dev/null +++ b/aliyun-ecs/src/test/resources/zones.json @@ -0,0 +1,477 @@ +{ + "RequestId": "A1E88D60-8179-4524-B4D4-1293A5CD986F", + "Zones": { + "Zone": [ + { + "DedicatedHostGenerations": { + "DedicatedHostGeneration": [] + }, + "AvailableResourceCreation": { + "ResourceTypes": [ + "VSwitch", + "IoOptimized", + "Instance", + "Disk" + ] + }, + "AvailableDedicatedHostTypes": { + "DedicatedHostType": [] + }, + "AvailableResources": { + "ResourcesInfo": [ + { + "IoOptimized": true, + "SystemDiskCategories": { + "supportedSystemDiskCategory": [ + "cloud_ssd", + "cloud_efficiency" + ] + }, + "InstanceTypes": { + "supportedInstanceType": [ + "ecs.hfg5.large", + "ecs.hfc5.xlarge", + "ecs.hfc5.8xlarge", + "ecs.hfc5.4xlarge", + "ecs.se1ne.2xlarge", + "ecs.hfg5.6xlarge", + "ecs.t5-c1m2.4xlarge", + "ecs.se1ne.xlarge", + "ecs.t5-c1m2.2xlarge", + "ecs.hfg5.xlarge", + "ecs.sn2ne.8xlarge", + "ecs.se1ne.4xlarge", + "ecs.sn2ne.4xlarge", + "ecs.sn1ne.8xlarge", + "ecs.t5-c1m1.xlarge", + "ecs.sn2ne.large", + "ecs.sn2ne.xlarge", + "ecs.hfg5.4xlarge", + "ecs.sn1ne.large", + "ecs.t5-c1m4.xlarge", + "ecs.sn1ne.2xlarge", + "ecs.hfc5.2xlarge", + "ecs.t5-lc1m4.large", + "ecs.hfg5.2xlarge", + "ecs.t5-c1m1.4xlarge", + "ecs.t5-c1m2.xlarge", + "ecs.t5-c1m1.large", + "ecs.sn2ne.2xlarge", + "ecs.hfc5.6xlarge", + "ecs.t5-lc1m2.small", + "ecs.t5-c1m4.large", + "ecs.t5-c1m1.2xlarge", + "ecs.sn1ne.4xlarge", + "ecs.t5-lc1m1.small", + "ecs.t5-c1m4.2xlarge", + "ecs.sn1ne.xlarge", + "ecs.se1ne.large", + "ecs.t5-lc1m2.large", + "ecs.hfc5.large", + "ecs.se1ne.8xlarge", + "ecs.t5-lc2m1.nano", + "ecs.t5-c1m2.large" + ] + }, + "InstanceTypeFamilies": { + "supportedInstanceTypeFamily": [ + "ecs.hfc5", + "ecs.sn1ne", + "ecs.hfg5", + "ecs.se1ne", + "ecs.t5", + "ecs.sn2ne" + ] + }, + "DataDiskCategories": { + "supportedDataDiskCategory": [ + "cloud_ssd", + "cloud_efficiency" + ] + }, + "InstanceGenerations": { + "supportedInstanceGeneration": [ + "ecs-3", + "ecs-4" + ] + }, + "NetworkTypes": { + "supportedNetworkCategory": [ + "vpc" + ] + } + } + ] + }, + "AvailableInstanceTypes": { + "InstanceTypes": [ + "ecs.hfc5.xlarge", + "ecs.hfc5.8xlarge", + "ecs.t5-c1m2.4xlarge", + "ecs.hfg5.6xlarge", + "ecs.se1ne.2xlarge", + "ecs.sn1ne.3xlarge", + "ecs.sn2ne.3xlarge", + "ecs.t5-c1m2.2xlarge", + "ecs.se1ne.3xlarge", + "ecs.hfg5.xlarge", + "ecs.sn2ne.8xlarge", + "ecs.hfg5.3xlarge", + "ecs.sn2ne.4xlarge", + "ecs.sn1ne.8xlarge", + "ecs.sn2ne.large", + "ecs.sn2ne.xlarge", + "ecs.hfg5.4xlarge", + "ecs.hfc5.2xlarge", + "ecs.sn1ne.2xlarge", + "ecs.se1ne.6xlarge", + "ecs.sn2ne.2xlarge", + "ecs.hfc5.3xlarge", + "ecs.sn2ne.6xlarge", + "ecs.t5-lc1m2.small", + "ecs.t5-c1m4.large", + "ecs.t5-lc1m1.small", + "ecs.t5-c1m4.2xlarge", + "ecs.sn1ne.xlarge", + "ecs.se1ne.large", + "ecs.t5-lc1m2.large", + "ecs.t5-c1m2.large", + "ecs.hfg5.large", + "ecs.hfc5.4xlarge", + "ecs.se1ne.xlarge", + "ecs.se1ne.4xlarge", + "ecs.t5-c1m1.xlarge", + "ecs.sn1ne.large", + "ecs.t5-c1m4.xlarge", + "ecs.sn1ne.6xlarge", + "ecs.t5-lc1m4.large", + "ecs.hfg5.2xlarge", + "ecs.t5-c1m1.4xlarge", + "ecs.t5-c1m2.xlarge", + "ecs.t5-c1m1.large", + "ecs.hfc5.6xlarge", + "ecs.sn1ne.4xlarge", + "ecs.t5-c1m1.2xlarge", + "ecs.hfc5.large", + "ecs.se1ne.8xlarge", + "ecs.t5-lc2m1.nano" + ] + }, + "ZoneId": "eu-central-1b", + "AvailableVolumeCategories": { + "VolumeCategories": [ + "san_ssd", + "san_efficiency" + ] + }, + "LocalName": "[0xe6][0xac][0xa7][0xe6][0xb4][0xb2][0xe4][0xb8][0xad][0xe9][0x83][0xa8]1 [0xe5][0x8f][0xaf][0xe7][0x94][0xa8][0xe5][0x8c][0xba]B", + "AvailableDiskCategories": { + "DiskCategories": [ + "cloud_ssd", + "cloud_efficiency" + ] + } + }, + { + "DedicatedHostGenerations": { + "DedicatedHostGeneration": [ + "ddh-3" + ] + }, + "AvailableResourceCreation": { + "ResourceTypes": [ + "IoOptimized", + "VSwitch", + "Instance", + "DedicatedHost", + "Disk" + ] + }, + "AvailableDedicatedHostTypes": { + "DedicatedHostType": [ + "ddh.se1ne" + ] + }, + "AvailableResources": { + "ResourcesInfo": [ + { + "IoOptimized": true, + "SystemDiskCategories": { + "supportedSystemDiskCategory": [ + "cloud_ssd", + "cloud_efficiency" + ] + }, + "InstanceTypes": { + "supportedInstanceType": [ + "ecs.hfc5.xlarge", + "ecs.hfc5.8xlarge", + "ecs.hfg5.8xlarge", + "ecs.n4.4xlarge", + "ecs.sn2.7xlarge", + "ecs.sn2ne.14xlarge", + "ecs.sn2.medium", + "ecs.gn5-c48g1.12xlarge", + "ecs.n4.xlarge", + "ecs.se1.large", + "ecs.t5-c1m2.4xlarge", + "ecs.hfg5.6xlarge", + "ecs.se1ne.2xlarge", + "ecs.t5-c1m2.2xlarge", + "ecs.hfg5.xlarge", + "ecs.xn4.small", + "ecs.se1.14xlarge", + "ecs.sn2ne.8xlarge", + "ecs.sn2ne.4xlarge", + "ecs.mn4.large", + "ecs.sn1ne.8xlarge", + "ecs.sn1.7xlarge", + "ecs.mn4.2xlarge", + "ecs.mn4.8xlarge", + "ecs.n4.2xlarge", + "ecs.sn2ne.large", + "ecs.hfg5.4xlarge", + "ecs.sn2ne.xlarge", + "ecs.hfc5.2xlarge", + "ecs.sn1ne.2xlarge", + "ecs.e4.small", + "ecs.i1.4xlarge", + "ecs.i2.16xlarge", + "ecs.sn2ne.2xlarge", + "ecs.se1.8xlarge", + "ecs.t5-lc1m2.small", + "ecs.t5-c1m4.large", + "ecs.sn2.3xlarge", + "ecs.n4.small", + "ecs.t5-lc1m1.small", + "ecs.i2.xlarge", + "ecs.se1ne.large", + "ecs.t5-c1m4.2xlarge", + "ecs.sn1ne.xlarge", + "ecs.t5-lc1m2.large", + "ecs.sn2.large", + "ecs.i2.2xlarge", + "ecs.sn1.large", + "ecs.t5-c1m2.large", + "ecs.mn4.xlarge", + "ecs.se1.xlarge", + "ecs.gn5-c8g1.4xlarge", + "ecs.hfg5.large", + "ecs.i1.8xlarge", + "ecs.gn5-c4g1.xlarge", + "ecs.hfc5.4xlarge", + "ecs.gn5-c8g1.2xlarge", + "ecs.se1.2xlarge", + "ecs.i1.2xlarge", + "ecs.se1ne.14xlarge", + "ecs.sn2.xlarge", + "ecs.se1ne.xlarge", + "ecs.se1ne.4xlarge", + "ecs.sn1.medium", + "ecs.n4.8xlarge", + "ecs.t5-c1m1.xlarge", + "ecs.sn1ne.large", + "ecs.t5-c1m4.xlarge", + "ecs.n4.large", + "ecs.sn1.3xlarge", + "ecs.hfg5.2xlarge", + "ecs.t5-lc1m4.large", + "ecs.t5-c1m1.4xlarge", + "ecs.gn5-c4g1.2xlarge", + "ecs.se1.4xlarge", + "ecs.t5-c1m2.xlarge", + "ecs.t5-c1m1.large", + "ecs.sn2.13xlarge", + "ecs.i2.8xlarge", + "ecs.i1.14xlarge", + "ecs.hfc5.6xlarge", + "ecs.i2.4xlarge", + "ecs.i1.xlarge", + "ecs.sn1ne.4xlarge", + "ecs.t5-c1m1.2xlarge", + "ecs.mn4.4xlarge", + "ecs.hfc5.large", + "ecs.se1ne.8xlarge", + "ecs.sn1.xlarge", + "ecs.t5-lc2m1.nano", + "ecs.mn4.small" + ] + }, + "InstanceTypeFamilies": { + "supportedInstanceTypeFamily": [ + "ecs.hfc5", + "ecs.gn5", + "ecs.sn1ne", + "ecs.hfg5", + "ecs.t5", + "ecs.mn4", + "ecs.sn1", + "ecs.sn2", + "ecs.d1", + "ecs.xn4", + "ecs.i1", + "ecs.n4", + "ecs.se1ne", + "ecs.e4", + "ecs.se1", + "ecs.i2", + "ecs.sn2ne" + ] + }, + "DataDiskCategories": { + "supportedDataDiskCategory": [ + "cloud_ssd", + "cloud_efficiency" + ] + }, + "InstanceGenerations": { + "supportedInstanceGeneration": [ + "ecs-3", + "ecs-2", + "ecs-4" + ] + }, + "NetworkTypes": { + "supportedNetworkCategory": [ + "vpc" + ] + } + } + ] + }, + "AvailableInstanceTypes": { + "InstanceTypes": [ + "ecs.hfc5.xlarge", + "ecs.hfg5.8xlarge", + "ecs.sn2.7xlarge", + "ecs.sn2ne.14xlarge", + "ecs.sn2.medium", + "ecs.n4.xlarge", + "ecs.t5-c1m2.4xlarge", + "ecs.se1.large", + "ecs.sn1ne.3xlarge", + "ecs.sn2ne.3xlarge", + "ecs.t5-c1m2.2xlarge", + "ecs.xn4.small", + "ecs.se1ne.3xlarge", + "ecs.i1.3xlarge", + "ecs.sn2ne.8xlarge", + "ecs.hfg5.3xlarge", + "ecs.mn4.large", + "ecs.sn1.7xlarge", + "ecs.mn4.8xlarge", + "ecs.n4.2xlarge", + "ecs.hfg5.4xlarge", + "ecs.hfc5.2xlarge", + "ecs.i1.4xlarge", + "ecs.i2.16xlarge", + "ecs.se1.8xlarge", + "ecs.hfc5.3xlarge", + "ecs.t5-lc1m2.small", + "ecs.sn2.3xlarge", + "ecs.t5-lc1m1.small", + "ecs.i2.xlarge", + "ecs.t5-c1m4.2xlarge", + "ecs.se1ne.large", + "ecs.i2.2xlarge", + "ecs.sn1.large", + "ecs.mn4.xlarge", + "ecs.hfg5.large", + "ecs.gn5-c4g1.xlarge", + "ecs.hfc5.4xlarge", + "ecs.gn5-c8g1.2xlarge", + "ecs.i1.2xlarge", + "ecs.se1ne.xlarge", + "ecs.d1-c8d3.8xlarge", + "ecs.se1ne.4xlarge", + "ecs.sn1.medium", + "ecs.n4.8xlarge", + "ecs.e4.xlarge", + "ecs.n4.large", + "ecs.sn1ne.6xlarge", + "ecs.t5-lc1m4.large", + "ecs.t5-c1m1.4xlarge", + "ecs.d1.2xlarge", + "ecs.se1.4xlarge", + "ecs.t5-c1m2.xlarge", + "ecs.t5-c1m1.large", + "ecs.i2.8xlarge", + "ecs.i1.14xlarge", + "ecs.hfc5.6xlarge", + "ecs.i2.4xlarge", + "ecs.t5-c1m1.2xlarge", + "ecs.t5-lc2m1.nano", + "ecs.sn1.xlarge", + "ecs.hfc5.8xlarge", + "ecs.n4.4xlarge", + "ecs.gn5-c48g1.12xlarge", + "ecs.hfg5.6xlarge", + "ecs.se1ne.2xlarge", + "ecs.i1.6xlarge", + "ecs.hfg5.xlarge", + "ecs.se1.14xlarge", + "ecs.sn2ne.4xlarge", + "ecs.sn1ne.8xlarge", + "ecs.mn4.2xlarge", + "ecs.sn2ne.large", + "ecs.sn2ne.xlarge", + "ecs.i1-c10d1.8xlarge", + "ecs.e4.4xlarge", + "ecs.sn1ne.2xlarge", + "ecs.e4.small", + "ecs.se1ne.6xlarge", + "ecs.sn2ne.2xlarge", + "ecs.sn2ne.6xlarge", + "ecs.t5-c1m4.large", + "ecs.n4.small", + "ecs.gn5-c28g1.14xlarge", + "ecs.sn1ne.xlarge", + "ecs.t5-lc1m2.large", + "ecs.sn2.large", + "ecs.i1-c5d1.4xlarge", + "ecs.t5-c1m2.large", + "ecs.d1.6xlarge", + "ecs.se1.xlarge", + "ecs.gn5-c8g1.4xlarge", + "ecs.i1.8xlarge", + "ecs.e4.large", + "ecs.se1.2xlarge", + "ecs.se1ne.14xlarge", + "ecs.sn2.xlarge", + "ecs.gn5-c28g1.7xlarge", + "ecs.e4.2xlarge", + "ecs.t5-c1m1.xlarge", + "ecs.sn1ne.large", + "ecs.t5-c1m4.xlarge", + "ecs.sn1.3xlarge", + "ecs.hfg5.2xlarge", + "ecs.d1.4xlarge", + "ecs.gn5-c4g1.2xlarge", + "ecs.sn2.13xlarge", + "ecs.i1.xlarge", + "ecs.sn1ne.4xlarge", + "ecs.mn4.4xlarge", + "ecs.d1-c14d3.14xlarge", + "ecs.hfc5.large", + "ecs.se1ne.8xlarge", + "ecs.mn4.small" + ] + }, + "ZoneId": "eu-central-1a", + "AvailableVolumeCategories": { + "VolumeCategories": [ + "san_ssd", + "san_efficiency" + ] + }, + "LocalName": "[0xe6][0xac][0xa7][0xe6][0xb4][0xb2][0xe4][0xb8][0xad][0xe9][0x83][0xa8]1 [0xe5][0x8f][0xaf][0xe7][0x94][0xa8][0xe5][0x8c][0xba]A", + "AvailableDiskCategories": { + "DiskCategories": [ + "cloud_ssd", + "cloud_efficiency" + ] + } + } + ] + } +} \ No newline at end of file
