From b49fc853cb91a586d0e16416b33bf69f5a27b59d Mon Sep 17 00:00:00 2001 From: Suriya priya Date: Sun, 12 Oct 2014 23:52:48 -0700 Subject: [PATCH] Initial GCE commit --- .../pom.xml | 5 + .../cloud/controller/iaases/GCEIaas.java | 464 +++++++ .../validate/GCEPartitionValidator.java | 54 + .../jclouds/apis/gce/1.8.0-stratos/README.txt | 77 ++ .../jclouds/apis/gce/1.8.0-stratos/pom.xml | 135 ++ .../GoogleComputeEngineApi.java | 185 +++ .../GoogleComputeEngineApiMetadata.java | 104 ++ .../GoogleComputeEngineConstants.java | 81 ++ .../compute/GoogleComputeEngineService.java | 200 +++ .../GoogleComputeEngineServiceAdapter.java | 439 ++++++ ...ogleComputeEngineServiceContextModule.java | 283 ++++ ...leComputeEngineSecurityGroupExtension.java | 338 +++++ .../functions/BuildInstanceMetadata.java | 46 + .../FirewallTagNamingConvention.java | 62 + .../functions/FirewallToIpPermission.java | 87 ++ .../GoogleComputeEngineImageToImage.java | 80 ++ .../InstanceInZoneToNodeMetadata.java | 150 +++ .../MachineTypeInZoneToHardware.java | 100 ++ .../functions/NetworkToSecurityGroup.java | 82 ++ .../OrphanedGroupsFromDeadNodes.java | 57 + .../compute/functions/RegionToLocation.java | 45 + .../compute/functions/ZoneToLocation.java | 45 + .../compute/loaders/FindNetworkOrCreate.java | 62 + .../GoogleComputeEngineTemplateOptions.java | 382 ++++++ .../predicates/AllNodesInGroupTerminated.java | 48 + ...sWithGroupEncodedIntoNameThenAddToSet.java | 183 +++ ...faultLoginCredentialsForImageStrategy.java | 69 + ...odeCredentialsButOverrideFromTemplate.java | 57 + .../GoogleComputeEngineHttpApiModule.java | 177 +++ .../GoogleComputeEngineParserModule.java | 413 ++++++ .../OAuthModuleWithoutTypeAdapters.java | 51 + .../config/UserProject.java | 33 + .../domain/AbstractDisk.java | 121 ++ .../googlecomputeengine/domain/Address.java | 177 +++ .../domain/Deprecated.java | 195 +++ .../googlecomputeengine/domain/Disk.java | 123 ++ .../googlecomputeengine/domain/Firewall.java | 379 ++++++ .../googlecomputeengine/domain/Image.java | 286 ++++ .../googlecomputeengine/domain/Instance.java | 1187 +++++++++++++++++ .../domain/InstanceInZone.java | 52 + .../domain/InstanceTemplate.java | 445 ++++++ .../googlecomputeengine/domain/ListPage.java | 179 +++ .../domain/MachineType.java | 360 +++++ .../domain/MachineTypeInZone.java | 52 + .../googlecomputeengine/domain/Metadata.java | 139 ++ .../googlecomputeengine/domain/Network.java | 133 ++ .../googlecomputeengine/domain/Operation.java | 556 ++++++++ .../googlecomputeengine/domain/Project.java | 162 +++ .../googlecomputeengine/domain/Quota.java | 152 +++ .../googlecomputeengine/domain/Region.java | 175 +++ .../googlecomputeengine/domain/Resource.java | 283 ++++ .../googlecomputeengine/domain/Route.java | 433 ++++++ .../domain/SlashEncodedIds.java | 83 ++ .../googlecomputeengine/domain/Snapshot.java | 135 ++ .../googlecomputeengine/domain/Zone.java | 334 +++++ .../internal/NetworkAndAddressRange.java | 91 ++ .../features/AddressApi.java | 187 +++ .../googlecomputeengine/features/DiskApi.java | 255 ++++ .../features/FirewallApi.java | 227 ++++ .../features/GlobalOperationApi.java | 158 +++ .../features/ImageApi.java | 167 +++ .../features/InstanceApi.java | 381 ++++++ .../features/MachineTypeApi.java | 143 ++ .../features/NetworkApi.java | 204 +++ .../features/ProjectApi.java | 96 ++ .../features/RegionApi.java | 135 ++ .../features/RegionOperationApi.java | 163 +++ .../features/RouteApi.java | 184 +++ .../features/SnapshotApi.java | 160 +++ .../googlecomputeengine/features/ZoneApi.java | 135 ++ .../features/ZoneOperationApi.java | 163 +++ .../functions/CreateNetworkIfNeeded.java | 100 ++ .../internal/BaseToPagedIterable.java | 66 + .../BaseWithRegionToPagedIterable.java | 72 + .../internal/BaseWithZoneToPagedIterable.java | 72 + .../functions/internal/PATCH.java | 35 + .../functions/internal/ParseAddresses.java | 67 + .../functions/internal/ParseDisks.java | 67 + .../functions/internal/ParseFirewalls.java | 63 + .../internal/ParseGlobalOperations.java | 63 + .../functions/internal/ParseImages.java | 63 + .../functions/internal/ParseInstances.java | 65 + .../functions/internal/ParseMachineTypes.java | 64 + .../functions/internal/ParseNetworks.java | 63 + .../internal/ParseRegionOperations.java | 65 + .../functions/internal/ParseRegions.java | 63 + .../functions/internal/ParseRoutes.java | 63 + .../functions/internal/ParseSnapshots.java | 66 + .../internal/ParseZoneOperations.java | 65 + .../functions/internal/ParseZones.java | 63 + .../handlers/FirewallBinder.java | 56 + .../GoogleComputeEngineErrorHandler.java | 62 + .../handlers/InstanceBinder.java | 65 + .../handlers/MetadataBinder.java | 60 + .../handlers/RouteBinder.java | 56 + .../options/AttachDiskOptions.java | 128 ++ .../options/DeprecateOptions.java | 126 ++ .../options/FirewallOptions.java | 166 +++ .../options/ListOptions.java | 91 ++ .../options/RouteOptions.java | 202 +++ .../GlobalOperationDonePredicate.java | 59 + .../predicates/InstancePredicates.java | 33 + .../predicates/NetworkFirewallPredicates.java | 121 ++ .../RegionOperationDonePredicate.java | 69 + .../ZoneOperationDonePredicate.java | 68 + .../java/org/jclouds/oauth/v2/OAuthApi.java | 63 + .../jclouds/oauth/v2/OAuthApiMetadata.java | 80 ++ .../org/jclouds/oauth/v2/OAuthConstants.java | 78 ++ .../oauth/v2/config/Authentication.java | 35 + .../v2/config/OAuthAuthenticationModule.java | 52 + .../oauth/v2/config/OAuthHttpApiModule.java | 45 + .../jclouds/oauth/v2/config/OAuthModule.java | 86 ++ .../oauth/v2/config/OAuthProperties.java | 43 + .../jclouds/oauth/v2/config/OAuthScopes.java | 40 + .../org/jclouds/oauth/v2/domain/ClaimSet.java | 191 +++ .../org/jclouds/oauth/v2/domain/Header.java | 128 ++ .../oauth/v2/domain/OAuthCredentials.java | 129 ++ .../org/jclouds/oauth/v2/domain/Token.java | 149 +++ .../jclouds/oauth/v2/domain/TokenRequest.java | 131 ++ .../oauth/v2/domain/TokenRequestFormat.java | 45 + .../oauth/v2/filters/OAuthAuthenticator.java | 63 + .../oauth/v2/functions/BuildTokenRequest.java | 135 ++ .../oauth/v2/functions/FetchToken.java | 41 + .../functions/OAuthCredentialsSupplier.java | 125 ++ .../functions/SignOrProduceMacForToken.java | 119 ++ .../oauth/v2/handlers/OAuthErrorHandler.java | 64 + .../oauth/v2/handlers/OAuthTokenBinder.java | 45 + .../oauth/v2/json/ClaimSetTypeAdapter.java | 59 + .../oauth/v2/json/HeaderTypeAdapter.java | 52 + .../oauth/v2/json/JWTTokenRequestFormat.java | 96 ++ .../services/org.jclouds.apis.ApiMetadata | 19 + .../GoogleComputeEngineApiMetadataTest.java | 38 + ...ngineAuthenticatedRestContextLiveTest.java | 33 + .../PageSystemExpectTest.java | 114 ++ .../GoogleComputeEngineServiceExpectTest.java | 574 ++++++++ .../GoogleComputeEngineServiceLiveTest.java | 128 ++ ...eEngineSecurityGroupExtensionLiveTest.java | 28 + .../functions/FirewallToIpPermissionTest.java | 93 ++ .../GoogleComputeEngineImageToImageTest.java | 60 + .../InstanceInZoneToNodeMetadataTest.java | 286 ++++ .../functions/NetworkToSecurityGroupTest.java | 94 ++ .../OrphanedGroupsFromDeadNodesTest.java | 136 ++ .../loaders/FindNetworkOrCreateTest.java | 141 ++ .../features/AddressApiExpectTest.java | 163 +++ .../features/AddressApiLiveTest.java | 71 + .../features/DiskApiExpectTest.java | 226 ++++ .../features/DiskApiLiveTest.java | 85 ++ .../features/FirewallApiExpectTest.java | 301 +++++ .../features/FirewallApiLiveTest.java | 163 +++ .../GlobalOperationApiExpectTest.java | 158 +++ .../features/GlobalOperationApiLiveTest.java | 91 ++ .../features/ImageApiExpectTest.java | 159 +++ .../features/ImageApiLiveTest.java | 74 + .../features/InstanceApiExpectTest.java | 410 ++++++ .../features/InstanceApiLiveTest.java | 240 ++++ .../features/MachineTypeApiExpectTest.java | 113 ++ .../features/MachineTypeApiLiveTest.java | 73 + .../features/NetworkApiExpectTest.java | 164 +++ .../features/NetworkApiLiveTest.java | 83 ++ .../features/ProjectApiExpectTest.java | 96 ++ .../features/ProjectApiLiveTest.java | 123 ++ .../features/RegionApiExpectTest.java | 94 ++ .../features/RegionApiLiveTest.java | 74 + .../RegionOperationApiExpectTest.java | 195 +++ .../features/RegionOperationApiLiveTest.java | 91 ++ .../features/RouteApiExpectTest.java | 175 +++ .../features/RouteApiLiveTest.java | 96 ++ .../features/SnapshotApiExpectTest.java | 94 ++ .../features/SnapshotApiLiveTest.java | 92 ++ .../features/ZoneApiExpectTest.java | 97 ++ .../features/ZoneApiLiveTest.java | 74 + .../features/ZoneOperationApiExpectTest.java | 193 +++ .../features/ZoneOperationApiLiveTest.java | 90 ++ .../functions/CreateNetworkIfNeededTest.java | 132 ++ .../GoogleComputeEngineErrorHandlerTest.java | 92 ++ .../BaseGoogleComputeEngineApiExpectTest.java | 31 + .../BaseGoogleComputeEngineApiLiveTest.java | 160 +++ .../BaseGoogleComputeEngineExpectTest.java | 195 +++ .../BaseGoogleComputeEngineParseTest.java | 33 + ...ComputeEngineServiceContextExpectTest.java | 49 + ...eGoogleComputeEngineServiceExpectTest.java | 28 + .../parse/ParseAddressListTest.java | 61 + .../parse/ParseAddressTest.java | 51 + .../parse/ParseDiskListTest.java | 61 + .../parse/ParseDiskTest.java | 50 + .../parse/ParseFirewallListTest.java | 68 + .../parse/ParseFirewallTest.java | 60 + .../parse/ParseImageListTest.java | 71 + .../parse/ParseImageTest.java | 55 + .../parse/ParseInstanceListTest.java | 48 + .../parse/ParseInstanceSerialOutputTest.java | 38 + .../parse/ParseInstanceTest.java | 81 ++ .../parse/ParseMachineTypeListTest.java | 94 ++ .../parse/ParseMachineTypeTest.java | 57 + .../parse/ParseMetadataTest.java | 45 + .../parse/ParseNetworkListTest.java | 49 + .../parse/ParseNetworkTest.java | 48 + .../parse/ParseOperationListTest.java | 46 + .../parse/ParseOperationTest.java | 58 + .../parse/ParseProjectTest.java | 67 + .../parse/ParseQuotaTest.java | 39 + .../parse/ParseRegionListTest.java | 72 + .../parse/ParseRegionTest.java | 62 + .../parse/ParseRouteListTest.java | 62 + .../parse/ParseRouteTest.java | 56 + .../parse/ParseSnapshotListTest.java | 64 + .../parse/ParseSnapshotTest.java | 52 + .../parse/ParseZoneListTest.java | 70 + .../parse/ParseZoneTest.java | 55 + .../NetworkFirewallPredicatesTest.java | 162 +++ .../oauth/v2/OAuthApiMetadataTest.java | 38 + .../org/jclouds/oauth/v2/OAuthTestUtils.java | 75 ++ .../oauth/v2/features/OAuthApiExpectTest.java | 99 ++ .../oauth/v2/features/OAuthApiLiveTest.java | 80 ++ .../functions/OAuthCredentialsFromPKTest.java | 61 + .../OAuthCredentialsSupplierTest.java | 55 + .../v2/functions/SignerFunctionTest.java | 61 + .../v2/handlers/OAuthErrorHandlerTest.java | 92 ++ .../oauth/v2/internal/Base64UrlSafeTest.java | 40 + .../v2/internal/BaseOAuthApiExpectTest.java | 23 + .../v2/internal/BaseOAuthApiLiveTest.java | 56 + .../BaseOAuthAuthenticatedApiLiveTest.java | 110 ++ .../v2/internal/BaseOAuthExpectTest.java | 26 + .../v2/json/JWTTokenRequestFormatTest.java | 69 + .../oauth/v2/parse/ParseTokenTest.java | 40 + .../firewall_list.json | 37 + .../network_get.json | 10 + .../src/test/resources/address_get.json | 12 + .../src/test/resources/address_insert.json | 1 + .../src/test/resources/address_list.json | 31 + .../test/resources/disk_create_snapshot.json | 1 + .../src/test/resources/disk_get.json | 10 + .../src/test/resources/disk_insert.json | 1 + .../src/test/resources/disk_list.json | 17 + .../src/test/resources/firewall_get.json | 30 + .../src/test/resources/firewall_insert.json | 1 + .../src/test/resources/firewall_list.json | 58 + .../src/test/resources/global_operation.json | 15 + .../test/resources/global_operation_list.json | 22 + .../src/test/resources/image_get.json | 13 + .../src/test/resources/image_insert.json | 4 + .../src/test/resources/image_list.json | 24 + .../src/test/resources/image_list_empty.json | 6 + .../resources/image_list_multiple_page_1.json | 55 + .../resources/image_list_multiple_page_2.json | 47 + .../resources/image_list_single_page.json | 50 + .../resources/instance_add_access_config.json | 11 + .../test/resources/instance_attach_disk.json | 6 + .../src/test/resources/instance_get.json | 62 + .../src/test/resources/instance_insert.json | 1 + .../resources/instance_insert_simple.json | 1 + .../src/test/resources/instance_list.json | 69 + .../instance_list_central1b_empty.json | 6 + .../test/resources/instance_serial_port.json | 4 + .../test/resources/instance_set_metadata.json | 10 + .../src/test/resources/logback.xml | 83 ++ .../src/test/resources/machinetype.json | 22 + .../src/test/resources/machinetype_list.json | 57 + .../resources/machinetype_list_central1b.json | 43 + .../machinetype_list_central1b_empty.json | 6 + .../src/test/resources/metadata.json | 1 + .../src/test/resources/network_get.json | 10 + .../src/test/resources/network_insert.json | 1 + .../src/test/resources/network_list.json | 18 + .../src/test/resources/operation.json | 17 + .../src/test/resources/operation_error.json | 26 + .../src/test/resources/operation_list.json | 24 + .../src/test/resources/project.json | 69 + .../src/test/resources/quota.json | 5 + .../src/test/resources/region_get.json | 60 + .../src/test/resources/region_list.json | 126 ++ .../src/test/resources/region_operation.json | 16 + .../test/resources/region_operation_list.json | 23 + .../src/test/resources/route_get.json | 14 + .../src/test/resources/route_insert.json | 1 + .../src/test/resources/route_list.json | 34 + .../src/test/resources/snapshot_get.json | 13 + .../src/test/resources/snapshot_list.json | 33 + .../src/test/resources/tag_insert.json | 1 + .../src/test/resources/testpk.pem | 15 + .../src/test/resources/tokenResponse.json | 5 + .../src/test/resources/zone_get.json | 17 + .../src/test/resources/zone_list.json | 41 + .../src/test/resources/zone_list_short.json | 24 + .../src/test/resources/zone_operation.json | 16 + .../test/resources/zone_operation_error.json | 25 + .../test/resources/zone_operation_list.json | 23 + dependencies/pom.xml | 1 + .../pom.xml | 6 + tools/puppet3-agent/config-gce.sh | 101 ++ tools/puppet3-agent/init-gce.sh | 146 ++ tools/stratos-installer/conf/setup.conf | 4 + .../all/repository/conf/cloud-controller.xml | 8 + tools/stratos-installer/ec2.sh | 2 + tools/stratos-installer/gce.sh | 67 + tools/stratos-installer/openstack.sh | 2 + tools/stratos-installer/setup.sh | 12 +- tools/stratos-installer/vcloud.sh | 2 + 298 files changed, 29468 insertions(+), 1 deletion(-) create mode 100644 components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/GCEIaas.java create mode 100644 components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/validate/GCEPartitionValidator.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/README.txt create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/pom.xml create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/BuildInstanceMetadata.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermission.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImage.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadata.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/MachineTypeInZoneToHardware.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodes.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/RegionToLocation.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ZoneToLocation.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreate.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/PopulateDefaultLoginCredentialsForImageStrategy.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/UseNodeCredentialsButOverrideFromTemplate.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/OAuthModuleWithoutTypeAdapters.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/UserProject.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/AbstractDisk.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Address.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Deprecated.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Disk.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Firewall.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Image.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Instance.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/InstanceInZone.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/InstanceTemplate.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/ListPage.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/MachineType.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/MachineTypeInZone.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Metadata.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Operation.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Project.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Quota.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Region.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Resource.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Route.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/SlashEncodedIds.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Snapshot.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Zone.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/internal/NetworkAndAddressRange.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/DiskApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/GlobalOperationApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ImageApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/MachineTypeApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ProjectApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RegionApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RegionOperationApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/SnapshotApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ZoneApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ZoneOperationApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeeded.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseToPagedIterable.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToPagedIterable.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToPagedIterable.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/PATCH.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseAddresses.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseDisks.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseFirewalls.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseImages.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseInstances.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseMachineTypes.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseNetworks.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegions.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRoutes.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseSnapshots.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZones.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/FirewallBinder.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/GoogleComputeEngineErrorHandler.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/InstanceBinder.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/MetadataBinder.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/RouteBinder.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/AttachDiskOptions.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/DeprecateOptions.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/FirewallOptions.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/ListOptions.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/RouteOptions.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/InstancePredicates.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthApi.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/Authentication.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/Header.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/Token.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineAuthenticatedRestContextLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/PageSystemExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtensionLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermissionTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadataTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreateTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/MachineTypeApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/MachineTypeApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeededTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/handlers/GoogleComputeEngineErrorHandlerTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineParseTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineServiceContextExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineServiceExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseAddressListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseAddressTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseDiskListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseDiskTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseImageListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseImageTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceSerialOutputTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMachineTypeListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMachineTypeTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMetadataTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseNetworkListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseNetworkTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseProjectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseQuotaTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRouteListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRouteTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseSnapshotListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseSnapshotTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneListTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/GoogleComputeEngineServiceExpectTest/firewall_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/GoogleComputeEngineServiceExpectTest/network_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_insert.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_create_snapshot.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_insert.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_insert.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/global_operation.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/global_operation_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_insert.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_empty.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_multiple_page_1.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_multiple_page_2.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_single_page.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_add_access_config.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_attach_disk.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_insert.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_insert_simple.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_list_central1b_empty.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_serial_port.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_set_metadata.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/logback.xml create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list_central1b.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list_central1b_empty.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/metadata.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_insert.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation_error.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/project.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/quota.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_operation.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_operation_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_insert.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/snapshot_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/snapshot_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/tag_insert.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/testpk.pem create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/tokenResponse.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_get.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_list.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_list_short.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation_error.json create mode 100644 dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation_list.json create mode 100644 tools/puppet3-agent/config-gce.sh create mode 100644 tools/puppet3-agent/init-gce.sh create mode 100755 tools/stratos-installer/gce.sh diff --git a/components/org.apache.stratos.cloud.controller/pom.xml b/components/org.apache.stratos.cloud.controller/pom.xml index 59eaa46f06..c66dd7daf4 100644 --- a/components/org.apache.stratos.cloud.controller/pom.xml +++ b/components/org.apache.stratos.cloud.controller/pom.xml @@ -253,6 +253,11 @@ vcloud 1.8.0-stratos + + org.apache.stratos + gce + 1.8.0-stratos + com.jamesmurty.utils.wso2 diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/GCEIaas.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/GCEIaas.java new file mode 100644 index 0000000000..78588df27e --- /dev/null +++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/GCEIaas.java @@ -0,0 +1,464 @@ +/* + * 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.stratos.cloud.controller.iaases; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.stratos.cloud.controller.exception.CloudControllerException; +import org.apache.stratos.cloud.controller.interfaces.Iaas; +import org.apache.stratos.cloud.controller.jcloud.ComputeServiceBuilderUtil; +import org.apache.stratos.cloud.controller.pojo.IaasProvider; +import org.apache.stratos.cloud.controller.pojo.NetworkInterface; +import org.apache.stratos.cloud.controller.validate.GCEPartitionValidator; +import org.apache.stratos.cloud.controller.validate.interfaces.PartitionValidator; +import org.apache.stratos.cloud.controller.exception.InvalidHostException; +import org.apache.stratos.cloud.controller.exception.InvalidRegionException; +import org.apache.stratos.cloud.controller.exception.InvalidZoneException; +import org.jclouds.ContextBuilder; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.domain.TemplateBuilder; +import org.jclouds.compute.options.TemplateOptions; +import org.wso2.carbon.utils.CarbonUtils; +import org.jclouds.domain.Location; +import org.apache.stratos.cloud.controller.util.CloudControllerConstants; +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.features.DiskApi; +import org.jclouds.googlecomputeengine.features.InstanceApi; +import org.jclouds.googlecomputeengine.features.RegionApi; +import org.jclouds.googlecomputeengine.features.ZoneApi; +import org.jclouds.googlecomputeengine.domain.Disk; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.Region; +import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions.DiskType; +import com.google.inject.Key; +import com.google.inject.Injector; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; +import static org.jclouds.util.Predicates2.retry; +import static java.util.concurrent.TimeUnit.SECONDS; +import com.google.common.base.Predicate; +import java.util.concurrent.atomic.AtomicReference; +import com.google.common.util.concurrent.Atomics; + +public class GCEIaas extends Iaas { + + + private static final Log log = LogFactory.getLog(GCEIaas.class); + + private static final String PROJECTNAME = "projectName"; + + public GCEIaas(IaasProvider iaasProvider) { + super(iaasProvider); + } + + @Override + public void buildComputeServiceAndTemplate() { + + IaasProvider iaasInfo = getIaasProvider(); + + // builds and sets Compute Service + ComputeServiceBuilderUtil.buildDefaultComputeService(iaasInfo); + + + // builds and sets Template + buildTemplate(); + + } + + public void buildTemplate() { + IaasProvider iaasInfo = getIaasProvider(); + + if (iaasInfo.getComputeService() == null) { + String msg = "Compute service is null for IaaS provider: " + + iaasInfo.getName(); + log.fatal(msg); + throw new CloudControllerException(msg); + } + + log.info("gce buildTemplate"); + + TemplateBuilder templateBuilder = iaasInfo.getComputeService() + .templateBuilder(); + + // set image id specified + templateBuilder.imageId(iaasInfo.getImage()); + + if(!(iaasInfo instanceof IaasProvider)) { + templateBuilder.locationId(iaasInfo.getType()); + } + + String zone = iaasInfo.getProperty(CloudControllerConstants.AVAILABILITY_ZONE); + if(zone != null) { + Set locations = iaasInfo.getComputeService().listAssignableLocations(); + for(Location location : locations) { + if(location.getScope().toString().equalsIgnoreCase(CloudControllerConstants.ZONE_ELEMENT) && + location.getId().equals(zone)) { + templateBuilder.locationId(location.getId()); + log.info("ZONE has been set as " + zone + + " with id: " + location.getId()); + break; + } + } + } + + if (iaasInfo.getProperty(CloudControllerConstants.INSTANCE_TYPE) != null) { + // set instance type eg: m1.large + templateBuilder.hardwareId(iaasInfo.getProperty(CloudControllerConstants.INSTANCE_TYPE)); + } + + // build the Template + Template template = templateBuilder.build(); + + if(zone != null) { + if(!template.getLocation().getId().equals(zone)) { + log.warn("couldn't find assignable ZONE of id :" + zone + + " in the IaaS. Hence using the default location as " + template.getLocation().getScope().toString() + + " with the id " + template.getLocation().getId()); + } + } + + // if you wish to auto assign IPs, instance spawning call should be + // blocking, but if you + // wish to assign IPs manually, it can be non-blocking. + // is auto-assign-ip mode or manual-assign-ip mode? - default mode is + // non-blocking + boolean blockUntilRunning = Boolean.parseBoolean(iaasInfo + .getProperty("autoAssignIp")); + template.getOptions().as(TemplateOptions.class) + .blockUntilRunning(blockUntilRunning); + + // this is required in order to avoid creation of additional security + // groups by Jclouds. + template.getOptions().as(TemplateOptions.class) + .inboundPorts(22, 80, 8080, 443, 8243); + + if (zone != null) { + templateBuilder.locationId(zone); + log.debug("setting location to " + zone); + } + + // ability to define tags with Key-value pairs + Map keyValuePairTagsMap = new HashMap(); + + for (String propertyKey : iaasInfo.getProperties().keySet()){ + if(propertyKey.startsWith(CloudControllerConstants.TAGS_AS_KEY_VALUE_PAIRS_PREFIX)) { + keyValuePairTagsMap.put(propertyKey.substring(CloudControllerConstants.TAGS_AS_KEY_VALUE_PAIRS_PREFIX.length()), + iaasInfo.getProperties().get(propertyKey)); + template.getOptions() + .userMetadata(keyValuePairTagsMap); + } + log.info("usermeta data key:"+ propertyKey + " value: " + iaasInfo.getProperties().get(propertyKey)); + } + + if (iaasInfo.getNetworkInterfaces() != null) { + List networks = new ArrayList(iaasInfo.getNetworkInterfaces().length); + for (NetworkInterface ni:iaasInfo.getNetworkInterfaces()) { + networks.add(ni.getNetworkUuid()); + log.info("using network interface " + ni.getNetworkUuid()); + } + template.getOptions().as(TemplateOptions.class).networks(networks); + log.info("using network interface " + networks); + } + + // set Template + iaasInfo.setTemplate(template); + } + + @Override + public void setDynamicPayload() { + // in vCloud case we need to run a script + IaasProvider iaasInfo = getIaasProvider(); + + if (iaasInfo.getTemplate() == null || iaasInfo.getPayload() == null) { + if (log.isDebugEnabled()) { + log.debug("Payload for GCE not found"); + } + return; + } + + // Payload is a String value + String payload = new String(iaasInfo.getPayload()); + + log.info("setDynamicPayload " + payload); + + Map keyValuePairTagsMap = new HashMap(); + keyValuePairTagsMap.put("stratos_usermetadata", payload); + iaasInfo.getTemplate().getOptions().userMetadata(keyValuePairTagsMap); + } + + @Override + public boolean createKeyPairFromPublicKey(String region, String keyPairName, String publicKey) { + + // Not applicable for GCE - Not called by stratos cloud controller as well + return false; + } + + @Override + public String associateAddress(NodeMetadata node) { + + // TODO + return ""; + + } + + @Override + public String associatePredefinedAddress(NodeMetadata node, String ip) { + return ""; + } + + @Override + public void releaseAddress(String ip) { + // TODO + } + + @Override + public boolean isValidRegion(String region) throws InvalidRegionException { + IaasProvider iaasInfo = getIaasProvider(); + + if (region == null || iaasInfo == null) { + String msg = "Region or IaaSProvider is null: region: " + region + " - IaaSProvider: " + iaasInfo; + log.error(msg); + throw new InvalidRegionException(msg); + } + + GoogleComputeEngineApi api = getGCEApi(); + RegionApi regionApi = api.getRegionApiForProject(iaasInfo.getProperty(PROJECTNAME)); + + for(IterableWithMarker page : regionApi.list()) { + for(Region r : page) { + if (region.equalsIgnoreCase(r.getName())) { + log.debug("Found a matching region: " + region); + return true; + } + } + } + + String msg = "Invalid region: " + region +" in the iaas: "+iaasInfo.getType(); + log.error(msg); + throw new InvalidRegionException(msg); + } + + @Override + public boolean isValidZone(String region, String zone) throws InvalidZoneException { + IaasProvider iaasInfo = getIaasProvider(); + + if (zone == null || iaasInfo == null) { + String msg = "Zone or IaaSProvider is null: region: " + region + + " zone: " + zone + " - IaaSProvider: " + iaasInfo; + log.error(msg); + throw new InvalidZoneException(msg); + } + + GoogleComputeEngineApi api = getGCEApi(); + ZoneApi zoneApi = api.getZoneApiForProject(iaasInfo.getProperty(PROJECTNAME)); + + for(IterableWithMarker page : zoneApi.list()) { + for(Zone z : page) { + if (zone.equalsIgnoreCase(z.getName())) { + log.debug("Found a matching zone: " + zone); + return true; + } + } + } + + String msg = "Invalid zone: " + zone + " in the region: " + region + " and of the iaas: " + iaasInfo.getType(); + log.error(msg); + throw new InvalidZoneException(msg); + } + + @Override + public boolean isValidHost(String zone, String host) throws InvalidHostException { + IaasProvider iaasInfo = getIaasProvider(); + + // Not called by cloud controller + // there's no such concept in GCE + + String msg = "Invalid host: " + host + " in the zone: " + zone + " and of the iaas: " + iaasInfo.getType(); + log.error(msg); + throw new InvalidHostException(msg); + } + + @Override + public PartitionValidator getPartitionValidator() { + return new GCEPartitionValidator(); + } + + @Override + public String createVolume(int sizeGB, String snapshotId) { + // generate a random diskname + Random rand = new Random(); + String diskName = "stratos-disk-" + rand.nextInt(100000); + DiskApi diskApi = getGCEDiskApi(); + String zone = getZone(); + + log.debug("Creating volume: " + diskName + " in zone: " + zone + " of size: " + sizeGB); + + Operation oper = diskApi.createInZone(diskName, sizeGB, zone); + + oper = waitGCEOperationDone(oper); + if (oper.getStatus() != Operation.Status.DONE) { + log.error("Failed to create volume: " + diskName + " of size: " + sizeGB + + " in zone: " + zone + " operation: " + oper); + return null; + } + + return diskName; + } + + @Override + public String attachVolume(String instanceId, String volumeId, String deviceName) { + DiskApi diskApi = getGCEDiskApi(); + InstanceApi instApi = getGCEInstanceApi(); + String zone = getZone(); + + log.debug("Trying to attach volume: " + volumeId + " to instance: " + instanceId + + " in zone: " + zone + " at devicename: " + deviceName); + + Disk disk = diskApi.getInZone(zone, volumeId); + if (disk == null) { + log.error("Failed to get volume: " + volumeId + " in zone: " + zone); + return null; + } + + log.debug("Found volumeId: " + volumeId + " volume: " + disk); + + Operation oper = instApi.attachDiskInZone(zone, instanceId, + new AttachDiskOptions().type(DiskType.PERSISTENT) + .source(disk.getSelfLink()) + .mode(AttachDiskOptions.DiskMode.READ_WRITE) + .deviceName(deviceName)); + oper = waitGCEOperationDone(oper); + if (oper.getStatus() != Operation.Status.DONE) { + log.error("Failed to attach volume: " + volumeId + " to instance: " + instanceId + + " in zone: " + zone + " at device: " + deviceName + " operation: " + oper); + return null; + } + + return volumeId; + } + + @Override + public void detachVolume(String instanceId, String volumeId) { + DiskApi diskApi = getGCEDiskApi(); + InstanceApi instApi = getGCEInstanceApi(); + String zone = getZone(); + Instance inst = instApi.getInZone(zone, instanceId); + + log.debug("Trying to detach volume: " + volumeId + " from instance: " + instanceId + + " " + inst + " in zone: " + zone); + + if (inst == null) { + log.error("Failed to find instance: " + instanceId + " in zone: " + zone); + return; + } + + for(Instance.AttachedDisk disk : inst.getDisks()) { + Instance.PersistentAttachedDisk persistentDisk = (Instance.PersistentAttachedDisk)disk; + + log.debug("Found disk - src: " + persistentDisk.getSourceDiskName() + + " devicename: " + persistentDisk.getDeviceName()); + + if (persistentDisk.getSourceDiskName().equals(volumeId)) { + Operation oper = instApi.detachDiskInZone(zone, instanceId, persistentDisk.getDeviceName().get()); + oper = waitGCEOperationDone(oper); + if (oper.getStatus() != Operation.Status.DONE) { + log.error("Failed to detach volume: " + volumeId + " to instance: " + instanceId + + " in zone: " + zone + " at device: " + persistentDisk.getDeviceName() + + " result operation: " + oper); + } + return; + } + } + + log.error("Cannot find volume: " + volumeId + " in instance: " + instanceId); + } + + @Override + public void deleteVolume(String volumeId) { + DiskApi diskApi = getGCEDiskApi(); + String zone = getZone(); + + log.debug("Deleting volume: " + volumeId + " in zone: " + zone); + + Operation oper = diskApi.deleteInZone(zone, volumeId); + + oper = waitGCEOperationDone(oper); + if (oper.getStatus() != Operation.Status.DONE) { + log.error("Failed to delete volume: " + volumeId + " in zone: " + zone + + " operation: " + oper); + } + } + + @Override + public String getIaasDevice(String device) { + return device; + } + + private String getZone() { + IaasProvider iaasInfo = getIaasProvider(); + return iaasInfo.getProperty(CloudControllerConstants.AVAILABILITY_ZONE); + } + + private GoogleComputeEngineApi getGCEApi() { + IaasProvider iaasInfo = getIaasProvider(); + ComputeServiceContext context = iaasInfo.getComputeService().getContext(); + GoogleComputeEngineApi api = context.unwrapApi(GoogleComputeEngineApi.class); + + return api; + } + + private DiskApi getGCEDiskApi() { + IaasProvider iaasInfo = getIaasProvider(); + String projectName = iaasInfo.getProperty(PROJECTNAME); + return getGCEApi().getDiskApiForProject(projectName); + } + + private InstanceApi getGCEInstanceApi() { + IaasProvider iaasInfo = getIaasProvider(); + String projectName = iaasInfo.getProperty(PROJECTNAME); + return getGCEApi().getInstanceApiForProject(projectName); + } + + private Operation waitGCEOperationDone(Operation operation) { + int maxWaitTime = 15; // 15 seconds + IaasProvider iaasInfo = getIaasProvider(); + Injector injector = ContextBuilder.newBuilder(iaasInfo.getProvider()) + .credentials(iaasInfo.getIdentity(), iaasInfo.getCredential()) + .buildInjector(); + Predicate> zoneOperationDonePredicate = + injector.getInstance(Key.get(new TypeLiteral>>() { + }, Names.named("zone"))); + AtomicReference operationReference = Atomics.newReference(operation); + retry(zoneOperationDonePredicate, maxWaitTime, 1, SECONDS).apply(operationReference); + + return operationReference.get(); + } +} + diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/validate/GCEPartitionValidator.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/validate/GCEPartitionValidator.java new file mode 100644 index 0000000000..7d07d4062b --- /dev/null +++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/validate/GCEPartitionValidator.java @@ -0,0 +1,54 @@ +/* + * 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.stratos.cloud.controller.validate; + +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.stratos.cloud.controller.exception.InvalidPartitionException; +import org.apache.stratos.cloud.controller.interfaces.Iaas; +import org.apache.stratos.cloud.controller.pojo.IaasProvider; +import org.apache.stratos.cloud.controller.validate.interfaces.PartitionValidator; + + +/** + * The VCloud {@link PartitionValidator} implementation. + * + */ +public class GCEPartitionValidator implements PartitionValidator { + + private static final Log log = LogFactory.getLog(VCloudPartitionValidator.class); + private IaasProvider iaasProvider; + private Iaas iaas; + + @Override + public IaasProvider validate(String partitionId, Properties properties) throws InvalidPartitionException { + //TODO: implement real validation logic + return iaasProvider; + + } + + @Override + public void setIaasProvider(IaasProvider iaas) { + this.iaasProvider = iaas; + this.iaas = iaas.getIaas(); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/README.txt b/dependencies/jclouds/apis/gce/1.8.0-stratos/README.txt new file mode 100644 index 0000000000..a6ca119421 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/README.txt @@ -0,0 +1,77 @@ +====== +Stratos GCE provider 1.8.0 +====== + +This code in Stratos is copied from Jclouds GCE [1] +The jclouds GCE code has 2 directories oauth & google-compute-engine +In Stratos, these two directories are mered into one. + +[1] https://github.com/jclouds/jclouds-labs-google/tree/jclouds-labs-google-1.8.0 + + + + +====== +jclouds Google Compute Engine Provider +====== + + +Authenticating into the instances: +-------- + +User: +If no user is provided in GoogleComputeEngineTemplateOptions when launching an instance by default "jclouds" is used. + +Credential: + +GCE uses exclusively ssh keys to login into instances. +In order for an instance to be sshable a public key must be installed. Public keys are installed if they are present in the project or instance's metatada. + +For an instance to be ssable one of the following must happen: +1 - the project's metadata has an adequately built "sshKeys" entry and a corresponding private key is provided in GoogleComputeEngineTemplateOptions when createNodesInGroup is called. +2 - an instance of GoogleComputeEngineTemplateOptions with an adequate public and private key is provided. + +NOTE: if methods 2 is chosen the global project keys will not be installed in the instance. + +Please refer to Google's documentation on how to form valid project wide ssh keys metadata entries. + +FAQ: +-------- + +* Q. What is the identity for GCE? + +A. the identity is the developer email which can be obtained from the admin GUI. Its usually something in the form: @developer.gserviceaccount.com + +* Q. What is the credential for GCE + +A. the credential is a private key, in pem format. It can be extracted from the p12 keystore that is obtained when creating a "Service Account" (in the GUI: Google apis console > Api Access > Create another client ID > "Service Account" + +* Q. How to convert a p12 keystore into a pem format jclouds Google Compute Engine can handle: + +A. + +1. Convert the p12 file into pem format (it will ask for the keystore password, which is usually "notasecret"): + openssl pkcs12 -in .p12 -out .pem -nodes + +2. Extract only the pk and remove passphrase + openssl rsa -in .pem -out .pem + +The last file (.pem) should contain the pk that needs to be passed to `ContextBuilder.credential()` for the provider `google-compute-engine`. + + +Running the live tests: +-------- + +1. Place the following in your ~/.m2/settings.xml in a profile enabled when live: +``` + YOUR_ACCOUNT_NUMBER@developer.gserviceaccount.com + -----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQRRbRqVDtJLN1MO/xJoKqZuphDeBh5jIKueW3aNIiWs1XFcct+h +-- this text is literally from your .pem +aH7xmpHSTbbXmQkuuv+z8EKijigprd/FoJpTX1f5/R+4wQ== +-----END RSA PRIVATE KEY----- + +``` + +2. mvn clean install -Plive + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/pom.xml b/dependencies/jclouds/apis/gce/1.8.0-stratos/pom.xml new file mode 100644 index 0000000000..7874da111b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + org.apache.jclouds.labs + jclouds-labs-google + 1.8.0 + + + + org.apache.stratos + gce + 1.8.0-stratos + jclouds Google Compute Engine provider + jclouds components to access GoogleCompute + bundle + + + 1.8.0 + Email associated with the Google API client_id + + Private key (PKCS12 file) associated with the Google API client_id + + v1 + + imageId=debian-7-wheezy-v20131120,locationId=us-central1-a,minRam=2048 + org.jclouds.googlecomputeengine*;version="${project.version}" + + org.jclouds.compute.internal;version="${jclouds.version}", + org.jclouds.rest.internal;version="${jclouds.version}", + org.jclouds*;version="${jclouds.version}", + * + + + + + + org.apache.jclouds + jclouds-core + ${jclouds.version} + + + org.apache.jclouds + jclouds-compute + ${jclouds.version} + + + org.apache.jclouds + jclouds-compute + ${jclouds.version} + test-jar + test + + + org.apache.jclouds + jclouds-core + ${jclouds.version} + test-jar + test + + + org.apache.jclouds.driver + jclouds-slf4j + ${jclouds.version} + test + + + org.apache.jclouds.driver + jclouds-sshj + ${jclouds.version} + test + + + ch.qos.logback + logback-classic + test + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.google-compute-engine.identity} + + + ${test.google-compute-engine.credential} + + + ${test.google-compute-engine.api-version} + + + ${test.google-compute-engine.build-version} + + ${test.google-compute-engine.template} + + + + + + + + + + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java new file mode 100644 index 0000000000..6440d91ca0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java @@ -0,0 +1,185 @@ +/* + * 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.googlecomputeengine; + +import java.io.Closeable; + +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import org.jclouds.googlecomputeengine.features.AddressApi; +import org.jclouds.googlecomputeengine.features.DiskApi; +import org.jclouds.googlecomputeengine.features.FirewallApi; +import org.jclouds.googlecomputeengine.features.GlobalOperationApi; +import org.jclouds.googlecomputeengine.features.ImageApi; +import org.jclouds.googlecomputeengine.features.InstanceApi; +import org.jclouds.googlecomputeengine.features.MachineTypeApi; +import org.jclouds.googlecomputeengine.features.NetworkApi; +import org.jclouds.googlecomputeengine.features.ProjectApi; +import org.jclouds.googlecomputeengine.features.RegionApi; +import org.jclouds.googlecomputeengine.features.RegionOperationApi; +import org.jclouds.googlecomputeengine.features.RouteApi; +import org.jclouds.googlecomputeengine.features.SnapshotApi; +import org.jclouds.googlecomputeengine.features.ZoneApi; +import org.jclouds.googlecomputeengine.features.ZoneOperationApi; +import org.jclouds.rest.annotations.Delegate; + +import com.google.common.annotations.Beta; + + +/** + * Provides access to GoogleCompute. + *

+ * + * @see api doc + */ +@Beta +public interface GoogleComputeEngineApi extends Closeable { + + /** + * Provides access to Address features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + AddressApi getAddressApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Disk features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + DiskApi getDiskApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Firewall features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + FirewallApi getFirewallApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Global Operation features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + GlobalOperationApi getGlobalOperationApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Image features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + ImageApi getImageApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Instance features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + InstanceApi getInstanceApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to MachineType features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + MachineTypeApi getMachineTypeApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Network features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + NetworkApi getNetworkApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Project features + */ + @Delegate + ProjectApi getProjectApi(); + + /** + * Provides access to Region features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + RegionApi getRegionApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Region Operation features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + RegionOperationApi getRegionOperationApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Route features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + RouteApi getRouteApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Snapshot features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + SnapshotApi getSnapshotApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Zone features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + ZoneApi getZoneApiForProject(@PathParam("project") String projectName); + + /** + * Provides access to Zone Operation features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + ZoneOperationApi getZoneOperationApiForProject(@PathParam("project") String projectName); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java new file mode 100644 index 0000000000..1527529410 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java @@ -0,0 +1,104 @@ +/* + * 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.googlecomputeengine; + +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_PROVIDER_NAME; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.jclouds.reflect.Reflection2.typeToken; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.googlecomputeengine.compute.config.GoogleComputeEngineServiceContextModule; +import org.jclouds.googlecomputeengine.config.GoogleComputeEngineHttpApiModule; +import org.jclouds.googlecomputeengine.config.GoogleComputeEngineParserModule; +import org.jclouds.googlecomputeengine.config.OAuthModuleWithoutTypeAdapters; +import org.jclouds.oauth.v2.config.OAuthAuthenticationModule; +import org.jclouds.rest.internal.BaseHttpApiMetadata; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; + +/** + * Implementation of {@link ApiMetadata} for GoogleCompute v1 API + */ +public class GoogleComputeEngineApiMetadata extends BaseHttpApiMetadata { + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public GoogleComputeEngineApiMetadata() { + this(new Builder()); + } + + protected GoogleComputeEngineApiMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + Properties properties = BaseHttpApiMetadata.defaultProperties(); + properties.put("oauth.endpoint", "https://accounts.google.com/o/oauth2/token"); + properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); + properties.put(SIGNATURE_OR_MAC_ALGORITHM, "RS256"); + properties.put(PROPERTY_SESSION_INTERVAL, 3600); + properties.setProperty(TEMPLATE, "osFamily=GCEL,osVersionMatches=1[012].[01][04],locationId=us-central1-a," + + "loginUser=jclouds"); + properties.put(OPERATION_COMPLETE_INTERVAL, 500); + properties.put(OPERATION_COMPLETE_TIMEOUT, 600000); + return properties; + } + + public static class Builder extends BaseHttpApiMetadata.Builder { + + protected Builder() { + id(GCE_PROVIDER_NAME) + .name("Google Compute Engine Api") + .identityName("Email associated with the Google API client_id") + .credentialName("Private key literal associated with the Google API client_id") + .documentation(URI.create("https://developers.google.com/compute/docs")) + .version("v1") + .defaultEndpoint("https://www.googleapis.com/compute/v1") + .defaultProperties(GoogleComputeEngineApiMetadata.defaultProperties()) + .view(typeToken(ComputeServiceContext.class)) + .defaultModules(ImmutableSet.>builder() + .add(GoogleComputeEngineHttpApiModule.class) + .add(GoogleComputeEngineParserModule.class) + .add(OAuthAuthenticationModule.class) + .add(OAuthModuleWithoutTypeAdapters.class) + .add(GoogleComputeEngineServiceContextModule.class) + .build()); + } + + @Override + public GoogleComputeEngineApiMetadata build() { + return new GoogleComputeEngineApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java new file mode 100644 index 0000000000..d20ff98793 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java @@ -0,0 +1,81 @@ +/* + * 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.googlecomputeengine; + +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; + +import com.google.common.annotations.Beta; + +public final class GoogleComputeEngineConstants { + + public static final String GCE_PROVIDER_NAME = "google-compute-engine"; + + /** + * The name of the project that keeps public resources. + */ + public static final String GOOGLE_PROJECT = "google"; + + public static final String CENTOS_PROJECT = "centos-cloud"; + + public static final String DEBIAN_PROJECT = "debian-cloud"; + + public static final String COMPUTE_SCOPE = "https://www.googleapis.com/auth/compute"; + + public static final String COMPUTE_READONLY_SCOPE = "https://www.googleapis.com/auth/compute.readonly"; + + public static final String STORAGE_READONLY_SCOPE = "https://www.googleapis.com/auth/devstorage.read_only"; + + public static final String STORAGE_WRITEONLY_SCOPE = "https://www.googleapis.com/auth/devstorage.write_only"; + + + /** + * The total time, in msecs, to wait for an operation to complete. + */ + @Beta + public static final String OPERATION_COMPLETE_TIMEOUT = "jclouds.google-compute-engine.operation-complete-timeout"; + + /** + * The interval, in msecs, between calls to check whether an operation has completed. + */ + @Beta + public static final String OPERATION_COMPLETE_INTERVAL = "jclouds.google-compute-engine.operation-complete-interval"; + + public static final Location GOOGLE_PROVIDER_LOCATION = new LocationBuilder().scope(LocationScope.PROVIDER).id + (GCE_PROVIDER_NAME).description(GCE_PROVIDER_NAME).build(); + + + /** + * The key we look for in instance metadata for the URI for the image the instance was created from. + */ + public static final String GCE_IMAGE_METADATA_KEY = "jclouds-image"; + + /** + * Metadata key to check for whether we should delete an instance's boot disk when we delete the instance. + */ + public static final String GCE_DELETE_BOOT_DISK_METADATA_KEY = "jclouds-delete-boot-disk"; + + /** + * The suffix we append to auto-created boot disk names. + */ + public static final String GCE_BOOT_DISK_SUFFIX = "boot-disk"; + + private GoogleComputeEngineConstants() { + throw new AssertionError("intentionally unimplemented"); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java new file mode 100644 index 0000000000..3c140eb2df --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java @@ -0,0 +1,200 @@ +/* + * 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.googlecomputeengine.compute; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; +import static org.jclouds.util.Predicates2.retry; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; + +import org.jclouds.Constants; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.callables.RunScriptOnNode; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.TemplateBuilder; +import org.jclouds.compute.extensions.ImageExtension; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.compute.internal.BaseComputeService; +import org.jclouds.compute.internal.PersistNodeCredentials; +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; +import org.jclouds.compute.strategy.DestroyNodeStrategy; +import org.jclouds.compute.strategy.GetImageStrategy; +import org.jclouds.compute.strategy.GetNodeMetadataStrategy; +import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap; +import org.jclouds.compute.strategy.ListNodesStrategy; +import org.jclouds.compute.strategy.RebootNodeStrategy; +import org.jclouds.compute.strategy.ResumeNodeStrategy; +import org.jclouds.compute.strategy.SuspendNodeStrategy; +import org.jclouds.domain.Credentials; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.features.FirewallApi; +import org.jclouds.http.HttpResponse; +import org.jclouds.scriptbuilder.functions.InitAdminAccess; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Atomics; +import com.google.common.util.concurrent.ListeningExecutorService; + +public class GoogleComputeEngineService extends BaseComputeService { + + private final Function, Set> findOrphanedGroups; + private final GroupNamingConvention.Factory namingConvention; + private final GoogleComputeEngineApi api; + private final Supplier project; + private final Predicate> operationDonePredicate; + private final long operationCompleteCheckInterval; + private final long operationCompleteCheckTimeout; + + @Inject + protected GoogleComputeEngineService(ComputeServiceContext context, + Map credentialStore, + @Memoized Supplier> images, + @Memoized Supplier> hardwareProfiles, + @Memoized Supplier> locations, + ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, + GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, + RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, + ResumeNodeStrategy resumeNodeStrategy, + SuspendNodeStrategy suspendNodeStrategy, + Provider templateBuilderProvider, + @Named("DEFAULT") Provider templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate> + nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate> + nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) + Predicate> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + InitAdminAccess initAdminAccess, + RunScriptOnNode.Factory runScriptOnNodeFactory, + PersistNodeCredentials persistNodeCredentials, + ComputeServiceConstants.Timeouts timeouts, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + Optional imageExtension, + Optional securityGroupExtension, + Function, Set> findOrphanedGroups, + GroupNamingConvention.Factory namingConvention, + GoogleComputeEngineApi api, + @UserProject Supplier project, + @Named("global") Predicate> operationDonePredicate, + @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, + @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) { + + super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getImageStrategy, + getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, + resumeNodeStrategy, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, + nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, + persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + this.findOrphanedGroups = checkNotNull(findOrphanedGroups, "find orphaned groups function"); + this.namingConvention = checkNotNull(namingConvention, "naming convention factory"); + this.api = checkNotNull(api, "google compute api"); + this.project = checkNotNull(project, "user project name"); + this.operationDonePredicate = checkNotNull(operationDonePredicate, "operation completed predicate"); + this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval, + "operation completed check interval"); + this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout, + "operation completed check timeout"); + } + + @Override + protected synchronized void cleanUpIncidentalResourcesOfDeadNodes(Set deadNodes) { + Set orphanedGroups = findOrphanedGroups.apply(deadNodes); + for (String orphanedGroup : orphanedGroups) { + cleanUpNetworksAndFirewallsForGroup(orphanedGroup); + } + } + + + protected void cleanUpNetworksAndFirewallsForGroup(final String groupName) { + String resourceName = namingConvention.create().sharedNameForGroup(groupName); + final Network network = api.getNetworkApiForProject(project.get()).get(resourceName); + FirewallApi firewallApi = api.getFirewallApiForProject(project.get()); + Predicate firewallBelongsToNetwork = new Predicate() { + @Override + public boolean apply(Firewall input) { + return input != null && input.getNetwork().equals(network.getSelfLink()); + } + }; + + Set> operations = Sets.newHashSet(); + for (Firewall firewall : firewallApi.list().concat().filter(firewallBelongsToNetwork)) { + operations.add(new AtomicReference(firewallApi.delete(firewall.getName()))); + } + + for (AtomicReference operation : operations) { + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + if (operation.get().getHttpError().isPresent()) { + HttpResponse response = operation.get().getHttpError().get(); + logger.warn("delete orphaned firewall %s failed. Http Error Code: %d HttpError: %s", + operation.get().getTargetId(), response.getStatusCode(), response.getMessage()); + } + } + + AtomicReference operation = Atomics.newReference(api.getNetworkApiForProject(project.get()).delete(resourceName)); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + if (operation.get().getHttpError().isPresent()) { + HttpResponse response = operation.get().getHttpError().get(); + logger.warn("delete orphaned network failed. Http Error Code: " + response.getStatusCode() + + " HttpError: " + response.getMessage()); + } + } + + + /** + * returns template options, except of type {@link org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions}. + */ + @Override + public GoogleComputeEngineTemplateOptions templateOptions() { + return GoogleComputeEngineTemplateOptions.class.cast(super.templateOptions()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java new file mode 100644 index 0000000000..3a26d3420f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java @@ -0,0 +1,439 @@ +/* + * 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.googlecomputeengine.compute; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Iterables.contains; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.tryFind; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.CENTOS_PROJECT; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.DEBIAN_PROJECT; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_BOOT_DISK_SUFFIX; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_DELETE_BOOT_DISK_METADATA_KEY; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_METADATA_KEY; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; +import static org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type; +import static org.jclouds.googlecomputeengine.predicates.InstancePredicates.isBootDisk; +import static org.jclouds.util.Predicates2.retry; +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.annotation.Resource; +import javax.inject.Named; + +import org.jclouds.collect.Memoized; +import org.jclouds.compute.ComputeServiceAdapter; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.domain.Location; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention; +import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Disk; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk; +import org.jclouds.googlecomputeengine.domain.Instance.PersistentAttachedDisk; +import org.jclouds.googlecomputeengine.domain.InstanceInZone; +import org.jclouds.googlecomputeengine.domain.InstanceTemplate; +import org.jclouds.googlecomputeengine.domain.InstanceTemplate.PersistentDisk; +import org.jclouds.googlecomputeengine.domain.InstanceTemplate.PersistentDisk.Mode; +import org.jclouds.googlecomputeengine.domain.MachineType; +import org.jclouds.googlecomputeengine.domain.MachineTypeInZone; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.SlashEncodedIds; +import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.features.InstanceApi; +import org.jclouds.http.HttpResponse; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.primitives.Ints; +import com.google.common.util.concurrent.Atomics; +import com.google.common.util.concurrent.UncheckedTimeoutException; +import com.google.inject.Inject; + +public class GoogleComputeEngineServiceAdapter implements ComputeServiceAdapter { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final GoogleComputeEngineApi api; + private final Supplier userProject; + private final Supplier> zones; + private final Function> metatadaFromTemplateOptions; + private final Predicate> retryOperationDonePredicate; + private final long operationCompleteCheckInterval; + private final long operationCompleteCheckTimeout; + private final FirewallTagNamingConvention.Factory firewallTagNamingConvention; + + @Inject + public GoogleComputeEngineServiceAdapter(GoogleComputeEngineApi api, + @UserProject Supplier userProject, + Function> metatadaFromTemplateOptions, + @Named("zone") Predicate> operationDonePredicate, + @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, + @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout, + @Memoized Supplier> zones, + FirewallTagNamingConvention.Factory firewallTagNamingConvention) { + this.api = checkNotNull(api, "google compute api"); + this.userProject = checkNotNull(userProject, "user project name"); + this.metatadaFromTemplateOptions = checkNotNull(metatadaFromTemplateOptions, + "metadata from template options function"); + this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval, + "operation completed check interval"); + this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout, + "operation completed check timeout"); + this.retryOperationDonePredicate = retry(operationDonePredicate, operationCompleteCheckTimeout, + operationCompleteCheckInterval, TimeUnit.MILLISECONDS); + this.zones = checkNotNull(zones, "zones"); + this.firewallTagNamingConvention = checkNotNull(firewallTagNamingConvention, "firewallTagNamingConvention"); + } + + @Override + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName( + final String group, final String name, final Template template) { + + checkNotNull(template, "template"); + + GoogleComputeEngineTemplateOptions options = GoogleComputeEngineTemplateOptions.class.cast(template.getOptions()).clone(); + checkState(options.getNetwork().isPresent(), "network was not present in template options"); + Hardware hardware = checkNotNull(template.getHardware(), "hardware must be set"); + + checkNotNull(hardware.getUri(), "hardware must have a URI"); + checkNotNull(template.getImage().getUri(), "image URI is null"); + + // Note that the ordering is significant here - the first disk must be the boot disk. + List disks = Lists.newArrayList(); + + if (!tryFind(options.getDisks(), isBootDisk()).isPresent()) { + Disk bootDisk = createBootDisk(template, name); + + disks.add(new PersistentDisk(Mode.READ_WRITE, + bootDisk.getSelfLink(), + null, + true, + true)); + } + + disks.addAll(options.getDisks()); + + InstanceTemplate instanceTemplate = InstanceTemplate.builder() + .forMachineType(hardware.getUri()); + + if (options.isEnableNat()) { + instanceTemplate.addNetworkInterface(options.getNetwork().get(), Type.ONE_TO_ONE_NAT); + } else { + instanceTemplate.addNetworkInterface(options.getNetwork().get()); + } + + instanceTemplate.disks(disks); + + LoginCredentials credentials = getFromImageAndOverrideIfRequired(template.getImage(), options); + + ImmutableMap.Builder metadataBuilder = metatadaFromTemplateOptions.apply(options); + + metadataBuilder.put(GCE_IMAGE_METADATA_KEY, template.getImage().getUri().toString()); + + if (!options.shouldKeepBootDisk()) { + metadataBuilder.put(GCE_DELETE_BOOT_DISK_METADATA_KEY, Boolean.TRUE.toString()); + } + + instanceTemplate.metadata(metadataBuilder.build()); + instanceTemplate.serviceAccounts(options.getServiceAccounts()); + + final InstanceApi instanceApi = api.getInstanceApiForProject(userProject.get()); + final String zone = template.getLocation().getId(); + Operation operation = instanceApi.createInZone(name, zone, instanceTemplate); + + if (options.shouldBlockUntilRunning()) { + waitOperationDone(operation); + } + + // some times the newly created instances are not immediately returned + AtomicReference instance = Atomics.newReference(); + + retry(new Predicate>() { + @Override + public boolean apply(AtomicReference input) { + input.set(instanceApi.getInZone(zone, name)); + return input.get() != null; + } + }, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS).apply(instance); + + if (!options.getTags().isEmpty()) { + Operation tagsOperation = instanceApi.setTagsInZone(zone, + name, options.getTags(), instance.get().getTags().getFingerprint()); + + waitOperationDone(tagsOperation); + + retry(new Predicate>() { + @Override + public boolean apply(AtomicReference input) { + input.set(instanceApi.getInZone(zone, name)); + return input.get() != null; + } + }, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS).apply(instance); + } + + // Add tags for security groups + final FirewallTagNamingConvention naming = firewallTagNamingConvention.get(group); + Set tags = FluentIterable.from(Ints.asList(options.getInboundPorts())) + .transform(new Function(){ + @Override + public String apply(Integer input) { + return input != null + ? naming.name(input) + : null; + } + }) + .toSet(); + instanceApi.setTagsInZone(zone, instance.get().getName(), tags, instance.get().getTags().getFingerprint()); + + InstanceInZone instanceInZone = new InstanceInZone(instance.get(), zone); + + return new NodeAndInitialCredentials(instanceInZone, instanceInZone.slashEncode(), credentials); + } + + private Disk createBootDisk(Template template, String instanceName) { + URI imageUri = template.getImage().getUri(); + + GoogleComputeEngineTemplateOptions options = GoogleComputeEngineTemplateOptions.class.cast(template.getOptions()).clone(); + + int diskSize = options.getBootDiskSize().or(10l).intValue(); + + String diskName = instanceName + "-" + GCE_BOOT_DISK_SUFFIX; + + Operation diskOperation = api.getDiskApiForProject(userProject.get()) + .createFromImageWithSizeInZone(imageUri.toString(), + diskName, + diskSize, + template.getLocation().getId()); + + waitOperationDone(diskOperation); + + return api.getDiskApiForProject(userProject.get()).getInZone(template.getLocation().getId(), + diskName); + } + + @Override + public Iterable listHardwareProfiles() { + ImmutableSet.Builder builder = ImmutableSet.builder(); + + for (final Location zone : zones.get().values()) { + builder.addAll(api.getMachineTypeApiForProject(userProject.get()) + .listInZone(zone.getId()) + .concat() + .filter(new Predicate() { + @Override + public boolean apply(MachineType input) { + return !input.getDeprecated().isPresent(); + } + }) + .transform(new Function() { + + @Override + public MachineTypeInZone apply(MachineType arg0) { + return new MachineTypeInZone(arg0, arg0.getZone()); + } + })); + } + + return builder.build(); + } + + @Override + public Iterable listImages() { + return ImmutableSet.builder() + .addAll(api.getImageApiForProject(userProject.get()).list().concat()) + .addAll(api.getImageApiForProject(DEBIAN_PROJECT).list().concat()) + .addAll(api.getImageApiForProject(CENTOS_PROJECT).list().concat()) + .build(); + } + + @Override + public Image getImage(String id) { + return Objects.firstNonNull(api.getImageApiForProject(userProject.get()).get(id), + Objects.firstNonNull(api.getImageApiForProject(DEBIAN_PROJECT).get(id), + api.getImageApiForProject(CENTOS_PROJECT).get(id))); + + } + + @Override + public Iterable listLocations() { + return api.getZoneApiForProject(userProject.get()).list().concat(); + } + + @Override + public InstanceInZone getNode(String name) { + SlashEncodedIds slashEncodedIds = SlashEncodedIds.fromSlashEncoded(name); + + Instance instance = api.getInstanceApiForProject(userProject.get()).getInZone(slashEncodedIds.getFirstId(), + slashEncodedIds.getSecondId()); + + return instance == null ? null : new InstanceInZone(instance, slashEncodedIds.getFirstId()); + } + + @Override + public Iterable listNodes() { + return FluentIterable.from(zones.get().values()).transformAndConcat(new Function>() { + @Override + public ImmutableSet apply(final Location input) { + return api.getInstanceApiForProject(userProject.get()).listInZone(input.getId()).concat() + .transform(new Function() { + + @Override + public InstanceInZone apply(Instance arg0) { + return new InstanceInZone(arg0, input.getId()); + } + }).toSet(); + } + }).toSet(); + } + + @Override + public Iterable listNodesByIds(final Iterable ids) { + return filter(listNodes(), new Predicate() { + + @Override + public boolean apply(InstanceInZone instanceInZone) { + return contains(ids, instanceInZone.getInstance().getName()); + } + }); + } + + @Override + public void destroyNode(final String name) { + SlashEncodedIds slashEncodedIds = SlashEncodedIds.fromSlashEncoded(name); + String diskName = null; + try { + Instance instance = api.getInstanceApiForProject(userProject.get()).getInZone(slashEncodedIds.getFirstId(), + slashEncodedIds.getSecondId()); + if (instance.getMetadata().getItems().get(GCE_DELETE_BOOT_DISK_METADATA_KEY).equals("true")) { + Optional disk = tryFind(instance.getDisks(), new Predicate() { + @Override + public boolean apply(AttachedDisk input) { + return PersistentAttachedDisk.class.isInstance(input) && + PersistentAttachedDisk.class.cast(input).isBoot(); + } + }); + if (disk.isPresent()) { + diskName = PersistentAttachedDisk.class.cast(disk.get()).getSourceDiskName(); + } + } + } catch (Exception e) { + // TODO: what exception actually gets thrown here if the instance doesn't really exist? + } + waitOperationDone(api.getInstanceApiForProject(userProject.get()).deleteInZone(slashEncodedIds.getFirstId(), + slashEncodedIds.getSecondId())); + + if (diskName != null) { + waitOperationDone(api.getDiskApiForProject(userProject.get()).deleteInZone(slashEncodedIds.getFirstId(), + diskName)); + } + + } + + @Override + public void rebootNode(final String name) { + SlashEncodedIds slashEncodedIds = SlashEncodedIds.fromSlashEncoded(name); + + waitOperationDone(api.getInstanceApiForProject(userProject.get()).resetInZone(slashEncodedIds.getFirstId(), + slashEncodedIds.getSecondId())); + } + + @Override + public void resumeNode(String name) { + throw new UnsupportedOperationException("resume is not supported by GCE"); + } + + @Override + public void suspendNode(String name) { + throw new UnsupportedOperationException("suspend is not supported by GCE"); + } + + private LoginCredentials getFromImageAndOverrideIfRequired(org.jclouds.compute.domain.Image image, + GoogleComputeEngineTemplateOptions options) { + LoginCredentials defaultCredentials = image.getDefaultCredentials(); + String[] keys = defaultCredentials.getPrivateKey().split(":"); + String publicKey = keys[0]; + String privateKey = keys[1]; + + LoginCredentials.Builder credentialsBuilder = defaultCredentials.toBuilder(); + credentialsBuilder.privateKey(privateKey); + + // LoginCredentials from image stores the public key along with the private key in the privateKey field + // @see GoogleComputePopulateDefaultLoginCredentialsForImageStrategy + // so if options doesn't have a public key set we set it from the default + if (options.getPublicKey() == null) { + options.authorizePublicKey(publicKey); + } + if (options.hasLoginPrivateKeyOption()) { + credentialsBuilder.privateKey(options.getPrivateKey()); + } + if (options.getLoginUser() != null) { + credentialsBuilder.identity(options.getLoginUser()); + } + if (options.hasLoginPasswordOption()) { + credentialsBuilder.password(options.getLoginPassword()); + } + if (options.shouldAuthenticateSudo() != null) { + credentialsBuilder.authenticateSudo(options.shouldAuthenticateSudo()); + } + LoginCredentials credentials = credentialsBuilder.build(); + options.overrideLoginCredentials(credentials); + return credentials; + } + + private void waitOperationDone(Operation operation) { + AtomicReference operationRef = Atomics.newReference(operation); + + // wait for the operation to complete + if (!retryOperationDonePredicate.apply(operationRef)) { + throw new UncheckedTimeoutException("operation did not reach DONE state" + operationRef.get()); + } + + // check if the operation failed + if (operationRef.get().getHttpError().isPresent()) { + HttpResponse response = operationRef.get().getHttpError().get(); + throw new IllegalStateException("operation failed. Http Error Code: " + response.getStatusCode() + + " HttpError: " + response.getMessage()); + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java new file mode 100644 index 0000000000..730c51527e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java @@ -0,0 +1,283 @@ +/* + * 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.googlecomputeengine.compute.config; + +import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Maps.uniqueIndex; +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; + +import java.net.URI; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Named; +import javax.inject.Singleton; + +import com.google.inject.Scopes; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceAdapter; +import org.jclouds.compute.config.ComputeServiceAdapterContextModule; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.extensions.ImageExtension; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.compute.GoogleComputeEngineService; +import org.jclouds.googlecomputeengine.compute.GoogleComputeEngineServiceAdapter; +import org.jclouds.googlecomputeengine.compute.extensions.GoogleComputeEngineSecurityGroupExtension; +import org.jclouds.googlecomputeengine.compute.functions.BuildInstanceMetadata; +import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention; +import org.jclouds.googlecomputeengine.compute.functions.FirewallToIpPermission; +import org.jclouds.googlecomputeengine.compute.functions.GoogleComputeEngineImageToImage; +import org.jclouds.googlecomputeengine.compute.functions.InstanceInZoneToNodeMetadata; +import org.jclouds.googlecomputeengine.compute.functions.MachineTypeInZoneToHardware; +import org.jclouds.googlecomputeengine.compute.functions.NetworkToSecurityGroup; +import org.jclouds.googlecomputeengine.compute.functions.OrphanedGroupsFromDeadNodes; +import org.jclouds.googlecomputeengine.compute.functions.RegionToLocation; +import org.jclouds.googlecomputeengine.compute.functions.ZoneToLocation; +import org.jclouds.googlecomputeengine.compute.loaders.FindNetworkOrCreate; +import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; +import org.jclouds.googlecomputeengine.compute.predicates.AllNodesInGroupTerminated; +import org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet; +import org.jclouds.googlecomputeengine.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; +import org.jclouds.googlecomputeengine.compute.strategy.UseNodeCredentialsButOverrideFromTemplate; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.InstanceInZone; +import org.jclouds.googlecomputeengine.domain.MachineTypeInZone; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Region; +import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.functions.CreateNetworkIfNeeded; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Injector; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; + +public class GoogleComputeEngineServiceContextModule + extends ComputeServiceAdapterContextModule { + + @Override + protected void configure() { + super.configure(); + + bind(ComputeService.class).to(GoogleComputeEngineService.class); + + bind(new TypeLiteral>() {}) + .to(GoogleComputeEngineServiceAdapter.class); + + bind(new TypeLiteral>() {}) + .to(InstanceInZoneToNodeMetadata.class); + + bind(new TypeLiteral>() {}) + .to(MachineTypeInZoneToHardware.class); + + bind(new TypeLiteral>() {}) + .to(GoogleComputeEngineImageToImage.class); + + bind(new TypeLiteral>() { + }) + .to(RegionToLocation.class); + + bind(new TypeLiteral>() {}) + .to(ZoneToLocation.class); + + bind(new TypeLiteral>>() {}) + .to(FirewallToIpPermission.class); + + bind(new TypeLiteral>() {}) + .to(NetworkToSecurityGroup.class); + + bind(new TypeLiteral>>() {}) + .to(BuildInstanceMetadata.class); + + bind(org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy.class) + .to(PopulateDefaultLoginCredentialsForImageStrategy.class); + + bind(org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to( + CreateNodesWithGroupEncodedIntoNameThenAddToSet.class); + + bind(TemplateOptions.class).to(GoogleComputeEngineTemplateOptions.class); + + bind(new TypeLiteral, Set>>() {}) + .to(OrphanedGroupsFromDeadNodes.class); + + bind(new TypeLiteral>() {}).to(AllNodesInGroupTerminated.class); + + bind(new TypeLiteral>() {}) + .to(CreateNetworkIfNeeded.class); + + bind(new TypeLiteral>() {}) + .to(FindNetworkOrCreate.class); + + bind(new TypeLiteral() {}) + .to(GoogleComputeEngineSecurityGroupExtension.class); + + bind(PrioritizeCredentialsFromTemplate.class).to(UseNodeCredentialsButOverrideFromTemplate.class); + + install(new LocationsFromComputeServiceAdapterModule() {}); + + bind(FirewallTagNamingConvention.Factory.class).in(Scopes.SINGLETON); + } + + @Provides + @Singleton + @Memoized + public Supplier> provideImagesMap( + AtomicReference authException, + final Supplier> images, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, + new Supplier>() { + @Override + public Map get() { + return uniqueIndex(images.get(), new Function() { + @Override + public URI apply(org.jclouds.compute.domain.Image input) { + return input.getUri(); + } + }); + } + }, + seconds, TimeUnit.SECONDS); + } + + @Provides + @Singleton + @Memoized + public Supplier> provideHardwaresMap( + AtomicReference authException, + final Supplier> hardwares, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, + new Supplier>() { + @Override + public Map get() { + return uniqueIndex(hardwares.get(), new Function() { + @Override + public URI apply(Hardware input) { + return input.getUri(); + } + }); + } + }, + seconds, TimeUnit.SECONDS); + } + + @Provides + @Singleton + @Memoized + public Supplier> provideZones( + AtomicReference authException, + final GoogleComputeEngineApi api, final Function zoneToLocation, + @UserProject final Supplier userProject, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, + new Supplier>() { + @Override + public Map get() { + return uniqueIndex(transform(api.getZoneApiForProject(userProject.get()).list().concat(), zoneToLocation), + new Function() { + @Override + public URI apply(Location input) { + return (URI) input.getMetadata().get("selfLink"); + } + }); + } + }, + seconds, TimeUnit.SECONDS); + } + + @Provides + @Singleton + @Memoized + public Supplier> provideRegions( + AtomicReference authException, + final GoogleComputeEngineApi api, + @UserProject final Supplier userProject, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, + new Supplier>() { + @Override + public Map get() { + return uniqueIndex(api.getRegionApiForProject(userProject.get()).list().concat(), + new Function() { + @Override + public URI apply(Region input) { + return input.getSelfLink(); + } + }); + } + }, + seconds, TimeUnit.SECONDS); + } + + @Provides + @Singleton + protected LoadingCache networkMap( + CacheLoader in) { + return CacheBuilder.newBuilder().build(in); + } + + @Override + protected Optional provideImageExtension(Injector i) { + return Optional.absent(); + } + + @Override + protected Optional provideSecurityGroupExtension(Injector i) { + return Optional.of(i.getInstance(SecurityGroupExtension.class)); + } + + @VisibleForTesting + public static final Map toPortableNodeStatus = + ImmutableMap.builder() + .put(Instance.Status.PROVISIONING, NodeMetadata.Status.PENDING) + .put(Instance.Status.STAGING, NodeMetadata.Status.PENDING) + .put(Instance.Status.RUNNING, NodeMetadata.Status.RUNNING) + .put(Instance.Status.STOPPING, NodeMetadata.Status.PENDING) + .put(Instance.Status.STOPPED, NodeMetadata.Status.SUSPENDED) + .put(Instance.Status.TERMINATED, NodeMetadata.Status.TERMINATED).build(); + + @Singleton + @Provides + protected Map toPortableNodeStatus() { + return toPortableNodeStatus; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java new file mode 100644 index 0000000000..f1113e0706 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java @@ -0,0 +1,338 @@ +/* + * 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.googlecomputeengine.compute.extensions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; +import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.DEFAULT_INTERNAL_NETWORK_RANGE; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.equalsIpPermission; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.providesIpPermission; +import static org.jclouds.util.Predicates2.retry; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.SlashEncodedIds; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.options.FirewallOptions; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.googlecomputeengine.options.ListOptions.Builder; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.base.Supplier; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.Atomics; + +/** + * An extension to compute service to allow for the manipulation of {@link org.jclouds.compute.domain.SecurityGroup}s. Implementation + * is optional by providers. + */ +public class GoogleComputeEngineSecurityGroupExtension implements SecurityGroupExtension { + + protected final Supplier userProject; + protected final GroupNamingConvention.Factory namingConvention; + protected final LoadingCache networkCreator; + protected final Function groupConverter; + protected final GoogleComputeEngineApi api; + protected final Predicate> operationDonePredicate; + protected final long operationCompleteCheckInterval; + protected final long operationCompleteCheckTimeout; + + @Inject + public GoogleComputeEngineSecurityGroupExtension(GoogleComputeEngineApi api, + @UserProject Supplier userProject, + GroupNamingConvention.Factory namingConvention, + LoadingCache networkCreator, + Function groupConverter, + @Named("global") Predicate> operationDonePredicate, + @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, + @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) { + this.api = checkNotNull(api, "api"); + this.userProject = checkNotNull(userProject, "userProject"); + this.namingConvention = checkNotNull(namingConvention, "namingConvention"); + this.networkCreator = checkNotNull(networkCreator, "networkCreator"); + this.groupConverter = checkNotNull(groupConverter, "groupConverter"); + this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval, + "operation completed check interval"); + this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout, + "operation completed check timeout"); + this.operationDonePredicate = checkNotNull(operationDonePredicate, "operationDonePredicate"); + } + + @Override + public Set listSecurityGroups() { + return api.getNetworkApiForProject(userProject.get()).list().concat().transform(groupConverter).toSet(); + } + + @Override + public Set listSecurityGroupsInLocation(final Location location) { + return listSecurityGroups(); + } + + @Override + public Set listSecurityGroupsForNode(String id) { + SlashEncodedIds slashEncodedIds = SlashEncodedIds.fromSlashEncoded(id); + + Instance instance = api.getInstanceApiForProject(userProject.get()).getInZone(slashEncodedIds.getFirstId(), + slashEncodedIds.getSecondId()); + + if (instance == null) { + return ImmutableSet.of(); + } + + ImmutableSet.Builder builder = ImmutableSet.builder(); + + + for (NetworkInterface nwInterface : instance.getNetworkInterfaces()) { + String networkUrl = nwInterface.getNetwork().getPath(); + Network nw = api.getNetworkApiForProject(userProject.get()).get(networkUrl.substring(networkUrl.lastIndexOf('/') + 1)); + + SecurityGroup grp = groupForTagsInNetwork(nw, instance.getTags().getItems()); + if (grp != null) { + builder.add(grp); + } + } + + return builder.build(); + } + + @Override + public SecurityGroup getSecurityGroupById(String id) { + checkNotNull(id, "id"); + Network network = api.getNetworkApiForProject(userProject.get()).get(id); + + if (network == null) { + return null; + } + + return groupConverter.apply(network); + } + + @Override + public SecurityGroup createSecurityGroup(String name, Location location) { + return createSecurityGroup(name); + } + + public SecurityGroup createSecurityGroup(String name) { + checkNotNull(name, "name"); + + NetworkAndAddressRange nAr = new NetworkAndAddressRange(name, DEFAULT_INTERNAL_NETWORK_RANGE, null); + + Network nw = networkCreator.apply(nAr); + + return groupConverter.apply(nw); + } + + @Override + public boolean removeSecurityGroup(String id) { + checkNotNull(id, "id"); + if (api.getNetworkApiForProject(userProject.get()).get(id) == null) { + return false; + } + + ListOptions options = new ListOptions.Builder().filter("network eq .*/" + id); + + FluentIterable fws = api.getFirewallApiForProject(userProject.get()).list(options).concat(); + + for (Firewall fw : fws) { + AtomicReference operation = Atomics.newReference(api.getFirewallApiForProject(userProject.get()) + .delete(fw.getName())); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not delete firewall, operation failed" + operation); + } + + AtomicReference operation = Atomics.newReference( + api.getNetworkApiForProject(userProject.get()).delete(id)); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not create network, operation failed" + operation); + + return true; + } + + @Override + public SecurityGroup addIpPermission(IpPermission ipPermission, SecurityGroup group) { + checkNotNull(group, "group"); + checkNotNull(ipPermission, "ipPermission"); + + checkNotNull(api.getNetworkApiForProject(userProject.get()).get(group.getId()) == null, "network for group is null"); + + ListOptions options = new ListOptions.Builder().filter("network eq .*/" + group.getName()); + + if (api.getFirewallApiForProject(userProject.get()).list(options).concat().anyMatch(providesIpPermission(ipPermission))) { + // Permission already exists. + return group; + } + + FirewallOptions fwOptions = new FirewallOptions(); + String uniqueFwName = namingConvention.createWithoutPrefix().uniqueNameForGroup(group.getName()); + fwOptions.name(uniqueFwName); + fwOptions.network(group.getUri()); + if (!ipPermission.getGroupIds().isEmpty()) { + fwOptions.sourceTags(ipPermission.getGroupIds()); + } + if (!ipPermission.getCidrBlocks().isEmpty()) { + fwOptions.sourceRanges(ipPermission.getCidrBlocks()); + } + Firewall.Rule.Builder ruleBuilder = Firewall.Rule.builder(); + ruleBuilder.IpProtocol(ipPermission.getIpProtocol()); + if (ipPermission.getToPort() > 0) { + ruleBuilder.addPortRange(ipPermission.getFromPort(), ipPermission.getToPort()); + } + fwOptions.addAllowedRule(ruleBuilder.build()); + + AtomicReference operation = Atomics.newReference(api.getFirewallApiForProject(userProject + .get()).createInNetwork( + uniqueFwName, + group.getUri(), + fwOptions)); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not create firewall, operation failed" + operation); + + return getSecurityGroupById(group.getId()); + } + + @Override + public SecurityGroup addIpPermission(IpProtocol protocol, int fromPort, int toPort, + Multimap tenantIdGroupNamePairs, Iterable cidrBlocks, + Iterable groupIds, SecurityGroup group) { + + IpPermission.Builder permBuilder = IpPermission.builder(); + permBuilder.ipProtocol(protocol); + permBuilder.fromPort(fromPort); + permBuilder.toPort(toPort); + permBuilder.groupIds(groupIds); + permBuilder.cidrBlocks(cidrBlocks); + + return addIpPermission(permBuilder.build(), group); + + } + + @Override + public SecurityGroup removeIpPermission(IpPermission ipPermission, SecurityGroup group) { + checkNotNull(group, "group"); + checkNotNull(ipPermission, "ipPermission"); + + checkNotNull(api.getNetworkApiForProject(userProject.get()).get(group.getId()) == null, "network for group is null"); + + ListOptions options = new ListOptions.Builder().filter("network eq .*/" + group.getName()); + + FluentIterable fws = api.getFirewallApiForProject(userProject.get()).list(options).concat(); + + for (Firewall fw : fws) { + if (equalsIpPermission(ipPermission).apply(fw)) { + AtomicReference operation = Atomics.newReference(api.getFirewallApiForProject(userProject.get()) + .delete(fw.getName())); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not delete firewall, operation failed" + operation); + } + } + + return getSecurityGroupById(group.getId()); + } + + @Override + public SecurityGroup removeIpPermission(IpProtocol protocol, int fromPort, int toPort, + Multimap tenantIdGroupNamePairs, Iterable cidrBlocks, + Iterable groupIds, SecurityGroup group) { + + IpPermission.Builder permBuilder = IpPermission.builder(); + permBuilder.ipProtocol(protocol); + permBuilder.fromPort(fromPort); + permBuilder.toPort(toPort); + permBuilder.groupIds(groupIds); + permBuilder.cidrBlocks(cidrBlocks); + + return removeIpPermission(permBuilder.build(), group); + + } + + @Override + public boolean supportsTenantIdGroupNamePairs() { + return false; + } + + @Override + public boolean supportsTenantIdGroupIdPairs() { + return false; + } + + @Override + public boolean supportsGroupIds() { + return true; + } + + @Override + public boolean supportsPortRangesForGroups() { + return true; + } + + private SecurityGroup groupForTagsInNetwork(Network nw, final Set tags) { + ListOptions opts = new Builder().filter("network eq .*/" + nw.getName()); + Set fws = api.getFirewallApiForProject(userProject.get()).list(opts).concat() + .filter(new Predicate() { + @Override + public boolean apply(final Firewall input) { + // If any of the targetTags on the firewall apply or the firewall has no target tags... + return Iterables.any(input.getTargetTags(), Predicates.in(tags)) + || Predicates.equalTo(0).apply(input.getTargetTags().size()); + } + }).toSet(); + + if (fws.isEmpty()) { + return null; + } + + return groupConverter.apply(nw); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/BuildInstanceMetadata.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/BuildInstanceMetadata.java new file mode 100644 index 0000000000..80b18b1d5f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/BuildInstanceMetadata.java @@ -0,0 +1,46 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.lang.String.format; + +import javax.inject.Singleton; + +import org.jclouds.compute.options.TemplateOptions; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; + +/** + * Prepares metadata from the provided TemplateOptions + */ +@Singleton +public class BuildInstanceMetadata implements Function> { + + @Override + public ImmutableMap.Builder apply(TemplateOptions input) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + if (input.getPublicKey() != null) { + builder.put("sshKeys", format("%s:%s %s@localhost", checkNotNull(input.getLoginUser(), + "loginUser cannot be null"), input.getPublicKey(), input.getLoginUser())); + } + builder.putAll(input.getUserMetadata()); + return builder; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.java new file mode 100644 index 0000000000..1d2508b2ea --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.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.googlecomputeengine.compute.functions; + +import com.google.common.base.Predicate; +import org.jclouds.compute.functions.GroupNamingConvention; + +import javax.inject.Inject; + +/** + * The convention for naming instance tags that firewall rules recognise. + */ +public class FirewallTagNamingConvention { + + public static class Factory { + + private final GroupNamingConvention.Factory namingConvention; + + @Inject + public Factory(GroupNamingConvention.Factory namingConvention) { + this.namingConvention = namingConvention; + } + + public FirewallTagNamingConvention get(String groupName) { + return new FirewallTagNamingConvention(namingConvention.create().sharedNameForGroup(groupName)); + } + } + + private final String sharedResourceName; + + public FirewallTagNamingConvention(String sharedResourceName) { + this.sharedResourceName = sharedResourceName; + } + + public String name(int port) { + return String.format("%s-port-%s", sharedResourceName, port); + } + + public Predicate isFirewallTag() { + return new Predicate() { + @Override + public boolean apply(String input) { + return input != null && input.startsWith(sharedResourceName + "-port-"); + } + }; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermission.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermission.java new file mode 100644 index 0000000000..ea069e01b0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermission.java @@ -0,0 +1,87 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import javax.annotation.Resource; +import javax.inject.Named; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Firewall.Rule; +import org.jclouds.logging.Logger; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Range; + +/** + * A function for transforming a GCE-specific Firewall into a generic + * IpPermission object. + */ +public class FirewallToIpPermission implements Function> { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + public FirewallToIpPermission() { + } + + + @Override + public Iterable apply(Firewall fw) { + ImmutableSet.Builder setBuilder = ImmutableSet.builder(); + + for (Rule rule : fw.getAllowed()) { + if (!rule.getPorts().isEmpty()) { + for (Range r : rule.getPorts().asRanges()) { + IpPermission.Builder builder = populateBuilder(fw, rule.getIpProtocol()); + builder.fromPort(r.lowerEndpoint()); + builder.toPort(r.upperEndpoint()); + setBuilder.add(builder.build()); + } + } else { + setBuilder.add(populateBuilder(fw, rule.getIpProtocol()).build()); + } + } + + return setBuilder.build(); + } + + /** + * Convenience method for populating common parts of the IpPermission. + * @param fw + * @param protocol + * @return a pre-populated builder. + */ + private IpPermission.Builder populateBuilder(Firewall fw, IpProtocol protocol) { + IpPermission.Builder builder = IpPermission.builder(); + + builder.ipProtocol(protocol); + + if (!fw.getSourceRanges().isEmpty()) { + builder.cidrBlocks(fw.getSourceRanges()); + } + if (!fw.getSourceTags().isEmpty()) { + builder.groupIds(fw.getSourceTags()); + } + + return builder; + } +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImage.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImage.java new file mode 100644 index 0000000000..b783fc98e0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImage.java @@ -0,0 +1,80 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static com.google.common.base.Joiner.on; +import static com.google.common.collect.Iterables.getLast; +import static com.google.common.collect.Iterables.limit; +import static com.google.common.collect.Iterables.skip; +import static org.jclouds.compute.domain.Image.Status; + +import java.util.List; + +import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.googlecomputeengine.domain.Image; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; + +/** + * Transforms a google compute domain specific image to a generic Image object. + */ +public class GoogleComputeEngineImageToImage implements Function { + + + @Override + public org.jclouds.compute.domain.Image apply(Image image) { + ImageBuilder builder = new ImageBuilder() + .id(image.getName()) + .name(image.getName()) + .providerId(image.getId()) + .description(image.getDescription().orNull()) + .status(Status.AVAILABLE) + .uri(image.getSelfLink()); + + List splits = Lists.newArrayList(image.getName().split("-")); + OperatingSystem.Builder osBuilder = defaultOperatingSystem(image); + if (splits == null || splits.size() == 0 || splits.size() < 3) { + return builder.operatingSystem(osBuilder.build()).build(); + } + + OsFamily family = OsFamily.fromValue(splits.get(0)); + if (family != OsFamily.UNRECOGNIZED) { + osBuilder.family(family); + } + + String version = on(".").join(limit(skip(splits, 1), splits.size() - 2)); + osBuilder.version(version); + + if (image.getDeprecated().isPresent()) { + builder.userMetadata(ImmutableMap.of("deprecatedState", image.getDeprecated().get().getState().orNull())); + } + builder.version(getLast(splits)); + return builder.operatingSystem(osBuilder.build()).build(); + } + + private OperatingSystem.Builder defaultOperatingSystem(Image image) { + return OperatingSystem.builder() + .family(OsFamily.LINUX) + .is64Bit(true) + .description(image.getName()); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadata.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadata.java new file mode 100644 index 0000000000..c1ddea1d68 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadata.java @@ -0,0 +1,150 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.compute.util.ComputeServiceUtils.groupFromMapOrName; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_METADATA_KEY; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; + +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadataBuilder; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.InstanceInZone; +import org.jclouds.googlecomputeengine.domain.SlashEncodedIds; + +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.base.Supplier; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; + +/** + * Transforms a google compute domain Instance into a generic NodeMetatada object. + */ +public class InstanceInZoneToNodeMetadata implements Function { + + private final Map toPortableNodeStatus; + private final GroupNamingConvention nodeNamingConvention; + private final Supplier> images; + private final Supplier> hardwares; + private final Supplier> locations; + private final FirewallTagNamingConvention.Factory firewallTagNamingConvention; + private final GoogleComputeEngineApi api; + private final Supplier userProject; + + @Inject + public InstanceInZoneToNodeMetadata(Map toPortableNodeStatus, + GroupNamingConvention.Factory namingConvention, + @Memoized Supplier> images, + @Memoized Supplier> hardwares, + @Memoized Supplier> locations, + FirewallTagNamingConvention.Factory firewallTagNamingConvention, + GoogleComputeEngineApi api, + @UserProject Supplier userProject) { + this.toPortableNodeStatus = toPortableNodeStatus; + this.nodeNamingConvention = namingConvention.createWithoutPrefix(); + this.images = images; + this.hardwares = hardwares; + this.locations = locations; + this.firewallTagNamingConvention = checkNotNull(firewallTagNamingConvention, "firewallTagNamingConvention"); + this.api = checkNotNull(api, "api"); + this.userProject = checkNotNull(userProject, "userProject"); + } + + @Override + public NodeMetadata apply(InstanceInZone instanceInZone) { + Instance input = instanceInZone.getInstance(); + + String group = groupFromMapOrName(input.getMetadata().getItems(), + input.getName(), nodeNamingConvention); + FluentIterable tags = FluentIterable.from(input.getTags().getItems()); + if (group != null) { + tags = tags.filter(Predicates.not(firewallTagNamingConvention.get(group).isFirewallTag())); + } + + NodeMetadataBuilder builder = new NodeMetadataBuilder(); + + builder.id(SlashEncodedIds.fromTwoIds(checkNotNull(locations.get().get(input.getZone()), + "location for %s", input.getZone()) + .getId(), input.getName()).slashEncode()) + .name(input.getName()) + .providerId(input.getId()) + .hostname(input.getName()) + .location(checkNotNull(locations.get().get(input.getZone()), "location for %s", input.getZone())) + .hardware(hardwares.get().get(input.getMachineType())) + .status(toPortableNodeStatus.get(input.getStatus())) + .tags(tags) + .uri(input.getSelfLink()) + .userMetadata(input.getMetadata().getItems()) + .group(group) + .privateAddresses(collectPrivateAddresses(input)) + .publicAddresses(collectPublicAddresses(input)); + + if (input.getMetadata().getItems().containsKey(GCE_IMAGE_METADATA_KEY)) { + try { + URI imageUri = URI.create(input.getMetadata().getItems() + .get(GCE_IMAGE_METADATA_KEY)); + + Map imagesMap = images.get(); + + Image image = checkNotNull(imagesMap.get(imageUri), + "no image for %s. images: %s", imageUri, + imagesMap.values()); + builder.imageId(image.getId()); + } catch (IllegalArgumentException e) { + // Swallow any exception here - it just means we don't actually have a valid image URI, so we skip it. + } + } + + return builder.build(); + } + + private Set collectPrivateAddresses(Instance input) { + ImmutableSet.Builder privateAddressesBuilder = ImmutableSet.builder(); + for (Instance.NetworkInterface networkInterface : input.getNetworkInterfaces()) { + if (networkInterface.getNetworkIP().isPresent()) { + privateAddressesBuilder.add(networkInterface.getNetworkIP().get()); + } + } + return privateAddressesBuilder.build(); + } + + private Set collectPublicAddresses(Instance input) { + ImmutableSet.Builder publicAddressesBuilder = ImmutableSet.builder(); + for (Instance.NetworkInterface networkInterface : input.getNetworkInterfaces()) { + for (Instance.NetworkInterface.AccessConfig accessConfig : networkInterface.getAccessConfigs()) { + if (accessConfig.getNatIP().isPresent()) { + publicAddressesBuilder.add(accessConfig.getNatIP().get()); + } + } + } + return publicAddressesBuilder.build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/MachineTypeInZoneToHardware.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/MachineTypeInZoneToHardware.java new file mode 100644 index 0000000000..16091cd57a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/MachineTypeInZoneToHardware.java @@ -0,0 +1,100 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.getOnlyElement; + +import java.net.URI; +import java.util.Map; + +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.HardwareBuilder; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.Processor; +import org.jclouds.compute.domain.Volume; +import org.jclouds.compute.domain.VolumeBuilder; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.domain.MachineType; +import org.jclouds.googlecomputeengine.domain.MachineTypeInZone; +import org.jclouds.googlecomputeengine.domain.SlashEncodedIds; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; + +/** + * Transforms a google compute domain specific machine type to a generic Hardware object. + */ +public class MachineTypeInZoneToHardware implements Function { + + private final Supplier> locations; + + @Inject + public MachineTypeInZoneToHardware(@Memoized Supplier> locations) { + this.locations = locations; + } + + @Override + public Hardware apply(final MachineTypeInZone input) { + Iterable zonesForMachineType = filter(locations.get().values(), new Predicate() { + @Override + public boolean apply(Location l) { + return l.getId().equals(input.getMachineType().getZone()); + } + }); + + Location location = checkNotNull(getOnlyElement(zonesForMachineType), + "location for %s", + input.getMachineType().getZone()); + + // TODO Figure out a robust way to deal with machineTypes with imageSizeGb==0 rather than just blocking them. + return new HardwareBuilder() + .id(SlashEncodedIds.fromTwoIds(input.getMachineType().getZone(), input.getMachineType().getName()).slashEncode()) + .location(location) + .name(input.getMachineType().getName()) + .hypervisor("kvm") + .processor(new Processor(input.getMachineType().getGuestCpus(), 1.0)) + .providerId(input.getMachineType().getId()) + .ram(input.getMachineType().getMemoryMb()) + .uri(input.getMachineType().getSelfLink()) + .userMetadata(ImmutableMap.of("imageSpaceGb", Integer.toString(input.getMachineType().getImageSpaceGb()))) + .volumes(collectVolumes(input.getMachineType())) + .supportsImage(input.getMachineType().getImageSpaceGb() > 0 + ? Predicates.alwaysTrue() + : Predicates.alwaysFalse()) + .build(); + } + + private Iterable collectVolumes(MachineType input) { + ImmutableSet.Builder volumes = ImmutableSet.builder(); + for (MachineType.ScratchDisk disk : input.getScratchDisks()) { + volumes.add(new VolumeBuilder() + .type(Volume.Type.LOCAL) + .size(new Integer(disk.getDiskGb()).floatValue()) + .bootDevice(true) + .durable(false).build()); + } + return volumes.build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java new file mode 100644 index 0000000000..1a9be54181 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java @@ -0,0 +1,82 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.domain.SecurityGroupBuilder; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.logging.Logger; +import org.jclouds.net.domain.IpPermission; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableSet; + +/** + * A function for transforming a GCE-specific Network into a generic + * SecurityGroup object. + */ +public class NetworkToSecurityGroup implements Function { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final Function> firewallToPerms; + private final GoogleComputeEngineApi api; + private final Supplier project; + + @Inject + public NetworkToSecurityGroup(Function> firewallToPerms, + GoogleComputeEngineApi api, + @UserProject Supplier project) { + this.firewallToPerms = firewallToPerms; + this.api = api; + this.project = project; + } + + @Override + public SecurityGroup apply(Network network) { + SecurityGroupBuilder builder = new SecurityGroupBuilder(); + + builder.id(network.getName()); + builder.providerId(network.getId()); + builder.name(network.getName()); + builder.uri(network.getSelfLink()); + + ImmutableSet.Builder permBuilder = ImmutableSet.builder(); + + ListOptions options = new ListOptions.Builder().filter("network eq .*/" + network.getName()); + + for (Firewall fw : api.getFirewallApiForProject(project.get()).list(options).concat()) { + permBuilder.addAll(firewallToPerms.apply(fw)); + } + + builder.ipPermissions(permBuilder.build()); + + return builder.build(); + } +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodes.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodes.java new file mode 100644 index 0000000000..3301c8f765 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodes.java @@ -0,0 +1,57 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.compute.domain.NodeMetadata; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.Sets; + +@Singleton +public class OrphanedGroupsFromDeadNodes implements Function, Set> { + + private final Predicate isOrphanedGroupPredicate; + + @Inject + public OrphanedGroupsFromDeadNodes(Predicate isOrphanedGroupPredicate) { + this.isOrphanedGroupPredicate = isOrphanedGroupPredicate; + } + + + @Override + public Set apply(Set deadNodes) { + Set groups = Sets.newLinkedHashSet(); + for (NodeMetadata deadNode : deadNodes) { + groups.add(deadNode.getGroup()); + } + Set orphanedGroups = Sets.newLinkedHashSet(); + for (String group : groups) { + if (isOrphanedGroupPredicate.apply(group)) { + orphanedGroups.add(group); + } + } + return orphanedGroups; + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/RegionToLocation.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/RegionToLocation.java new file mode 100644 index 0000000000..2f880ded0d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/RegionToLocation.java @@ -0,0 +1,45 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GOOGLE_PROVIDER_LOCATION; + +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.jclouds.googlecomputeengine.domain.Region; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; + +/** + * Transforms a google compute domain specific region to a generic Region object. + */ +public class RegionToLocation implements Function { + + @Override + public Location apply(Region input) { + return new LocationBuilder() + .description(input.getDescription().orNull()) + .metadata(ImmutableMap.of("selfLink", (Object) checkNotNull(input.getSelfLink(), "region URI"))) + .id(input.getName()) + .scope(LocationScope.REGION) + .parent(GOOGLE_PROVIDER_LOCATION) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ZoneToLocation.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ZoneToLocation.java new file mode 100644 index 0000000000..0dc1c78ff5 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ZoneToLocation.java @@ -0,0 +1,45 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GOOGLE_PROVIDER_LOCATION; + +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.jclouds.googlecomputeengine.domain.Zone; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; + +/** + * Transforms a google compute domain specific zone to a generic Zone object. + */ +public class ZoneToLocation implements Function { + + @Override + public Location apply(Zone input) { + return new LocationBuilder() + .description(input.getDescription().orNull()) + .metadata(ImmutableMap.of("selfLink", (Object) checkNotNull(input.getSelfLink(), "zone URI"))) + .id(input.getName()) + .scope(LocationScope.ZONE) + .parent(GOOGLE_PROVIDER_LOCATION) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreate.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreate.java new file mode 100644 index 0000000000..2c84787a0a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreate.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.googlecomputeengine.compute.loaders; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.cache.CacheLoader; + +public class FindNetworkOrCreate extends CacheLoader { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + protected final GoogleComputeEngineApi api; + protected final Function networkCreator; + protected final Supplier userProject; + + @Inject + public FindNetworkOrCreate(GoogleComputeEngineApi api, + Function networkCreator, + @UserProject Supplier userProject) { + this.api = checkNotNull(api, "api"); + this.networkCreator = checkNotNull(networkCreator, "networkCreator"); + this.userProject = checkNotNull(userProject, "userProject"); + } + + @Override + public Network load(NetworkAndAddressRange in) { + Network network = api.getNetworkApiForProject(userProject.get()).get(in.getName()); + if (network != null) { + return network; + } else { + return networkCreator.apply(in); + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java new file mode 100644 index 0000000000..c6aad00130 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java @@ -0,0 +1,382 @@ +/* + * 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.googlecomputeengine.compute.options; + +import static com.google.common.base.Optional.fromNullable; +import static org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.InstanceTemplate.PersistentDisk; +import org.jclouds.scriptbuilder.domain.Statement; + +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; + +/** + * Instance options specific to Google Compute Engine. + */ +public class GoogleComputeEngineTemplateOptions extends TemplateOptions { + + private Optional network = Optional.absent(); + private Optional networkName = Optional.absent(); + private Set serviceAccounts = Sets.newLinkedHashSet(); + private boolean enableNat = true; + private Set disks = Sets.newLinkedHashSet(); + private Optional bootDiskSize = Optional.absent(); + private boolean keepBootDisk = false; + + @Override + public GoogleComputeEngineTemplateOptions clone() { + GoogleComputeEngineTemplateOptions options = new GoogleComputeEngineTemplateOptions(); + copyTo(options); + return options; + } + + @Override + public void copyTo(TemplateOptions to) { + super.copyTo(to); + if (to instanceof GoogleComputeEngineTemplateOptions) { + GoogleComputeEngineTemplateOptions eTo = GoogleComputeEngineTemplateOptions.class.cast(to); + eTo.network(getNetwork().orNull()); + eTo.serviceAccounts(getServiceAccounts()); + eTo.enableNat(isEnableNat()); + eTo.disks(getDisks()); + eTo.keepBootDisk(shouldKeepBootDisk()); + } + } + + /** + * @deprecated See TemplateOptions#networks + * @see #getNetworkName() + */ + @Deprecated + public GoogleComputeEngineTemplateOptions network(String networkName) { + return this.networks(networkName); + } + + /** + * @see #getNetwork() + */ + public GoogleComputeEngineTemplateOptions network(URI network) { + this.network = fromNullable(network); + return this; + } + + /** + * @see #getServiceAccounts() + * @see ServiceAccount + */ + public GoogleComputeEngineTemplateOptions addServiceAccount(ServiceAccount serviceAccout) { + this.serviceAccounts.add(serviceAccout); + return this; + } + + /** + * @see #getServiceAccounts() + * @see ServiceAccount + */ + public GoogleComputeEngineTemplateOptions serviceAccounts(Set serviceAccounts) { + this.serviceAccounts = Sets.newLinkedHashSet(serviceAccounts); + return this; + } + + /** + * @see #getDisks() + * @see org.jclouds.googlecomputeengine.domain.InstanceTemplate.PersistentDisk + */ + public GoogleComputeEngineTemplateOptions addDisk(PersistentDisk disk) { + this.disks.add(disk); + return this; + } + + /** + * @see #getDisks() + * @see org.jclouds.googlecomputeengine.domain.InstanceTemplate.PersistentDisk + */ + public GoogleComputeEngineTemplateOptions disks(Set disks) { + this.disks = Sets.newLinkedHashSet(disks); + return this; + } + + /** + * @see #isEnableNat() + */ + public GoogleComputeEngineTemplateOptions enableNat(boolean enableNat) { + this.enableNat = enableNat; + return this; + } + + /** + * @see #getBootDiskSize() + */ + public GoogleComputeEngineTemplateOptions bootDiskSize(Long bootDiskSize) { + this.bootDiskSize = fromNullable(bootDiskSize); + return this; + } + + /** + * @see #shouldKeepBootDisk() + */ + public GoogleComputeEngineTemplateOptions keepBootDisk(boolean keepBootDisk) { + this.keepBootDisk = keepBootDisk; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions blockOnPort(int port, int seconds) { + return GoogleComputeEngineTemplateOptions.class.cast(super.blockOnPort(port, seconds)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions inboundPorts(int... ports) { + return GoogleComputeEngineTemplateOptions.class.cast(super.inboundPorts(ports)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions authorizePublicKey(String publicKey) { + return GoogleComputeEngineTemplateOptions.class.cast(super.authorizePublicKey(publicKey)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions installPrivateKey(String privateKey) { + return GoogleComputeEngineTemplateOptions.class.cast(super.installPrivateKey(privateKey)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions blockUntilRunning(boolean blockUntilRunning) { + return GoogleComputeEngineTemplateOptions.class.cast(super.blockUntilRunning(blockUntilRunning)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions dontAuthorizePublicKey() { + return GoogleComputeEngineTemplateOptions.class.cast(super.dontAuthorizePublicKey()); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions nameTask(String name) { + return GoogleComputeEngineTemplateOptions.class.cast(super.nameTask(name)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions runAsRoot(boolean runAsRoot) { + return GoogleComputeEngineTemplateOptions.class.cast(super.runAsRoot(runAsRoot)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions runScript(Statement script) { + return GoogleComputeEngineTemplateOptions.class.cast(super.runScript(script)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions overrideLoginCredentials(LoginCredentials overridingCredentials) { + return GoogleComputeEngineTemplateOptions.class.cast(super.overrideLoginCredentials(overridingCredentials)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions overrideLoginPassword(String password) { + return GoogleComputeEngineTemplateOptions.class.cast(super.overrideLoginPassword(password)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions overrideLoginPrivateKey(String privateKey) { + return GoogleComputeEngineTemplateOptions.class.cast(super.overrideLoginPrivateKey(privateKey)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions overrideLoginUser(String loginUser) { + return GoogleComputeEngineTemplateOptions.class.cast(super.overrideLoginUser(loginUser)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) { + return GoogleComputeEngineTemplateOptions.class.cast(super.overrideAuthenticateSudo(authenticateSudo)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions userMetadata(Map userMetadata) { + return GoogleComputeEngineTemplateOptions.class.cast(super.userMetadata(userMetadata)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions userMetadata(String key, String value) { + return GoogleComputeEngineTemplateOptions.class.cast(super.userMetadata(key, value)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions nodeNames(Iterable nodeNames) { + return GoogleComputeEngineTemplateOptions.class.cast(super.nodeNames(nodeNames)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions networks(Iterable networks) { + return GoogleComputeEngineTemplateOptions.class.cast(super.networks(networks)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions networks(String... networks) { + return GoogleComputeEngineTemplateOptions.class.cast(super.networks(networks)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions tags(Iterable tags) { + return GoogleComputeEngineTemplateOptions.class.cast(super.tags(tags)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions wrapInInitScript(boolean wrapInInitScript) { + return GoogleComputeEngineTemplateOptions.class.cast(super.wrapInInitScript(wrapInInitScript)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions runScript(String script) { + return GoogleComputeEngineTemplateOptions.class.cast(super.runScript(script)); + } + + /** + * {@inheritDoc} + */ + @Override + public GoogleComputeEngineTemplateOptions blockOnComplete(boolean blockOnComplete) { + return GoogleComputeEngineTemplateOptions.class.cast(super.blockOnComplete(blockOnComplete)); + } + + /** + * @return the ServiceAccounts to enable in the instances. + */ + public Set getServiceAccounts() { + return serviceAccounts; + } + + /** + * @return the PersistentDisks for this instance. + */ + public Set getDisks() { + return disks; + } + + /** + * @return the URI of an existing network the instances will be attached to. If no network URI or network name are + * provided a new network will be created for the project. + */ + public Optional getNetwork() { + return network; + } + + /** + * @return the name of an existing network the instances will be attached to, the network is assumed to belong to + * user's project. If no network URI network name are provided a new network will be created for the project. + * Note that this is now pulling from the first element in the networks field from TemplateOptions. + */ + public Optional getNetworkName() { + return fromNullable(Iterables.getFirst(getNetworks(), null)); + } + + /** + * @return whether an AccessConfig with Type ONE_TO_ONE_NAT should be enabled in the instances. When true + * instances will have a NAT address that will be publicly accessible. + */ + public boolean isEnableNat() { + return enableNat; + } + + /** + * @return the boot disk size, if specified. Defaults to 10gb. + */ + public Optional getBootDiskSize() { + return bootDiskSize; + } + + /** + * @return whether we should keep the boot disk around when deleting the instance. Defaults to false. + */ + public boolean shouldKeepBootDisk() { + return keepBootDisk; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java new file mode 100644 index 0000000000..38066ba697 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java @@ -0,0 +1,48 @@ +/* + * 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.googlecomputeengine.compute.predicates; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.all; +import static com.google.common.collect.Sets.filter; +import static org.jclouds.compute.predicates.NodePredicates.TERMINATED; +import static org.jclouds.compute.predicates.NodePredicates.all; +import static org.jclouds.compute.predicates.NodePredicates.inGroup; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.compute.ComputeService; + +import com.google.common.base.Predicate; + +@Singleton +public class AllNodesInGroupTerminated implements Predicate { + + private final ComputeService computeService; + + @Inject + public AllNodesInGroupTerminated(ComputeService computeService) { + this.computeService = checkNotNull(computeService, "compute service"); + } + + + @Override + public boolean apply(String groupName) { + return all(filter(computeService.listNodesDetailsMatching(all()), inGroup(groupName)), TERMINATED); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java new file mode 100644 index 0000000000..14af9cd86a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java @@ -0,0 +1,183 @@ +/* + * 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.googlecomputeengine.compute.strategy; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableSet.of; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; +import static org.jclouds.util.Predicates2.retry; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.Constants; +import org.jclouds.compute.config.CustomizationResponse; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; +import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; +import org.jclouds.compute.strategy.ListNodesStrategy; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention; +import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.features.FirewallApi; +import org.jclouds.googlecomputeengine.options.FirewallOptions; + +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Atomics; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; + +public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends + org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet { + + public static final String EXTERIOR_RANGE = "0.0.0.0/0"; + public static final String DEFAULT_INTERNAL_NETWORK_RANGE = "10.0.0.0/8"; + + private final GoogleComputeEngineApi api; + private final Supplier userProject; + private final LoadingCache networkMap; + private final Predicate> operationDonePredicate; + private final long operationCompleteCheckInterval; + private final long operationCompleteCheckTimeout; + private final FirewallTagNamingConvention.Factory firewallTagNamingConvention; + + @Inject + protected CreateNodesWithGroupEncodedIntoNameThenAddToSet( + CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy, + ListNodesStrategy listNodesStrategy, + GroupNamingConvention.Factory namingConvention, + @Named(Constants.PROPERTY_USER_THREADS) + ListeningExecutorService userExecutor, + CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory + customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, + GoogleComputeEngineApi api, + @UserProject Supplier userProject, + @Named("global") Predicate> operationDonePredicate, + @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, + @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout, + LoadingCache networkMap, + FirewallTagNamingConvention.Factory firewallTagNamingConvention) { + super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, + customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); + + this.api = checkNotNull(api, "google compute api"); + this.userProject = checkNotNull(userProject, "user project name"); + this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval, + "operation completed check interval"); + this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout, + "operation completed check timeout"); + this.operationDonePredicate = checkNotNull(operationDonePredicate, "operationDonePredicate"); + this.networkMap = checkNotNull(networkMap, "networkMap"); + this.firewallTagNamingConvention = checkNotNull(firewallTagNamingConvention, "firewallTagNamingConvention"); + } + + @Override + public synchronized Map> execute(String group, int count, + Template template, + Set goodNodes, + Map badNodes, + Multimap customizationResponses) { + + String sharedResourceName = namingConvention.create().sharedNameForGroup(group); + Template mutableTemplate = template.clone(); + GoogleComputeEngineTemplateOptions templateOptions = GoogleComputeEngineTemplateOptions.class.cast(mutableTemplate + .getOptions()); + assert template.getOptions().equals(templateOptions) : "options didn't clone properly"; + + // get or create the network and create a firewall with the users configuration + Network network = getOrCreateNetwork(templateOptions, sharedResourceName); + getOrCreateFirewalls(templateOptions, network, firewallTagNamingConvention.get(group)); + templateOptions.network(network.getSelfLink()); + templateOptions.userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group); + + return super.execute(group, count, mutableTemplate, goodNodes, badNodes, customizationResponses); + } + + /** + * Try and find a network either previously created by jclouds or user defined. + */ + private Network getOrCreateNetwork(GoogleComputeEngineTemplateOptions templateOptions, String sharedResourceName) { + + String networkName = templateOptions.getNetworkName().or(sharedResourceName); + + return networkMap.apply(new NetworkAndAddressRange(networkName, DEFAULT_INTERNAL_NETWORK_RANGE, null)); + } + + /** + * Ensures that a firewall exists for every inbound port that the instance requests. + *

+ * For each port, there must be a firewall with a name following the {@link FirewallTagNamingConvention}, + * with a target tag also following the {@link FirewallTagNamingConvention}, which opens the requested port + * for all sources on both TCP and UDP protocols. + * @see org.jclouds.googlecomputeengine.features.FirewallApi#patch(String, org.jclouds.googlecomputeengine.options.FirewallOptions) + */ + private void getOrCreateFirewalls(GoogleComputeEngineTemplateOptions templateOptions, Network network, + FirewallTagNamingConvention naming) { + + String projectName = userProject.get(); + FirewallApi firewallApi = api.getFirewallApiForProject(projectName); + Set> operations = Sets.newHashSet(); + + for (Integer port : templateOptions.getInboundPorts()) { + String name = naming.name(port); + Firewall firewall = firewallApi.get(name); + if (firewall == null) { + ImmutableSet rules = ImmutableSet.of(Firewall.Rule.permitTcpRule(port), Firewall.Rule.permitUdpRule(port)); + FirewallOptions firewallOptions = new FirewallOptions() + .name(name) + .network(network.getSelfLink()) + .allowedRules(rules) + .sourceTags(templateOptions.getTags()) + .sourceRanges(of(DEFAULT_INTERNAL_NETWORK_RANGE, EXTERIOR_RANGE)) + .targetTags(ImmutableSet.of(name)); + AtomicReference operation = Atomics.newReference(firewallApi.createInNetwork( + firewallOptions.getName(), + network.getSelfLink(), + firewallOptions)); + operations.add(operation); + } + } + + for (AtomicReference operation : operations) { + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + checkState(!operation.get().getHttpError().isPresent(), + "Could not create firewall, operation failed" + operation); + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/PopulateDefaultLoginCredentialsForImageStrategy.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/PopulateDefaultLoginCredentialsForImageStrategy.java new file mode 100644 index 0000000000..082d9ed879 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/PopulateDefaultLoginCredentialsForImageStrategy.java @@ -0,0 +1,69 @@ +/* + * 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.googlecomputeengine.compute.strategy; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE; + +import java.security.NoSuchAlgorithmException; +import java.util.Map; + +import javax.annotation.PostConstruct; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.compute.domain.TemplateBuilderSpec; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.ssh.internal.RsaSshKeyPairGenerator; + +import com.google.inject.Inject; + +@Singleton +public class PopulateDefaultLoginCredentialsForImageStrategy implements + org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy { + + private final TemplateBuilderSpec templateBuilder; + private final RsaSshKeyPairGenerator keyPairGenerator; + private String compoundKey; + + @Inject + PopulateDefaultLoginCredentialsForImageStrategy(@Named(TEMPLATE) String templateSpec, + RsaSshKeyPairGenerator keyPairGenerator) + throws NoSuchAlgorithmException { + this.templateBuilder = TemplateBuilderSpec.parse(checkNotNull(templateSpec, "template builder spec")); + checkNotNull(templateBuilder.getLoginUser(), "template builder spec must provide a loginUser"); + this.keyPairGenerator = checkNotNull(keyPairGenerator, "keypair generator"); + } + + @PostConstruct + private void generateKeys() { + Map keys = keyPairGenerator.get(); + // as we need to store both the pubk and the pk, store them separated by : (base64 does not contain that char) + compoundKey = String.format("%s:%s", checkNotNull(keys.get("public"), "public key cannot be null"), + checkNotNull(keys.get("private"), "private key cannot be null")); + } + + @Override + public LoginCredentials apply(Object image) { + return LoginCredentials.builder() + .authenticateSudo(templateBuilder.getAuthenticateSudo() != null ? + templateBuilder.getAuthenticateSudo() : false) + .privateKey(compoundKey) + .user(templateBuilder.getLoginUser()).build(); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/UseNodeCredentialsButOverrideFromTemplate.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/UseNodeCredentialsButOverrideFromTemplate.java new file mode 100644 index 0000000000..ff75a03b76 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/UseNodeCredentialsButOverrideFromTemplate.java @@ -0,0 +1,57 @@ +/* + * 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.googlecomputeengine.compute.strategy; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.options.RunScriptOptions; +import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate; +import org.jclouds.domain.LoginCredentials; + +import com.google.common.base.Function; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * GCE needs the credentials to create the node so the node credentials already take the Image credentials into account, + * as such only overriding the TemplateOptions credentials is required. + */ +@Singleton +public class UseNodeCredentialsButOverrideFromTemplate extends PrioritizeCredentialsFromTemplate { + + + @Inject + public UseNodeCredentialsButOverrideFromTemplate( + Function credentialsFromImageOrTemplateOptions) { + super(credentialsFromImageOrTemplateOptions); + } + + public LoginCredentials apply(Template template, LoginCredentials fromNode) { + RunScriptOptions options = checkNotNull(template.getOptions(), "template options are required"); + LoginCredentials.Builder builder = LoginCredentials.builder(fromNode); + if (options.getLoginUser() != null) + builder.user(template.getOptions().getLoginUser()); + if (options.getLoginPassword() != null) + builder.password(options.getLoginPassword()); + if (options.getLoginPrivateKey() != null) + builder.privateKey(options.getLoginPrivateKey()); + if (options.shouldAuthenticateSudo() != null && options.shouldAuthenticateSudo()) + builder.authenticateSudo(true); + return builder.build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java new file mode 100644 index 0000000000..2a1b3f2a9e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java @@ -0,0 +1,177 @@ +/* + * 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.googlecomputeengine.config; + +import static com.google.common.base.Suppliers.compose; +import static com.google.inject.name.Names.named; +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; + +import java.net.URI; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.domain.Credentials; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Project; +import org.jclouds.googlecomputeengine.domain.SlashEncodedIds; +import org.jclouds.googlecomputeengine.handlers.GoogleComputeEngineErrorHandler; +import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate; +import org.jclouds.googlecomputeengine.predicates.RegionOperationDonePredicate; +import org.jclouds.googlecomputeengine.predicates.ZoneOperationDonePredicate; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.Uris; +import org.jclouds.http.annotation.ClientError; +import org.jclouds.http.annotation.Redirection; +import org.jclouds.http.annotation.ServerError; +import org.jclouds.json.config.GsonModule.DateAdapter; +import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; +import org.jclouds.location.Provider; +import org.jclouds.location.suppliers.ImplicitLocationSupplier; +import org.jclouds.location.suppliers.implicit.FirstZone; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ConfiguresHttpApi; +import org.jclouds.rest.config.HttpApiModule; +import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.collect.Iterables; +import com.google.inject.Provides; +import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; + +/** + * Configures the GoogleCompute connection. + */ +@ConfiguresHttpApi +public class GoogleComputeEngineHttpApiModule extends HttpApiModule { + public GoogleComputeEngineHttpApiModule() { + } + + @Override + protected void configure() { + bind(DateAdapter.class).to(Iso8601DateAdapter.class); + bind(new TypeLiteral>>() { + }).annotatedWith(named("global")).to(GlobalOperationDonePredicate.class); + bind(new TypeLiteral>>() { + }).annotatedWith(named("region")).to(RegionOperationDonePredicate.class); + bind(new TypeLiteral>>() { + }).annotatedWith(named("zone")).to(ZoneOperationDonePredicate.class); + bind(ImplicitLocationSupplier.class).to(FirstZone.class).in(Scopes.SINGLETON); + super.configure(); + } + + @Override + protected void bindErrorHandlers() { + bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(GoogleComputeEngineErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(GoogleComputeEngineErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(GoogleComputeEngineErrorHandler.class); + } + + @Provides + @Singleton + @UserProject + public Supplier supplyProject(@Provider final Supplier creds, + final GoogleComputeEngineApi api, + AtomicReference authException, + @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, + compose(new Function() { + public String apply(Credentials in) { + // ID should be of the form project_id@developer.gserviceaccount.com + // OR (increasingly often) project_id-extended_uid@developer.gserviceaccount.com + // where project_id is the NUMBER; + // HERE we also accept simply "project" as the identity, if no "@" is present; + // this is used in tests, but not sure if it is valid in the wild. + String projectName = in.identity; + if (projectName.indexOf("@") != -1) { + projectName = Iterables.get(Splitter.on("@").split(projectName), 0); + if (projectName.indexOf("-") != -1) { + // if ID is of the form project_id-extended_uid@developer.gserviceaccount.com + projectName = Iterables.get(Splitter.on("-").split(projectName), 0); + } + } + Project project = api.getProjectApi().get(projectName); + return project.getName(); + } + }, creds), seconds, TimeUnit.SECONDS); + } + + @Provides + @Singleton + @Named("machineTypeToURI") + public Function provideMachineTypeNameToURIFunction(@Provider final Supplier endpoint, + @UserProject final Supplier userProject) { + return new Function() { + @Override + public URI apply(String input) { + SlashEncodedIds slashEncodedIds = SlashEncodedIds.fromSlashEncoded(input); + return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()) + .appendPath("/zones/").appendPath(slashEncodedIds.getFirstId()) + .appendPath("/machineTypes/").appendPath(slashEncodedIds.getSecondId()).build(); + } + }; + } + + @Provides + @Singleton + @Named("networkToURI") + public Function provideNetworkNameToURIFunction(@Provider final Supplier endpoint, + @UserProject final Supplier userProject) { + return new Function() { + @Override + public URI apply(String input) { + return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()) + .appendPath("/global/networks/").appendPath(input).build(); + } + }; + } + + @Provides + @Singleton + @Named("zoneToURI") + public Function provideZoneNameToURIFunction(@Provider final Supplier endpoint, + @UserProject final Supplier userProject) { + return new Function() { + @Override + public URI apply(String input) { + return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()) + .appendPath("/zones/").appendPath(input).build(); + } + }; + } + + @Provides + @Singleton + @Named("regionToURI") + public Function provideRegionNameToURIFunction(@Provider final Supplier endpoint, + @UserProject final Supplier userProject) { + return new Function() { + @Override + public URI apply(String input) { + return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get()) + .appendPath("/regions/").appendPath(input).build(); + } + }; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java new file mode 100644 index 0000000000..cd7e8d1bfc --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java @@ -0,0 +1,413 @@ +/* + * 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.googlecomputeengine.config; + +import static org.jclouds.googlecomputeengine.domain.Firewall.Rule; + +import java.beans.ConstructorProperties; +import java.lang.reflect.Type; +import java.net.URI; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +import javax.inject.Singleton; + +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.InstanceTemplate; +import org.jclouds.googlecomputeengine.domain.Metadata; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Project; +import org.jclouds.googlecomputeengine.domain.Quota; +import org.jclouds.googlecomputeengine.options.FirewallOptions; +import org.jclouds.googlecomputeengine.options.RouteOptions; +import org.jclouds.json.config.GsonModule; +import org.jclouds.net.domain.IpProtocol; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.json.ClaimSetTypeAdapter; +import org.jclouds.oauth.v2.json.HeaderTypeAdapter; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Range; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; + +public class GoogleComputeEngineParserModule extends AbstractModule { + + @Override + protected void configure() { + bind(GsonModule.DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class); + } + + @Provides + @Singleton + public Map provideCustomAdapterBindings() { + return new ImmutableMap.Builder() + .put(Metadata.class, new MetadataTypeAdapter()) + .put(Operation.class, new OperationTypeAdapter()) + .put(Header.class, new HeaderTypeAdapter()) + .put(ClaimSet.class, new ClaimSetTypeAdapter()) + .put(Project.class, new ProjectTypeAdapter()) + .put(Instance.class, new InstanceTypeAdapter()) + .put(InstanceTemplate.class, new InstanceTemplateTypeAdapter()) + .put(FirewallOptions.class, new FirewallOptionsTypeAdapter()) + .put(RouteOptions.class, new RouteOptionsTypeAdapter()) + .put(Rule.class, new RuleTypeAdapter()) + .build(); + } + + /** + * Parser for operations that unwraps errors avoiding an extra intermediate object. + * + * @see + */ + @Singleton + private static class OperationTypeAdapter implements JsonDeserializer { + + @Override + public Operation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws + JsonParseException { + Operation.Builder operationBuilder = ((Operation) context.deserialize(json, + OperationInternal.class)).toBuilder(); + JsonObject error = json.getAsJsonObject().getAsJsonObject("error"); + if (error != null) { + JsonArray array = error.getAsJsonArray("errors"); + if (array != null) { + for (JsonElement element : array) { + operationBuilder.addError((Operation.Error) context.deserialize(element, Operation.Error.class)); + } + } + } + return operationBuilder.build(); + } + + private static class OperationInternal extends Operation { + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "targetLink", "targetId", + "clientOperationId", "status", "statusMessage", "user", "progress", "insertTime", "startTime", + "endTime", "httpErrorStatusCode", "httpErrorMessage", "operationType", "region", "zone" + }) + private OperationInternal(String id, Date creationTimestamp, URI selfLink, String name, + String description, URI targetLink, String targetId, String clientOperationId, + Status status, String statusMessage, String user, int progress, Date insertTime, + Date startTime, Date endTime, int httpErrorStatusCode, String httpErrorMessage, + String operationType, URI region, URI zone) { + super(id, creationTimestamp, selfLink, name, description, targetLink, targetId, clientOperationId, + status, statusMessage, user, progress, insertTime, startTime, endTime, httpErrorStatusCode, + httpErrorMessage, operationType, null, region, zone); + } + } + } + + @Singleton + private static class InstanceTemplateTypeAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(InstanceTemplate src, Type typeOfSrc, JsonSerializationContext context) { + InstanceTemplateInternal template = new InstanceTemplateInternal(src); + JsonObject instance = (JsonObject) context.serialize(template, InstanceTemplateInternal.class); + + // deal with network + JsonArray networkInterfaces = new JsonArray(); + for (InstanceTemplate.NetworkInterface networkInterface : template.getNetworkInterfaces()){ + networkInterfaces.add(context.serialize(networkInterface, InstanceTemplate.NetworkInterface.class)); + } + instance.add("networkInterfaces", networkInterfaces); + + // deal with persistent disks + if (src.getDisks() != null && !src.getDisks().isEmpty()) { + JsonArray disks = new JsonArray(); + for (InstanceTemplate.PersistentDisk persistentDisk : src.getDisks()) { + JsonObject disk = (JsonObject) context.serialize(persistentDisk, InstanceTemplate.PersistentDisk.class); + disk.addProperty("type", "PERSISTENT"); + disks.add(disk); + } + instance.add("disks", disks); + } + + // deal with metadata + if (src.getMetadata() != null && !src.getMetadata().isEmpty()) { + Metadata metadata = Metadata.builder() + .items(src.getMetadata()) + .build(); + JsonObject metadataJson = (JsonObject) context.serialize(metadata); + instance.add("metadata", metadataJson); + return instance; + } + + return instance; + } + + private static class InstanceTemplateInternal extends InstanceTemplate { + private InstanceTemplateInternal(InstanceTemplate template) { + super(template.getMachineType()); + name(template.getName()); + description(template.getDescription()); + image(template.getImage()); + serviceAccounts(template.getServiceAccounts()); + networkInterfaces(template.getNetworkInterfaces()); + } + } + } + + @Singleton + private static class InstanceTypeAdapter implements JsonDeserializer { + + @Override + public Instance deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws + JsonParseException { + Instance.Builder instanceBuilder = ((Instance) context.deserialize(json, + InstanceInternal.class)).toBuilder(); + JsonObject object = (JsonObject) json; + if (object.get("disks") != null) { + JsonArray disks = (JsonArray) object.get("disks"); + for (JsonElement element : disks) { + JsonObject disk = (JsonObject) element; + if (disk.get("type").getAsString().equals("PERSISTENT")) { + instanceBuilder.addDisk((Instance.PersistentAttachedDisk) context.deserialize(disk, + Instance.PersistentAttachedDisk.class)); + } else { + instanceBuilder.addDisk((Instance.AttachedDisk) context.deserialize(disk, + Instance.AttachedDisk.class)); + } + } + + } + + return Instance.builder().fromInstance(instanceBuilder.build()).build(); + } + + + private static class InstanceInternal extends Instance { + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "tags", "machineType", + "status", "statusMessage", "zone", "networkInterfaces", "metadata", "serviceAccounts" + }) + private InstanceInternal(String id, Date creationTimestamp, URI selfLink, String name, String description, + Tags tags, URI machineType, Status status, String statusMessage, + URI zone, Set networkInterfaces, Metadata metadata, + Set serviceAccounts) { + super(id, creationTimestamp, selfLink, name, description, tags, machineType, + status, statusMessage, zone, networkInterfaces, null, metadata, serviceAccounts); + } + } + } + + /** + * Parser for Metadata. + */ + @Singleton + private static class MetadataTypeAdapter implements JsonDeserializer, JsonSerializer { + + + @Override + public Metadata deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws + JsonParseException { + ImmutableMap.Builder builder = ImmutableMap.builder(); + JsonObject metadata = json.getAsJsonObject(); + JsonArray items = metadata.getAsJsonArray("items"); + if (items != null) { + for (JsonElement element : items) { + JsonObject object = element.getAsJsonObject(); + builder.put(object.get("key").getAsString(), object.get("value").getAsString()); + } + } + String fingerprint = null; + if (metadata.getAsJsonPrimitive("fingerprint") != null) { + fingerprint = metadata.getAsJsonPrimitive("fingerprint").getAsString(); + } else { + fingerprint = ""; + } + return new Metadata(fingerprint, builder.build()); + } + + @Override + public JsonElement serialize(Metadata src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject metadataObject = new JsonObject(); + metadataObject.add("kind", new JsonPrimitive("compute#metadata")); + JsonArray items = new JsonArray(); + for (Map.Entry entry : src.getItems().entrySet()) { + JsonObject object = new JsonObject(); + object.addProperty("key", entry.getKey()); + object.addProperty("value", entry.getValue()); + items.add(object); + } + metadataObject.add("items", items); + if (src.getFingerprint() != null) { + metadataObject.addProperty("fingerprint", src.getFingerprint()); + } + return metadataObject; + } + } + + + + @Singleton + private static class ProjectTypeAdapter implements JsonDeserializer { + + @Override + public Project deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws + JsonParseException { + return Project.builder().fromProject((Project) context.deserialize(json, ProjectInternal.class)).build(); + } + + private static class ProjectInternal extends Project { + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "commonInstanceMetadata", "quotas", + "externalIpAddresses" + }) + private ProjectInternal(String id, Date creationTimestamp, URI selfLink, String name, String description, + Metadata commonInstanceMetadata, Set quotas, Set externalIpAddresses) { + super(id, creationTimestamp, selfLink, name, description, commonInstanceMetadata, quotas, + externalIpAddresses); + } + + } + } + + @Singleton + private static class FirewallOptionsTypeAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(FirewallOptions src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject firewall = new JsonObject(); + if (src.getName() != null) { + firewall.addProperty("name", src.getName()); + } + if (src.getNetwork() != null) { + firewall.addProperty("network", src.getNetwork().toString()); + } + if (!src.getSourceRanges().isEmpty()) { + firewall.add("sourceRanges", buildArrayOfStrings(src.getSourceRanges())); + } + if (!src.getSourceTags().isEmpty()) { + firewall.add("sourceTags", buildArrayOfStrings(src.getSourceTags())); + } + if (!src.getTargetTags().isEmpty()) { + firewall.add("targetTags", buildArrayOfStrings(src.getTargetTags())); + } + if (!src.getAllowed().isEmpty()) { + JsonArray rules = new JsonArray(); + for (Rule rule : src.getAllowed()) { + rules.add(context.serialize(rule, Firewall.Rule.class)); + } + firewall.add("allowed", rules); + } + return firewall; + } + } + + @Singleton + private static class RouteOptionsTypeAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(RouteOptions src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject route = new JsonObject(); + if (src.getName() != null) { + route.addProperty("name", src.getName()); + } + if (src.getNetwork() != null) { + route.addProperty("network", src.getNetwork().toString()); + } + if (src.getNextHopGateway() != null) { + route.addProperty("nextHopGateway", src.getNextHopGateway().toString()); + } + if (src.getNextHopInstance() != null) { + route.addProperty("nextHopInstance", src.getNextHopInstance().toString()); + } + if (src.getNextHopNetwork() != null) { + route.addProperty("nextHopNetwork", src.getNextHopNetwork().toString()); + } + if (src.getDestRange() != null) { + route.addProperty("destRange", src.getDestRange()); + } + if (src.getDescription() != null) { + route.addProperty("description", src.getDescription()); + } + if (src.getPriority() != null) { + route.addProperty("priority", src.getPriority()); + } + if (src.getNextHopIp() != null) { + route.addProperty("nextHopIp", src.getNextHopIp()); + } + if (!src.getTags().isEmpty()) { + route.add("tags", buildArrayOfStrings(src.getTags())); + } + return route; + } + } + + private static JsonArray buildArrayOfStrings(Set strings) { + JsonArray array = new JsonArray(); + for (String string : strings) { + array.add(new JsonPrimitive(string)); + } + return array; + } + + + private static class RuleTypeAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public Firewall.Rule deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws + JsonParseException { + JsonObject rule = json.getAsJsonObject(); + Rule.Builder builder = Rule.builder(); + builder.IpProtocol(IpProtocol.fromValue(rule.get("IPProtocol").getAsString())); + if (rule.get("ports") != null) { + JsonArray ports = (JsonArray) rule.get("ports"); + for (JsonElement port : ports) { + String portAsString = port.getAsString(); + if (portAsString.contains("-")) { + String[] split = portAsString.split("-"); + builder.addPortRange(Integer.parseInt(split[0]), Integer.parseInt(split[1])); + } else { + builder.addPort(Integer.parseInt(portAsString)); + } + } + } + return builder.build(); + } + + @Override + public JsonElement serialize(Firewall.Rule src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject ruleObject = new JsonObject(); + ruleObject.addProperty("IPProtocol", src.getIpProtocol().value()); + if (src.getPorts() != null && !src.getPorts().isEmpty()) { + JsonArray ports = new JsonArray(); + for (Range range : src.getPorts().asRanges()) { + ports.add(new JsonPrimitive(range.lowerEndpoint() == range.upperEndpoint() ? range.lowerEndpoint() + "" : + range.lowerEndpoint() + "-" + range.upperEndpoint())); + } + ruleObject.add("ports", ports); + } + return ruleObject; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/OAuthModuleWithoutTypeAdapters.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/OAuthModuleWithoutTypeAdapters.java new file mode 100644 index 0000000000..157dd9b10d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/OAuthModuleWithoutTypeAdapters.java @@ -0,0 +1,51 @@ +/* + * 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.googlecomputeengine.config; + +import org.jclouds.oauth.v2.config.OAuthModule; +import org.jclouds.oauth.v2.domain.OAuthCredentials; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.functions.BuildTokenRequest; +import org.jclouds.oauth.v2.functions.FetchToken; +import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier; +import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.inject.TypeLiteral; + +/** + * Overrides OAuthModule leaving TypeAdapters bindings out. + *

+ * TODO overcome this by using multibindings on GSonModule? + */ +public class OAuthModuleWithoutTypeAdapters extends OAuthModule { + + @Override + protected void configure() { + bind(new TypeLiteral>() { + }).to(SignOrProduceMacForToken.class); + bind(new TypeLiteral>() { + }).to(OAuthCredentialsSupplier.class); + bind(new TypeLiteral>() { + }).to(BuildTokenRequest.class); + bind(new TypeLiteral>() { + }).to(FetchToken.class); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/UserProject.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/UserProject.java new file mode 100644 index 0000000000..e932d1cee0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/config/UserProject.java @@ -0,0 +1,33 @@ +/* + * 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.googlecomputeengine.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Qualifies a property as the user's project id. + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) +@Qualifier +public @interface UserProject { +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/AbstractDisk.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/AbstractDisk.java new file mode 100644 index 0000000000..2cc8d8e4e1 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/AbstractDisk.java @@ -0,0 +1,121 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Date; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; + +/** + * A persistent disk resource + * + * @see + */ +@Beta +public abstract class AbstractDisk extends Resource { + + protected final Integer sizeGb; + protected final String status; + + protected AbstractDisk(Kind kind, String id, Date creationTimestamp, URI selfLink, String name, String description, + Integer sizeGb, String status) { + super(kind, id, creationTimestamp, selfLink, name, description); + this.sizeGb = checkNotNull(sizeGb, "sizeGb of %s", name); + this.status = checkNotNull(status, "status of %s", name); + } + + /** + * @return size of the persistent disk, specified in GB. + */ + public int getSizeGb() { + return sizeGb; + } + + /** + * @return the status of disk creation. + */ + public String getStatus() { + return status; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("sizeGb", sizeGb) + .add("status", status); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new ConcreteBuilder(); + } + + public Builder toBuilder() { + return new ConcreteBuilder().fromAbstractDisk(this); + } + + public abstract static class Builder> extends Resource.Builder { + + protected Integer sizeGb; + protected String status; + + /** + * @see org.jclouds.googlecomputeengine.domain.AbstractDisk#getSizeGb() + */ + public T sizeGb(Integer sizeGb) { + this.sizeGb = sizeGb; + return self(); + } + + /** + * @see org.jclouds.googlecomputeengine.domain.AbstractDisk#getStatus() + */ + public T status(String status) { + this.status = status; + return self(); + } + + public T fromAbstractDisk(AbstractDisk in) { + return super.fromResource(in) + .sizeGb(in.getSizeGb()) + .status(in.getStatus()); + } + + } + + private static class ConcreteBuilder extends Builder { + @Override + protected ConcreteBuilder self() { + return this; + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Address.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Address.java new file mode 100644 index 0000000000..207cf753a6 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Address.java @@ -0,0 +1,177 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; + +/** + * Represents an Address resource. + * + * @see + */ +@Beta +public final class Address extends Resource { + + private final String status; + private final Optional user; + private final URI region; + private final String address; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "status", "user", + "region", "address" + }) + private Address(String id, Date creationTimestamp, URI selfLink, String name, String description, + String status, URI user, URI region, String address) { + super(Kind.ADDRESS, id, creationTimestamp, selfLink, name, description); + this.status = checkNotNull(status, "status of %s", name); + this.user = fromNullable(user); + this.region = checkNotNull(region, "region of %s", name); + this.address = checkNotNull(address, "address of %s", name); + } + + /** + * @return The status of the address. Valid items are RESERVED and IN USE. + * A reserved address is currently available to the project and can be + * used by a resource. An in-use address is currently being used by a resource. + */ + public String getStatus() { + return status; + } + + /** + * @return URL of the resource currently using this address. + */ + public Optional getUser() { + return user; + } + + /** + * @return URL of the region where the address resides. + */ + public URI getRegion() { + return region; + } + + /** + * @return The IP address represented by this resource. + */ + public String getAddress() { + return address; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Address that = Address.class.cast(obj); + return equal(this.kind, that.kind) + && equal(this.name, that.name) + && equal(this.region, that.region); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("status", status) + .add("user", user.orNull()) + .add("region", region) + .add("address", address); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromAddress(this); + } + + public static final class Builder extends Resource.Builder { + private String status; + private URI user; + private URI region; + private String address; + + /** + * @see org.jclouds.googlecomputeengine.domain.Address#getStatus() + */ + public Builder status(String status) { + this.status = status; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Address#getUser() + */ + public Builder user(URI user) { + this.user = user; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Address#getRegion() + */ + public Builder region(URI region) { + this.region = region; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Address#getAddress() + */ + public Builder address(String address) { + this.address = address; + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Address build() { + return new Address(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, status, user, region, address); + } + + public Builder fromAddress(Address in) { + return super.fromResource(in) + .status(in.getStatus()) + .user(in.getUser().orNull()) + .region(in.getRegion()) + .address(in.getAddress()); + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Deprecated.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Deprecated.java new file mode 100644 index 0000000000..5a48acf95f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Deprecated.java @@ -0,0 +1,195 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; + +import java.beans.ConstructorProperties; +import java.net.URI; + +import com.google.common.base.Objects; +import com.google.common.base.Optional; + +/** + * Deprecation information for an image or kernel + */ +public class Deprecated { + private final Optional state; + private final Optional replacement; + private final Optional deprecated; + private final Optional obsolete; + private final Optional deleted; + + @ConstructorProperties({"state", "replacement", "deprecated", "obsolete", "deleted"}) + public Deprecated(String state, URI replacement, String deprecated, String obsolete, + String deleted) { + this.state = fromNullable(state); + this.replacement = fromNullable(replacement); + this.deprecated = fromNullable(deprecated); + this.obsolete = fromNullable(obsolete); + this.deleted = fromNullable(deleted); + } + + /** + * @return The deprecation state of this image. + */ + public Optional getState() { + return state; + } + + /** + * @return A fully-qualified URL of the suggested replacement for the deprecated image. + */ + public Optional getReplacement() { + return replacement; + } + + /** + * @return An optional RFC3339 timestamp for when the deprecation state of this resource will be changed to DEPRECATED. + */ + public Optional getDeprecated() { + return deprecated; + } + + /** + * @return An optional RFC3339 timestamp on or after which the deprecation state of this resource will be changed toOBSOLETE. + */ + public Optional getObsolete() { + return obsolete; + } + + /** + * @return An optional RFC3339 timestamp on or after which the deprecation state of this resource will be changed to DELETED. + */ + public Optional getDeleted() { + return deleted; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(state, replacement, deprecated, obsolete, deleted); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Deprecated that = Deprecated.class.cast(obj); + return equal(this.state, that.state) + && equal(this.replacement, that.replacement) + && equal(this.deprecated, that.deprecated) + && equal(this.obsolete, that.obsolete) + && equal(this.deleted, that.deleted); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .omitNullValues() + .add("state", state.orNull()) + .add("replacement", replacement.orNull()) + .add("deprecated", deprecated.orNull()) + .add("obsolete", obsolete.orNull()) + .add("deleted", deleted.orNull()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromDeprecated(this); + } + + public static class Builder { + private String state; + private URI replacement; + private String deprecated; + private String obsolete; + private String deleted; + + /** + * @see org.jclouds.googlecomputeengine.domain.Deprecated#getState() + */ + public Builder state(String state) { + this.state = state; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Deprecated#getReplacement() + */ + public Builder replacement(URI replacement) { + this.replacement = replacement; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Deprecated#getDeprecated() + */ + public Builder deprecated(String deprecated) { + this.deprecated = deprecated; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Deprecated#getObsolete() + */ + public Builder obsolete(String obsolete) { + this.obsolete = obsolete; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Deprecated#getDeprecated() + */ + public Builder deleted(String deleted) { + this.deleted = deleted; + return this; + } + + public Deprecated build() { + return new Deprecated(state, replacement, deprecated, obsolete, deleted); + } + + public Builder fromDeprecated(Deprecated in) { + return new Builder().state(in.getState().orNull()) + .replacement(in.getReplacement().orNull()) + .deprecated(in.getDeprecated().orNull()) + .obsolete(in.getObsolete().orNull()) + .deleted(in.getDeleted().orNull()); + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Disk.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Disk.java new file mode 100644 index 0000000000..91d1502b2f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Disk.java @@ -0,0 +1,123 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; + +/** + * A persistent disk resource + * + * @see + */ +@Beta +public final class Disk extends AbstractDisk { + + private final URI zone; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "sizeGb", "zone", + "status" + }) + private Disk(String id, Date creationTimestamp, URI selfLink, String name, String description, + Integer sizeGb, URI zone, String status) { + super(Kind.DISK, id, creationTimestamp, selfLink, name, description, sizeGb, status); + this.zone = checkNotNull(zone, "zone of %s", name); + } + + /** + * @return URL for the zone where the persistent disk resides. + */ + public URI getZone() { + return zone; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Disk that = Disk.class.cast(obj); + return equal(this.kind, that.kind) + && equal(this.name, that.name) + && equal(this.zone, that.zone); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("zone", zone); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromDisk(this); + } + + public static final class Builder extends AbstractDisk.Builder { + + private URI zone; + + /** + * @see Disk#getZone() + */ + public Builder zone(URI zone) { + this.zone = zone; + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Disk build() { + return new Disk(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, super.sizeGb, zone, super.status); + } + + public Builder fromDisk(Disk in) { + return super.fromAbstractDisk(in) + .zone(in.getZone()); + } + + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Firewall.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Firewall.java new file mode 100644 index 0000000000..aee2cd41c3 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Firewall.java @@ -0,0 +1,379 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Range.closed; +import static com.google.common.collect.Range.singleton; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.Set; + +import org.jclouds.net.domain.IpProtocol; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.RangeSet; +import com.google.common.collect.TreeRangeSet; + +/** + * Represents a network firewall + * + * @see + * @see + */ +@Beta +public final class Firewall extends Resource { + + private final URI network; + private final Set sourceRanges; + private final Set sourceTags; + private final Set targetTags; + private final Set allowed; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "network", "sourceRanges", + "sourceTags", "targetTags", "allowed" + }) + protected Firewall(String id, Date creationTimestamp, URI selfLink, String name, String description, + URI network, Set sourceRanges, Set sourceTags, Set targetTags, + Set allowed) { + super(Kind.FIREWALL, id, creationTimestamp, selfLink, name, description); + this.network = checkNotNull(network, "network of %s", name); + this.sourceRanges = sourceRanges == null ? ImmutableSet.of() : sourceRanges; + this.sourceTags = sourceTags == null ? ImmutableSet.of() : sourceTags; + this.targetTags = targetTags == null ? ImmutableSet.of() : targetTags; + this.allowed = allowed == null ? ImmutableSet.of() : allowed; + } + + /** + * @return URI of the network to which this firewall is applied; provided by the client when the firewall is created. + */ + public URI getNetwork() { + return network; + } + + /** + * One or both of sourceRanges and sourceTags may be set; an inbound connection is allowed if either the range or + * the tag of the source matches. + * + * @return a list of IP address blocks expressed in CIDR format which this rule applies to. + */ + public Set getSourceRanges() { + return sourceRanges; + } + + /** + * @return a list of instance items which this rule applies to. One or both of sourceRanges and sourceTags may be + * set; an inbound connection is allowed if either the range or the tag of the source matches. + */ + public Set getSourceTags() { + return sourceTags; + } + + /** + * If no targetTags are specified, the firewall rule applies to all instances on the specified network. + * + * @return a list of instance items indicating sets of instances located on network which may make network + * connections as specified in allowed. + */ + public Set getTargetTags() { + return targetTags; + } + + /** + * Each rule specifies a protocol and port-range tuple that describes a permitted connection. + * + * @return the list of rules specified by this firewall. + */ + public Set getAllowed() { + return allowed; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .add("network", network) + .add("sourceRanges", sourceRanges) + .add("sourceTags", sourceTags) + .add("targetTags", targetTags) + .add("allowed", allowed); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromFirewall(this); + } + + public static final class Builder extends Resource.Builder { + + private URI network; + private ImmutableSet.Builder sourceRanges = ImmutableSet.builder(); + private ImmutableSet.Builder sourceTags = ImmutableSet.builder(); + private ImmutableSet.Builder targetTags = ImmutableSet.builder(); + private ImmutableSet.Builder allowed = ImmutableSet.builder(); + + /** + * @see Firewall#getNetwork() + */ + public Builder network(URI network) { + this.network = network; + return this; + } + + /** + * @see Firewall#getSourceRanges() + */ + public Builder addSourceRange(String sourceRange) { + this.sourceRanges.add(checkNotNull(sourceRange)); + return this; + } + + /** + * @see Firewall#getSourceRanges() + */ + public Builder sourceRanges(Set sourceRanges) { + this.sourceRanges.addAll(checkNotNull(sourceRanges)); + return this; + } + + /** + * @see Firewall#getSourceTags() + */ + public Builder addSourceTag(String sourceTag) { + this.sourceTags.add(checkNotNull(sourceTag)); + return this; + } + + /** + * @see Firewall#getSourceTags() + */ + public Builder sourceTags(Set sourceTags) { + this.sourceTags.addAll(checkNotNull(sourceTags)); + return this; + } + + /** + * @see Firewall#getTargetTags() + */ + public Builder addTargetTag(String targetTag) { + this.targetTags.add(checkNotNull(targetTag)); + return this; + } + + /** + * @see Firewall#getTargetTags() + */ + public Builder targetTags(Set targetTags) { + this.targetTags.addAll(checkNotNull(targetTags)); + return this; + } + + /** + * @see Firewall#getAllowed() + */ + public Builder addAllowed(Rule firewallRule) { + this.allowed.add(checkNotNull(firewallRule)); + return this; + } + + /** + * @see Firewall#getAllowed() + */ + public Builder allowed(Set firewallRules) { + this.allowed = ImmutableSet.builder(); + this.allowed.addAll(firewallRules); + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Firewall build() { + return new Firewall(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, network, sourceRanges.build(), sourceTags.build(), targetTags.build(), + allowed.build()); + } + + public Builder fromFirewall(Firewall in) { + return super.fromResource(in).network(in.getNetwork()).sourceRanges(in.getSourceRanges()).sourceTags(in + .getSourceTags()).targetTags(in.getTargetTags()).allowed(in.getAllowed()); + } + + } + + /** + * A Firewall rule. Rule specifies a protocol and port-range tuple that describes a + * permitted connection. + * + * @see + */ + public static final class Rule { + + private final IpProtocol ipProtocol; + private final RangeSet ports; + + /* Some handy shortcuts */ + public static Rule permitTcpRule(Integer start, Integer end) { return Rule.builder().IpProtocol(IpProtocol.TCP).addPortRange(start, end).build(); } + public static Rule permitTcpRule(Integer port) { return Rule.builder().IpProtocol(IpProtocol.TCP).addPort(port).build(); } + public static Rule permitUdpRule(Integer start, Integer end) { return Rule.builder().IpProtocol(IpProtocol.UDP).addPortRange(start, end).build(); } + public static Rule permitUdpRule(Integer port) { return Rule.builder().IpProtocol(IpProtocol.UDP).addPort(port).build(); } + @ConstructorProperties({ + "IpProtocol", "ports" + }) + private Rule(IpProtocol IpProtocol, RangeSet ports) { + this.ipProtocol = checkNotNull(IpProtocol); + this.ports = ports == null ? TreeRangeSet.create() : ports; + } + + /** + * This can either be a well known protocol string (tcp, udp or icmp) or the IP protocol number. + * + * @return this is the IP protocol that is allowed for this rule. + */ + public IpProtocol getIpProtocol() { + return ipProtocol; + } + + /** + * Each entry must be either an integer or a range. If not specified, connections through any port are allowed. + * Example inputs include: ["22"], ["80,"443"], and ["12345-12349"]. + *

+ * It is an error to specify this for any protocol that isn't UDP or TCP. + * + * @return An optional list of ports which are allowed. + */ + public RangeSet getPorts() { + return ports; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(ipProtocol, ports); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Rule that = Rule.class.cast(obj); + return equal(this.ipProtocol, that.ipProtocol) + && equal(this.ports, that.ports); + } + + /** + * {@inheritDoc} + */ + public Objects.ToStringHelper string() { + return toStringHelper(this) + .add("IpProtocol", ipProtocol).add("ports", ports); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromFirewallRule(this); + } + + public static final class Builder { + + private IpProtocol ipProtocol; + private RangeSet ports = TreeRangeSet.create(); + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall.Rule#getIpProtocol() + */ + public Builder IpProtocol(IpProtocol IpProtocol) { + this.ipProtocol = IpProtocol; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall.Rule#getPorts() + */ + public Builder addPort(Integer port) { + this.ports.add(singleton(checkNotNull(port, "port"))); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall.Rule#getPorts() + */ + public Builder addPortRange(Integer start, Integer end) { + checkState(checkNotNull(start, "start") < checkNotNull(end, "end"), + "start of range must be lower than end of range"); + this.ports.add(closed(start, end)); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall.Rule#getPorts() + */ + public Builder ports(RangeSet ports) { + this.ports = TreeRangeSet.create(); + this.ports.addAll(ports); + return this; + } + + public Rule build() { + return new Rule(ipProtocol, ports); + } + + public Builder fromFirewallRule(Rule firewallRule) { + return new Builder().IpProtocol(firewallRule.getIpProtocol()).ports(firewallRule.getPorts()); + } + } + + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Image.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Image.java new file mode 100644 index 0000000000..424aaa1206 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Image.java @@ -0,0 +1,286 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; + +/** + * Represents a disk image to use on an instance. + * + * @see + */ +@Beta +public final class Image extends Resource { + + private final String sourceType; + private final RawDisk rawDisk; + private final Optional deprecated; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "sourceType", + "rawDisk", "deprecated" + }) + protected Image(String id, Date creationTimestamp, URI selfLink, String name, String description, + String sourceType, RawDisk rawDisk, Deprecated deprecated) { + super(Kind.IMAGE, id, creationTimestamp, selfLink, name, description); + this.sourceType = checkNotNull(sourceType, "sourceType of %s", name); + // rawDisk may be null for user created private images + this.rawDisk = rawDisk; // checkNotNull(rawDisk, "rawDisk of %s", name); + this.deprecated = fromNullable(deprecated); + } + + /** + * @return must be RAW; provided by the client when the disk image is created. + */ + public String getSourceType() { + return sourceType; + } + + /** + * @return the raw disk image parameters. + */ + public RawDisk getRawDisk() { + return rawDisk; + } + + /** + * @return the deprecation information for this image + */ + public Optional getDeprecated() { + return deprecated; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("sourceType", sourceType) + .add("rawDisk", rawDisk) + .add("deprecated", deprecated.orNull()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromImage(this); + } + + public static final class Builder extends Resource.Builder { + + private String sourceType; + private RawDisk rawDisk; + private Deprecated deprecated; + + /** + * @see Image#getSourceType() + */ + public Builder sourceType(String sourceType) { + this.sourceType = checkNotNull(sourceType, "sourceType"); + return this; + } + + /** + * @see Image#getDeprecated() + */ + public Builder deprecated(Deprecated deprecated) { + this.deprecated = checkNotNull(deprecated, "deprecated"); + return this; + } + + /** + * @see Image#getRawDisk() + */ + public Builder rawDisk(RawDisk rawDisk) { + this.rawDisk = checkNotNull(rawDisk); + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Image build() { + return new Image(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, sourceType, rawDisk, deprecated); + } + + public Builder fromImage(Image in) { + return super.fromResource(in) + .sourceType(in.getSourceType()) + .rawDisk(in.getRawDisk()) + .deprecated(in.getDeprecated().orNull()); + } + + } + + /** + * A raw disk image, usually the base for an image. + * + * @see + */ + public static class RawDisk { + + private final String source; + private final String containerType; + private final Optional sha1Checksum; + + @ConstructorProperties({ + "source", "containerType", "sha1Checksum" + }) + private RawDisk(String source, String containerType, String sha1Checksum) { + this.source = checkNotNull(source, "source"); + this.containerType = checkNotNull(containerType, "containerType"); + this.sha1Checksum = fromNullable(sha1Checksum); + } + + /** + * @return the full Google Cloud Storage URL where the disk image is stored; provided by the client when the disk + * image is created. + */ + public String getSource() { + return source; + } + + /** + * @return the format used to encode and transmit the block device. + */ + public String getContainerType() { + return containerType; + } + + /** + * @return an optional SHA1 checksum of the disk image before unpackaging; provided by the client when the disk + * image is created. + */ + public Optional getSha1Checksum() { + return sha1Checksum; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(source, containerType, sha1Checksum); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + RawDisk that = RawDisk.class.cast(obj); + return equal(this.source, that.source) + && equal(this.containerType, that.containerType) + && equal(this.sha1Checksum, that.sha1Checksum); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .omitNullValues() + .add("source", source) + .add("containerType", containerType) + .add("sha1Checksum", sha1Checksum.orNull()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromImageRawDisk(this); + } + + public static class Builder { + + private String source; + private String containerType; + private String sha1Checksum; + + /** + * @see org.jclouds.googlecomputeengine.domain.Image.RawDisk#getSource() + */ + public Builder source(String source) { + this.source = checkNotNull(source); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Image.RawDisk#getContainerType() + */ + public Builder containerType(String containerType) { + this.containerType = checkNotNull(containerType); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Image.RawDisk#getSha1Checksum() + */ + public Builder sha1Checksum(String sha1Checksum) { + this.sha1Checksum = sha1Checksum; + return this; + } + + public RawDisk build() { + return new RawDisk(source, containerType, sha1Checksum); + } + + public Builder fromImageRawDisk(RawDisk rawDisk) { + return new Builder().source(rawDisk.getSource()) + .containerType(rawDisk.getContainerType()) + .sha1Checksum(rawDisk.getSha1Checksum().orNull()); + } + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Instance.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Instance.java new file mode 100644 index 0000000000..e67366e3dc --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Instance.java @@ -0,0 +1,1187 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.getLast; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.Set; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; + +/** + * Represents a virtual machine. + * + * @see + */ +@Beta +public class Instance extends Resource { + + public enum Status { + PROVISIONING, + STAGING, + RUNNING, + STOPPING, + STOPPED, + TERMINATED + } + + protected final Tags tags; + protected final URI machineType; + protected final Status status; + protected final Optional statusMessage; + protected final URI zone; + protected final Set networkInterfaces; + protected final Set disks; + protected final Metadata metadata; + protected final Set serviceAccounts; + + protected Instance(String id, Date creationTimestamp, URI selfLink, String name, String description, + Tags tags, URI machineType, Status status, String statusMessage, + URI zone, Set networkInterfaces, Set disks, + Metadata metadata, Set serviceAccounts) { + super(Kind.INSTANCE, id, creationTimestamp, selfLink, name, description); + this.tags = checkNotNull(tags, "tags"); + this.machineType = checkNotNull(machineType, "machineType of %s", name); + this.status = checkNotNull(status, "status"); + this.statusMessage = fromNullable(statusMessage); + this.zone = checkNotNull(zone, "zone of %s", name); + this.networkInterfaces = networkInterfaces == null ? ImmutableSet.of() : networkInterfaces; + this.disks = disks == null ? ImmutableSet.of() : disks; + this.metadata = checkNotNull(metadata, "metadata"); + this.serviceAccounts = serviceAccounts == null ? ImmutableSet.of() : serviceAccounts; + } + + /** + * Used to identify valid sources or targets for network firewalls. Provided by the client when the instance is + * created. Each tag must be unique, must be 1-63 characters long, and comply with RFC1035. + * + * @return an optional set of items applied to this instance. + */ + public Tags getTags() { + return tags; + } + + /** + * @return URL of the machine type resource describing which machine type to use to host the instance. + */ + public URI getMachineType() { + return machineType; + } + + /** + * @return Instance status + */ + public Status getStatus() { + return status; + } + + /** + * @return an optional, human-readable explanation of the status. + */ + @Nullable + public Optional getStatusMessage() { + return statusMessage; + } + + /** + * @return URL of the zone resource describing where this instance should be hosted; provided by the client when + * the instance is created. + */ + public URI getZone() { + return zone; + } + + /** + * @return set of NetworkInterfaces + * @see NetworkInterface + */ + public Set getNetworkInterfaces() { + return networkInterfaces; + } + + /** + * @return array of disks associated with this instance. Persistent disks must be created before + * you can assign them. + * @see org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk + */ + public Set getDisks() { + return disks; + } + + /** + * @return metadata for this instance + */ + public Metadata getMetadata() { + return metadata; + } + + /** + * @return list of service accounts each with specified scopes. + * @see ServiceAccount + */ + public Set getServiceAccounts() { + return serviceAccounts; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Instance that = Instance.class.cast(obj); + return equal(this.kind, that.kind) + && equal(this.name, that.name) + && equal(this.zone, that.zone); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("items", tags) + .add("machineType", machineType) + .add("status", status) + .add("statusMessage", statusMessage.orNull()) + .add("zone", zone) + .add("networkInterfaces", networkInterfaces) + .add("disks", disks) + .add("metadata", metadata) + .add("serviceAccounts", serviceAccounts); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromInstance(this); + } + + public static final class Builder extends Resource.Builder { + + private Tags tags; + private URI machineType; + private Status status; + private String statusMessage; + private URI zone; + private Metadata metadata; + private ImmutableSet.Builder networkInterfaces = ImmutableSet.builder(); + private ImmutableSet.Builder disks = ImmutableSet.builder(); + private ImmutableSet.Builder serviceAccounts = ImmutableSet.builder(); + + + /** + * @see Instance#getTags() + */ + public Builder tags(Tags tags) { + this.tags = tags; + return this; + } + + /** + * @see Instance#getMachineType() + */ + public Builder machineType(URI machineType) { + this.machineType = machineType; + return this; + } + + /** + * @see Instance#getStatus() + */ + public Builder status(Status status) { + this.status = status; + return this; + } + + /** + * @see Instance#getStatusMessage() + */ + public Builder statusMessage(String statusMessage) { + this.statusMessage = statusMessage; + return this; + } + + /** + * @see Instance#getZone() + */ + public Builder zone(URI zone) { + this.zone = zone; + return this; + } + + /** + * @see Instance#getNetworkInterfaces() + */ + public Builder addNetworkInterface(NetworkInterface networkInterface) { + this.networkInterfaces.add(networkInterface); + return this; + } + + /** + * @see Instance#getNetworkInterfaces() + */ + public Builder networkInterfaces(Set networkInterfaces) { + this.networkInterfaces.addAll(networkInterfaces); + return this; + } + + /** + * @see Instance#getDisks() + */ + public Builder addDisk(AttachedDisk disk) { + this.disks.add(disk); + return this; + } + + /** + * @see Instance#getDisks() + */ + public Builder disks(Set disks) { + this.disks.addAll(disks); + return this; + } + + /** + * @see Instance#getMetadata() + */ + public Builder metadata(Metadata metadata) { + this.metadata = metadata; + return this; + } + + /** + * @see Instance#getServiceAccounts() + */ + public Builder addServiceAccount(ServiceAccount serviceAccount) { + this.serviceAccounts.add(serviceAccount); + return this; + } + + /** + * @see Instance#getServiceAccounts() + */ + public Builder serviceAccounts(Set serviceAccounts) { + this.serviceAccounts.addAll(serviceAccounts); + return this; + } + + + @Override + protected Builder self() { + return this; + } + + public Instance build() { + return new Instance(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, tags, machineType, status, statusMessage, zone, + networkInterfaces.build(), disks.build(), metadata, serviceAccounts.build()); + } + + public Builder fromInstance(Instance in) { + return super.fromResource(in) + .tags(in.getTags()) + .machineType(in.getMachineType()) + .status(in.getStatus()) + .statusMessage(in.getStatusMessage().orNull()) + .zone(in.getZone()) + .networkInterfaces(in.getNetworkInterfaces()) + .disks(in.getDisks()) + .metadata(in.getMetadata()) + .serviceAccounts(in.getServiceAccounts()); + } + } + + + + + /** + * Tags for an instance, with their fingerprint. + */ + public static class Tags { + private final String fingerprint; + private final Set items; + + @ConstructorProperties({"fingerprint", "items"}) + public Tags(String fingerprint, @Nullable Set items) { + this.fingerprint = checkNotNull(fingerprint); + this.items = items == null ? ImmutableSet.of() : items; + } + + /** + * Used to identify valid sources or targets for network firewalls. Provided by the client when the instance is + * created. Each tag must be unique, must be 1-63 characters long, and comply with RFC1035. + * + * @return an optional set of items applied to this instance. + */ + public Set getItems() { + return items; + } + + /** + * Gets the fingerprint for the items - needed for updating them. + * + * @return the fingerprint string for the items. + */ + public String getFingerprint() { + return fingerprint; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(fingerprint, items); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Tags that = Tags.class.cast(obj); + return equal(this.items, that.items) + && equal(this.fingerprint, that.fingerprint); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .add("items", items) + .add("fingerprint", fingerprint); + } + + public static Builder builder() { + return new Builder(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static final class Builder { + + private ImmutableSet.Builder items = ImmutableSet.builder(); + private String fingerprint; + + /** + * @see Tags#getItems() + */ + public Builder addItem(String item) { + this.items.add(item); + return this; + } + + /** + * @see Tags#getItems() + */ + public Builder items(Set items) { + this.items.addAll(items); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.Tags#getFingerprint() + */ + public Builder fingerprint(String fingerprint) { + this.fingerprint = fingerprint; + return this; + } + + public Tags build() { + return new Tags(this.fingerprint, this.items.build()); + } + + public Builder fromTags(Tags in) { + return this.fingerprint(in.getFingerprint()) + .items(in.getItems()); + } + } + } + + /** + * A disk attached to an Instance. + * + * @see + */ + public static class AttachedDisk { + + private final int index; + + public AttachedDisk(Integer index) { + this.index = checkNotNull(index, "index"); + } + + public boolean isPersistent() { + return false; + } + + /** + * @return a zero-based index to assign to this disk, where 0 is reserved for the boot disk. + */ + public int getIndex() { + return index; + } + + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(index); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + AttachedDisk that = AttachedDisk.class.cast(obj); + return equal(this.index, that.index); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this).add("index", index); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static AttachedDisk ephemeralDiskAtIndex(Integer index) { + return new AttachedDisk(index); + } + } + + public static class PersistentAttachedDisk extends AttachedDisk { + public enum Mode { + READ_WRITE, + READ_ONLY; + } + + @ConstructorProperties({"mode", "source", "deviceName", "index", "deleteOnTerminate", + "boot"}) + public PersistentAttachedDisk(Mode mode, URI source, String deviceName, Integer index, + boolean deleteOnTerminate, boolean boot) { + super(index); + this.mode = checkNotNull(mode, "mode"); + this.source = checkNotNull(source, "source"); + this.deviceName = fromNullable(deviceName); + this.deleteOnTerminate = deleteOnTerminate; + this.boot = boot; + } + + private final Mode mode; + private final URI source; + private final boolean deleteOnTerminate; + private final Optional deviceName; + private final boolean boot; + + @Override + public boolean isPersistent() { + return true; + } + + /** + * @return the mode in which to attach this disk, either READ_WRITE or READ_ONLY. + */ + public Mode getMode() { + return mode; + } + + /** + * @return the URL of the persistent disk resource. + */ + public URI getSource() { + return source; + } + + /** + * @return the Name of the persistent disk resource + */ + public String getSourceDiskName() { + return getLast(Splitter.on("/").split(source.toString()), null); + } + + /** + * @return Must be unique within the instance when specified. This represents a unique + * device name that is reflected into the /dev/ tree of a Linux operating system running within the + * instance. If not specified, a default will be chosen by the system. + */ + public Optional getDeviceName() { + return deviceName; + } + + + /** + * @return If true, delete the disk and all its data when the associated instance is deleted. + */ + public boolean isDeleteOnTerminate() { + return deleteOnTerminate; + } + + /** + * @return If true, this is the boot disk for this instance. + */ + public boolean isBoot() { + return boot; + } + + public static Builder builder() { + return new Builder(); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this).add("boot", boot); + } + + + public static final class Builder { + + private Mode mode; + private URI source; + private String deviceName; + private Integer index; + private boolean deleteOnTerminate; + private boolean boot; + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.PersistentAttachedDisk#getMode() + */ + public Builder mode(Mode mode) { + this.mode = mode; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.PersistentAttachedDisk#getSource() + */ + public Builder source(URI source) { + this.source = source; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.PersistentAttachedDisk#getDeviceName() + */ + public Builder deviceName(String deviceName) { + this.deviceName = deviceName; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk#getIndex() + */ + public Builder index(Integer index) { + this.index = index; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.PersistentAttachedDisk#isDeleteOnTerminate() + */ + public Builder deleteOnTerminate(Boolean deleteOnTerminate) { + this.deleteOnTerminate = deleteOnTerminate; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.PersistentAttachedDisk#isBoot() + */ + public Builder boot(Boolean boot) { + this.boot = boot; + return this; + } + + public PersistentAttachedDisk build() { + return new PersistentAttachedDisk(this.mode, this.source, this.deviceName, this.index, + this.deleteOnTerminate, this.boot); + } + + public Builder fromPersistentAttachedDisk(PersistentAttachedDisk in) { + return this.mode(in.getMode()) + .source(in.getSource()) + .deviceName(in.getDeviceName().orNull()) + .index(in.getIndex()) + .deleteOnTerminate(in.isDeleteOnTerminate()) + .boot(in.isBoot()); + } + } + } + + /** + * A network interface for an Instance. + * + * @see + */ + public static final class NetworkInterface { + + private final String name; + private final URI network; + private final Optional networkIP; + private final Set accessConfigs; + + @ConstructorProperties({ + "name", "network", "networkIP", "accessConfigs" + }) + private NetworkInterface(String name, URI network, String networkIP, + Set accessConfigs) { + this.name = checkNotNull(name, "name"); + this.network = checkNotNull(network, "network"); + this.networkIP = fromNullable(networkIP); + this.accessConfigs = accessConfigs == null ? ImmutableSet.of() : accessConfigs; + } + + /** + * @return the name of the network interface + */ + public String getName() { + return name; + } + + /** + * @return URL of the network resource attached to this interface. + */ + public URI getNetwork() { + return network; + } + + /** + * @return An IPV4 internal network address to assign to this instance. + */ + public Optional getNetworkIP() { + return networkIP; + } + + /** + * @return array of access configurations for this interface. + */ + public Set getAccessConfigs() { + return accessConfigs; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(name, network, networkIP, accessConfigs); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + NetworkInterface that = NetworkInterface.class.cast(obj); + return equal(this.name, that.name) + && equal(this.network, that.network); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .add("name", name) + .add("network", network).add("networkIP", networkIP).add("accessConfigs", + accessConfigs); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromNetworkInterface(this); + } + + public static class Builder { + + private String name; + private URI network; + private String networkIP; + private ImmutableSet.Builder accessConfigs = ImmutableSet.builder(); + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface#getNetwork() + */ + public Builder network(URI network) { + this.network = network; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface#getNetworkIP() + */ + public Builder networkIP(String networkIP) { + this.networkIP = networkIP; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface#getAccessConfigs() + */ + public Builder addAccessConfig(AccessConfig accessConfig) { + this.accessConfigs.add(accessConfig); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface#getAccessConfigs() + */ + public Builder accessConfigs(Set accessConfigs) { + this.accessConfigs = ImmutableSet.builder(); + this.accessConfigs.addAll(accessConfigs); + return this; + } + + public NetworkInterface build() { + return new NetworkInterface(this.name, this.network, this.networkIP, this.accessConfigs.build()); + } + + public Builder fromNetworkInterface(NetworkInterface in) { + return this.network(in.getNetwork()) + .networkIP(in.getNetworkIP().orNull()) + .accessConfigs(in.getAccessConfigs()); + } + } + + /** + * Access configuration to an instance's network. + *

+ * This specifies how this interface is configured to interact with other network services, + * such as connecting to the internet. Currently, ONE_TO_ONE_NAT is the only access config supported. + */ + public static final class AccessConfig { + + public enum Type { + ONE_TO_ONE_NAT + } + + private Optional name; + private Type type; + private Optional natIP; + + @ConstructorProperties({ + "name", "type", "natIP" + }) + private AccessConfig(String name, Type type, String natIP) { + this.name = fromNullable(name); + this.type = checkNotNull(type, "type"); + this.natIP = fromNullable(natIP); + } + + /** + * @return name of this access configuration. + */ + public Optional getName() { + return name; + } + + /** + * @return type of configuration. Must be set to ONE_TO_ONE_NAT. This configures port-for-port NAT to the + * internet. + */ + public Type getType() { + return type; + } + + /** + * @return an external IP address associated with this instance, if there is one. + */ + @Nullable + public Optional getNatIP() { + return natIP; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(name, type, natIP); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + AccessConfig that = AccessConfig.class.cast(obj); + return equal(this.name, that.name) + && equal(this.type, that.type) + && equal(this.natIP, that.natIP); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .add("name", name).add("type", type).add("natIP", natIP); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromAccessConfig(this); + } + + public static class Builder { + + private String name; + private Type type; + private String natIP; + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig#getType() + */ + public Builder type(Type type) { + this.type = type; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig#getNatIP() + */ + public Builder natIP(String natIP) { + this.natIP = natIP; + return this; + } + + public AccessConfig build() { + return new AccessConfig(name, type, natIP); + } + + public Builder fromAccessConfig(AccessConfig in) { + return this.name(in.getName().orNull()) + .type(in.getType()) + .natIP(in.getNatIP().orNull()); + } + } + } + } + + /** + * The output of an instance's serial port; + * + * @see + */ + public static final class SerialPortOutput { + + private final Optional selfLink; + private final String contents; + + @ConstructorProperties({ + "selfLink", "contents" + }) + public SerialPortOutput(String selfLink, String contents) { + this.selfLink = fromNullable(selfLink); + this.contents = checkNotNull(contents, "contents"); + } + + /** + * @return unique identifier for the resource; defined by the server (output only). + */ + public Optional getSelfLink() { + return selfLink; + } + + /** + * @return the contents of the console output. + */ + public String getContents() { + return contents; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(selfLink, contents); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + SerialPortOutput that = SerialPortOutput.class.cast(obj); + return equal(this.selfLink, that.selfLink); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this).add("selfLink", selfLink).add("contents", contents); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromInstanceSerialPortOutput(this); + } + + public static final class Builder { + + private String selfLink; + private String contents; + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.SerialPortOutput#getSelfLink() + */ + public Builder selfLink(String selfLink) { + this.selfLink = checkNotNull(selfLink); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.SerialPortOutput#getContents() + */ + public Builder contents(String contents) { + this.contents = contents; + return this; + } + + public SerialPortOutput build() { + return new SerialPortOutput(selfLink, contents); + } + + public Builder fromInstanceSerialPortOutput(SerialPortOutput in) { + return this.selfLink(in.getSelfLink().orNull()) + .contents(in.getContents()); + } + } + + } + + /** + * A service account for which access tokens are to be made available to the instance through metadata queries. + * + * @see + */ + public static final class ServiceAccount { + + private final String email; + private final Set scopes; + + @ConstructorProperties({ + "email", "scopes" + }) + public ServiceAccount(String email, Set scopes) { + this.email = checkNotNull(email, "email"); + this.scopes = checkNotNull(scopes, "scopes"); + } + + /** + * @return email address of the service account. + */ + public String getEmail() { + return email; + } + + /** + * @return the list of scopes to be made available for this service account. + */ + public Set getScopes() { + return scopes; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(email, scopes); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + ServiceAccount that = ServiceAccount.class.cast(obj); + return equal(this.email, that.email) + && equal(this.scopes, that.scopes); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this).add("email", email).add("scopes", scopes); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromInstanceServiceAccount(this); + } + + public static final class Builder { + + private String email; + private ImmutableSet.Builder scopes = ImmutableSet.builder(); + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount#getEmail() + */ + public Builder email(String email) { + this.email = checkNotNull(email); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount#getScopes() + */ + public Builder addScopes(String scopes) { + this.scopes.add(scopes); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount#getScopes() + */ + public Builder scopes(Set scopes) { + this.scopes.addAll(scopes); + return this; + } + + public ServiceAccount build() { + return new ServiceAccount(email, scopes.build()); + } + + public Builder fromInstanceServiceAccount(ServiceAccount in) { + return this.email(in.getEmail()).scopes(in.getScopes()); + } + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/InstanceInZone.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/InstanceInZone.java new file mode 100644 index 0000000000..09a30885f7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/InstanceInZone.java @@ -0,0 +1,52 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; + +public class InstanceInZone extends SlashEncodedIds { + protected final Instance instance; + + public InstanceInZone(Instance instance, String zoneId) { + super(zoneId, checkNotNull(instance, "instance").getName()); + this.instance = instance; + } + + public Instance getInstance() { + return instance; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + InstanceInZone that = InstanceInZone.class.cast(obj); + return equal(this.instance, that.instance) + && equal(this.firstId, that.firstId) + && equal(this.secondId, that.secondId); + } + + @Override + public String toString() { + return "[instance=" + instance + ", zoneId=" + firstId + "]"; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/InstanceTemplate.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/InstanceTemplate.java new file mode 100644 index 0000000000..e86bed2c9c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/InstanceTemplate.java @@ -0,0 +1,445 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type; + +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * Optional information for creating an instance. + */ +public class InstanceTemplate { + + protected String name; + protected String description; + protected URI machineType; + protected URI image; + protected Set serviceAccounts = Sets.newLinkedHashSet(); + + protected transient List disks = Lists.newArrayList(); + protected transient Set networkInterfaces = Sets.newLinkedHashSet(); + protected transient Map metadata = Maps.newLinkedHashMap(); + protected transient String machineTypeName; + + + protected InstanceTemplate(URI machineType) { + this.machineType = checkNotNull(machineType, "machineType"); + } + + protected InstanceTemplate(String machineTypeName) { + this.machineTypeName = checkNotNull(machineTypeName, "machineTypeName"); + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getName() + */ + public InstanceTemplate name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getDescription() + */ + public InstanceTemplate description(String description) { + this.description = description; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getImage() + */ + public InstanceTemplate image(URI image) { + this.image = image; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getMachineType() + */ + public InstanceTemplate machineType(URI machineType) { + this.machineType = machineType; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getMachineType() + */ + public InstanceTemplate machineType(String machineTypeName) { + this.machineTypeName = machineTypeName; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getDisks() + */ + public InstanceTemplate addDisk(PersistentDisk.Mode mode, URI source) { + this.disks.add(new PersistentDisk(mode, source, null, false, false)); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getDisks() + */ + public InstanceTemplate addDisk(PersistentDisk.Mode mode, URI source, Boolean deleteOnTerminate) { + this.disks.add(new PersistentDisk(mode, source, null, deleteOnTerminate, false)); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getDisks() + */ + public InstanceTemplate addDisk(PersistentDisk.Mode mode, URI source, String deviceName, Boolean deleteOnTerminate) { + this.disks.add(new PersistentDisk(mode, source, deviceName, deleteOnTerminate, false)); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getDisks() + */ + public InstanceTemplate addDisk(PersistentDisk.Mode mode, URI source, String deviceName, + Boolean deleteOnTerminate, Boolean boot) { + this.disks.add(new PersistentDisk(mode, source, deviceName, deleteOnTerminate, boot)); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getDisks() + */ + public InstanceTemplate disks(List disks) { + this.disks = Lists.newArrayList(); + this.disks.addAll(checkNotNull(disks, "disks")); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getNetworkInterfaces() + */ + public InstanceTemplate addNetworkInterface(URI network) { + this.networkInterfaces.add(new NetworkInterface(checkNotNull(network, "network"), null, null)); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getNetworkInterfaces() + */ + public InstanceTemplate addNetworkInterface(URI network, Type type) { + this.networkInterfaces.add(new NetworkInterface(checkNotNull(network, "network"), null, + ImmutableSet.of(Instance.NetworkInterface.AccessConfig.builder() + .type(type) + .build()))); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getNetworkInterfaces() + */ + public InstanceTemplate addNetworkInterface(NetworkInterface networkInterface) { + this.networkInterfaces.add(networkInterface); + return this; + } + + public InstanceTemplate networkInterfaces(Set networkInterfaces) { + this.networkInterfaces = Sets.newLinkedHashSet(networkInterfaces); + return this; + } + + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getMetadata() + */ + public InstanceTemplate addMetadata(String key, String value) { + this.metadata.put(checkNotNull(key, "key"), checkNotNull(value, "value of %", key)); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getMetadata() + */ + public InstanceTemplate metadata(Map metadata) { + this.metadata = Maps.newLinkedHashMap(); + this.metadata.putAll(checkNotNull(metadata, "metadata")); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getServiceAccounts() + */ + public InstanceTemplate addServiceAccount(Instance.ServiceAccount serviceAccount) { + this.serviceAccounts.add(checkNotNull(serviceAccount, "serviceAccount")); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getServiceAccounts() + */ + public InstanceTemplate serviceAccounts(Set serviceAccounts) { + this.serviceAccounts = Sets.newLinkedHashSet(); + this.serviceAccounts.addAll(checkNotNull(serviceAccounts, "serviceAccounts")); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getDescription() + */ + public String getDescription() { + return description; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getDisks() + */ + public List getDisks() { + return disks; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getImage() + */ + public URI getImage() { + return image; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getMachineType() + */ + public URI getMachineType() { + return machineType; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getMachineType() + */ + public String getMachineTypeName() { + return machineTypeName; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getMetadata() + */ + public Map getMetadata() { + return metadata; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getNetworkInterfaces() + */ + public Set getNetworkInterfaces() { + return networkInterfaces; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getServiceAccounts() + */ + public Set getServiceAccounts() { + return serviceAccounts; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Instance#getName() + */ + public String getName() { + return name; + } + + public static Builder builder() { + return new Builder(); + } + + public static InstanceTemplate fromInstanceTemplate(InstanceTemplate instanceTemplate) { + return Builder.fromInstanceTemplate(instanceTemplate); + } + + public static class Builder { + + public InstanceTemplate forMachineType(URI machineType) { + return new InstanceTemplate(machineType); + } + + public InstanceTemplate forMachineType(String machineTypeName) { + return new InstanceTemplate(machineTypeName); + } + + public static InstanceTemplate fromInstanceTemplate(InstanceTemplate instanceTemplate) { + return InstanceTemplate.builder() + .forMachineType(instanceTemplate.getMachineType()) + .networkInterfaces(instanceTemplate.getNetworkInterfaces()) + .name(instanceTemplate.getName()) + .description(instanceTemplate.getDescription()) + .image(instanceTemplate.getImage()) + .disks(instanceTemplate.getDisks()) + .metadata(instanceTemplate.getMetadata()) + .serviceAccounts(instanceTemplate.getServiceAccounts()); + } + } + + + public static class PersistentDisk { + + public enum Mode { + READ_WRITE, + READ_ONLY + } + + public PersistentDisk(Mode mode, URI source, String deviceName, Boolean deleteOnTerminate, + Boolean boot) { + this.mode = checkNotNull(mode, "mode"); + this.source = checkNotNull(source, "source"); + this.deviceName = deviceName; + this.deleteOnTerminate = checkNotNull(deleteOnTerminate, "deleteOnTerminate"); + this.boot = checkNotNull(boot, "boot"); + } + + private final Mode mode; + private final URI source; + private final Boolean deleteOnTerminate; + private final String deviceName; + private final Boolean boot; + + /** + * @return the mode in which to attach this disk, either READ_WRITE or READ_ONLY. + */ + public Mode getMode() { + return mode; + } + + /** + * @return the URL of the persistent disk resource. + */ + public URI getSource() { + return source; + } + + /** + * @return Must be unique within the instance when specified. This represents a unique + * device name that is reflected into the /dev/ tree of a Linux operating system running within the + * instance. If not specified, a default will be chosen by the system. + */ + public String getDeviceName() { + return deviceName; + } + + + /** + * @return If true, delete the disk and all its data when the associated instance is deleted. + */ + public boolean isDeleteOnTerminate() { + return deleteOnTerminate; + } + + /** + * @return If true, boot from this disk. + */ + public boolean isBoot() { + return boot; + } + } + + public static class NetworkInterface { + + private final URI network; + private final String networkIP; + private final Set accessConfigs; + + public NetworkInterface(URI network, String networkIP, Set + accessConfigs) { + this.networkIP = networkIP; + this.network = network; + this.accessConfigs = accessConfigs != null ? accessConfigs : ImmutableSet.of(); + } + + public Set getAccessConfigs() { + return accessConfigs; + } + + public URI getNetwork() { + return network; + } + + public String getNetworkIP() { + return networkIP; + } + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object instanceof InstanceTemplate) { + final InstanceTemplate other = InstanceTemplate.class.cast(object); + return equal(description, other.description) + && equal(image, other.image) + && equal(disks, other.disks) + && equal(networkInterfaces, other.networkInterfaces) + && equal(metadata, other.metadata) + && equal(serviceAccounts, other.serviceAccounts); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(description, image, disks, networkInterfaces, metadata, serviceAccounts); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + Objects.ToStringHelper toString = Objects.toStringHelper("") + .omitNullValues(); + toString.add("description", description); + if (disks.size() > 0) + toString.add("disks", disks); + if (metadata.size() > 0) + toString.add("metadata", metadata); + if (serviceAccounts.size() > 0) + toString.add("serviceAccounts", serviceAccounts); + toString.add("image", image); + toString.add("networkInterfaces", networkInterfaces); + return toString; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/ListPage.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/ListPage.java new file mode 100644 index 0000000000..63107e7f82 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/ListPage.java @@ -0,0 +1,179 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.googlecomputeengine.domain.Resource.Kind; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Iterator; + +import org.jclouds.collect.IterableWithMarker; + +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; + +/** + * The collection returned from any listFirstPage() method. + */ +public class ListPage extends IterableWithMarker { + + private final Kind kind; + private final String id; + private final URI selfLink; + private final String nextPageToken; + private final Iterable items; + + @ConstructorProperties({ + "kind", "id", "selfLink", "nextPageToken", "items" + }) + protected ListPage(Kind kind, String id, URI selfLink, String nextPageToken, Iterable items) { + this.id = checkNotNull(id, "id"); + this.kind = checkNotNull(kind, "kind of %id", id); + this.selfLink = checkNotNull(selfLink, "selfLink of %id", id); + this.nextPageToken = nextPageToken; + this.items = items != null ? ImmutableSet.copyOf(items) : ImmutableSet.of(); + } + + public Kind getKind() { + return kind; + } + + public String getId() { + return id; + } + + public URI getSelfLink() { + return selfLink; + } + + @Override + public Optional nextMarker() { + return Optional.fromNullable(nextPageToken); + } + + @Override + public Iterator iterator() { + return checkNotNull(items, "items").iterator(); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(kind, id); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + ListPage that = ListPage.class.cast(obj); + return equal(this.kind, that.kind) + && equal(this.id, that.id); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .omitNullValues() + .add("kind", kind) + .add("id", id) + .add("selfLink", selfLink) + .add("nextPageToken", nextPageToken) + .add("items", items); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromPagedList(this); + } + + public static final class Builder { + + private Kind kind; + private String id; + private URI selfLink; + private String nextPageToken; + private ImmutableSet.Builder items = ImmutableSet.builder(); + + public Builder kind(Kind kind) { + this.kind = kind; + return this; + } + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder selfLink(URI selfLink) { + this.selfLink = selfLink; + return this; + } + + public Builder addItem(T item) { + this.items.add(item); + return this; + } + + public Builder items(Iterable items) { + this.items.addAll(items); + return this; + } + + public Builder nextPageToken(String nextPageToken) { + this.nextPageToken = nextPageToken; + return this; + } + + public ListPage build() { + return new ListPage(kind, id, selfLink, nextPageToken, items.build()); + } + + public Builder fromPagedList(ListPage in) { + return this + .kind(in.getKind()) + .id(in.getId()) + .selfLink(in.getSelfLink()) + .nextPageToken((String) in.nextMarker().orNull()) + .items(in); + + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/MachineType.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/MachineType.java new file mode 100644 index 0000000000..1c59ac75a4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/MachineType.java @@ -0,0 +1,360 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.List; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; + +/** + * Represents a machine type used to host an instance. + * + * @see + */ +@Beta +public final class MachineType extends Resource { + + private final Integer guestCpus; + private final Integer memoryMb; + private final Integer imageSpaceGb; + private final List scratchDisks; + private final Integer maximumPersistentDisks; + private final Long maximumPersistentDisksSizeGb; + private final String zone; + private final Optional deprecated; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "guestCpus", "memoryMb", + "imageSpaceGb", "scratchDisks", "maximumPersistentDisks", "maximumPersistentDisksSizeGb", "zone", + "deprecated" + }) + private MachineType(String id, Date creationTimestamp, URI selfLink, String name, String description, + int guestCpus, int memoryMb, int imageSpaceGb, List scratchDisks, + int maximumPersistentDisks, long maximumPersistentDisksSizeGb, String zone, + @Nullable Deprecated deprecated) { + super(Kind.MACHINE_TYPE, id, creationTimestamp, selfLink, name, description); + this.guestCpus = checkNotNull(guestCpus, "guestCpus of %s", name); + this.memoryMb = checkNotNull(memoryMb, "memoryMb of %s", name); + this.imageSpaceGb = checkNotNull(imageSpaceGb, "imageSpaceGb of %s", name); + this.scratchDisks = scratchDisks == null ? ImmutableList.of() : scratchDisks; + this.maximumPersistentDisks = checkNotNull(maximumPersistentDisks, "maximumPersistentDisks of %s", name); + this.maximumPersistentDisksSizeGb = maximumPersistentDisksSizeGb; + this.zone = checkNotNull(zone, "zone of %s", name); + this.deprecated = fromNullable(deprecated); + } + + /** + * @return count of CPUs exposed to the instance. + */ + public int getGuestCpus() { + return guestCpus; + } + + /** + * @return physical memory assigned to the instance, defined in MB. + */ + public int getMemoryMb() { + return memoryMb; + } + + /** + * @return space allotted for the image, defined in GB. + */ + public int getImageSpaceGb() { + return imageSpaceGb; + } + + /** + * @return extended scratch disks assigned to the instance. + */ + public List getScratchDisks() { + return scratchDisks; + } + + /** + * @return maximum persistent disks allowed. + */ + public int getMaximumPersistentDisks() { + return maximumPersistentDisks; + } + + /** + * @return maximum total persistent disks size (GB) allowed. + */ + public long getMaximumPersistentDisksSizeGb() { + return maximumPersistentDisksSizeGb; + } + + /** + * @return the zones that this machine type can run in. + */ + public String getZone() { + return zone; + } + + /** + * @return the deprecation information for this machine type + */ + public Optional getDeprecated() { + return deprecated; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + MachineType that = MachineType.class.cast(obj); + return equal(this.kind, that.kind) + && equal(this.name, that.name) + && equal(this.zone, that.zone); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .add("guestCpus", guestCpus) + .add("memoryMb", memoryMb) + .add("imageSpaceGb", imageSpaceGb) + .add("scratchDisks", scratchDisks) + .add("maximumPersistentDisks", maximumPersistentDisks) + .add("maximumPersistentDisksSizeGb", maximumPersistentDisksSizeGb) + .add("zone", zone) + .add("deprecated", deprecated.orNull()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromMachineType(this); + } + + public static final class Builder extends Resource.Builder { + + private Integer guestCpus; + private Integer memoryMb; + private Integer imageSpaceGb; + private ImmutableList.Builder scratchDisks = ImmutableList.builder(); + private Integer maximumPersistentDisks; + private Long maximumPersistentDisksSizeGb; + private String zone; + private Deprecated deprecated; + + /** + * @see MachineType#getGuestCpus() + */ + public Builder guestCpus(int guesCpus) { + this.guestCpus = guesCpus; + return this; + } + + /** + * @see MachineType#getMemoryMb() + */ + public Builder memoryMb(int memoryMb) { + this.memoryMb = memoryMb; + return this; + } + + /** + * @see MachineType#getImageSpaceGb() + */ + public Builder imageSpaceGb(int imageSpaceGb) { + this.imageSpaceGb = imageSpaceGb; + return this; + } + + /** + * @see MachineType#getScratchDisks() + */ + public Builder addScratchDisk(int diskGb) { + this.scratchDisks.add(ScratchDisk.builder().diskGb(diskGb).build()); + return this; + } + + /** + * @see MachineType#getScratchDisks() + */ + public Builder scratchDisks(List scratchDisks) { + this.scratchDisks.addAll(scratchDisks); + return this; + } + + /** + * @see MachineType#getMaximumPersistentDisks() + */ + public Builder maximumPersistentDisks(int maximumPersistentDisks) { + this.maximumPersistentDisks = maximumPersistentDisks; + return this; + } + + /** + * @see MachineType#getMaximumPersistentDisksSizeGb() + */ + public Builder maximumPersistentDisksSizeGb(long maximumPersistentDisksSizeGb) { + this.maximumPersistentDisksSizeGb = maximumPersistentDisksSizeGb; + return this; + } + + /** + * @see MachineType#getZone() + */ + public Builder zone(String zone) { + this.zone = zone; + return this; + } + + /** + * @see MachineType#getDeprecated() + */ + public Builder deprecated(Deprecated deprecated) { + this.deprecated = deprecated; + return this; + } + + @Override + protected Builder self() { + return this; + } + + public MachineType build() { + return new MachineType(id, creationTimestamp, selfLink, name, description, guestCpus, memoryMb, + imageSpaceGb, scratchDisks.build(), maximumPersistentDisks, maximumPersistentDisksSizeGb, + zone, deprecated); + } + + + public Builder fromMachineType(MachineType in) { + return super.fromResource(in).memoryMb(in.getMemoryMb()).imageSpaceGb(in.getImageSpaceGb()).scratchDisks(in + .getScratchDisks()).maximumPersistentDisks(in.getMaximumPersistentDisks()) + .maximumPersistentDisksSizeGb(in.getMaximumPersistentDisksSizeGb()).zone(in.getZone()) + .deprecated(in.getDeprecated().orNull()); + } + } + + /** + * An scratch disk of a MachineType + */ + public static final class ScratchDisk { + + private final int diskGb; + + @ConstructorProperties({ + "diskGb" + }) + private ScratchDisk(int diskGb) { + this.diskGb = diskGb; + } + + /** + * @return size of the scratch disk, defined in GB. + */ + public int getDiskGb() { + return diskGb; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(diskGb); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + ScratchDisk that = ScratchDisk.class.cast(obj); + return equal(this.diskGb, that.diskGb); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .add("diskGb", diskGb); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromScratchDisk(this); + } + + public static class Builder { + + private int diskGb; + + /** + * @see org.jclouds.googlecomputeengine.domain.MachineType.ScratchDisk#getDiskGb() + */ + public Builder diskGb(int diskGb) { + this.diskGb = diskGb; + return this; + } + + public ScratchDisk build() { + return new ScratchDisk(diskGb); + } + + public Builder fromScratchDisk(ScratchDisk in) { + return new Builder().diskGb(in.getDiskGb()); + } + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/MachineTypeInZone.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/MachineTypeInZone.java new file mode 100644 index 0000000000..0a4b5fb99f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/MachineTypeInZone.java @@ -0,0 +1,52 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; + +public class MachineTypeInZone extends SlashEncodedIds { + protected final MachineType machineType; + + public MachineTypeInZone(MachineType machineType, String zoneId) { + super(zoneId, checkNotNull(machineType, "machineType").getName()); + this.machineType = machineType; + } + + public MachineType getMachineType() { + return machineType; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + MachineTypeInZone that = MachineTypeInZone.class.cast(obj); + return equal(this.machineType, that.machineType) + && equal(this.firstId, that.firstId) + && equal(this.secondId, that.secondId); + } + + @Override + public String toString() { + return "[machineType=" + machineType + ", zoneId=" + firstId + "]"; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Metadata.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Metadata.java new file mode 100644 index 0000000000..53a8cfb713 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Metadata.java @@ -0,0 +1,139 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; + +import java.beans.ConstructorProperties; +import java.util.Map; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableMap; + +/** + * Metadata for an instance or project, with their fingerprint. + */ +public class Metadata { + @Nullable + private final String fingerprint; + private final Map items; + + @ConstructorProperties({"fingerprint", "items"}) + public Metadata(@Nullable String fingerprint, @Nullable Map items) { + this.fingerprint = fingerprint; + this.items = items == null ? ImmutableMap.of() : items; + } + + /** + * @return an optional map of metadata key/value pairs for this instance/project + */ + public Map getItems() { + return items; + } + + /** + * Gets the fingerprint for the items - needed for updating them. + * + * @return the fingerprint string for the items. + */ + public String getFingerprint() { + return fingerprint; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(fingerprint, items); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Metadata that = Metadata.class.cast(obj); + return equal(this.items, that.items) + && equal(this.fingerprint, that.fingerprint); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .add("items", items) + .add("fingerprint", fingerprint); + } + + public static Builder builder() { + return new Builder(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static final class Builder { + + private ImmutableMap.Builder items = ImmutableMap.builder(); + private String fingerprint; + + /** + * @see Metadata#getItems() + */ + public Builder addItem(String key, String value) { + this.items.put(key, value); + return this; + } + + /** + * @see Metadata#getItems() + */ + public Builder items(Map items) { + this.items.putAll(items); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Metadata#getFingerprint() + */ + public Builder fingerprint(String fingerprint) { + this.fingerprint = fingerprint; + return this; + } + + public Metadata build() { + return new Metadata(this.fingerprint, this.items.build()); + } + + public Builder fromMetadata(Metadata in) { + return this.fingerprint(in.getFingerprint()) + .items(in.getItems()); + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java new file mode 100644 index 0000000000..0919c896ba --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java @@ -0,0 +1,133 @@ +/* + * 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.googlecomputeengine.domain; + + +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; + +/** + * Represents a network used to enable instance communication. + * + * @see + */ +@Beta +public final class Network extends Resource { + + private final String IPv4Range; + private final Optional gatewayIPv4; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "IPv4Range", + "gatewayIPv4" + }) + protected Network(String id, Date creationTimestamp, URI selfLink, String name, String description, + String IPv4Range, String gatewayIPv4) { + super(Kind.NETWORK, id, creationTimestamp, selfLink, name, description); + this.IPv4Range = checkNotNull(IPv4Range); + this.gatewayIPv4 = fromNullable(gatewayIPv4); + } + + /** + * @return Required; The range of internal addresses that are legal on this network. This range is a CIDR + * specification, for example: 192.168.0.0/16. + */ + public String getIPv4Range() { + return IPv4Range; + } + + /** + * This must be within the range specified by IPv4Range, and is typically the first usable address in that range. + * If not specified, the default value is the first usable address in IPv4Range. + * + * @return an optional address that is used for default routing to other networks. + */ + public Optional getGatewayIPv4() { + return gatewayIPv4; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("IPv4Range", IPv4Range) + .add("gatewayIPv4", gatewayIPv4.orNull()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromNetwork(this); + } + + public static final class Builder extends Resource.Builder { + + private String IPv4Range; + private String gatewayIPv4; + + /** + * @see Network#getIPv4Range() + */ + public Builder IPv4Range(String IPv4Range) { + this.IPv4Range = IPv4Range; + return this; + } + + /** + * @see Network#getGatewayIPv4() + */ + public Builder gatewayIPv4(String gatewayIPv4) { + this.gatewayIPv4 = gatewayIPv4; + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Network build() { + return new Network(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, IPv4Range, gatewayIPv4); + } + + public Builder fromNetwork(Network in) { + return super.fromResource(in); + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Operation.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Operation.java new file mode 100644 index 0000000000..deab87353c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Operation.java @@ -0,0 +1,556 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.List; + +import org.jclouds.http.HttpResponse; +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; + +/** + * Describes an operation being executed on some Resource + * + * @see + */ +@Beta +public class Operation extends Resource { + + public static enum Status { + PENDING, + RUNNING, + DONE + } + + private final URI targetLink; + private final Optional targetId; + private final Optional clientOperationId; + private final Status status; + private final Optional statusMessage; + private final String user; + private final Optional progress; + private final Date insertTime; + private final Optional startTime; + private final Optional endTime; + private final Optional httpError; + private final String operationType; + private final List errors; + private final Optional zone; + private final Optional region; + + protected Operation(String id, Date creationTimestamp, URI selfLink, String name, String description, + URI targetLink, String targetId, String clientOperationId, Status status, + String statusMessage, String user, Integer progress, Date insertTime, Date startTime, + Date endTime, Integer httpErrorStatusCode, String httpErrorMessage, String operationType, + @Nullable List errors, URI region, URI zone) { + super(Kind.OPERATION, id, creationTimestamp, selfLink, name, description); + this.targetLink = checkNotNull(targetLink, "targetLink of %s", name); + this.targetId = fromNullable(targetId); + this.clientOperationId = fromNullable(clientOperationId); + this.status = checkNotNull(status, "status of %s", name); + this.statusMessage = fromNullable(statusMessage); + this.user = checkNotNull(user, "user of %s", name); + this.progress = fromNullable(progress); + this.insertTime = checkNotNull(insertTime, "insertTime of %s", name); + this.startTime = fromNullable(startTime); + this.endTime = fromNullable(endTime); + this.httpError = httpErrorStatusCode != null && httpErrorStatusCode != 0 ? + Optional.of(HttpResponse.builder() + .statusCode(httpErrorStatusCode) + .message(httpErrorMessage) + .build()) + : Optional.absent(); + this.operationType = checkNotNull(operationType, "insertTime of %s", name); + this.errors = errors == null ? ImmutableList.of() : ImmutableList.copyOf(errors); + this.region = fromNullable(region); + this.zone = fromNullable(zone); + } + + /** + * @return URL of the resource the operation is mutating. + */ + public URI getTargetLink() { + return targetLink; + } + + /** + * @return An optional identifier specified by the client when the mutation was initiated. Must be unique for all + * operation resources in the project. + */ + public Optional getClientOperationId() { + return clientOperationId; + } + + /** + * @return unique target id which identifies a particular incarnation of the target. + */ + public Optional getTargetId() { + return targetId; + } + + /** + * @return region this operation is in, if any. + */ + public Optional getRegion() { + return region; + } + + /** + * @return zone this operation is in, if any. + */ + public Optional getZone() { + return zone; + } + + /** + * @return Status of the operation. Can be one of the following: PENDING, RUNNING, or DONE. + */ + public Status getStatus() { + return status; + } + + /** + * @return An optional textual description of the current status of the operation. + */ + public Optional getStatusMessage() { + return statusMessage; + } + + /** + * @return User who requested the operation, for example "user@example.com". + */ + public String getUser() { + return user; + } + + /** + * @return an optional progress indicator that ranges from 0 to 100. This should not be used to guess at when the + * operation will be complete. This number should be monotonically increasing as the operation progresses + * (output only). + */ + public Optional getProgress() { + return progress; + } + + /** + * @return the time that this operation was requested. + */ + public Date getInsertTime() { + return insertTime; + } + + /** + * @return the time that this operation was started by the server. + */ + public Optional getStartTime() { + return startTime; + } + + /** + * @return the time that this operation was completed. + */ + public Optional getEndTime() { + return endTime; + } + + /** + * @return if operation fails, the HttpResponse with error status code returned and the message, e.g. NOT_FOUND. + */ + public Optional getHttpError() { + return httpError; + } + + /** + * @return type of the operation. Examples include insert, update, and delete. + */ + public String getOperationType() { + return operationType; + } + + /** + * @return if error occurred during processing of this operation, this field will be populated. + */ + public List getErrors() { + return errors; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("targetLink", targetLink) + .add("targetId", targetId.orNull()) + .add("clientOperationId", clientOperationId.orNull()) + .add("status", status) + .add("statusMessage", statusMessage.orNull()) + .add("user", user) + .add("progress", progress.orNull()) + .add("insertTime", insertTime) + .add("startTime", startTime.orNull()) + .add("endTime", endTime.orNull()) + .add("httpError", httpError.orNull()) + .add("operationType", operationType) + .add("errors", errors) + .add("region", region.orNull()) + .add("zone", zone.orNull()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromOperation(this); + } + + public static final class Builder extends Resource.Builder { + + private URI targetLink; + private String targetId; + private String clientOperationId; + private Status status; + private String statusMessage; + private String user; + private Integer progress; + private Date insertTime; + private Date startTime; + private Date endTime; + private Integer httpErrorStatusCode; + private String httpErrorMessage; + private String operationType; + private ImmutableList.Builder errors = ImmutableList.builder(); + private URI region; + private URI zone; + + /** + * @see Operation#getTargetLink() + */ + public Builder targetLink(URI targetLink) { + this.targetLink = targetLink; + return self(); + } + + /** + * @see Operation#getRegion() + */ + public Builder region(URI region) { + this.region = region; + return self(); + } + + /** + * @see Operation#getZone() + */ + public Builder zone(URI zone) { + this.zone = zone; + return self(); + } + + /** + * @see Operation#getTargetId() + */ + public Builder targetId(String targetId) { + this.targetId = targetId; + return self(); + } + + /** + * @see Operation#getClientOperationId() + */ + public Builder clientOperationId(String clientOperationId) { + this.clientOperationId = clientOperationId; + return self(); + } + + /** + * @see Operation#getStatus() + */ + public Builder status(Status status) { + this.status = status; + return self(); + } + + /** + * @see Operation#getStatusMessage() + */ + public Builder statusMessage(String statusMessage) { + this.statusMessage = statusMessage; + return self(); + } + + /** + * @see Operation#getUser() + */ + public Builder user(String user) { + this.user = user; + return self(); + } + + /** + * @see Operation#getProgress() + */ + public Builder progress(Integer progress) { + this.progress = progress; + return self(); + } + + /** + * @see Operation#getInsertTime() + */ + public Builder insertTime(Date insertTime) { + this.insertTime = insertTime; + return self(); + } + + /** + * @see Operation#getStartTime() + */ + public Builder startTime(Date startTime) { + this.startTime = startTime; + return self(); + } + + /** + * @see Operation#getEndTime() + */ + public Builder endTime(Date endTime) { + this.endTime = endTime; + return self(); + } + + /** + * @see Operation#getHttpError() + */ + public Builder httpErrorStatusCode(Integer httpErrorStatusCode) { + this.httpErrorStatusCode = httpErrorStatusCode; + return self(); + } + + /** + * @see Operation#getHttpError() + */ + public Builder httpErrorMessage(String httpErrorMessage) { + this.httpErrorMessage = httpErrorMessage; + return self(); + } + + /** + * @see Operation#getOperationType() + */ + public Builder operationType(String operationType) { + this.operationType = operationType; + return self(); + } + + /** + * @see Operation#getErrors() + */ + public Builder errors(Iterable errors) { + if (errors != null) + this.errors.addAll(errors); + return self(); + } + + /** + * @see Operation#getErrors() + */ + public Builder addError(Error error) { + this.errors.add(error); + return self(); + } + + @Override + protected Builder self() { + return this; + } + + public Operation build() { + return new Operation(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, targetLink, targetId, clientOperationId, status, statusMessage, user, progress, + insertTime, startTime, endTime, httpErrorStatusCode, httpErrorMessage, operationType, + errors.build(), region, zone); + } + + public Builder fromOperation(Operation in) { + return super.fromResource(in) + .targetLink(in.getTargetLink()) + .targetId(in.getTargetId().orNull()) + .clientOperationId(in.getClientOperationId().orNull()) + .status(in.getStatus()) + .statusMessage(in.getStatusMessage().orNull()) + .user(in.getUser()) + .progress(in.getProgress().get()) + .insertTime(in.getInsertTime()) + .startTime(in.getStartTime().orNull()) + .endTime(in.getEndTime().orNull()) + .httpErrorStatusCode(in.getHttpError().isPresent() ? in.getHttpError().get().getStatusCode() : null) + .httpErrorMessage(in.getHttpError().isPresent() ? in.getHttpError().get().getMessage() : null) + .operationType(in.getOperationType()).errors(in.getErrors()) + .zone(in.getZone().orNull()).region(in.getRegion().orNull()); + } + } + + /** + * A particular error for an operation including the details. + */ + public static final class Error { + + private final String code; + private final Optional location; + private final Optional message; + + @ConstructorProperties({ + "code", "location", "message" + }) + private Error(String code, String location, String message) { + this.code = checkNotNull(code, "code"); + this.location = fromNullable(location); + this.message = fromNullable(message); + } + + /** + * @return the error type identifier for this error. + */ + public String getCode() { + return code; + } + + /** + * @return indicates the field in the request which caused the error.. + */ + public Optional getLocation() { + return location; + } + + /** + * @return an optional, human-readable error message. + */ + public Optional getMessage() { + return message; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(code, location, message); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Error that = Error.class.cast(obj); + return equal(this.code, that.code) + && equal(this.location, that.location) + && equal(this.message, that.message); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .omitNullValues() + .add("code", code) + .add("location", location.orNull()) + .add("message", message.orNull()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromOperationErrorDetail(this); + } + + public static final class Builder { + + private String code; + private String location; + private String message; + + /** + * @see org.jclouds.googlecomputeengine.domain.Operation.Error#getCode() + */ + public Builder code(String code) { + this.code = code; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Operation.Error#getLocation() + */ + public Builder location(String location) { + this.location = location; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Operation.Error#getMessage() + */ + public Builder message(String message) { + this.message = message; + return this; + } + + public Error build() { + return new Error(code, location, message); + } + + public Builder fromOperationErrorDetail(Error in) { + return new Builder().code(in.getCode()).location(in.getLocation().orNull()).message + (in.getMessage().orNull()); + } + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Project.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Project.java new file mode 100644 index 0000000000..ac3867b333 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Project.java @@ -0,0 +1,162 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Date; +import java.util.Set; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; + +/** + * A Project resource is the root collection and settings resource for all Google Compute Engine resources. + * + * @see + */ +@Beta +public class Project extends Resource { + + private final Metadata commonInstanceMetadata; + private final Set quotas; + private final Set externalIpAddresses; + + protected Project(String id, Date creationTimestamp, URI selfLink, String name, String description, + Metadata commonInstanceMetadata, Set quotas, Set externalIpAddresses) { + super(Kind.PROJECT, id, creationTimestamp, selfLink, name, description); + this.commonInstanceMetadata = checkNotNull(commonInstanceMetadata, "commonInstanceMetadata"); + this.quotas = quotas == null ? ImmutableSet.of() : ImmutableSet.copyOf(quotas); + this.externalIpAddresses = externalIpAddresses == null ? ImmutableSet.of() : ImmutableSet.copyOf + (externalIpAddresses); + } + + /** + * @return metadata key/value pairs available to all instances contained in this project. + */ + public Metadata getCommonInstanceMetadata() { + return commonInstanceMetadata; + } + + /** + * @return quotas assigned to this project. + */ + public Set getQuotas() { + return quotas; + } + + /** + * @return internet available IP addresses available for use in this project. + */ + @Nullable + public Set getExternalIpAddresses() { + return externalIpAddresses; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .add("commonInstanceMetadata", commonInstanceMetadata) + .add("quotas", quotas) + .add("externalIpAddresses", externalIpAddresses); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromProject(this); + } + + public static final class Builder extends Resource.Builder { + + private Metadata commonInstanceMetadata; + private ImmutableSet.Builder quotas = ImmutableSet.builder(); + private ImmutableSet.Builder externalIpAddresses = ImmutableSet.builder(); + + /** + * @see Project#getCommonInstanceMetadata() + */ + public Builder commonInstanceMetadata(Metadata commonInstanceMetadata) { + this.commonInstanceMetadata = commonInstanceMetadata; + return this; + } + + /** + * @see Project#getQuotas() + */ + public Builder addQuota(String metric, double usage, double limit) { + this.quotas.add(Quota.builder().metric(metric).usage(usage).limit(limit).build()); + return this; + } + + /** + * @see Project#getQuotas() + */ + public Builder quotas(Set quotas) { + this.quotas.addAll(checkNotNull(quotas)); + return this; + } + + /** + * @see Project#getExternalIpAddresses() + */ + public Builder addExternalIpAddress(String externalIpAddress) { + this.externalIpAddresses.add(checkNotNull(externalIpAddress, "externalIpAddress")); + return this; + } + + /** + * @see Project#getExternalIpAddresses() + */ + public Builder externalIpAddresses(Set externalIpAddresses) { + this.externalIpAddresses.addAll(checkNotNull(externalIpAddresses, "externalIpAddresses")); + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Project build() { + return new Project(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, commonInstanceMetadata, quotas.build(), externalIpAddresses.build()); + } + + public Builder fromProject(Project in) { + return super.fromResource(in).commonInstanceMetadata(in.getCommonInstanceMetadata()).quotas(in.getQuotas()) + .externalIpAddresses(in.getExternalIpAddresses()); + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Quota.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Quota.java new file mode 100644 index 0000000000..3c171307c7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Quota.java @@ -0,0 +1,152 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Objects.ToStringHelper; + +/** + * Quotas assigned to a given project or region. + * + * @see + */ +@Beta +public class Quota { + private String metric; + private double usage; + private double limit; + + @ConstructorProperties({ + "metric", "usage", "limit" + }) + public Quota(String metric, Double usage, Double limit) { + this.metric = metric != null ? metric : "undefined"; + this.usage = checkNotNull(usage, "usage"); + this.limit = checkNotNull(limit, "limit"); + } + + /** + * @return name of the quota metric. + */ + public String getMetric() { + return metric; + } + + /** + * @return current usage of this metric. + */ + public Double getUsage() { + return usage; + } + + /** + * @return quota limit for this metric. + */ + public Double getLimit() { + return limit; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(metric); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || this.getClass() != obj.getClass()) return false; + Quota that = Quota.class.cast(obj); + return Objects.equal(this.metric, that.metric); + } + + /** + * {@inheritDoc} + */ + public ToStringHelper string() { + return Objects.toStringHelper(this) + .omitNullValues() + .add("metric", metric) + .add("usage", usage) + .add("limit", limit); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromQuota(this); + } + + public static class Builder { + + private String metric; + private Double usage; + private Double limit; + + /** + * @see org.jclouds.googlecomputeengine.domain.Quota#getMetric() + */ + public Builder metric(String metric) { + this.metric = checkNotNull(metric, "metric"); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Quota#getUsage() + */ + public Builder usage(Double usage) { + this.usage = usage; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Quota#getLimit() + */ + public Builder limit(Double limit) { + this.limit = limit; + return this; + } + + public Quota build() { + return new Quota(metric, usage, limit); + } + + public Builder fromQuota(Quota quota) { + return new Builder().metric(quota.getMetric()).usage(quota.getUsage()).limit(quota.getLimit()); + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Region.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Region.java new file mode 100644 index 0000000000..aa459bf6da --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Region.java @@ -0,0 +1,175 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.Set; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; + +/** + * Represents a region resource. + * + * @see + */ +@Beta +public final class Region extends Resource { + + public enum Status { + UP, + DOWN + } + + private final Status status; + private final Set zones; + private final Set quotas; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "status", + "zones", "quotas" + }) + private Region(String id, Date creationTimestamp, URI selfLink, String name, String description, + Status status, Set zones, Set quotas) { + super(Kind.REGION, id, creationTimestamp, selfLink, name, description); + this.status = checkNotNull(status, "status of %name", name); + this.zones = zones == null ? ImmutableSet.of() : ImmutableSet + .copyOf(zones); + this.quotas = quotas == null ? ImmutableSet.of() : ImmutableSet.copyOf(quotas); + } + + /** + * @return Status of the region. "UP" or "DOWN". + */ + public Status getStatus() { + return status; + } + + /** + * @return the zones that can be used in this region. + */ + @Nullable + public Set getZones() { + return zones; + } + + /** + * @return quotas assigned to this project. + */ + public Set getQuotas() { + return quotas; + } + + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .add("status", status) + .add("zones", zones) + .add("quotas", quotas); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromRegion(this); + } + + public static final class Builder extends Resource.Builder { + + private Status status; + private ImmutableSet.Builder zones = ImmutableSet.builder(); + private ImmutableSet.Builder quotas = ImmutableSet.builder(); + + /** + * @see org.jclouds.googlecomputeengine.domain.Region#getStatus() + */ + public Builder status(Status status) { + this.status = status; + return this; + } + + /** + * @see Region#getZones() + */ + public Builder zone(URI zone) { + this.zones.add(checkNotNull(zone, "zone")); + return this; + } + + /** + * @see Region#getZones() + */ + public Builder zones(Set zones) { + this.zones.addAll(checkNotNull(zones, "zones")); + return this; + } + + /** + * @see Region#getQuotas() + */ + public Builder addQuota(String metric, double usage, double limit) { + this.quotas.add(Quota.builder().metric(metric).usage(usage).limit(limit).build()); + return this; + } + + /** + * @see Region#getQuotas() + */ + public Builder quotas(Set quotas) { + this.quotas.addAll(checkNotNull(quotas)); + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Region build() { + return new Region(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, status, zones.build(), quotas.build()); + } + + public Builder fromRegion(Region in) { + return super.fromResource(in) + .status(in.getStatus()) + .zones(in.getZones()) + .quotas(in.getQuotas()); + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Resource.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Resource.java new file mode 100644 index 0000000000..4d0a1c8243 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Resource.java @@ -0,0 +1,283 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.ToStringHelper; +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.annotations.Beta; +import com.google.common.base.CaseFormat; +import com.google.common.base.Joiner; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; + +/** + * Base class for Google Compute Engine resources. + */ +@Beta +public class Resource { + + public enum Kind { + ADDRESS, + ADDRESS_LIST, + DISK, + DISK_LIST, + FIREWALL, + FIREWALL_LIST, + IMAGE, + IMAGE_LIST, + OPERATION, + OPERATION_LIST, + INSTANCE, + INSTANCE_LIST, + MACHINE_TYPE, + MACHINE_TYPE_LIST, + PROJECT, + NETWORK, + NETWORK_LIST, + REGION, + REGION_LIST, + ROUTE, + ROUTE_LIST, + SNAPSHOT, + SNAPSHOT_LIST, + ZONE, + ZONE_LIST; + + public String value() { + return Joiner.on("#").join("compute", CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name())); + } + + @Override + public String toString() { + return value(); + } + + public static Kind fromValue(String kind) { + return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat + .UPPER_UNDERSCORE, + Iterables.getLast(Splitter.on("#").split(checkNotNull(kind, + "kind"))))); + } + } + + protected final Kind kind; + protected final String id; + protected final Optional creationTimestamp; + protected final URI selfLink; + protected final String name; + protected final Optional description; + + @ConstructorProperties({ + "kind", "id", "creationTimestamp", "selfLink", "name", "description" + }) + protected Resource(Kind kind, String id, Date creationTimestamp, URI selfLink, String name, + String description) { + this.kind = checkNotNull(kind, "kind"); + this.id = checkNotNull(id, "id"); + this.creationTimestamp = fromNullable(creationTimestamp); + this.selfLink = checkNotNull(selfLink, "selfLink"); + this.name = checkNotNull(name, "name"); + this.description = fromNullable(description); + } + + /** + * @return the Type of the resource + */ + public Kind getKind() { + return kind; + } + + /** + * @return unique identifier for the resource; defined by the server. + */ + public String getId() { + return id; + } + + /** + * @return creation timestamp in RFC3339 text format. + */ + public Optional getCreationTimestamp() { + return creationTimestamp; + } + + /** + * @return server defined URL for the resource. + */ + public URI getSelfLink() { + return selfLink; + } + + /** + * @return name of the resource. + */ + public String getName() { + return name; + } + + /** + * @return an optional textual description of the resource. + */ + @Nullable + public Optional getDescription() { + return description; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(kind, name); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Resource that = Resource.class.cast(obj); + return equal(this.kind, that.kind) + && equal(this.name, that.name); + } + + /** + * {@inheritDoc} + */ + protected ToStringHelper string() { + return toStringHelper(this) + .omitNullValues() + .add("kind", kind) + .add("id", id) + .add("name", name) + .add("creationTimestamp", creationTimestamp.orNull()) + .add("selfLink", selfLink) + .add("name", name) + .add("description", description.orNull()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new ConcreteBuilder(); + } + + public Builder toBuilder() { + return new ConcreteBuilder().fromResource(this); + } + + public abstract static class Builder> { + + protected abstract T self(); + + protected Kind kind; + protected String id; + protected Date creationTimestamp; + protected URI selfLink; + protected String name; + protected String description; + + /** + * @see Resource#getKind() + */ + protected T kind(Kind kind) { + this.kind = kind; + return self(); + } + + /** + * @see Resource#getId() + */ + public T id(String id) { + this.id = id; + return self(); + } + + /** + * @see Resource#getCreationTimestamp() + */ + public T creationTimestamp(Date creationTimestamp) { + this.creationTimestamp = creationTimestamp; + return self(); + } + + /** + * @see Resource#getSelfLink() + */ + public T selfLink(URI selfLink) { + this.selfLink = selfLink; + return self(); + } + + /** + * @see Resource#getName() + */ + public T name(String name) { + this.name = name; + return self(); + } + + /** + * @see Resource#getDescription() + */ + public T description(String description) { + this.description = description; + return self(); + } + + public Resource build() { + return new Resource(kind, id, creationTimestamp, selfLink, name, description); + } + + public T fromResource(Resource in) { + return this + .kind(in.getKind()) + .id(in.getId()) + .creationTimestamp(in.getCreationTimestamp().orNull()) + .selfLink(in.getSelfLink()) + .name(in.getName()) + .description(in.getDescription().orNull()); + } + } + + private static class ConcreteBuilder extends Builder { + @Override + protected ConcreteBuilder self() { + return this; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Route.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Route.java new file mode 100644 index 0000000000..df5bb1dd81 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Route.java @@ -0,0 +1,433 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +/** + * Represents a route resource. + * + * @see + */ +@Beta +public final class Route extends Resource { + + private final URI network; + private final Set tags; + private final String destRange; + private final Integer priority; + private final Optional nextHopInstance; + private final Optional nextHopIp; + private final Optional nextHopNetwork; + private final Optional nextHopGateway; + private final Set warnings; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "network", "tags", + "destRange", "priority", "nextHopInstance", "nextHopIp", "nextHopNetwork", + "nextHopGateway", "warnings" + }) + private Route(String id, Date creationTimestamp, URI selfLink, String name, String description, + URI network, Set tags, String destRange, Integer priority, + URI nextHopInstance, String nextHopIp, URI nextHopNetwork, + URI nextHopGateway, Set warnings) { + super(Kind.ROUTE, id, creationTimestamp, selfLink, name, description); + this.network = checkNotNull(network, "network for %name", name); + this.tags = tags == null ? ImmutableSet.of() : tags; + this.destRange = checkNotNull(destRange, "destination range for %name", name); + this.priority = checkNotNull(priority, "priority of %name", name); + this.nextHopInstance = fromNullable(nextHopInstance); + this.nextHopIp = fromNullable(nextHopIp); + this.nextHopNetwork = fromNullable(nextHopNetwork); + this.nextHopGateway = fromNullable(nextHopGateway); + this.warnings = warnings == null ? ImmutableSet.of() : warnings; + } + + /** + * @return Network for this Route. + */ + public URI getNetwork() { + return network; + } + + /** + * @return The set of instance items to which this route applies. + */ + public Set getTags() { + return tags; + } + + /** + * @return The destination range of outgoing packets that this route applies to. + */ + public String getDestRange() { + return destRange; + } + + /** + * @return The priority of this route. Priority is used to break ties in the case + * where there is more than one matching route of maximum length. A lower value + * is higher priority; a priority of 100 is higher than 200. + */ + public Integer getPriority() { + return priority; + } + + /** + * @return The fully-qualified URL to an instance that should handle matching packets. + */ + public Optional getNextHopInstance() { + return nextHopInstance; + } + + /** + * @return The network IP address of an instance that should handle matching packets. + */ + public Optional getNextHopIp() { + return nextHopIp; + } + + /** + * @return The URL of the local network if it should handle matching packets. + */ + public Optional getNextHopNetwork() { + return nextHopNetwork; + } + + /** + * @return The URL to a gateway that should handle matching packets. Currently, this is only the internet gateway. + */ + public Optional getNextHopGateway() { + return nextHopGateway; + } + + /** + * @return If potential misconfigurations are detected for this route, this field will be populated with warning messages. + */ + public Set getWarnings() { + return warnings; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .add("network", network) + .add("tags", tags) + .add("destRange", destRange) + .add("priority", priority) + .add("nextHopInstance", nextHopInstance.orNull()) + .add("nextHopIp", nextHopIp.orNull()) + .add("nextHopNetwork", nextHopNetwork.orNull()) + .add("nextHopGateway", nextHopGateway.orNull()) + .add("warnings", warnings); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromRoute(this); + } + + public static final class Builder extends Resource.Builder { + + private URI network; + private ImmutableSet.Builder tags = ImmutableSet.builder(); + private String destRange; + private Integer priority; + private URI nextHopInstance; + private String nextHopIp; + private URI nextHopNetwork; + private URI nextHopGateway; + private ImmutableSet.Builder warnings = ImmutableSet.builder(); + + + /** + * @see Route#getNetwork() + */ + public Builder network(URI network) { + this.network = network; + return this; + } + + /** + * @see Route#getTags() + */ + public Builder addTag(String tag) { + this.tags.add(tag); + return this; + } + + /** + * @see Route#getTags() + */ + public Builder tags(Set tags) { + this.tags.addAll(tags); + return this; + } + + /** + * @see Route#getDestRange() + */ + public Builder destRange(String destRange) { + this.destRange = destRange; + return this; + } + + /** + * @see Route#getPriority() + */ + public Builder priority(Integer priority) { + this.priority = priority; + return this; + } + + /** + * @see Route#getNextHopInstance() + */ + public Builder nextHopInstance(URI nextHopInstance) { + this.nextHopInstance = nextHopInstance; + return this; + } + + /** + * @see Route#getNextHopIp() + */ + public Builder nextHopIp(String nextHopIp) { + this.nextHopIp = nextHopIp; + return this; + } + + /** + * @see Route#getNextHopNetwork() + */ + public Builder nextHopNetwork(URI nextHopNetwork) { + this.nextHopNetwork = nextHopNetwork; + return this; + } + + /** + * @see Route#getNextHopGateway() + */ + public Builder nextHopGateway(URI nextHopGateway) { + this.nextHopGateway = nextHopGateway; + return this; + } + + /** + * @see Route#getWarnings() + */ + public Builder addWarning(Warning warning) { + this.warnings.add(warning); + return this; + } + + /** + * @see Route#getWarnings() + */ + public Builder warnings(Set warnings) { + this.warnings.addAll(warnings); + return this; + } + + + @Override + protected Builder self() { + return this; + } + + public Route build() { + return new Route(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, network, tags.build(), destRange, priority, + nextHopInstance, nextHopIp, nextHopNetwork, nextHopGateway, + warnings.build()); + } + + public Builder fromRoute(Route in) { + return super.fromResource(in) + .network(in.getNetwork()) + .tags(in.getTags()) + .destRange(in.getDestRange()) + .priority(in.getPriority()) + .nextHopInstance(in.getNextHopInstance().orNull()) + .nextHopIp(in.getNextHopIp().orNull()) + .nextHopNetwork(in.getNextHopNetwork().orNull()) + .nextHopGateway(in.getNextHopGateway().orNull()) + .warnings(in.getWarnings()); + } + } + + /** + * If potential misconfigurations are detected for this route, this field will be populated with warning messages. + */ + public static class Warning { + private final String code; + private final Optional message; + private final Map data; + + @ConstructorProperties({ + "code", "message", "data" + }) + public Warning(String code, String message, Map data) { + this.code = checkNotNull(code, "code"); + this.message = fromNullable(message); + this.data = data == null ? ImmutableMap.of() : data; + } + + /** + * @return The warning type identifier for this warning. + */ + public String getCode() { + return code; + } + + /** + * @return Optional human-readable details for this warning. + */ + public Optional getMessage() { + return message; + } + + /** + * @return Metadata for this warning + */ + public Map getData() { + return data; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(code, message, data); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Warning that = Warning.class.cast(obj); + return equal(this.code, that.code) + && equal(this.message, that.message) + && equal(this.data, that.data); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .add("code", code) + .add("message", message) + .add("data", data); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromWarning(this); + } + + public static final class Builder { + private String code; + private String message; + private ImmutableMap.Builder data = ImmutableMap.builder(); + + /** + * @see Warning#getCode() + */ + public Builder code(String code) { + this.code = code; + return this; + } + + /** + * @see Warning#getMessage() + */ + public Builder message(String message) { + this.message = message; + return this; + } + + /** + * @see Warning#getData() + */ + public Builder data(Map data) { + this.data = new ImmutableMap.Builder().putAll(data); + return this; + } + + /** + * @see Warning#getData() + */ + public Builder addData(String key, String value) { + this.data.put(checkNotNull(key, "key"), checkNotNull(value, "value of %s", key)); + return this; + } + + public Warning build() { + return new Warning(code, message, data.build()); + } + + public Builder fromWarning(Warning in) { + return this.code(in.getCode()) + .message(in.getMessage().orNull()) + .data(in.getData()); + } + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/SlashEncodedIds.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/SlashEncodedIds.java new file mode 100644 index 0000000000..0080b29aa2 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/SlashEncodedIds.java @@ -0,0 +1,83 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Objects; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; + +public class SlashEncodedIds { + public static SlashEncodedIds fromSlashEncoded(String id) { + Iterable parts = Splitter.on('/').split(checkNotNull(id, "id")); + checkArgument(Iterables.size(parts) == 2, "id must be in format firstId/secondId"); + return new SlashEncodedIds(Iterables.get(parts, 0), Iterables.get(parts, 1)); + } + + public static SlashEncodedIds fromTwoIds(String firstId, String secondId) { + return new SlashEncodedIds(firstId, secondId); + } + + private static String slashEncodeTwoIds(String firstId, String secondId) { + return checkNotNull(firstId, "firstId") + "/" + checkNotNull(secondId, "secondId"); + } + + public String slashEncode() { + return slashEncodeTwoIds(firstId, secondId); + } + + protected final String firstId; + protected final String secondId; + + protected SlashEncodedIds(String firstId, String secondId) { + this.firstId = checkNotNull(firstId, "firstId"); + this.secondId = checkNotNull(secondId, "secondId"); + } + + @Override + public int hashCode() { + return Objects.hashCode(firstId, secondId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SlashEncodedIds other = (SlashEncodedIds) obj; + return Objects.equal(firstId, other.firstId) && Objects.equal(secondId, other.secondId); + } + + public String getFirstId() { + return firstId; + } + + public String getSecondId() { + return secondId; + } + + @Override + public String toString() { + return "[firstId=" + firstId + ", secondId=" + secondId + "]"; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Snapshot.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Snapshot.java new file mode 100644 index 0000000000..69af2754c2 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Snapshot.java @@ -0,0 +1,135 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; + +/** + * A Persistent Disk Snapshot resource. + * + * @see + */ +@Beta +public final class Snapshot extends AbstractDisk { + + private final Optional sourceDisk; + private final String sourceDiskId; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "diskSizeGb", + "status", "sourceDisk", "sourceDiskId" + }) + private Snapshot(String id, Date creationTimestamp, URI selfLink, String name, String description, + Integer sizeGb, String status, URI sourceDisk, String sourceDiskId) { + super(Kind.SNAPSHOT, id, creationTimestamp, selfLink, name, description, sizeGb, status); + this.sourceDisk = fromNullable(sourceDisk); + this.sourceDiskId = checkNotNull(sourceDiskId, "sourceDiskId of %s", name); + } + + /** + * @return The source disk used to create this snapshot. Once the source disk + * has been deleted from the system, this field will be cleared, and will + * not be set even if a disk with the same name has been re-created (output only). + */ + public Optional getSourceDisk() { + return sourceDisk; + } + + /** + * @return The ID value of the disk used to create this snapshot. This value + * may be used to determine whether the snapshot was taken from the current + * or a previous instance of a given disk name. + */ + public String getSourceDiskId() { + return sourceDiskId; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .omitNullValues() + .add("sourceDisk", sourceDisk.orNull()) + .add("sourceDiskId", sourceDiskId); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromSnapshot(this); + } + + public static final class Builder extends AbstractDisk.Builder { + + private URI sourceDisk; + private String sourceDiskId; + + /** + * @see Snapshot#getSourceDisk() + */ + public Builder sourceDisk(URI sourceDisk) { + this.sourceDisk = sourceDisk; + return this; + } + + /** + * @see Snapshot#getSourceDiskId() + */ + public Builder sourceDiskId(String sourceDiskId) { + this.sourceDiskId = sourceDiskId; + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Snapshot build() { + return new Snapshot(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, super.sizeGb, super.status, sourceDisk, sourceDiskId); + } + + public Builder fromSnapshot(Snapshot in) { + return super.fromAbstractDisk(in) + .sourceDisk(in.getSourceDisk().orNull()) + .sourceDiskId(in.getSourceDiskId()); + } + + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Zone.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Zone.java new file mode 100644 index 0000000000..232386cb54 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/Zone.java @@ -0,0 +1,334 @@ +/* + * 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.googlecomputeengine.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.Set; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; + +/** + * Represents a zone resource. + * + * @see + */ +@Beta +public final class Zone extends Resource { + + public enum Status { + UP, + DOWN + } + + private final Status status; + private final Set maintenanceWindows; + private final Set availableMachineTypes; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "status", "maintenanceWindows", + "availableMachineTypes" + }) + private Zone(String id, Date creationTimestamp, URI selfLink, String name, String description, + Status status, Set maintenanceWindows, Set availableMachineTypes) { + super(Kind.ZONE, id, creationTimestamp, selfLink, name, description); + this.status = checkNotNull(status, "status of %name", name); + this.maintenanceWindows = maintenanceWindows == null ? ImmutableSet.of() : ImmutableSet + .copyOf(maintenanceWindows); + this.availableMachineTypes = availableMachineTypes == null ? ImmutableSet.of() : ImmutableSet + .copyOf(availableMachineTypes); + } + + /** + * @return Status of the zone. "UP" or "DOWN". + */ + public Status getStatus() { + return status; + } + + /** + * @return scheduled maintenance windows for the zone. When the zone is in a maintenance window, + * all resources which reside in the zone will be unavailable. + */ + public Set getMaintenanceWindows() { + return maintenanceWindows; + } + + /** + * @return the machine types that can be used in this zone. + */ + @Nullable + public Set getAvailableMachineTypes() { + return availableMachineTypes; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .add("status", status) + .add("maintenanceWindows", maintenanceWindows) + .add("availableMachineTypes", availableMachineTypes); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromZone(this); + } + + public static final class Builder extends Resource.Builder { + + private Status status; + private ImmutableSet.Builder maintenanceWindows = ImmutableSet.builder(); + private ImmutableSet.Builder availableMachineTypes = ImmutableSet.builder(); + + /** + * @see Zone#getStatus() + */ + public Builder status(Status status) { + this.status = status; + return this; + } + + /** + * @see Zone#getMaintenanceWindows() + */ + public Builder addMaintenanceWindow(MaintenanceWindow maintenanceWindow) { + this.maintenanceWindows.add(checkNotNull(maintenanceWindow, "maintenanceWindow")); + return this; + } + + /** + * @see Zone#getMaintenanceWindows() + */ + public Builder maintenanceWindows(Set maintenanceWindows) { + this.maintenanceWindows.addAll(checkNotNull(maintenanceWindows, "maintenanceWindows")); + return this; + } + + /** + * @see Zone#getAvailableMachineTypes() + */ + public Builder addAvailableMachineType(String availableMachineType) { + this.availableMachineTypes.add(checkNotNull(availableMachineType, "availableMachineType")); + return this; + } + + /** + * @see Zone#getAvailableMachineTypes() + */ + public Builder availableMachineTypes(Set availableMachineTypes) { + this.availableMachineTypes.addAll(checkNotNull(availableMachineTypes, "availableMachineTypes")); + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Zone build() { + return new Zone(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, status, maintenanceWindows.build(), availableMachineTypes.build()); + } + + public Builder fromZone(Zone in) { + return super.fromResource(in) + .status(in.getStatus()) + .maintenanceWindows(in.getMaintenanceWindows()) + .availableMachineTypes(in.getAvailableMachineTypes()); + } + } + + /** + * Scheduled maintenance windows for the zone. When the zone is in a maintenance window, + * all resources which reside in the zone will be unavailable. + * + * @see + */ + public static final class MaintenanceWindow { + + private final String name; + private final Optional description; + private final Date beginTime; + private final Date endTime; + + @ConstructorProperties({ + "name", "description", "beginTime", "endTime" + }) + private MaintenanceWindow(String name, String description, Date beginTime, Date endTime) { + this.name = checkNotNull(name, "name"); + this.description = fromNullable(description); + this.beginTime = checkNotNull(beginTime, "beginTime of %name", name); + this.endTime = checkNotNull(endTime, "endTime of %name", name); + } + + /** + * @return name of the maintenance window. + */ + public String getName() { + return name; + } + + /** + * @return textual description of the maintenance window. + */ + public Optional getDescription() { + return description; + } + + /** + * @return begin time of the maintenance window. + */ + public Date getBeginTime() { + return beginTime; + } + + /** + * @return end time of the maintenance window. + */ + public Date getEndTime() { + return endTime; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(name, description, beginTime, endTime); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + MaintenanceWindow that = MaintenanceWindow.class.cast(obj); + return equal(this.name, that.name) + && equal(this.beginTime, that.beginTime) + && equal(this.endTime, that.endTime); + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return toStringHelper(this) + .omitNullValues() + .add("name", name) + .add("description", description.orNull()) + .add("beginTime", beginTime) + .add("endTime", endTime); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromZoneMaintenanceWindow(this); + } + + public static final class Builder { + + private String name; + private String description; + private Date beginTime; + private Date endTime; + + /** + * @see org.jclouds.googlecomputeengine.domain.Zone.MaintenanceWindow#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Zone.MaintenanceWindow#getDescription() + */ + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Zone.MaintenanceWindow#getBeginTime() + */ + public Builder beginTime(Date beginTime) { + this.beginTime = beginTime; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Zone.MaintenanceWindow#getEndTime() + */ + public Builder endTime(Date endTime) { + this.endTime = endTime; + return this; + } + + + public MaintenanceWindow build() { + return new MaintenanceWindow(name, description, beginTime, endTime); + } + + public Builder fromZoneMaintenanceWindow(MaintenanceWindow in) { + return new Builder() + .name(in.getName()) + .description(in.getDescription().orNull()) + .beginTime(in.getBeginTime()) + .endTime(in.getEndTime()); + } + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/internal/NetworkAndAddressRange.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/internal/NetworkAndAddressRange.java new file mode 100644 index 0000000000..66fbd6613c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/domain/internal/NetworkAndAddressRange.java @@ -0,0 +1,91 @@ +/* + * 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.googlecomputeengine.domain.internal; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.base.Objects; +import com.google.common.base.Objects.ToStringHelper; +import com.google.common.base.Optional; + +/** + * Container for network, IPv4 range and optional gateway, for creation caching + */ +public class NetworkAndAddressRange { + protected final String name; + protected final String ipV4Range; + protected final Optional gateway; + + @ConstructorProperties({ + "name", "ipV4Range", "gateway" + }) + public NetworkAndAddressRange(String name, String ipV4Range, @Nullable String gateway) { + this.name = checkNotNull(name, "name"); + this.ipV4Range = checkNotNull(ipV4Range, "ipV4Range"); + this.gateway = fromNullable(gateway); + } + + public String getName() { + return name; + } + + public String getIpV4Range() { + return ipV4Range; + } + + @Nullable + public Optional getGateway() { + return gateway; + } + + @Override + public int hashCode() { + // We only do hashcode/equals on name. + // the ip v4 range and gateway are included for creation rather than caching. + return Objects.hashCode(name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + NetworkAndAddressRange that = NetworkAndAddressRange.class.cast(obj); + return equal(this.name, that.name); + } + + protected ToStringHelper string() { + return toStringHelper(this) + .omitNullValues() + .add("name", name) + .add("ipV4Range", ipV4Range) + .add("gateway", gateway.orNull()); + } + + @Override + public String toString() { + return string().toString(); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java new file mode 100644 index 0000000000..40ec7dcd74 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java @@ -0,0 +1,187 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Address; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.ParseAddresses; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.binders.BindToJsonPayload; + +/** + * Provides access to Addresses via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface AddressApi { + + /** + * Returns the specified address resource. + * + * @param region Name of the region the address is in. + * @param addressName name of the address resource to return. + * @return a Address resource. + */ + @Named("Addresss:get") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/regions/{region}/addresses/{address}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Address getInRegion(@PathParam("region") String region, @PathParam("address") String addressName); + + /** + * Creates a address resource in the specified project specifying the size of the address. + * + * + * @param region the name of the region where the address is to be created. + * @param addressName the name of address. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Addresss:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/regions/{region}/addresses") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(BindToJsonPayload.class) + Operation createInRegion(@PathParam("region") String region, @PayloadParam("name") String addressName); + + /** + * Deletes the specified address resource. + * + * @param region the region the address is in. + * @param addressName name of the address resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Addresss:delete") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/regions/{region}/addresses/{address}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation deleteInRegion(@PathParam("region") String region, @PathParam("address") String addressName); + + /** + * @see org.jclouds.googlecomputeengine.features.AddressApi#listAtMarkerInRegion(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Addresss:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/regions/{region}/addresses") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseAddresses.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage
listFirstPageInRegion(@PathParam("region") String region); + + /** + * @see org.jclouds.googlecomputeengine.features.AddressApi#listAtMarkerInRegion(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Addresss:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/regions/{region}/addresses") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseAddresses.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage
listAtMarkerInRegion(@PathParam("region") String region, @QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the listPage of address resources contained within the specified project and region. + * By default the listPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has + * not been set. + * + * @param region the region to search in + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the listPage + * @see org.jclouds.googlecomputeengine.options.ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Addresss:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/regions/{region}/addresses") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseAddresses.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage
listAtMarkerInRegion(@PathParam("region") String region, @QueryParam("pageToken") @Nullable String marker, ListOptions listOptions); + + /** + * A paged version of AddressApi#listPageInRegion(String) + * + * @param region the region to list in + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see org.jclouds.collect.PagedIterable + * @see org.jclouds.googlecomputeengine.features.AddressApi#listAtMarkerInRegion(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Addresss:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/regions/{region}/addresses") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseAddresses.class) + @Transform(ParseAddresses.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable
listInRegion(@PathParam("region") String region); + + @Named("Addresss:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/regions/{region}/addresses") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseAddresses.class) + @Transform(ParseAddresses.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable
listInRegion(@PathParam("region") String region, ListOptions options); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/DiskApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/DiskApi.java new file mode 100644 index 0000000000..fa26c25ac0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/DiskApi.java @@ -0,0 +1,255 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Disk; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.ParseDisks; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.binders.BindToJsonPayload; + +/** + * Provides access to Disks via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface DiskApi { + + /** + * Returns the specified persistent disk resource. + * + * @param zone Name of the zone the disk is in. + * @param diskName name of the persistent disk resource to return. + * @return a Disk resource. + */ + @Named("Disks:get") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks/{disk}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Disk getInZone(@PathParam("zone") String zone, @PathParam("disk") String diskName); + + /** + * Creates a persistent disk resource in the specified project specifying the size of the disk. + * + * @param diskName the name of disk. + * @param sizeGb the size of the disk + * @param zone the name of the zone where the disk is to be created. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Disks:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(BindToJsonPayload.class) + Operation createInZone(@PayloadParam("name") String diskName, + @PayloadParam("sizeGb") int sizeGb, + @PathParam("zone") String zone); + + /** + * Creates a persistent disk resource from the specified image, in the specified project, + * specifying the size of the disk. + * + * @param sourceImage fully qualified URL for the image to be copied. + * @param diskName the name of disk. + * @param sizeGb the size of the disk + * @param zone the name of the zone where the disk is to be created. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Disks:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(BindToJsonPayload.class) + Operation createFromImageWithSizeInZone(@QueryParam("sourceImage") String sourceImage, + @PayloadParam("name") String diskName, + @PayloadParam("sizeGb") int sizeGb, + @PathParam("zone") String zone); + + /** + * Creates a persistent disk resource from the specified image, in the specified project, + * with the default disk size. + * + * @param sourceImage fully qualified URL for the image to be copied. + * @param diskName the name of disk. + * @param zone the name of the zone where the disk is to be created. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Disks:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(BindToJsonPayload.class) + Operation createFromImageInZone(@QueryParam("sourceImage") String sourceImage, + @PayloadParam("name") String diskName, + @PathParam("zone") String zone); + + /** + * Deletes the specified persistent disk resource. + * + * @param zone the zone the disk is in. + * @param diskName name of the persistent disk resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Disks:delete") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks/{disk}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation deleteInZone(@PathParam("zone") String zone, @PathParam("disk") String diskName); + + /** + * @see DiskApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Disks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseDisks.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPageInZone(@PathParam("zone") String zone); + + /** + * @see DiskApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Disks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseDisks.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInZone(@PathParam("zone") String zone, @QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the listPage of persistent disk resources contained within the specified project and zone. + * By default the listPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has + * not been set. + * + * @param zone the zone to search in + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the listPage + * @see ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Disks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseDisks.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInZone(@PathParam("zone") String zone, @QueryParam("pageToken") @Nullable String marker, ListOptions listOptions); + + /** + * A paged version of DiskApi#listPageInZone(String) + * + * @param zone the zone to list in + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see DiskApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Disks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseDisks.class) + @Transform(ParseDisks.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInZone(@PathParam("zone") String zone); + + @Named("Disks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseDisks.class) + @Transform(ParseDisks.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInZone(@PathParam("zone") String zone, ListOptions options); + + /** + * Create a snapshot of a given disk in a zone. + * + * @param zone the zone the disk is in. + * @param diskName the name of the disk. + * @param snapshotName the name for the snapshot to be craeted. + * + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Disks:createSnapshot") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/disks/{disk}/createSnapshot") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @MapBinder(BindToJsonPayload.class) + @Nullable + Operation createSnapshotInZone(@PathParam("zone") String zone, + @PathParam("disk") String diskName, + @PayloadParam("name") String snapshotName); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java new file mode 100644 index 0000000000..677b56a1e4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java @@ -0,0 +1,227 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import java.net.URI; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.PATCH; +import org.jclouds.googlecomputeengine.functions.internal.ParseFirewalls; +import org.jclouds.googlecomputeengine.handlers.FirewallBinder; +import org.jclouds.googlecomputeengine.options.FirewallOptions; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.binders.BindToJsonPayload; + +/** + * Provides access to Firewalls via their REST API. + *

+ * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface FirewallApi { + /** + * Returns the specified image resource. + * + * @param firewallName name of the firewall resource to return. + * @return an Firewall resource + */ + @Named("Firewalls:get") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/firewalls/{firewall}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Firewall get(@PathParam("firewall") String firewallName); + + /** + * Creates a firewall resource in the specified project using the data included in the request. + * + * @param name the name of the firewall to be inserted. + * @param network the network to which to add the firewall + * @param firewallOptions the options of the firewall to add + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Firewalls:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/global/firewalls") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(FirewallBinder.class) + Operation createInNetwork(@PayloadParam("name") String name, + @PayloadParam("network") URI network, + @PayloadParam("options") FirewallOptions firewallOptions); + + /** + * Updates the specified firewall resource with the data included in the request. + * + * @param firewallName the name firewall to be updated. + * @param firewallOptions the new firewall. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Firewalls:update") + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/global/firewalls/{firewall}") + @OAuthScopes({COMPUTE_SCOPE}) + Operation update(@PathParam("firewall") String firewallName, + @BinderParam(BindToJsonPayload.class) FirewallOptions firewallOptions); + + /** + * Updates the specified firewall resource, with patch semantics, with the data included in the request. + * + * @param firewallName the name firewall to be updated. + * @param firewallOptions the new firewall. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Firewalls:patch") + @PATCH + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/global/firewalls/{firewall}") + @OAuthScopes({COMPUTE_SCOPE}) + Operation patch(@PathParam("firewall") String firewallName, + @BinderParam(BindToJsonPayload.class) FirewallOptions firewallOptions); + + /** + * Deletes the specified image resource. + * + * @param firewallName name of the firewall resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. If the image did not exist the result is null. + */ + @Named("Firewalls:delete") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/firewalls/{firewall}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + Operation delete(@PathParam("firewall") String firewallName); + + /** + * @see FirewallApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Firewalls:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPage(); + + /** + * @see FirewallApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Firewalls:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the list of firewall resources available to the specified project. + * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not + * been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list + * @see ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Firewalls:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker, ListOptions options); + + /** + * @see FirewallApi#list(org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Firewalls:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Transform(ParseFirewalls.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(); + + /** + * A paged version of FirewallApi#list() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see FirewallApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Firewalls:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Transform(ParseFirewalls.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(ListOptions options); +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/GlobalOperationApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/GlobalOperationApi.java new file mode 100644 index 0000000000..af3221c40f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/GlobalOperationApi.java @@ -0,0 +1,158 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.ParseGlobalOperations; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to Global Operations via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface GlobalOperationApi { + + /** + * Retrieves the specified operation resource. + * + * @param operationName name of the operation resource to return. + * @return If successful, this method returns an Operation resource + */ + @Named("GlobalOperations:get") + @GET + @Path("/global/operations/{operation}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(NullOnNotFoundOr404.class) + Operation get(@PathParam("operation") String operationName); + + /** + * Deletes the specified operation resource. + * + * @param operationName name of the operation resource to delete. + */ + @Named("GlobalOperations:delete") + @DELETE + @Path("/global/operations/{operation}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + void delete(@PathParam("operation") String operationName); + + /** + * @see org.jclouds.googlecomputeengine.features.GlobalOperationApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("GlobalOperations:list") + @GET + @Path("/global/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseGlobalOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPage(); + + /** + * @see org.jclouds.googlecomputeengine.features.GlobalOperationApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("GlobalOperations:list") + @GET + @Path("/global/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseGlobalOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the listFirstPage of operation resources contained within the specified project. + * By default the listFirstPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() + * has not been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list, starting at marker + * @see org.jclouds.googlecomputeengine.options.ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("GlobalOperations:list") + @GET + @Path("/global/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseGlobalOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker, + ListOptions listOptions); + + /** + * @see org.jclouds.googlecomputeengine.features.GlobalOperationApi#list(org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("GlobalOperations:list") + @GET + @Path("/global/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseGlobalOperations.class) + @Transform(ParseGlobalOperations.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(); + + /** + * A paged version of GlobalOperationApi#listFirstPage() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see org.jclouds.collect.PagedIterable + * @see org.jclouds.googlecomputeengine.features.GlobalOperationApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("GlobalOperations:list") + @GET + @Path("/global/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseGlobalOperations.class) + @Transform(ParseGlobalOperations.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(ListOptions listOptions); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ImageApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ImageApi.java new file mode 100644 index 0000000000..cbac67e843 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ImageApi.java @@ -0,0 +1,167 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.ParseImages; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to Images via their REST API. + *

+ * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface ImageApi { + /** + * Returns the specified image resource. + * + * @param imageName name of the image resource to return. + * @return an Image resource + */ + @Named("Images:get") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/images/{image}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Image get(@PathParam("image") String imageName); + + /** + * Deletes the specified image resource. + * + * @param imageName name of the image resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. If the image did not exist the result is null. + */ + @Named("Images:delete") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/images/{image}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation delete(@PathParam("image") String imageName); + + /** + * @see ImageApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Images:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/images") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseImages.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPage(); + + /** + * @see ImageApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Images:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/images") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseImages.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the list of image resources available to the specified project. + * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not + * been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list + * @see ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Images:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/images") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseImages.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker, ListOptions listOptions); + + /** + * A paged version of ImageApi#list() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see ImageApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Images:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/images") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseImages.class) + @Transform(ParseImages.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(); + + /** + * A paged version of ImageApi#list() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see ImageApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Images:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/images") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseImages.class) + @Transform(ParseImages.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(ListOptions options); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java new file mode 100644 index 0000000000..ab80fb538d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java @@ -0,0 +1,381 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import java.util.Map; +import java.util.Set; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.InstanceTemplate; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.ParseInstances; +import org.jclouds.googlecomputeengine.handlers.InstanceBinder; +import org.jclouds.googlecomputeengine.handlers.MetadataBinder; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.binders.BindToJsonPayload; + +/** + * Provides access to Instances via their REST API. + * + * @see + * @see InstanceApi + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface InstanceApi { + + /** + * Returns the specified instance resource. + * + * @param zone zone the instance is in. + * @param instanceName name of the instance resource to return. + * @return an Instance resource + */ + @Named("Instances:get") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances/{instance}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Instance getInZone(@PathParam("zone") String zone, @PathParam("instance") String instanceName); + + /** + * Creates a instance resource in the specified project using the data included in the request. + * + * + * @param instanceName this name of the instance to be created + * @param zone the name of the zone where the instance will be created + * @param template the instance template + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Instances:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(InstanceBinder.class) + Operation createInZone(@PayloadParam("name") String instanceName, @PathParam("zone") String zone, + @PayloadParam("template") InstanceTemplate template); + + + /** + * Deletes the specified instance resource. + * + * @param zone the instance is in. + * @param instanceName name of the instance resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. If the instance did not exist the result is null. + */ + @Named("Instances:delete") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances/{instance}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation deleteInZone(@PathParam("zone") String zone, @PathParam("instance") String instanceName); + + /** + * A paged version of InstanceApi#listInZone() + * + * @param zone zone instances are in + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see InstanceApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Instances:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPageInZone(@PathParam("zone") String zone); + + /** + * Retrieves the list of instance resources available to the specified project. + * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not + * been set. + * + * @param zone zone instances are in + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list + * @see ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Instances:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInZone(@PathParam("zone") String zone, @Nullable String marker, + ListOptions listOptions); + + /** + * @see InstanceApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Instances:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInZone(@PathParam("zone") String zone, + @Nullable String marker); + + /** + * @see InstanceApi#listInZone(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Instances:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Transform(ParseInstances.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInZone(@PathParam("zone") String zone); + + /** + * @see InstanceApi#listInZone(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Instances:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseInstances.class) + @Transform(ParseInstances.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInZone(@PathParam("zone") String zone, ListOptions options); + + /** + * Adds an access config to an instance's network interface. + * + * @param zone zone instance is in + * @param instanceName the instance name. + * @param accessConfig the AccessConfig to add. + * @param networkInterfaceName network interface name. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Instances:addAccessConfig") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances/{instance}/addAccessConfig") + @OAuthScopes({COMPUTE_SCOPE}) + Operation addAccessConfigToNicInZone(@PathParam("zone") String zone, + @PathParam("instance") String instanceName, + @BinderParam(BindToJsonPayload.class) + Instance.NetworkInterface.AccessConfig accessConfig, + @QueryParam("network_interface") String networkInterfaceName); + + /** + * Deletes an access config from an instance's network interface. + * + * @param zone zone instance is in + * @param instanceName the instance name. + * @param accessConfigName the name of the access config to delete + * @param networkInterfaceName network interface name. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Instances:deleteAccessConfig") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances/{instance}/deleteAccessConfig") + @OAuthScopes(COMPUTE_SCOPE) + Operation deleteAccessConfigFromNicInZone(@PathParam("zone") String zone, + @PathParam("instance") String instanceName, + @QueryParam("access_config") String accessConfigName, + @QueryParam("network_interface") String networkInterfaceName); + + /** + * Returns the specified instance's serial port output. + * + * @param zone zone instance is in + * @param instanceName the instance name. + * @return if successful, this method returns a SerialPortOutput containing the instance's serial output. + */ + @Named("Instances:serialPort") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances/{instance}/serialPort") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + Instance.SerialPortOutput getSerialPortOutputInZone(@PathParam("zone") String zone, + @PathParam("instance") String instanceName); + + /** + * Hard-resets the instance. + * + * @param zone the zone the instance is in + * @param instanceName the instance name + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. If the instance did not exist the result is null. + */ + @Named("Instances:reset") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances/{instance}/reset") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation resetInZone(@PathParam("zone") String zone, + @PathParam("instance") String instanceName); + + /** + * Attaches a disk to an instance + * + * @param zone The zone the instance is in. + * @param instanceName The instance name to attach to + * @param attachDiskOptions The options for attaching the disk. + * + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Instances:attachDisk") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances/{instance}/attachDisk") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation attachDiskInZone(@PathParam("zone") String zone, + @PathParam("instance") String instanceName, + @BinderParam(BindToJsonPayload.class) AttachDiskOptions attachDiskOptions); + + /** + * Detaches an attached disk from an instance + * + * @param zone The zone the instance is in. + * @param instanceName The instance name to attach to + * @param deviceName The device name of the disk to detach. + * + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Instances:detachDisk") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("/zones/{zone}/instances/{instance}/detachDisk") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation detachDiskInZone(@PathParam("zone") String zone, + @PathParam("instance") String instanceName, + @QueryParam("deviceName") String deviceName); + + /** + * Sets metadata for an instance using the data included in the request. + *

+ * NOTE: This *sets* metadata items on the project (vs *adding* items to metadata), + * if there are pre-existing metadata items that must be kept these must be fetched first and then re-set on the + * new Metadata, e.g. + *


+    *    Metadata.Builder current = instanceApi.getInZone("us-central1-a", "myInstance").getMetadata().toBuilder();
+    *    current.addItem("newItem","newItemValue");
+    *    instanceApi.setMetadataInZone("us-central1-a", "myInstance", current.build());
+    * 
+ * + * @param zone The zone the instance is in + * @param instanceName The name of the instance + * @param metadata the metadata to set + * @param fingerprint The current fingerprint for the items + * + * @return an Operations resource. To check on the status of an operation, poll the Operations resource returned + * to you, and look for the status field. + */ + @Named("Instances:setMetadata") + @POST + @Path("/zones/{zone}/instances/{instance}/setMetadata") + @OAuthScopes(COMPUTE_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Fallback(NullOnNotFoundOr404.class) + @MapBinder(MetadataBinder.class) + @Nullable + Operation setMetadataInZone(@PathParam("zone") String zone, + @PathParam("instance") String instanceName, + @PayloadParam("items") Map metadata, + @PayloadParam("fingerprint") String fingerprint); + + /** + * Sets items for an instance + * + * @param zone The zone the instance is in + * @param instanceName the name of the instance + * @param items A set of items + * @param fingerprint The current fingerprint for the items + * @return an Operations resource. To check on the status of an operation, poll the Operations resource returned + * to you, and look for the status field. + */ + @Named("Instances:setTags") + @POST + @Path("/zones/{zone}/instances/{instance}/setTags") + @OAuthScopes(COMPUTE_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Fallback(NullOnNotFoundOr404.class) + @MapBinder(BindToJsonPayload.class) + @Nullable + Operation setTagsInZone(@PathParam("zone") String zone, + @PathParam("instance") String instanceName, + @PayloadParam("items") Set items, + @PayloadParam("fingerprint") String fingerprint); + +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/MachineTypeApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/MachineTypeApi.java new file mode 100644 index 0000000000..e88362b1bf --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/MachineTypeApi.java @@ -0,0 +1,143 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.MachineType; +import org.jclouds.googlecomputeengine.functions.internal.ParseMachineTypes; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to MachineTypes via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface MachineTypeApi { + + /** + * Returns the specified machine type resource + * + * @param zone the name of the zone the machine type is in + * @param machineTypeName name of the machine type resource to return. + * @return If successful, this method returns a MachineType resource + */ + @Named("MachineTypes:get") + @GET + @Path("/zones/{zone}/machineTypes/{machineType}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + MachineType getInZone(@PathParam("zone") String zone, @PathParam("machineType") String machineTypeName); + + /** + * @see MachineTypeApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("MachineTypes:list") + @GET + @Path("/zones/{zone}/machineTypes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseMachineTypes.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPageInZone(@PathParam("zone") String zone); + + /** + * @see MachineTypeApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("MachineTypes:list") + @GET + @Path("/zones/{zone}/machineTypes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseMachineTypes.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInZone(@PathParam("zone") String zone, @QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the list of machine type resources available to the specified project. + * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not + * been set. + * + * @param zone The name of the zone to list in. + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list + * @see ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("MachineTypes:list") + @GET + @Path("/zones/{zone}/machineTypes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseMachineTypes.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInZone(@PathParam("zone") String zone, + @QueryParam("pageToken") @Nullable String marker, + ListOptions listOptions); + + /** + * @see MachineTypeApi#listInZone(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("MachineTypes:list") + @GET + @Path("/zones/{zone}/machineTypes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseMachineTypes.class) + @Transform(ParseMachineTypes.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInZone(@PathParam("zone") String zone); + + /** + * A paged version of MachineTypeApi#listInZone(String) + * + * @param zone the zone to list in + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see MachineTypeApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("MachineTypes:list") + @GET + @Path("/zones/{zone}/machineTypes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseMachineTypes.class) + @Transform(ParseMachineTypes.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInZone(@PathParam("zone") String zone, ListOptions listOptions); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java new file mode 100644 index 0000000000..82fe8e2fd5 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java @@ -0,0 +1,204 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.ParseNetworks; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.binders.BindToJsonPayload; + +/** + * Provides access to Networks via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface NetworkApi { + + /** + * Returns the specified persistent network resource. + * + * @param networkName name of the persistent network resource to return. + * @return a Network resource. + */ + @Named("Networks:get") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/networks/{network}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + Network get(@PathParam("network") String networkName); + + /** + * Creates a persistent network resource in the specified project with the specified range. + * + * @param networkName the network name + * @param IPv4Range the range of the network to be inserted. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Networks:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/global/networks") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(BindToJsonPayload.class) + Operation createInIPv4Range(@PayloadParam("name") String networkName, + @PayloadParam("IPv4Range") String IPv4Range); + + /** + * Creates a persistent network resource in the specified project with the specified range and specified gateway. + * + * @param networkName the network name + * @param IPv4Range the range of the network to be inserted. + * @param gatewayIPv4 the range of the network to be inserted. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Networks:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/global/networks") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(BindToJsonPayload.class) + Operation createInIPv4RangeWithGateway(@PayloadParam("name") String networkName, + @PayloadParam("IPv4Range") String IPv4Range, + @PayloadParam("gatewayIPv4") String gatewayIPv4); + + /** + * Deletes the specified persistent network resource. + * + * @param networkName name of the persistent network resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Networks:delete") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/networks/{network}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + Operation delete(@PathParam("network") String networkName); + + /** + * @see NetworkApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Networks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/networks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseNetworks.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPage(); + + /** + * @see NetworkApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Networks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/networks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseNetworks.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the list of persistent network resources contained within the specified project. + * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not + * been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list + * @see ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Networks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/networks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseNetworks.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker, + ListOptions options); + + /** + * @see NetworkApi#list(org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Networks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/networks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseNetworks.class) + @Transform(ParseNetworks.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(); + + /** + * A paged version of NetworkApi#list() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see NetworkApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Networks:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/networks") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseNetworks.class) + @Transform(ParseNetworks.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(ListOptions options); +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ProjectApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ProjectApi.java new file mode 100644 index 0000000000..94cfe052b8 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ProjectApi.java @@ -0,0 +1,96 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import java.util.Map; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Project; +import org.jclouds.googlecomputeengine.handlers.MetadataBinder; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SkipEncoding; + +/** + * Provides access to Projects via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface ProjectApi { + + /** + * Returns the specified project resource. + * + * @param projectName name of the project to return + * @return if successful, this method returns a Project resource + */ + @Named("Projects:get") + @GET + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(NullOnNotFoundOr404.class) + @Path("/projects/{project}") + Project get(@PathParam("project") String projectName); + + /** + * Sets metadata common to all instances within the specified project using the data included in the request. + *

+ * NOTE: This *sets* metadata items on the project (vs *adding* items to metadata), + * if there are pre-existing metadata items that must be kept these must be fetched first and then re-set on the + * new Metadata, e.g. + *


+    *    Metadata.Builder current = projectApi.get("myProject").getCommonInstanceMetadata().toBuilder();
+    *    current.addItem("newItem","newItemValue");
+    *    projectApi.setCommonInstanceMetadata(current.build());
+    * 
+ * + * @param projectName name of the project to return + * @param metadata the metadata to set + * @param fingerprint The current fingerprint for the metadata + * @return an Operations resource. To check on the status of an operation, poll the Operations resource returned + * to you, and look for the status field. + */ + @Named("Projects:setCommonInstanceMetadata") + @POST + @Path("/projects/{project}/setCommonInstanceMetadata") + @OAuthScopes(COMPUTE_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @MapBinder(MetadataBinder.class) + Operation setCommonInstanceMetadata(@PathParam("project") String projectName, + @PayloadParam("items") Map metadata, + @PayloadParam("fingerprint") String fingerprint); +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RegionApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RegionApi.java new file mode 100644 index 0000000000..872918d7c7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RegionApi.java @@ -0,0 +1,135 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Region; +import org.jclouds.googlecomputeengine.functions.internal.ParseRegions; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to Regions via their REST API. + * + * @see
+ */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface RegionApi { + + /** + * Returns the specified region resource + * + * @param regionName name of the region resource to return. + * @return If successful, this method returns a Region resource + */ + @Named("Regions:get") + @GET + @Path("/regions/{region}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + Region get(@PathParam("region") String regionName); + + /** + * @see org.jclouds.googlecomputeengine.features.RegionApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Regions:list") + @GET + @Path("/regions") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRegions.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPage(); + + /** + * @see org.jclouds.googlecomputeengine.features.RegionApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Regions:list") + @GET + @Path("/regions") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRegions.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(String marker); + + /** + * Retrieves the listFirstPage of region resources available to the specified project. + * By default the listFirstPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() + * has not been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the listFirstPage + * @see org.jclouds.googlecomputeengine.options.ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Regions:list") + @GET + @Path("/regions") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRegions.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(String marker, ListOptions listOptions); + + /** + * @see org.jclouds.googlecomputeengine.features.RegionApi#list(org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Regions:list") + @GET + @Path("/regions") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRegions.class) + @Transform(ParseRegions.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(); + + /** + * A paged version of RegionApi#listFirstPage() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see org.jclouds.googlecomputeengine.features.RegionApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + * @see org.jclouds.collect.PagedIterable + */ + @Named("Regions:list") + @GET + @Path("/regions") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRegions.class) + @Transform(ParseRegions.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(ListOptions listOptions); +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RegionOperationApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RegionOperationApi.java new file mode 100644 index 0000000000..9f5c48d60b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RegionOperationApi.java @@ -0,0 +1,163 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.ParseRegionOperations; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to Operations via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface RegionOperationApi { + + /** + * Retrieves the specified operation resource. + * + * @param region the region the operation is in + * @param operationName name of the operation resource to return. + * @return If successful, this method returns an Operation resource + */ + @Named("RegionOperations:get") + @GET + @Path("/regions/{region}/operations/{operation}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(NullOnNotFoundOr404.class) + Operation getInRegion(@PathParam("region") String region, @PathParam("operation") String operationName); + + /** + * Deletes the specified operation resource. + * + * @param region the region the operation is in + * @param operationName name of the operation resource to delete. + */ + @Named("RegionOperations:delete") + @DELETE + @Path("/regions/{region}/operations/{operation}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + void deleteInRegion(@PathParam("region") String region, @PathParam("operation") String operationName); + + /** + * @see org.jclouds.googlecomputeengine.features.RegionOperationApi#listAtMarkerInRegion(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("RegionOperations:list") + @GET + @Path("/regions/{region}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseRegionOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPageInRegion(@PathParam("region") String region); + + /** + * @see org.jclouds.googlecomputeengine.features.RegionOperationApi#listAtMarkerInRegion(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("RegionOperations:list") + @GET + @Path("/regions/{region}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseRegionOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInRegion(@PathParam("region") String region, + @QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the listFirstPage of operation resources contained within the specified project. + * By default the listFirstPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() + * has not been set. + * + * @param region the region to list in + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list, starting at marker + * @see org.jclouds.googlecomputeengine.options.ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("RegionOperations:list") + @GET + @Path("/regions/{region}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseRegionOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInRegion(@PathParam("region") String region, + @QueryParam("pageToken") @Nullable String marker, + ListOptions listOptions); + + /** + * @see org.jclouds.googlecomputeengine.features.RegionOperationApi#listInRegion(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("RegionOperations:list") + @GET + @Path("/regions/{region}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseRegionOperations.class) + @Transform(ParseRegionOperations.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInRegion(@PathParam("region") String region); + + /** + * A paged version of RegionOperationApi#listFirstPageInRegion(String) + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see org.jclouds.collect.PagedIterable + * @see org.jclouds.googlecomputeengine.features.RegionOperationApi#listAtMarkerInRegion(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("RegionOperations:list") + @GET + @Path("/regions/{region}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseRegionOperations.class) + @Transform(ParseRegionOperations.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInRegion(@PathParam("region") String region, ListOptions listOptions); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java new file mode 100644 index 0000000000..54051817c0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java @@ -0,0 +1,184 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import java.net.URI; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Route; +import org.jclouds.googlecomputeengine.functions.internal.ParseRoutes; +import org.jclouds.googlecomputeengine.handlers.RouteBinder; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.googlecomputeengine.options.RouteOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to Routes via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface RouteApi { + + /** + * Returns the specified route resource + * + * @param routeName name of the region resource to return. + * @return If successful, this method returns a Route resource + */ + @Named("Routes:get") + @GET + @Path("/global/routes/{route}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + Route get(@PathParam("route") String routeName); + + /** + * @see org.jclouds.googlecomputeengine.features.RouteApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Routes:list") + @GET + @Path("/global/routes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRoutes.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPage(); + + /** + * @see org.jclouds.googlecomputeengine.features.RouteApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Routes:list") + @GET + @Path("/global/routes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRoutes.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(String marker); + + /** + * Retrieves the listFirstPage of route resources available to the specified project. + * By default the listFirstPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() + * has not been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the listFirstPage + * @see org.jclouds.googlecomputeengine.options.ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Routes:list") + @GET + @Path("/global/routes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRoutes.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(String marker, ListOptions listOptions); + + /** + * @see org.jclouds.googlecomputeengine.features.RouteApi#list(org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Routes:list") + @GET + @Path("/global/routes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRoutes.class) + @Transform(ParseRoutes.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(); + + /** + * A paged version of RegionApi#listFirstPage() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see org.jclouds.googlecomputeengine.features.RouteApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + * @see org.jclouds.collect.PagedIterable + */ + @Named("Routes:list") + @GET + @Path("/global/routes") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseRoutes.class) + @Transform(ParseRoutes.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(ListOptions listOptions); + + /** + * Deletes the specified route resource. + * + * @param routeName name of the route resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. If the route did not exist the result is null. + */ + @Named("Routes:delete") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/routes/{route}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation delete(@PathParam("route") String routeName); + + /** + * Creates a route resource in the specified project using the data included in the request. + * + * @param name the name of the route to be inserted. + * @param network the network to which to add the route + * @param routeOptions the options of the route to add + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Routes:insert") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/global/routes") + @OAuthScopes({COMPUTE_SCOPE}) + @MapBinder(RouteBinder.class) + Operation createInNetwork(@PayloadParam("name") String name, + @PayloadParam("network") URI network, + @PayloadParam("options") RouteOptions routeOptions); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/SnapshotApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/SnapshotApi.java new file mode 100644 index 0000000000..89fe8d5d76 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/SnapshotApi.java @@ -0,0 +1,160 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Snapshot; +import org.jclouds.googlecomputeengine.functions.internal.ParseSnapshots; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to Snapshots via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface SnapshotApi { + + /** + * Returns the specified snapshot resource. + * + * @param snapshotName name of the snapshot resource to return. + * @return a Snapshot resource. + */ + @Named("Snapshots:get") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/snapshots/{snapshot}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Snapshot get(@PathParam("snapshot") String snapshotName); + + /** + * Deletes the specified snapshot resource. + * + * @param snapshotName name of the snapshot resource to delete. + * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to + * you, and look for the status field. + */ + @Named("Snapshots:delete") + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/snapshots/{snapshot}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + @Nullable + Operation delete(@PathParam("snapshot") String snapshotName); + + /** + * @see org.jclouds.googlecomputeengine.features.SnapshotApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Snapshots:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/snapshots") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseSnapshots.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPage(); + + /** + * @see org.jclouds.googlecomputeengine.features.SnapshotApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Snapshots:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/snapshots") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseSnapshots.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the listPage of persistent disk resources contained within the specified project and zone. + * By default the listPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has + * not been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the listPage + * @see org.jclouds.googlecomputeengine.options.ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("Snapshots:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/snapshots") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseSnapshots.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(@QueryParam("pageToken") @Nullable String marker, ListOptions listOptions); + + /** + * A paged version of SnapshotApi#listPage(String) + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see org.jclouds.collect.PagedIterable + * @see org.jclouds.googlecomputeengine.features.SnapshotApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Snapshots:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/snapshots") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseSnapshots.class) + @Transform(ParseSnapshots.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(); + + @Named("Snapshots:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/global/snapshots") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseSnapshots.class) + @Transform(ParseSnapshots.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(ListOptions options); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ZoneApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ZoneApi.java new file mode 100644 index 0000000000..246c66dde5 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ZoneApi.java @@ -0,0 +1,135 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.functions.internal.ParseZones; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to Zones via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface ZoneApi { + + /** + * Returns the specified zone resource + * + * @param zoneName name of the zone resource to return. + * @return If successful, this method returns a Zone resource + */ + @Named("Zones:get") + @GET + @Path("/zones/{zone}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + Zone get(@PathParam("zone") String zoneName); + + /** + * @see ZoneApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Zones:list") + @GET + @Path("/zones") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseZones.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPage(); + + /** + * @see ZoneApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Zones:list") + @GET + @Path("/zones") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseZones.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(String marker); + + /** + * Retrieves the listFirstPage of zone resources available to the specified project. + * By default the listFirstPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() + * has not been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the listFirstPage + * @see ListOptions + * @see ListPage + */ + @Named("Zones:list") + @GET + @Path("/zones") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseZones.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarker(String marker, ListOptions listOptions); + + /** + * @see ZoneApi#list(org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("Zones:list") + @GET + @Path("/zones") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseZones.class) + @Transform(ParseZones.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(); + + /** + * A paged version of ZoneApi#listFirstPage() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see ZoneApi#listAtMarker(String, org.jclouds.googlecomputeengine.options.ListOptions) + * @see PagedIterable + */ + @Named("Zones:list") + @GET + @Path("/zones") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseZones.class) + @Transform(ParseZones.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable list(ListOptions listOptions); +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ZoneOperationApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ZoneOperationApi.java new file mode 100644 index 0000000000..37cd2c96ac --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/features/ZoneOperationApi.java @@ -0,0 +1,163 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.functions.internal.ParseZoneOperations; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; + +/** + * Provides access to Operations via their REST API. + * + * @see + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface ZoneOperationApi { + + /** + * Retrieves the specified operation resource. + * + * @param zone the zone the operation is in + * @param operationName name of the operation resource to return. + * @return If successful, this method returns an Operation resource + */ + @Named("ZoneOperations:get") + @GET + @Path("/zones/{zone}/operations/{operation}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(NullOnNotFoundOr404.class) + Operation getInZone(@PathParam("zone") String zone, @PathParam("operation") String operationName); + + /** + * Deletes the specified operation resource. + * + * @param zone the zone the operation is in + * @param operationName name of the operation resource to delete. + */ + @Named("ZoneOperations:delete") + @DELETE + @Path("/zones/{zone}/operations/{operation}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + void deleteInZone(@PathParam("zone") String zone, @PathParam("operation") String operationName); + + /** + * @see ZoneOperationApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("ZoneOperations:list") + @GET + @Path("/zones/{zone}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseZoneOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listFirstPageInZone(@PathParam("zone") String zone); + + /** + * @see ZoneOperationApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("ZoneOperations:list") + @GET + @Path("/zones/{zone}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseZoneOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInZone(@PathParam("zone") String zone, + @QueryParam("pageToken") @Nullable String marker); + + /** + * Retrieves the listFirstPage of operation resources contained within the specified project. + * By default the listFirstPage as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() + * has not been set. + * + * @param zone the zone to list in + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list, starting at marker + * @see ListOptions + * @see org.jclouds.googlecomputeengine.domain.ListPage + */ + @Named("ZoneOperations:list") + @GET + @Path("/zones/{zone}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseZoneOperations.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListPage listAtMarkerInZone(@PathParam("zone") String zone, + @QueryParam("pageToken") @Nullable String marker, + ListOptions listOptions); + + /** + * @see ZoneOperationApi#listInZone(String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("ZoneOperations:list") + @GET + @Path("/zones/{zone}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseZoneOperations.class) + @Transform(ParseZoneOperations.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInZone(@PathParam("zone") String zone); + + /** + * A paged version of ZoneOperationApi#listFirstPageInZone(String) + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see ZoneOperationApi#listAtMarkerInZone(String, String, org.jclouds.googlecomputeengine.options.ListOptions) + */ + @Named("ZoneOperations:list") + @GET + @Path("/zones/{zone}/operations") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Consumes(MediaType.APPLICATION_JSON) + @ResponseParser(ParseZoneOperations.class) + @Transform(ParseZoneOperations.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listInZone(@PathParam("zone") String zone, ListOptions listOptions); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeeded.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeeded.java new file mode 100644 index 0000000000..c6bc1ac5f0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeeded.java @@ -0,0 +1,100 @@ +/* + * 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.googlecomputeengine.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; +import static org.jclouds.util.Predicates2.retry; + +import java.util.concurrent.atomic.AtomicReference; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.util.concurrent.Atomics; + +@Singleton +public class CreateNetworkIfNeeded implements Function { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + protected final GoogleComputeEngineApi api; + protected final Supplier userProject; + private final Predicate> operationDonePredicate; + private final long operationCompleteCheckInterval; + private final long operationCompleteCheckTimeout; + + @Inject + public CreateNetworkIfNeeded(GoogleComputeEngineApi api, + @UserProject Supplier userProject, + @Named("global") Predicate> operationDonePredicate, + @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, + @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) { + this.api = checkNotNull(api, "api"); + this.userProject = checkNotNull(userProject, "userProject"); + this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval, + "operation completed check interval"); + this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout, + "operation completed check timeout"); + this.operationDonePredicate = checkNotNull(operationDonePredicate, "operationDonePredicate"); + } + + @Override + public Network apply(NetworkAndAddressRange input) { + checkNotNull(input, "input"); + + Network nw = api.getNetworkApiForProject(userProject.get()).get(input.getName()); + if (nw != null) { + return nw; + } + + if (input.getGateway().isPresent()) { + AtomicReference operation = Atomics.newReference(api.getNetworkApiForProject(userProject + .get()).createInIPv4RangeWithGateway(input.getName(), input.getIpV4Range(), input.getGateway().get())); + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not create network, operation failed" + operation); + } else { + AtomicReference operation = Atomics.newReference(api.getNetworkApiForProject(userProject + .get()).createInIPv4Range(input.getName(), input.getIpV4Range())); + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not create network, operation failed" + operation); + } + return checkNotNull(api.getNetworkApiForProject(userProject.get()).get(input.getName()), + "no network with name %s was found", input.getName()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseToPagedIterable.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseToPagedIterable.java new file mode 100644 index 0000000000..588be0a0ae --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseToPagedIterable.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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Predicates.instanceOf; +import static com.google.common.collect.Iterables.tryFind; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.collect.PagedIterables; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.InvocationContext; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Optional; + +@Beta +public abstract class BaseToPagedIterable> implements + Function, PagedIterable>, InvocationContext { + + private GeneratedHttpRequest request; + + @Override + public PagedIterable apply(ListPage input) { + if (input.nextMarker() == null) + return PagedIterables.of(input); + + Optional project = tryFind(request.getCaller().get().getArgs(), instanceOf(String.class)); + + Optional listOptions = tryFind(request.getInvocation().getArgs(), instanceOf(ListOptions.class)); + + assert project.isPresent() : String.format("programming error, method %s should have a string param for the " + + "project", request.getCaller().get().getInvokable()); + + return PagedIterables.advance( + input, fetchNextPage(project.get().toString(), (ListOptions) listOptions.orNull())); + } + + protected abstract Function> fetchNextPage(String projectName, + ListOptions listOptions); + + @SuppressWarnings("unchecked") + @Override + public I setContext(HttpRequest request) { + this.request = GeneratedHttpRequest.class.cast(request); + return (I) this; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToPagedIterable.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToPagedIterable.java new file mode 100644 index 0000000000..a4cc52d299 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToPagedIterable.java @@ -0,0 +1,72 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Predicates.instanceOf; +import static com.google.common.collect.Iterables.tryFind; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.collect.PagedIterables; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.InvocationContext; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Optional; + +@Beta +public abstract class BaseWithRegionToPagedIterable> implements + Function, PagedIterable>, InvocationContext { + + private GeneratedHttpRequest request; + + @Override + public PagedIterable apply(ListPage input) { + if (input.nextMarker() == null) + return PagedIterables.of(input); + + Optional project = tryFind(request.getCaller().get().getArgs(), instanceOf(String.class)); + + Optional region = tryFind(request.getInvocation().getArgs(), instanceOf(String.class)); + + Optional listOptions = tryFind(request.getInvocation().getArgs(), instanceOf(ListOptions.class)); + + assert project.isPresent() : String.format("programming error, method %s should have a string param for the " + + "project", request.getCaller().get().getInvokable()); + + assert region.isPresent() : String.format("programming error, method %s should have a string param for the " + + "region", request.getCaller().get().getInvokable()); + + return PagedIterables.advance( + input, fetchNextPage(project.get().toString(), region.get().toString(), (ListOptions) listOptions.orNull())); + } + + protected abstract Function> fetchNextPage(String projectName, + String regionName, + ListOptions listOptions); + + @SuppressWarnings("unchecked") + @Override + public I setContext(HttpRequest request) { + this.request = GeneratedHttpRequest.class.cast(request); + return (I) this; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToPagedIterable.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToPagedIterable.java new file mode 100644 index 0000000000..d9dcbf21dd --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToPagedIterable.java @@ -0,0 +1,72 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Predicates.instanceOf; +import static com.google.common.collect.Iterables.tryFind; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.collect.PagedIterables; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.InvocationContext; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Optional; + +@Beta +public abstract class BaseWithZoneToPagedIterable> implements + Function, PagedIterable>, InvocationContext { + + private GeneratedHttpRequest request; + + @Override + public PagedIterable apply(ListPage input) { + if (input.nextMarker() == null) + return PagedIterables.of(input); + + Optional project = tryFind(request.getCaller().get().getArgs(), instanceOf(String.class)); + + Optional zone = tryFind(request.getInvocation().getArgs(), instanceOf(String.class)); + + Optional listOptions = tryFind(request.getInvocation().getArgs(), instanceOf(ListOptions.class)); + + assert project.isPresent() : String.format("programming error, method %s should have a string param for the " + + "project", request.getCaller().get().getInvokable()); + + assert zone.isPresent() : String.format("programming error, method %s should have a string param for the " + + "zone", request.getCaller().get().getInvokable()); + + return PagedIterables.advance( + input, fetchNextPage(project.get().toString(), zone.get().toString(), (ListOptions) listOptions.orNull())); + } + + protected abstract Function> fetchNextPage(String projectName, + String zoneName, + ListOptions listOptions); + + @SuppressWarnings("unchecked") + @Override + public I setContext(HttpRequest request) { + this.request = GeneratedHttpRequest.class.cast(request); + return (I) this; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/PATCH.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/PATCH.java new file mode 100644 index 0000000000..4e287dc015 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/PATCH.java @@ -0,0 +1,35 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.ws.rs.HttpMethod; + +/** + * Indicates that the annotated method responds to HTTP PATCH requests + * + * @see javax.ws.rs.HttpMethod + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@HttpMethod("PATCH") +public @interface PATCH { +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseAddresses.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseAddresses.java new file mode 100644 index 0000000000..59b4408312 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseAddresses.java @@ -0,0 +1,67 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Address; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +@Singleton +public class ParseAddresses extends ParseJson> { + + @Inject + public ParseAddresses(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseWithRegionToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final String regionName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker
apply(Object input) { + return api.getAddressApiForProject(projectName) + .listAtMarkerInRegion(regionName, input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseDisks.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseDisks.java new file mode 100644 index 0000000000..eca4a11fc5 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseDisks.java @@ -0,0 +1,67 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Disk; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +@Singleton +public class ParseDisks extends ParseJson> { + + @Inject + public ParseDisks(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseWithZoneToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final String zoneName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getDiskApiForProject(projectName) + .listAtMarkerInZone(zoneName, input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseFirewalls.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseFirewalls.java new file mode 100644 index 0000000000..05d11bda95 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseFirewalls.java @@ -0,0 +1,63 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseFirewalls extends ParseJson> { + + @Inject + public ParseFirewalls(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getFirewallApiForProject(projectName).listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java new file mode 100644 index 0000000000..b2a589e067 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java @@ -0,0 +1,63 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseGlobalOperations extends ParseJson> { + + @Inject + public ParseGlobalOperations(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getGlobalOperationApiForProject(projectName).listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseImages.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseImages.java new file mode 100644 index 0000000000..6d23343a3c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseImages.java @@ -0,0 +1,63 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseImages extends ParseJson> { + + @Inject + public ParseImages(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getImageApiForProject(projectName).listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseInstances.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseInstances.java new file mode 100644 index 0000000000..001a98c843 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseInstances.java @@ -0,0 +1,65 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseInstances extends ParseJson> { + + @Inject + public ParseInstances(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseWithZoneToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String project, + final String zone, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getInstanceApiForProject(project) + .listAtMarkerInZone(zone, input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseMachineTypes.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseMachineTypes.java new file mode 100644 index 0000000000..be78b92e0d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseMachineTypes.java @@ -0,0 +1,64 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.MachineType; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseMachineTypes extends ParseJson> { + + @Inject + public ParseMachineTypes(Json json) { + super(json, new TypeLiteral>() {}); + } + + public static class ToPagedIterable extends BaseWithZoneToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String project, + final String zone, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getMachineTypeApiForProject(project) + .listAtMarkerInZone(zone, input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseNetworks.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseNetworks.java new file mode 100644 index 0000000000..0aa550b5f8 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseNetworks.java @@ -0,0 +1,63 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseNetworks extends ParseJson> { + + @Inject + public ParseNetworks(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getNetworkApiForProject(projectName).listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java new file mode 100644 index 0000000000..84c8954b31 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java @@ -0,0 +1,65 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseRegionOperations extends ParseJson> { + + @Inject + public ParseRegionOperations(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseWithRegionToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final String regionName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getRegionOperationApiForProject(projectName) + .listAtMarkerInRegion(regionName, input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegions.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegions.java new file mode 100644 index 0000000000..ca1819eb5a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegions.java @@ -0,0 +1,63 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Region; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseRegions extends ParseJson> { + + @Inject + public ParseRegions(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getRegionApiForProject(projectName).listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRoutes.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRoutes.java new file mode 100644 index 0000000000..6191892f05 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRoutes.java @@ -0,0 +1,63 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Route; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseRoutes extends ParseJson> { + + @Inject + public ParseRoutes(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getRouteApiForProject(projectName).listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseSnapshots.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseSnapshots.java new file mode 100644 index 0000000000..66ac2e7dae --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseSnapshots.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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Snapshot; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +@Singleton +public class ParseSnapshots extends ParseJson> { + + @Inject + public ParseSnapshots(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getSnapshotApiForProject(projectName) + .listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java new file mode 100644 index 0000000000..28cc4435f4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java @@ -0,0 +1,65 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseZoneOperations extends ParseJson> { + + @Inject + public ParseZoneOperations(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseWithZoneToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final String zoneName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getZoneOperationApiForProject(projectName) + .listAtMarkerInZone(zoneName, input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZones.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZones.java new file mode 100644 index 0000000000..f3e54eae2b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZones.java @@ -0,0 +1,63 @@ +/* + * 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.googlecomputeengine.functions.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; + +public class ParseZones extends ParseJson> { + + @Inject + public ParseZones(Json json) { + super(json, new TypeLiteral>() { + }); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeEngineApi api; + + @Inject + protected ToPagedIterable(GoogleComputeEngineApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getZoneApiForProject(projectName).listAtMarker(input.toString(), options); + } + }; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/FirewallBinder.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/FirewallBinder.java new file mode 100644 index 0000000000..b5ce22e868 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/FirewallBinder.java @@ -0,0 +1,56 @@ +/* + * 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.googlecomputeengine.handlers; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Map; + +import javax.inject.Inject; + +import org.jclouds.googlecomputeengine.options.FirewallOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.MapBinder; +import org.jclouds.rest.binders.BindToJsonPayload; + +public class FirewallBinder implements MapBinder { + + @Inject + private BindToJsonPayload jsonBinder; + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Map postParams) { + FirewallOptions options = (FirewallOptions) checkNotNull(postParams.get("options"), "firewallOptions"); + String name = (String) checkNotNull(postParams.get("name"), "name"); + URI network = (URI) checkNotNull(postParams.get("network"), "network"); + options.name(name); + options.network(network); + return bindToRequest(request, options); + } + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Object input) { + return jsonBinder.bindToRequest(request, input); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/GoogleComputeEngineErrorHandler.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/GoogleComputeEngineErrorHandler.java new file mode 100644 index 0000000000..109b050101 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/GoogleComputeEngineErrorHandler.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.googlecomputeengine.handlers; + +import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; + +import javax.inject.Singleton; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ResourceNotFoundException; + +/** + * This will parse and set an appropriate exception on the command object. + */ +@Singleton +public class GoogleComputeEngineErrorHandler implements HttpErrorHandler { + public void handleError(HttpCommand command, HttpResponse response) { + // it is important to always read fully and close streams + byte[] data = closeClientButKeepContentStream(response); + String message = data != null ? new String(data) : null; + + Exception exception = message != null ? new HttpResponseException(command, response, message) + : new HttpResponseException(command, response); + message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(), + response.getStatusLine()); + switch (response.getStatusCode()) { + case 400: + break; + case 401: + case 403: + exception = new AuthorizationException(message, exception); + break; + case 404: + if (!command.getCurrentRequest().getMethod().equals("DELETE")) { + exception = new ResourceNotFoundException(message, exception); + } + break; + case 409: + exception = new IllegalStateException(message, exception); + break; + } + command.setException(exception); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/InstanceBinder.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/InstanceBinder.java new file mode 100644 index 0000000000..2559edea11 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/InstanceBinder.java @@ -0,0 +1,65 @@ +/* + * 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.googlecomputeengine.handlers; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.googlecomputeengine.domain.InstanceTemplate; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.MapBinder; +import org.jclouds.rest.binders.BindToJsonPayload; + +import com.google.common.base.Function; + +public class InstanceBinder implements MapBinder { + + @Inject + private BindToJsonPayload jsonBinder; + + @Inject + @Named("machineTypeToURI") + Function machineTypesToURI; + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Map postParams) { + InstanceTemplate template = (InstanceTemplate) checkNotNull(postParams.get("template"), "template"); + template.name(checkNotNull(postParams.get("name"), "name").toString()); + + if (template.getMachineTypeName() != null) { + template.machineType(machineTypesToURI.apply(template.getMachineTypeName())); + } + template.machineType((String) null); + return bindToRequest(request, template); + } + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Object input) { + return jsonBinder.bindToRequest(request, input); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/MetadataBinder.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/MetadataBinder.java new file mode 100644 index 0000000000..b96afb46ab --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/MetadataBinder.java @@ -0,0 +1,60 @@ +/* + * 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.googlecomputeengine.handlers; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; + +import javax.inject.Inject; + +import org.jclouds.googlecomputeengine.domain.Metadata; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.MapBinder; +import org.jclouds.rest.binders.BindToJsonPayload; + +import com.google.common.collect.ImmutableMap; + +public class MetadataBinder implements MapBinder { + + @Inject + private BindToJsonPayload jsonBinder; + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Map postParams) { + Map items = + ImmutableMap.copyOf((Map) checkNotNull(postParams.get("items"), "item")); + String fingerprint = (String) checkNotNull(postParams.get("fingerprint"), "fingerprint"); + Metadata metadata = Metadata.builder() + .fingerprint(fingerprint) + .items(items) + .build(); + return bindToRequest(request, metadata); + } + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Object input) { + return jsonBinder.bindToRequest(request, input); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/RouteBinder.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/RouteBinder.java new file mode 100644 index 0000000000..2863b44f0b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/handlers/RouteBinder.java @@ -0,0 +1,56 @@ +/* + * 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.googlecomputeengine.handlers; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Map; + +import javax.inject.Inject; + +import org.jclouds.googlecomputeengine.options.RouteOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.MapBinder; +import org.jclouds.rest.binders.BindToJsonPayload; + +public class RouteBinder implements MapBinder { + + @Inject + private BindToJsonPayload jsonBinder; + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Map postParams) { + RouteOptions options = (RouteOptions) checkNotNull(postParams.get("options"), "routeOptions"); + String name = (String) checkNotNull(postParams.get("name"), "name"); + URI network = (URI) checkNotNull(postParams.get("network"), "network"); + options.name(name); + options.network(network); + return bindToRequest(request, options); + } + + /** + * {@inheritDoc} + */ + @Override + public R bindToRequest(R request, Object input) { + return jsonBinder.bindToRequest(request, input); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/AttachDiskOptions.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/AttachDiskOptions.java new file mode 100644 index 0000000000..5ad2846067 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/AttachDiskOptions.java @@ -0,0 +1,128 @@ +/* + * 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.googlecomputeengine.options; + +import java.net.URI; + +/** + * Options for attaching disks to instances. + * + * @see + */ +public class AttachDiskOptions { + + public enum DiskType { + SCRATCH, + PERSISTENT + } + + public enum DiskMode { + READ_WRITE, + READ_ONLY + } + + private DiskType type; + private DiskMode mode; + private URI source; + private String deviceName; + private boolean boot; + + /** + * The disk type + * + * @return the disk type. + */ + public DiskType getType() { + return type; + } + + /** + * The disk mode + * + * @return the disk mode + */ + public DiskMode getMode() { + return mode; + } + + /** + * The URI of the source disk - optional, if DiskType.SCRATCH is used. + * + * @return the URI + */ + public URI getSource() { + return source; + } + + /** + * The device name on the instance - optional. + * + * @return the device name + */ + public String getDeviceName() { + return deviceName; + } + + /** + * Indicates that this is a boot disk. VM will use the first partition of the disk for its root filesystem. + * + * @return true if this is a boot disk, false otherwise + */ + public boolean getBoot() { + return boot; + } + + /** + * @see AttachDiskOptions#getType() + */ + public AttachDiskOptions type(DiskType type) { + this.type = type; + return this; + } + + /** + * @see AttachDiskOptions#getMode() + */ + public AttachDiskOptions mode(DiskMode mode) { + this.mode = mode; + return this; + } + + /** + * @see AttachDiskOptions#getSource() + */ + public AttachDiskOptions source(URI source) { + this.source = source; + return this; + } + + /** + * @see AttachDiskOptions#getDeviceName() + */ + public AttachDiskOptions deviceName(String deviceName) { + this.deviceName = deviceName; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.options.AttachDiskOptions#getBoot() + */ + public AttachDiskOptions boot(boolean boot) { + this.boot = boot; + return this; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/DeprecateOptions.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/DeprecateOptions.java new file mode 100644 index 0000000000..382bf71a31 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/DeprecateOptions.java @@ -0,0 +1,126 @@ +/* + * 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.googlecomputeengine.options; + +import java.net.URI; +import java.util.Date; + +/** + * Options to set the deprecation status of a resource. Currently only for images. + * + * @see + */ +public class DeprecateOptions { + + public enum State { + DEPRECATED, + OBSOLETE, + DELETED + } + + private State state; + private URI replacement; + private Date deprecated; + private Date obsolete; + private Date deleted; + + /** + * The new deprecation state. + * + * @return the new deprecation state. + */ + public State getState() { + return state; + } + + /** + * Optional URL for replacement of deprecated resource. + * + * @return the URL + */ + public URI getReplacement() { + return replacement; + } + + /** + * Optional RFC3339 timestamp for when the deprecation state was changed to DEPRECATED. + * + * @return the timestamp + */ + public Date getDeprecated() { + return deprecated; + } + + /** + * Optional RFC3339 timestamp for when the deprecation state was changed to OBSOLETE. + * + * @return the timestamp + */ + public Date getObsolete() { + return obsolete; + } + + /** + * Optional RFC3339 timestamp for when the deprecation state was changed to DELETED. + * + * @return the timestamp + */ + public Date getDeleted() { + return deleted; + } + + /** + * @see DeprecateOptions#getState() + */ + public DeprecateOptions state(State state) { + this.state = state; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.options.DeprecateOptions#getReplacement() + */ + public DeprecateOptions replacement(URI replacement) { + this.replacement = replacement; + return this; + } + + /** + * @see DeprecateOptions#getDeprecated() + */ + public DeprecateOptions deprecated(Date deprecated) { + this.deprecated = deprecated; + return this; + } + + /** + * @see DeprecateOptions#getObsolete() + */ + public DeprecateOptions obsolete(Date obsolete) { + this.obsolete = obsolete; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.options.DeprecateOptions#getDeleted() + */ + public DeprecateOptions deleted(Date deleted) { + this.deleted = deleted; + return this; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/FirewallOptions.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/FirewallOptions.java new file mode 100644 index 0000000000..d70d4d03b9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/FirewallOptions.java @@ -0,0 +1,166 @@ +/* + * 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.googlecomputeengine.options; + +import java.net.URI; +import java.util.Set; + +import org.jclouds.googlecomputeengine.domain.Firewall; + +import com.google.common.collect.ImmutableSet; + +/** + * Options to create a firewall. + * + * @see Firewall + */ +public class FirewallOptions { + + private String name; + private URI network; + private ImmutableSet.Builder sourceRanges = ImmutableSet.builder(); + private ImmutableSet.Builder sourceTags = ImmutableSet.builder(); + private ImmutableSet.Builder targetTags = ImmutableSet.builder(); + private ImmutableSet.Builder allowed = ImmutableSet.builder(); + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getAllowed() + */ + public Set getAllowed() { + return allowed.build(); + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getAllowed() + */ + public FirewallOptions addAllowedRule(Firewall.Rule allowedRule) { + this.allowed.add(allowedRule); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getAllowed() + */ + public FirewallOptions allowedRules(Set allowedRules) { + this.allowed = ImmutableSet.builder(); + this.allowed.addAll(allowedRules); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getName() + */ + public FirewallOptions name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getName() + */ + public String getName() { + return name; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getNetwork() + */ + public FirewallOptions network(URI network) { + this.network = network; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getNetwork() + */ + public URI getNetwork() { + return network; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getSourceRanges() + */ + public Set getSourceRanges() { + return sourceRanges.build(); + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getSourceRanges() + */ + public FirewallOptions addSourceRange(String sourceRange) { + this.sourceRanges.add(sourceRange); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getSourceRanges() + */ + public FirewallOptions sourceRanges(Set sourceRanges) { + this.sourceRanges = ImmutableSet.builder(); + this.sourceRanges.addAll(sourceRanges); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getSourceTags() + */ + public Set getSourceTags() { + return sourceTags.build(); + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getSourceTags() + */ + public FirewallOptions addSourceTag(String sourceTag) { + this.sourceTags.add(sourceTag); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getSourceTags() + */ + public FirewallOptions sourceTags(Set sourceTags) { + this.sourceTags = ImmutableSet.builder(); + this.sourceTags.addAll(sourceTags); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getTargetTags() + */ + public Set getTargetTags() { + return targetTags.build(); + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getTargetTags() + */ + public FirewallOptions addTargetTag(String targetTag) { + this.targetTags.add(targetTag); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Firewall#getTargetTags() + */ + public FirewallOptions targetTags(Set targetTags) { + this.targetTags = ImmutableSet.builder(); + this.targetTags.addAll(targetTags); + return this; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/ListOptions.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/ListOptions.java new file mode 100644 index 0000000000..9a3e88ebe7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/ListOptions.java @@ -0,0 +1,91 @@ +/* + * 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.googlecomputeengine.options; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * Allows to optionally specify a filter, max results and a page token for listFirstPage() REST methods. + * + * @see + */ +public class ListOptions extends BaseHttpRequestOptions { + + /** + * Optional. Filter expression for filtering listed resources, in the form filter={expression}. Your {expression} + * must contain the following: + *

+ * {@code } + *

    + *
  • {@code }: The name of the field you want to compare. The field name must be valid for the + * type of resource being filtered. Only atomic field types are supported (string, number, + * boolean). Array and object fields are not currently supported.
  • + *
  • {@code }: The comparison string, either eq (equals) or ne (not equals).
  • + *
  • {@code }: The literal string value to filter to. The literal value must be valid + * for the type of field (string, number, boolean). For string fields, the literal value is interpreted as a + * regular expression using RE2 syntax. The literal value must match the entire field. For example, + * when filtering instances, name eq my_instance won't work, but name eq .*my_instance will work.
  • + *
+ *

+ * For example: + *

+ * {@code filter=status ne RUNNING} + *

+ * The above filter returns only results whose status field does not equal RUNNING. You can also enclose your + * literal string in single, double, or no quotes. For example, all three of the following would be valid + * expressions: + *

+ * {@code filter=status ne "RUNNING"}
+ * {@code filter=status ne 'RUNNING'}
+ * {@code filter=status ne RUNNING}
+ *

+ * Complex regular expressions can also be used, like the following: + * {@code name eq '."my_instance_[0-9]+'} + */ + public ListOptions filter(String filter) { + this.queryParameters.put("filter", checkNotNull(filter, "filter")); + return this; + } + + /** + * Sets Maximum count of results to be returned. Maximum and default value is 100. Acceptable items are 0 to + * 100, inclusive. (Default: 100) + */ + public ListOptions maxResults(Integer maxResults) { + this.queryParameters.put("maxResults", checkNotNull(maxResults, "maxResults") + ""); + return this; + } + + public static class Builder { + + /** + * @see ListOptions#filter(String) + */ + public ListOptions filter(String filter) { + return new ListOptions().filter(filter); + } + + /** + * @see ListOptions#maxResults(Integer) + */ + public ListOptions maxResults(Integer maxResults) { + return new ListOptions().maxResults(maxResults); + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/RouteOptions.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/RouteOptions.java new file mode 100644 index 0000000000..ec891ceb7c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/options/RouteOptions.java @@ -0,0 +1,202 @@ +/* + * 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.googlecomputeengine.options; + +import java.net.URI; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; + +/** + * Options to create a route. + * + * @see org.jclouds.googlecomputeengine.domain.Route + */ +public class RouteOptions { + + private String name; + private URI network; + private String destRange; + private URI nextHopInstance; + private String nextHopIp; + private URI nextHopNetwork; + private URI nextHopGateway; + private String description; + private Integer priority; + + private ImmutableSet.Builder tags = ImmutableSet.builder(); + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getName() + */ + public String getName() { + return name; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getName() + */ + public RouteOptions name(String name) { + this.name = name; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getDescription() + */ + public String getDescription() { + return description; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getDescription() + */ + public RouteOptions description(String description) { + this.description = description; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getDestRange() + */ + public String getDestRange() { + return destRange; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getDestRange() + */ + public RouteOptions destRange(String destRange) { + this.destRange = destRange; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNextHopIp() + */ + public String getNextHopIp() { + return nextHopIp; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNextHopIp() + */ + public RouteOptions nextHopIp(String nextHopIp) { + this.nextHopIp = nextHopIp; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getPriority() + */ + public Integer getPriority() { + return priority; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getPriority() + */ + public RouteOptions priority(Integer priority) { + this.priority = priority; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNetwork() + */ + public RouteOptions network(URI network) { + this.network = network; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNetwork() + */ + public URI getNetwork() { + return network; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNextHopInstance() + */ + public RouteOptions nextHopInstance(URI nextHopInstance) { + this.nextHopInstance = nextHopInstance; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNextHopInstance() + */ + public URI getNextHopInstance() { + return nextHopInstance; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNextHopNetwork() + */ + public RouteOptions nextHopNetwork(URI nextHopNetwork) { + this.nextHopNetwork = nextHopNetwork; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNextHopNetwork() + */ + public URI getNextHopNetwork() { + return nextHopNetwork; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNextHopGateway() + */ + public RouteOptions nextHopGateway(URI nextHopGateway) { + this.nextHopGateway = nextHopGateway; + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getNextHopGateway() + */ + public URI getNextHopGateway() { + return nextHopGateway; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getTags() + */ + public Set getTags() { + return tags.build(); + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getTags() + */ + public RouteOptions addTag(String tag) { + this.tags.add(tag); + return this; + } + + /** + * @see org.jclouds.googlecomputeengine.domain.Route#getTags() + */ + public RouteOptions tags(Set tags) { + this.tags = ImmutableSet.builder(); + this.tags.addAll(tags); + return this; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java new file mode 100644 index 0000000000..ac34bcc588 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java @@ -0,0 +1,59 @@ +/* + * 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.googlecomputeengine.predicates; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.concurrent.atomic.AtomicReference; + +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Operation; + +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.inject.Inject; + +/** + * Tests that a Global Operation is done, returning the completed Operation when it is. + */ +public class GlobalOperationDonePredicate implements Predicate> { + + private final GoogleComputeEngineApi api; + private final Supplier project; + + @Inject + public GlobalOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier project) { + this.api = api; + this.project = project; + } + + @Override + public boolean apply(AtomicReference input) { + checkNotNull(input, "input"); + Operation current = api.getGlobalOperationApiForProject(project.get()).get(input.get().getName()); + switch (current.getStatus()) { + case DONE: + input.set(current); + return true; + case PENDING: + case RUNNING: + default: + return false; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/InstancePredicates.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/InstancePredicates.java new file mode 100644 index 0000000000..8cde680f51 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/InstancePredicates.java @@ -0,0 +1,33 @@ +/* + * 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.googlecomputeengine.predicates; + +import org.jclouds.googlecomputeengine.domain.InstanceTemplate.PersistentDisk; + +import com.google.common.base.Predicate; + +public class InstancePredicates { + + public static Predicate isBootDisk() { + return new Predicate() { + @Override + public boolean apply(PersistentDisk input) { + return input.isBoot(); + } + }; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java new file mode 100644 index 0000000000..63d2767bec --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java @@ -0,0 +1,121 @@ +/* + * 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.googlecomputeengine.predicates; + +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Firewall.Rule; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Range; +import com.google.common.collect.Sets; + +public class NetworkFirewallPredicates { + + public static Predicate hasProtocol(final IpProtocol protocol) { + return new Predicate() { + + @Override + public boolean apply(Firewall fw) { + for (Rule rule : fw.getAllowed()) { + if (rule.getIpProtocol().equals(protocol)) { + return true; + } + } + + return false; + } + }; + } + + public static Predicate hasPortRange(final Range portRange) { + return new Predicate() { + + @Override + public boolean apply(Firewall fw) { + return Iterables.any(fw.getAllowed(), new Predicate() { + @Override + public boolean apply(Rule input) { + return input.getPorts().encloses(portRange); + } + }); + } + }; + } + + public static Predicate hasSourceTag(final String sourceTag) { + return new Predicate() { + @Override + public boolean apply(Firewall input) { + return input.getSourceTags() != null && input.getSourceTags().contains(sourceTag); + } + }; + } + + public static Predicate hasSourceRange(final String sourceRange) { + return new Predicate() { + @Override + public boolean apply(Firewall input) { + return input.getSourceRanges() != null && input.getSourceRanges().contains(sourceRange); + } + }; + } + + public static Predicate equalsIpPermission(final IpPermission permission) { + return new Predicate() { + @Override + public boolean apply(Firewall input) { + return Iterables.elementsEqual(permission.getGroupIds(), input.getSourceTags()) + && Iterables.elementsEqual(permission.getCidrBlocks(), input.getSourceRanges()) + && (input.getAllowed().size() == 1 + && ruleEqualsIpPermission(permission).apply(Iterables.getOnlyElement(input.getAllowed()))); + } + }; + } + + public static Predicate providesIpPermission(final IpPermission permission) { + return new Predicate() { + @Override + public boolean apply(Firewall input) { + boolean groupsMatchTags = (permission.getGroupIds().isEmpty() && input.getSourceTags().isEmpty()) + || !Sets.intersection(permission.getGroupIds(), input.getSourceTags()).isEmpty(); + boolean cidrsMatchRanges = (permission.getCidrBlocks().isEmpty() && input.getSourceRanges().isEmpty()) + || !Sets.intersection(permission.getCidrBlocks(), input.getSourceRanges()).isEmpty(); + boolean firewallHasPorts = hasProtocol(permission.getIpProtocol()).apply(input) + && ((permission.getFromPort() == 0 && permission.getToPort() == 0) + || hasPortRange(Range.closed(permission.getFromPort(), permission.getToPort())).apply(input)); + + return groupsMatchTags && cidrsMatchRanges && firewallHasPorts; + } + }; + } + + private static Predicate ruleEqualsIpPermission(final IpPermission permission) { + return new Predicate() { + @Override + public boolean apply(Firewall.Rule input) { + return permission.getIpProtocol().equals(input.getIpProtocol()) + && ((input.getPorts().isEmpty() && permission.getFromPort() == 0 && permission.getToPort() == 0) + || (input.getPorts().asRanges().size() == 1 + && permission.getFromPort() == Iterables.getOnlyElement(input.getPorts().asRanges()).lowerEndpoint() + && permission.getToPort() == Iterables.getOnlyElement(input.getPorts().asRanges()).upperEndpoint())); + } + }; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java new file mode 100644 index 0000000000..1f3dee6340 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java @@ -0,0 +1,69 @@ +/* + * 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.googlecomputeengine.predicates; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import org.jclouds.collect.Memoized; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Region; + +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.inject.Inject; + +/** + * Tests that a Global Operation is done, returning the completed Operation when it is. + */ +public class RegionOperationDonePredicate implements Predicate> { + + private final GoogleComputeEngineApi api; + private final Supplier project; + private final Supplier> regions; + + @Inject + RegionOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier project, + @Memoized Supplier> regions) { + this.api = api; + this.project = project; + this.regions = regions; + } + + @Override + public boolean apply(AtomicReference input) { + checkNotNull(input, "input"); + + Operation current = api.getRegionOperationApiForProject(project.get()) + .getInRegion(regions.get().get(input.get().getRegion().get()).getName(), + input.get().getName()); + switch (current.getStatus()) { + case DONE: + input.set(current); + return true; + case PENDING: + case RUNNING: + default: + return false; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java new file mode 100644 index 0000000000..c63c6f39e1 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.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.googlecomputeengine.predicates; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import org.jclouds.collect.Memoized; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Operation; + +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.inject.Inject; + +/** + * Tests that a Zone Operation is done, returning the completed Operation when it is. + */ +public class ZoneOperationDonePredicate implements Predicate> { + + private final GoogleComputeEngineApi api; + private final Supplier project; + private final Supplier> zones; + + @Inject + ZoneOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier project, + @Memoized Supplier> zones) { + this.api = api; + this.project = project; + this.zones = zones; + } + + @Override + public boolean apply(AtomicReference input) { + checkNotNull(input, "input"); + Operation current = api.getZoneOperationApiForProject(project.get()) + .getInZone(zones.get().get(input.get().getZone().get()).getId(), + input.get().getName()); + switch (current.getStatus()) { + case DONE: + input.set(current); + return true; + case PENDING: + case RUNNING: + default: + return false; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthApi.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthApi.java new file mode 100644 index 0000000000..12e8fcbb92 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthApi.java @@ -0,0 +1,63 @@ +/* + * 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.oauth.v2; + +import java.io.Closeable; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.core.MediaType; + +import org.jclouds.oauth.v2.config.Authentication; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.handlers.OAuthTokenBinder; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.Endpoint; + +/** + * Provides access to OAuth via REST api. + *

+ * Usually this is not directly used by a client, which instead specifies + * OAuthAuthenticator as a request filter, which in turn uses this class to + * perform token requests. + * + * @see OAuthAsyncApi + */ +@Endpoint(Authentication.class) +public interface OAuthApi extends Closeable { + + /** + * Authenticates/Authorizes access to a resource defined in TokenRequest + * against an OAuth v2 authentication/authorization server. + * + * @param tokenRequest + * specified the principal and the required permissions + * @return a Token object with the token required to access the resource + * along with its expiration time + * @throws AuthorizationException + * if the principal cannot be authenticated or has no permissions + * for the specifed resources. + */ + @Named("authenticate") + @POST + @Consumes(MediaType.APPLICATION_JSON) + Token authenticate(@BinderParam(OAuthTokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException; + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java new file mode 100644 index 0000000000..3ef26e69c7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -0,0 +1,80 @@ +/* + * 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.oauth.v2; + +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.oauth.v2.config.OAuthHttpApiModule; +import org.jclouds.oauth.v2.config.OAuthModule; +import org.jclouds.rest.internal.BaseHttpApiMetadata; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; + +/** + * Implementation of {@link ApiMetadata} for OAuth 2 API + */ +public class OAuthApiMetadata extends BaseHttpApiMetadata { + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public OAuthApiMetadata() { + this(new Builder()); + } + + protected OAuthApiMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + Properties properties = BaseHttpApiMetadata.defaultProperties(); + properties.put(SIGNATURE_OR_MAC_ALGORITHM, "RS256"); + properties.put(PROPERTY_SESSION_INTERVAL, 3600); + return properties; + } + + public static class Builder extends BaseHttpApiMetadata.Builder { + + protected Builder() { + id("oauth") + .name("OAuth API") + .identityName("service_account") + .credentialName("service_key") + .documentation(URI.create("TODO")) + .version("2") + .defaultProperties(OAuthApiMetadata.defaultProperties()) + .defaultModules(ImmutableSet.>of(OAuthModule.class, OAuthHttpApiModule.class)); + } + + @Override + public OAuthApiMetadata build() { + return new OAuthApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java new file mode 100644 index 0000000000..9b140d46d9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java @@ -0,0 +1,78 @@ +/* + * 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.oauth.v2; + +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +/** + * The constants for OAuth \ + */ +public final class OAuthConstants { + + /** + * Selected algorithm when a signature or mac isn't required. + */ + public static final String NO_ALGORITHM = "none"; + + /** + * Static mapping between the oauth algorithm name and the Crypto provider signature algorithm name. + * + * @see doc + * @see org.jclouds.oauth.v2.json.JWTTokenRequestFormat + */ + public static final Map OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES = ImmutableMap + .builder() + .put("RS256", "SHA256withRSA") + .put("RS384", "SHA384withRSA") + .put("RS512", "SHA512withRSA") + .put("HS256", "HmacSHA256") + .put("HS384", "HmacSHA384") + .put("HS512", "HmacSHA512") + .put("ES256", "SHA256withECDSA") + .put("ES384", "SHA384withECDSA") + .put("ES512", "SHA512withECDSA") + .put(NO_ALGORITHM, NO_ALGORITHM).build(); + + /** + * Static mapping between the oauth algorithm name and the Crypto provider KeyFactory algorithm name. + * + * @see doc + */ + public static final Map OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES = ImmutableMap + .builder() + .put("RS256", "RSA") + .put("RS384", "RSA") + .put("RS512", "RSA") + .put("HS256", "DiffieHellman") + .put("HS384", "DiffieHellman") + .put("HS512", "DiffieHellman") + .put("ES256", "EC") + .put("ES384", "EC") + .put("ES512", "EC") + .put(NO_ALGORITHM, NO_ALGORITHM).build(); + + /** + * The (optional) set of additional claims to use, provided in Map form + */ + public static final String ADDITIONAL_CLAIMS = "jclouds.oauth.additional-claims"; + + private OAuthConstants() { + throw new AssertionError("intentionally unimplemented"); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/Authentication.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/Authentication.java new file mode 100644 index 0000000000..4f1107a0b7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/Authentication.java @@ -0,0 +1,35 @@ +/* + * 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.oauth.v2.config; + + +import javax.inject.Qualifier; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Qualifies OAuth related resources, such as Endpoint. + * + * @see org.jclouds.oauth.v2.OAuthAsyncApi + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) +@Qualifier +public @interface Authentication { +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java new file mode 100644 index 0000000000..fb2d4137cc --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java @@ -0,0 +1,52 @@ +/* + * 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.oauth.v2.config; + +import static org.jclouds.rest.config.BinderUtils.bindHttpApi; + +import java.net.URI; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.oauth.v2.OAuthApi; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; + +/** + * An OAuth module to be used form other providers. + */ +public class OAuthAuthenticationModule extends AbstractModule { + + @Override + protected void configure() { + bindHttpApi(binder(), OAuthApi.class); + } + + /** + * When oauth is used as a module the oauth endpoint is a normal property + */ + @Provides + @Singleton + @Authentication + protected Supplier provideAuthenticationEndpoint(@Named("oauth.endpoint") String endpoint) { + return Suppliers.ofInstance(URI.create(endpoint)); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java new file mode 100644 index 0000000000..6b4fdf959e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java @@ -0,0 +1,45 @@ +/* + * 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.oauth.v2.config; + +import java.net.URI; + +import javax.inject.Singleton; + +import org.jclouds.oauth.v2.OAuthApi; +import org.jclouds.providers.ProviderMetadata; +import org.jclouds.rest.ConfiguresHttpApi; +import org.jclouds.rest.config.HttpApiModule; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.inject.Provides; + +/** + * OAuth module to when accessing OAuth stand-alone. + */ +@ConfiguresHttpApi +public class OAuthHttpApiModule extends HttpApiModule { + + @Provides + @Singleton + @Authentication + protected Supplier provideAuthenticationEndpoint(ProviderMetadata providerMetadata) { + return Suppliers.ofInstance(URI.create(providerMetadata.getEndpoint())); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java new file mode 100644 index 0000000000..11fca2f982 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java @@ -0,0 +1,86 @@ +/* + * 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.oauth.v2.config; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.OAuthCredentials; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.functions.BuildTokenRequest; +import org.jclouds.oauth.v2.functions.FetchToken; +import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier; +import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken; +import org.jclouds.oauth.v2.json.ClaimSetTypeAdapter; +import org.jclouds.oauth.v2.json.HeaderTypeAdapter; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import javax.inject.Named; +import javax.inject.Singleton; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; + +/** + * Base OAuth module + */ +public class OAuthModule extends AbstractModule { + + + @Override + protected void configure() { + bind(new TypeLiteral>() {}).to(SignOrProduceMacForToken.class); + bind(new TypeLiteral>() {}).toInstance(ImmutableMap.of( + Header.class, new HeaderTypeAdapter(), + ClaimSet.class, new ClaimSetTypeAdapter())); + bind(new TypeLiteral>() {}).to(OAuthCredentialsSupplier.class); + bind(new TypeLiteral>() {}).to(BuildTokenRequest.class); + bind(new TypeLiteral>() {}).to(FetchToken.class); + } + + /** + * Provides a cache for tokens. Cache is time based and by default expires after 59 minutes + * (the maximum time a token is valid is 60 minutes). + * This cache and expiry period is system-wide and does not attend to per-instance expiry time + * (e.g. "expires_in" from Google Compute -- which is set to the standard 3600 seconds). + */ + // NB: If per-instance expiry time is required, significant refactoring will be needed. + @Provides + @Singleton + public LoadingCache provideAccessCache(Function getAccess, + @Named(PROPERTY_SESSION_INTERVAL) long + sessionIntervalInSeconds) { + // since the session interval is also the token expiration time requested to the server make the token expire a + // bit before the deadline to make sure there aren't session expiration exceptions + sessionIntervalInSeconds = sessionIntervalInSeconds > 30 ? sessionIntervalInSeconds - 30 : + sessionIntervalInSeconds; + return CacheBuilder.newBuilder().expireAfterWrite(sessionIntervalInSeconds, TimeUnit.SECONDS).build(CacheLoader + .from(getAccess)); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java new file mode 100644 index 0000000000..7b1bf17fce --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java @@ -0,0 +1,43 @@ +/* + * 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.oauth.v2.config; + +/** + * Configurable properties for jclouds OAuth + */ +public class OAuthProperties { + + /** + * The selected signature algorithm to use to sign the requests. + *

+ * This refers to the name the oauth provider expects, i.e., "RSA + */ + public static final String SIGNATURE_OR_MAC_ALGORITHM = "jclouds.oauth.signature-or-mac-algorithm"; + + /** + * The oauth audience, who this token is intended for. For instance in JWT and for + * google API's this property maps to: {"aud","https://accounts.google.com/o/oauth2/token"} + * + * @see doc + */ + public static final String AUDIENCE = "jclouds.oauth.audience"; + + /** + * Optional list of comma-separated scopes to use when no OAuthScopes annotation is present. + */ + public static final String SCOPES = "jclouds.oauth.scopes"; +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java new file mode 100644 index 0000000000..57ffd29b4a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java @@ -0,0 +1,40 @@ +/* + * 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.oauth.v2.config; + +import javax.inject.Qualifier; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to annotate REST methods/ifaces that use OAuthAuthentication. + *

+ * Sets the scopes for the token request for that particular method. + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = {ElementType.TYPE, ElementType.METHOD}) +@Qualifier +public @interface OAuthScopes { + + /** + * @return the OAuth scopes required to access the resource. + */ + String[] value(); + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java new file mode 100644 index 0000000000..5c0b348d0f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java @@ -0,0 +1,191 @@ +/* + * 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.oauth.v2.domain; + +import com.google.common.base.Objects; +import com.google.common.base.Splitter; +import com.google.common.collect.ForwardingMap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Objects.ToStringHelper; +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +/** + * The claimset for the token. + * + * @see doc + */ +public class ClaimSet extends ForwardingMap { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromClaimSet(this); + } + + public static class Builder { + + private Set requiredClaims; + private ImmutableMap.Builder claims = new ImmutableMap.Builder(); + private long emissionTime; + private long expirationTime; + + public Builder() { + this(ImmutableSet.of()); + } + + /** + * Constructor that allows to predefine a mandatory set of claims as a comma-separated string, e.g, "iss,iat". + */ + public Builder(String commaSeparatedRequiredClaims) { + this(ImmutableSet.copyOf(Splitter.on(",").split(checkNotNull(commaSeparatedRequiredClaims)))); + } + + /** + * Constructor that allows to predefine a mandatory set of claims as a set of strings. + */ + public Builder(Set requiredClaims) { + this.requiredClaims = ImmutableSet.copyOf(checkNotNull(requiredClaims)); + } + + /** + * Adds a Claim, i.e. key/value pair, e.g., "scope":"all_permissions". + */ + public Builder addClaim(String name, String value) { + claims.put(checkNotNull(name), checkNotNull(value, "value of %s", name)); + return this; + } + + /** + * @see ClaimSet#getEmissionTime() + */ + public Builder emissionTime(long emmissionTime) { + this.emissionTime = emmissionTime; + return this; + } + + /** + * @see ClaimSet#getExpirationTime() + */ + public Builder expirationTime(long expirationTime) { + this.expirationTime = expirationTime; + return this; + } + + /** + * Adds a map containing multiple claims + */ + public Builder addAllClaims(Map claims) { + this.claims.putAll(checkNotNull(claims)); + return this; + } + + public ClaimSet build() { + Map claimsMap = claims.build(); + checkState(Sets.intersection(claimsMap.keySet(), requiredClaims).size() == requiredClaims.size(), + "not all required claims were present"); + if (expirationTime == 0) { + expirationTime = emissionTime + 3600; + } + return new ClaimSet(claimsMap, emissionTime, expirationTime); + } + + public Builder fromClaimSet(ClaimSet claimSet) { + return new Builder().addAllClaims(claimSet.claims).expirationTime(expirationTime).emissionTime(emissionTime); + } + } + + private final Map claims; + private final long emissionTime; + private final long expirationTime; + + private ClaimSet(Map claims, long emissionTime, long expirationTime) { + this.claims = claims; + this.emissionTime = emissionTime; + this.expirationTime = expirationTime; + } + + /** + * The emission time, in seconds since the epoch. + */ + public long getEmissionTime() { + return emissionTime; + } + + /** + * The expiration time, in seconds since the emission time. + */ + public long getExpirationTime() { + return expirationTime; + } + + /** + * @returns the claims. + */ + @Override + protected Map delegate() { + return claims; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(claims); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ClaimSet other = (ClaimSet) obj; + return equal(claims, other.claims); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("claims", claims) + .add("emissionTime", emissionTime).add("expirationTIme", expirationTime); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/Header.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/Header.java new file mode 100644 index 0000000000..c230e1da4c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/Header.java @@ -0,0 +1,128 @@ +/* + * 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.oauth.v2.domain; + +import com.google.common.base.Objects; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The header for the OAuth token, contains the signer algorithm's name and the type of the token + * + * @see doc + */ +public class Header { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromHeader(this); + } + + public static class Builder { + + private String signerAlgorithm; + private String type; + + /** + * @see Header#getSignerAlgorithm() + */ + public Builder signerAlgorithm(String signerAlgorithm) { + this.signerAlgorithm = checkNotNull(signerAlgorithm); + return this; + } + + /** + * @see Header#getType() + */ + public Builder type(String type) { + this.type = checkNotNull(type); + return this; + } + + public Header build() { + return new Header(signerAlgorithm, type); + } + + public Builder fromHeader(Header header) { + return new Builder().signerAlgorithm(header.signerAlgorithm).type(header.type); + } + } + + private final String signerAlgorithm; + private final String type; + + protected Header(String signerAlgorithm, String type) { + this.signerAlgorithm = checkNotNull(signerAlgorithm); + this.type = checkNotNull(type); + } + + /** + * The name of the algorithm used to compute the signature, e.g., "RS256" + */ + public String getSignerAlgorithm() { + return signerAlgorithm; + } + + /** + * The type of the token, e.g., "JWT" + */ + public String getType() { + return type; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Header other = (Header) obj; + return equal(this.signerAlgorithm, other.signerAlgorithm) && equal(this.type, + other.type); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(signerAlgorithm, type); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected Objects.ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("signerAlgorithm", signerAlgorithm) + .add("type", type); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java new file mode 100644 index 0000000000..78cb402d08 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java @@ -0,0 +1,129 @@ +/* + * 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.oauth.v2.domain; + +import com.google.common.base.Objects; +import org.jclouds.domain.Credentials; + +import java.security.PrivateKey; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Special kind credentials for oauth authentication that includes {@link java.security.PrivateKey} to sign + * requests. + */ +public class OAuthCredentials extends Credentials { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromOauthCredentials(this); + } + + public static class Builder extends Credentials.Builder { + + protected PrivateKey privateKey; + + /** + * @see OAuthCredentials#privateKey + */ + public Builder privateKey(PrivateKey privateKey) { + this.privateKey = checkNotNull(privateKey); + return this; + } + + /** + * @see Credentials#identity + */ + public Builder identity(String identity) { + this.identity = checkNotNull(identity); + return this; + } + + /** + * @see Credentials#credential + */ + public Builder credential(String credential) { + this.credential = credential; + return this; + } + + public OAuthCredentials build() { + return new OAuthCredentials(checkNotNull(identity), credential, privateKey); + } + + public Builder fromOauthCredentials(OAuthCredentials credentials) { + return new Builder().privateKey(credentials.privateKey).identity(credentials.identity) + .credential(credentials.credential); + } + } + + /** + * The private key associated with Credentials#identity. + * Used to sign token requests. + */ + public final PrivateKey privateKey; + + public OAuthCredentials(String identity, String credential, PrivateKey privateKey) { + super(identity, credential); + this.privateKey = privateKey; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + OAuthCredentials other = (OAuthCredentials) obj; + return equal(this.identity, other.identity) && equal(this.credential, + other.credential) && equal(this.privateKey, + other.privateKey); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(identity, credential, privateKey); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected Objects.ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("identity", identity) + .add("credential", credential != null ? credential.hashCode() : null).add("privateKey", + privateKey.hashCode()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/Token.java new file mode 100644 index 0000000000..a18a7eb6e3 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -0,0 +1,149 @@ +/* + * 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.oauth.v2.domain; + +import com.google.common.base.Objects; + +import java.beans.ConstructorProperties; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The oauth token, obtained upon a successful token request and ready to embed in requests. + */ +public class Token { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromToken(this); + } + + public static class Builder { + + private String accessToken; + private String tokenType; + private long expiresIn; + + /** + * @see Token#getAccessToken() + */ + public Builder accessToken(String accessToken) { + this.accessToken = checkNotNull(accessToken); + return this; + } + + /** + * @see Token#getTokenType() + */ + public Builder tokenType(String tokenType) { + this.tokenType = checkNotNull(tokenType); + return this; + } + + /** + * @see Token#getExpiresIn() + */ + public Builder expiresIn(long expiresIn) { + this.expiresIn = expiresIn; + return this; + } + + public Token build() { + return new Token(accessToken, tokenType, expiresIn); + } + + public Builder fromToken(Token token) { + return new Builder().accessToken(token.accessToken).tokenType(token.tokenType).expiresIn(token.expiresIn); + } + } + + private final String accessToken; + private final String tokenType; + private final long expiresIn; + + @ConstructorProperties({"access_token", "token_type", "expires_in"}) + protected Token(String accessToken, String tokenType, long expiresIn) { + this.accessToken = accessToken; + this.tokenType = tokenType; + this.expiresIn = expiresIn; + } + + /** + * The access token obtained from the OAuth server. + */ + public String getAccessToken() { + return accessToken; + } + + /** + * The type of the token, e.g., "Bearer" + */ + public String getTokenType() { + return tokenType; + } + + /** + * In how many seconds this token expires. + */ + public long getExpiresIn() { + return expiresIn; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Token other = (Token) obj; + return equal(this.accessToken, other.accessToken) && equal(this.tokenType, + other.tokenType) && equal(this.expiresIn, + other.expiresIn); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(accessToken, tokenType, expiresIn); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected Objects.ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("accessToken", accessToken) + .add("tokenType", tokenType).add("expiresIn", expiresIn); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java new file mode 100644 index 0000000000..7d1a6a4438 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java @@ -0,0 +1,131 @@ +/* + * 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.oauth.v2.domain; + +import com.google.common.base.Objects; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A complete token request. + */ +public class TokenRequest { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromTokenRequest(this); + } + + public static class Builder { + private Header header; + private ClaimSet claimSet; + + /** + * @see TokenRequest#getClaimSet() + */ + public Builder header(Header header) { + this.header = header; + return this; + } + + /** + * @see TokenRequest#getHeader() + */ + public Builder claimSet(ClaimSet claimSet) { + this.claimSet = claimSet; + return this; + } + + public TokenRequest build() { + return new TokenRequest(header, claimSet); + } + + public Builder fromTokenRequest(TokenRequest tokeRequest) { + return new Builder().header(tokeRequest.header).claimSet(tokeRequest.claimSet); + } + } + + private final Header header; + private final ClaimSet claimSet; + + public TokenRequest(Header header, ClaimSet claimSet) { + this.header = checkNotNull(header); + this.claimSet = checkNotNull(claimSet); + } + + /** + * The header of this token request. + * + * @see Header + */ + public Header getHeader() { + return header; + } + + /** + * The claim set of this token request. + * + * @see ClaimSet + */ + public ClaimSet getClaimSet() { + return claimSet; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TokenRequest other = (TokenRequest) obj; + return equal(this.header, other.header) && equal(this.claimSet, + other.claimSet); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(header, claimSet); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected Objects.ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("header", header) + .add("claimSet", claimSet); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java new file mode 100644 index 0000000000..f4b80c177f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java @@ -0,0 +1,45 @@ +/* + * 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.oauth.v2.domain; + +import com.google.inject.ImplementedBy; +import org.jclouds.http.HttpRequest; +import org.jclouds.oauth.v2.json.JWTTokenRequestFormat; + +import java.util.Set; + +/** + * Transforms a TokenRequest into a specific format (e.g. JWT token) + */ +@ImplementedBy(JWTTokenRequestFormat.class) +public interface TokenRequestFormat { + + /** + * Transforms the provided HttpRequest into a particular token request with a specific format. + */ + R formatRequest(R httpRequest, TokenRequest tokenRequest); + + /** + * The name of the type of the token request, e.g., "JWT" + */ + String getTypeName(); + + /** + * The claims that must be present in the token request for it to be valid. + */ + Set requiredClaims(); +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java new file mode 100644 index 0000000000..e25bc201e1 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java @@ -0,0 +1,63 @@ +/* + * 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.oauth.v2.filters; + +import com.google.common.base.Function; +import com.google.common.cache.LoadingCache; +import org.jclouds.http.HttpException; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpRequestFilter; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import static com.google.common.base.Preconditions.checkState; + +/** + * To be used by client applications to embed an OAuth authentication in their REST requests. + *

+ * TODO when we're able to use the OAuthAuthentication an this should be used automatically + */ +@Singleton +public class OAuthAuthenticator implements HttpRequestFilter { + + private Function tokenRequestBuilder; + private Function tokenFetcher; + + @Inject + OAuthAuthenticator(Function tokenRequestBuilder, LoadingCache tokenFetcher) { + this.tokenRequestBuilder = tokenRequestBuilder; + this.tokenFetcher = tokenFetcher; + } + + @Override + public HttpRequest filter(HttpRequest request) throws HttpException { + checkState(request instanceof GeneratedHttpRequest, "request must be an instance of GeneratedHttpRequest"); + GeneratedHttpRequest generatedHttpRequest = GeneratedHttpRequest.class.cast(request); + TokenRequest tokenRequest = tokenRequestBuilder.apply(generatedHttpRequest); + Token token = tokenFetcher.apply(tokenRequest); + return request.toBuilder().addHeader("Authorization", String.format("%s %s", + token.getTokenType(), token.getAccessToken())).build(); + + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java new file mode 100644 index 0000000000..7b869dcfc0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java @@ -0,0 +1,135 @@ +/* + * 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.oauth.v2.functions; + +import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.oauth.v2.OAuthConstants.ADDITIONAL_CLAIMS; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; + +import java.util.Map; + +import javax.inject.Singleton; + +import org.jclouds.Constants; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.OAuthCredentials; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.domain.TokenRequestFormat; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.Invokable; +import com.google.inject.Inject; +import com.google.inject.name.Named; + +/** + * The default authenticator. + *

+ * Builds the default token request with the following claims: iss,scope,aud,iat,exp. + *

+ * TODO scopes etc should come from the REST method and not from a global property + */ +@Singleton +public class BuildTokenRequest implements Function { + + private final String assertionTargetDescription; + private final String signatureAlgorithm; + private final TokenRequestFormat tokenRequestFormat; + private final Supplier credentialsSupplier; + private final long tokenDuration; + + @Inject(optional = true) + @Named(ADDITIONAL_CLAIMS) + protected Map additionalClaims = ImmutableMap.of(); + + @Inject(optional = true) + @Named(SCOPES) + protected String globalScopes = null; + + // injectable so expect tests can override with a predictable value + @Inject(optional = true) + protected Supplier timeSourceMillisSinceEpoch = new Supplier() { + @Override + public Long get() { + return System.currentTimeMillis(); + } + }; + + @Inject + public BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, + @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureAlgorithm, + TokenRequestFormat tokenRequestFormat, Supplier credentialsSupplier, + @Named(Constants.PROPERTY_SESSION_INTERVAL) long tokenDuration) { + this.assertionTargetDescription = assertionTargetDescription; + this.signatureAlgorithm = signatureAlgorithm; + this.tokenRequestFormat = tokenRequestFormat; + this.credentialsSupplier = credentialsSupplier; + this.tokenDuration = tokenDuration; + } + + @Override + public TokenRequest apply(GeneratedHttpRequest request) { + long now = timeSourceMillisSinceEpoch.get() / 1000; + + // fetch the token + Header header = new Header.Builder() + .signerAlgorithm(signatureAlgorithm) + .type(tokenRequestFormat.getTypeName()) + .build(); + + ClaimSet claimSet = new ClaimSet.Builder(this.tokenRequestFormat.requiredClaims()) + .addClaim("iss", credentialsSupplier.get().identity) + .addClaim("scope", getOAuthScopes(request)) + .addClaim("aud", assertionTargetDescription) + .emissionTime(now) + .expirationTime(now + tokenDuration) + .addAllClaims(additionalClaims) + .build(); + + return new TokenRequest.Builder() + .header(header) + .claimSet(claimSet) + .build(); + } + + protected String getOAuthScopes(GeneratedHttpRequest request) { + Invokable invokable = request.getInvocation().getInvokable(); + + OAuthScopes classScopes = invokable.getOwnerType().getRawType().getAnnotation(OAuthScopes.class); + OAuthScopes methodScopes = invokable.getAnnotation(OAuthScopes.class); + + // if no annotations are present the rely on globally set scopes + if (classScopes == null && methodScopes == null) { + checkState(globalScopes != null, String.format("REST class or method should be annotated " + + "with OAuthScopes specifying required permissions. Alternatively a global property " + + "\"oauth.scopes\" may be set to define scopes globally. REST Class: %s, Method: %s", + invokable.getOwnerType(), + invokable.getName())); + return globalScopes; + } + + OAuthScopes scopes = methodScopes != null ? methodScopes : classScopes; + return Joiner.on(",").join(scopes.value()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java new file mode 100644 index 0000000000..593c8852ec --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java @@ -0,0 +1,41 @@ +/* + * 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.oauth.v2.functions; + +import com.google.common.base.Function; +import org.jclouds.oauth.v2.OAuthApi; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class FetchToken implements Function { + + private OAuthApi oAuthApi; + + @Inject + public FetchToken(OAuthApi oAuthApi) { + this.oAuthApi = oAuthApi; + } + + @Override + public Token apply(TokenRequest input) { + return this.oAuthApi.authenticate(input); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java new file mode 100644 index 0000000000..45620c0eb9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java @@ -0,0 +1,125 @@ +/* + * 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.oauth.v2.functions; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Charsets; +import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.io.ByteSource; +import com.google.common.util.concurrent.UncheckedExecutionException; +import org.jclouds.domain.Credentials; +import org.jclouds.location.Provider; +import org.jclouds.oauth.v2.domain.OAuthCredentials; +import org.jclouds.rest.AuthorizationException; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.PrivateKey; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Throwables.propagate; +import static java.lang.String.format; +import static org.jclouds.crypto.Pems.privateKeySpec; +import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; +import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.jclouds.util.Throwables2.getFirstThrowableOfType; + +/** + * Loads {@link OAuthCredentials} from a pem private key using the KeyFactory obtained from the JWT Algorithm + * Name<->KeyFactory name mapping in OAuthConstants. The pem pk algorithm must match the KeyFactory algorithm. + * + * @see org.jclouds.oauth.v2.OAuthConstants#OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES + */ +@Singleton +public class OAuthCredentialsSupplier implements Supplier { + + private final Supplier creds; + private final LoadingCache keyCache; + + @Inject + public OAuthCredentialsSupplier(@Provider Supplier creds, OAuthCredentialsForCredentials loader, + @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) { + this.creds = creds; + checkArgument(OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm), + format("No mapping for key factory for algorithm: %s", signatureOrMacAlgorithm)); + // throw out the private key related to old credentials + this.keyCache = CacheBuilder.newBuilder().maximumSize(2).build(checkNotNull(loader, "loader")); + } + + /** + * it is relatively expensive to extract a private key from a PEM. cache the relationship between current credentials + * so that the private key is only recalculated once. + */ + @VisibleForTesting + static class OAuthCredentialsForCredentials extends CacheLoader { + private final String keyFactoryAlgorithm; + + @Inject + public OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) { + this.keyFactoryAlgorithm = OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.get(checkNotNull( + signatureOrMacAlgorithm, "signatureOrMacAlgorithm")); + } + + @Override + public OAuthCredentials load(Credentials in) { + try { + String identity = in.identity; + String privateKeyInPemFormat = in.credential; + if (keyFactoryAlgorithm.equals(NO_ALGORITHM)) { + return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat).build(); + } + KeyFactory keyFactory = KeyFactory.getInstance(keyFactoryAlgorithm); + PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec(ByteSource.wrap( + privateKeyInPemFormat.getBytes(Charsets.UTF_8)))); + return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat) + .privateKey(privateKey).build(); + } catch (IOException e) { + throw propagate(e); + // catch security exceptions InvalidKeySpecException and NoSuchAlgorithmException as GSE + } catch (GeneralSecurityException e) { + throw new AuthorizationException("security exception loading credentials. " + e.getMessage(), e); + // catch IAE that is thrown when parsing the pk fails + } catch (IllegalArgumentException e) { + throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e); + } + } + } + + @Override + public OAuthCredentials get() { + try { + // loader always throws UncheckedExecutionException so no point in using get() + return keyCache.getUnchecked(checkNotNull(creds.get(), "credential supplier returned null")); + } catch (UncheckedExecutionException e) { + Throwable authorizationException = getFirstThrowableOfType(e, AuthorizationException.class); + if (authorizationException != null) { + throw (AuthorizationException) authorizationException; + } + throw propagate(e); + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java new file mode 100644 index 0000000000..471812a8b1 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java @@ -0,0 +1,119 @@ +/* + * 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.oauth.v2.functions; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.base.Throwables; +import org.jclouds.oauth.v2.domain.OAuthCredentials; + +import javax.annotation.PostConstruct; +import javax.crypto.Mac; +import javax.inject.Inject; +import javax.inject.Named; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.SignatureException; + +import static com.google.common.base.Preconditions.checkState; +import static java.lang.String.format; +import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; +import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; + +/** + * Function that signs/produces mac's for OAuth tokens, provided a {@link Signature} or a {@link Mac} algorithm and + * {@link PrivateKey} + */ +public class SignOrProduceMacForToken implements Function { + + private final Supplier credentials; + private final String signatureOrMacAlgorithm; + private Function signatureOrMacFunction; + + + @Inject + public SignOrProduceMacForToken(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm, + Supplier credentials) { + checkState(OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm), + format("the signature algorithm %s is not supported", signatureOrMacAlgorithm)); + this.signatureOrMacAlgorithm = OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.get(signatureOrMacAlgorithm); + this.credentials = credentials; + } + + @PostConstruct + public void loadSignatureOrMacOrNone() throws InvalidKeyException, NoSuchAlgorithmException { + if (signatureOrMacAlgorithm.equals(NO_ALGORITHM)) { + this.signatureOrMacFunction = new Function() { + @Override + public byte[] apply(byte[] input) { + return null; + } + }; + } else if (signatureOrMacAlgorithm.startsWith("SHA")) { + this.signatureOrMacFunction = new SignatureGenerator(signatureOrMacAlgorithm, credentials.get().privateKey); + } else { + this.signatureOrMacFunction = new MessageAuthenticationCodeGenerator(signatureOrMacAlgorithm, + credentials.get().privateKey); + } + } + + @Override + public byte[] apply(byte[] input) { + return signatureOrMacFunction.apply(input); + } + + private static class MessageAuthenticationCodeGenerator implements Function { + + private Mac mac; + + private MessageAuthenticationCodeGenerator(String macAlgorithm, PrivateKey privateKey) throws + NoSuchAlgorithmException, InvalidKeyException { + this.mac = Mac.getInstance(macAlgorithm); + this.mac.init(privateKey); + } + + @Override + public byte[] apply(byte[] input) { + this.mac.update(input); + return this.mac.doFinal(); + } + } + + private static class SignatureGenerator implements Function { + + private Signature signature; + + private SignatureGenerator(String signatureAlgorithm, PrivateKey privateKey) throws NoSuchAlgorithmException, + InvalidKeyException { + this.signature = Signature.getInstance(signatureAlgorithm); + this.signature.initSign(privateKey); + } + + @Override + public byte[] apply(byte[] input) { + try { + signature.update(input); + return signature.sign(); + } catch (SignatureException e) { + throw Throwables.propagate(e); + } + } + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java new file mode 100644 index 0000000000..78d78440f7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java @@ -0,0 +1,64 @@ +/* + * 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.oauth.v2.handlers; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ResourceNotFoundException; + +import javax.inject.Singleton; + +import static javax.ws.rs.core.Response.Status; +import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; + +/** + * This will parse and set an appropriate exception on the command object. + */ +@Singleton +public class OAuthErrorHandler implements HttpErrorHandler { + public void handleError(HttpCommand command, HttpResponse response) { + // it is important to always read fully and close streams + byte[] data = closeClientButKeepContentStream(response); + String message = data != null ? new String(data) : null; + + Exception exception = message != null ? new HttpResponseException(command, response, message) + : new HttpResponseException(command, response); + message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(), + response.getStatusLine()); + Status status = Status.fromStatusCode(response.getStatusCode()); + switch (status) { + case BAD_REQUEST: + break; + case UNAUTHORIZED: + case FORBIDDEN: + exception = new AuthorizationException(message, exception); + break; + case NOT_FOUND: + if (!command.getCurrentRequest().getMethod().equals("DELETE")) { + exception = new ResourceNotFoundException(message, exception); + } + break; + case CONFLICT: + exception = new IllegalStateException(message, exception); + break; + } + command.setException(exception); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java new file mode 100644 index 0000000000..1030804714 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java @@ -0,0 +1,45 @@ +/* + * 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.oauth.v2.handlers; + +import org.jclouds.http.HttpRequest; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.domain.TokenRequestFormat; +import org.jclouds.rest.Binder; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Generic implementation of a token binder. Uses a provided {@link TokenRequestFormat} to actually bind tokens to + * requests. + */ +@Singleton +public class OAuthTokenBinder implements Binder { + + private final TokenRequestFormat tokenRequestFormat; + + @Inject + OAuthTokenBinder(TokenRequestFormat tokenRequestFormat) { + this.tokenRequestFormat = tokenRequestFormat; + } + + @Override + public R bindToRequest(R request, Object input) { + return tokenRequestFormat.formatRequest(request, (TokenRequest) input); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java new file mode 100644 index 0000000000..62b3a26991 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java @@ -0,0 +1,59 @@ +/* + * 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.oauth.v2.json; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.jclouds.oauth.v2.domain.ClaimSet; + +import java.io.IOException; +import java.util.Map; + +/** + * JSON TypeAdapter for the ClaimSet type. Pull the claims maps to the root level and adds two properties for the + * expiration time and issuing time. + */ +public class ClaimSetTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, ClaimSet value) throws IOException { + out.beginObject(); + for (Map.Entry entry : value.entrySet()) { + out.name(entry.getKey()); + out.value(entry.getValue()); + } + out.name("exp"); + out.value(value.getExpirationTime()); + out.name("iat"); + out.value(value.getEmissionTime()); + out.endObject(); + } + + @Override + public ClaimSet read(JsonReader in) throws IOException { + ClaimSet.Builder builder = new ClaimSet.Builder(); + in.beginObject(); + while (in.hasNext()) { + String claimName = in.nextName(); + String claimValue = in.nextString(); + builder.addClaim(claimName, claimValue); + } + in.endObject(); + return builder.build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java new file mode 100644 index 0000000000..f911a54752 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java @@ -0,0 +1,52 @@ +/* + * 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.oauth.v2.json; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.jclouds.oauth.v2.domain.Header; + +import java.io.IOException; + +/** + * JSON TypeAdapter for the Header type. Simply transforms the field names. + */ +public class HeaderTypeAdapter extends TypeAdapter

{ + + @Override + public void write(JsonWriter out, Header value) throws IOException { + out.beginObject(); + out.name("alg"); + out.value(value.getSignerAlgorithm()); + out.name("typ"); + out.value(value.getType()); + out.endObject(); + } + + @Override + public Header read(JsonReader in) throws IOException { + Header.Builder builder = new Header.Builder(); + in.beginObject(); + in.nextName(); + builder.signerAlgorithm(in.nextString()); + in.nextName(); + builder.type(in.nextString()); + in.endObject(); + return builder.build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java new file mode 100644 index 0000000000..265cb26075 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java @@ -0,0 +1,96 @@ +/* + * 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.oauth.v2.json; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.base.Joiner.on; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; + +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.http.HttpRequest; +import org.jclouds.io.Payload; +import org.jclouds.json.Json; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.domain.TokenRequestFormat; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; + +/** + * Formats a token request into JWT format namely: + * - transforms the token request to json + * - creates the base64 header.claimset portions of the payload. + * - uses the provided signer function to create a signature + * - creates the full url encoded payload as described in: + * https://developers.google.com/accounts/docs/OAuth2ServiceAccount + *

+ */ +@Singleton +public class JWTTokenRequestFormat implements TokenRequestFormat { + + private static final String ASSERTION_FORM_PARAM = "assertion"; + private static final String GRANT_TYPE_FORM_PARAM = "grant_type"; + private static final String GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + + private final Function signer; + private final Json json; + + @Inject + public JWTTokenRequestFormat(Function signer, Json json) { + this.signer = signer; + this.json = json; + } + + @SuppressWarnings("unchecked") + @Override + public R formatRequest(R request, TokenRequest tokenRequest) { + + String encodedHeader = json.toJson(tokenRequest.getHeader()); + String encodedClaimSet = json.toJson(tokenRequest.getClaimSet()); + + encodedHeader = base64Url().omitPadding().encode(encodedHeader.getBytes(UTF_8)); + encodedClaimSet = base64Url().omitPadding().encode(encodedClaimSet.getBytes(UTF_8)); + + byte[] signature = signer.apply(on(".").join(encodedHeader, encodedClaimSet).getBytes(UTF_8)); + String encodedSignature = signature != null ? base64Url().omitPadding().encode(signature) : ""; + + // the final assertion in base 64 encoded {header}.{claimSet}.{signature} format + String assertion = on(".").join(encodedHeader, encodedClaimSet, encodedSignature); + Payload payload = newUrlEncodedFormPayload(ImmutableMultimap. builder() + .put(GRANT_TYPE_FORM_PARAM, GRANT_TYPE_JWT_BEARER) + .put(ASSERTION_FORM_PARAM, assertion).build()); + + return (R) request.toBuilder().payload(payload).build(); + } + + @Override + public String getTypeName() { + return "JWT"; + } + + @Override + public Set requiredClaims() { + // exp and ist (expiration and emission times) are assumed mandatory already + return ImmutableSet.of("iss", "scope", "aud"); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata new file mode 100644 index 0000000000..ab2c67dc00 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata @@ -0,0 +1,19 @@ +# +# 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. +# + +org.jclouds.googlecomputeengine.GoogleComputeEngineApiMetadata +org.jclouds.oauth.v2.OAuthApiMetadata diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java new file mode 100644 index 0000000000..5cb8a9957c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java @@ -0,0 +1,38 @@ +/* + * 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.googlecomputeengine; + +import org.jclouds.View; +import org.jclouds.apis.internal.BaseApiMetadataTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; + +/** + * Tests that GoogleComputeApiMetadata is properly registered in ServiceLoader + *

+ *

+ * META-INF/services/org.jclouds.apis.ApiMetadata
+ * 
+ */ +@Test(groups = "unit", testName = "GoogleComputeApiMetadataTest") +public class GoogleComputeEngineApiMetadataTest extends BaseApiMetadataTest { + public GoogleComputeEngineApiMetadataTest() { + super(new GoogleComputeEngineApiMetadata(), ImmutableSet.>of()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineAuthenticatedRestContextLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineAuthenticatedRestContextLiveTest.java new file mode 100644 index 0000000000..8961bb5a88 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineAuthenticatedRestContextLiveTest.java @@ -0,0 +1,33 @@ +/* + * 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.googlecomputeengine; + +import org.jclouds.oauth.v2.internal.BaseOAuthAuthenticatedApiLiveTest; +import org.testng.annotations.Test; + +@Test(groups = "live") +public class GoogleComputeEngineAuthenticatedRestContextLiveTest extends BaseOAuthAuthenticatedApiLiveTest { + + public GoogleComputeEngineAuthenticatedRestContextLiveTest() { + provider = "google-compute-engine"; + } + + @Override + public String getScopes() { + return GoogleComputeEngineConstants.COMPUTE_SCOPE; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/PageSystemExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/PageSystemExpectTest.java new file mode 100644 index 0000000000..8fa44b91b7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/PageSystemExpectTest.java @@ -0,0 +1,114 @@ +/* + * 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.googlecomputeengine; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.testng.Assert.assertSame; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.features.ImageApi; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +/** + * A test specifically for the paging system. The code used is common to all list() methods so we're using Images + * but it could be anything else. + */ +@Test(groups = "unit") +public class PageSystemExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public void testGetSinglePage() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_list_single_page.json")).build(); + + ImageApi imageApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getImageApiForProject("myproject"); + + PagedIterable images = imageApi.list(); + + // expect one page + assertSame(images.size(), 1); + // with three images + assertSame(images.concat().size(), 3); + } + + public void testGetMultiplePages() { + HttpRequest list1 = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images?maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpRequest list2 = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images?pageToken" + + "=CgVJTUFHRRIbZ29vZ2xlLmNlbnRvcy02LTItdjIwMTIwNjIx&maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpRequest list3 = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images?pageToken" + + "=CgVJTUFHRRIbZ29vZ2xlLmdjZWwtMTAtMDQtdjIwMTIxMTA2&maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse list1response = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_list_multiple_page_1.json")).build(); + + HttpResponse list2Response = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_list_multiple_page_2.json")).build(); + + HttpResponse list3Response = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_list_single_page.json")).build(); + + + ImageApi imageApi = orderedRequestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list1, list1response, list2, list2Response, list3, list3Response) + .getImageApiForProject("myproject"); + + PagedIterable images = imageApi.list(new ListOptions.Builder().maxResults(3)); + + int imageCounter = 0; + for (IterableWithMarker page : images) { + for (Image image : page) { + imageCounter++; + } + } + assertSame(imageCounter, 9); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java new file mode 100644 index 0000000000..2532f27e8d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java @@ -0,0 +1,574 @@ +/* + * 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.googlecomputeengine.compute; + +import static com.google.common.collect.Iterables.getOnlyElement; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_BOOT_DISK_SUFFIX; +import static org.jclouds.googlecomputeengine.features.GlobalOperationApiExpectTest.GET_GLOBAL_OPERATION_REQUEST; +import static org.jclouds.googlecomputeengine.features.GlobalOperationApiExpectTest.GET_GLOBAL_OPERATION_RESPONSE; +import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_DEBIAN_IMAGES_REQUEST; +import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_DEBIAN_IMAGES_RESPONSE; +import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_CENTOS_IMAGES_REQUEST; +import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_CENTOS_IMAGES_RESPONSE; +import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_PROJECT_IMAGES_REQUEST; +import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_PROJECT_IMAGES_RESPONSE; +import static org.jclouds.googlecomputeengine.features.InstanceApiExpectTest.LIST_CENTRAL1B_INSTANCES_REQUEST; +import static org.jclouds.googlecomputeengine.features.InstanceApiExpectTest.LIST_CENTRAL1B_INSTANCES_RESPONSE; +import static org.jclouds.googlecomputeengine.features.InstanceApiExpectTest.LIST_INSTANCES_REQUEST; +import static org.jclouds.googlecomputeengine.features.InstanceApiExpectTest.LIST_INSTANCES_RESPONSE; +import static org.jclouds.googlecomputeengine.features.MachineTypeApiExpectTest.LIST_CENTRAL1B_MACHINE_TYPES_REQUEST; +import static org.jclouds.googlecomputeengine.features.MachineTypeApiExpectTest.LIST_CENTRAL1B_MACHINE_TYPES_RESPONSE; +import static org.jclouds.googlecomputeengine.features.MachineTypeApiExpectTest.LIST_MACHINE_TYPES_REQUEST; +import static org.jclouds.googlecomputeengine.features.MachineTypeApiExpectTest.LIST_MACHINE_TYPES_RESPONSE; +import static org.jclouds.googlecomputeengine.features.NetworkApiExpectTest.GET_NETWORK_REQUEST; +import static org.jclouds.googlecomputeengine.features.ProjectApiExpectTest.GET_PROJECT_REQUEST; +import static org.jclouds.googlecomputeengine.features.ProjectApiExpectTest.GET_PROJECT_RESPONSE; +import static org.jclouds.googlecomputeengine.features.ZoneApiExpectTest.LIST_ZONES_REQ; +import static org.jclouds.googlecomputeengine.features.ZoneApiExpectTest.LIST_ZONES_RESPONSE; +import static org.jclouds.googlecomputeengine.features.ZoneApiExpectTest.LIST_ZONES_SHORT_RESPONSE; +import static org.jclouds.googlecomputeengine.features.ZoneOperationApiExpectTest.GET_ZONE_OPERATION_REQUEST; +import static org.jclouds.googlecomputeengine.features.ZoneOperationApiExpectTest.GET_ZONE_OPERATION_RESPONSE; +import static org.jclouds.util.Strings2.toStringAndClose; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.features.InstanceApiExpectTest; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineServiceExpectTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.util.Strings2; +import org.testng.annotations.Test; + +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + + +@Test(groups = "unit") +public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngineServiceExpectTest { + + + private HttpRequest INSERT_NETWORK_REQUEST = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/networks") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromStringWithContentType("{\"name\":\"jclouds-test\",\"IPv4Range\":\"10.0.0.0/8\"}", + MediaType.APPLICATION_JSON)) + .build(); + + private HttpRequest INSERT_FIREWALL_REQUEST = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromStringWithContentType("{\"name\":\"jclouds-test\",\"network\":\"https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/jclouds-test\"," + + "\"sourceRanges\":[\"10.0.0.0/8\",\"0.0.0.0/0\"],\"sourceTags\":[\"aTag\"],\"allowed\":[{\"IPProtocol\":\"tcp\"," + + "\"ports\":[\"22\"]}," + + "{\"IPProtocol\":\"udp\",\"ports\":[\"22\"]}]}", + MediaType.APPLICATION_JSON)) + .build(); + + private HttpResponse GET_NETWORK_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(payloadFromStringWithContentType("{\n" + + " \"kind\": \"compute#network\",\n" + + " \"id\": \"13024414170909937976\",\n" + + " \"creationTimestamp\": \"2012-10-24T20:13:19.967\",\n" + + " \"selfLink\": \"https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/jclouds-test\",\n" + + " \"name\": \"jclouds-test\",\n" + + " \"description\": \"test network\",\n" + + " \"IPv4Range\": \"10.0.0.0/8\",\n" + + " \"gatewayIPv4\": \"10.0.0.1\"\n" + + "}", MediaType.APPLICATION_JSON)).build(); + + private HttpResponse SUCESSFULL_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + private HttpRequest SET_TAGS_REQUEST = HttpRequest.builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/setTags") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromStringWithContentType("{\"items\":[\"aTag\"],\"fingerprint\":\"abcd\"}", + MediaType.APPLICATION_JSON)) + .build(); + + private HttpResponse SET_TAGS_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + private HttpResponse getInstanceResponseForInstanceAndNetworkAndStatus(String instanceName, String networkName, + String status) throws + IOException { + return HttpResponse.builder().statusCode(200) + .payload(payloadFromStringWithContentType( + replaceInstanceNameNetworkAndStatusOnResource("/instance_get.json", + instanceName, networkName, status), + "application/json")).build(); + } + + private HttpResponse getListInstancesResponseForSingleInstanceAndNetworkAndStatus(String instanceName, + String networkName, + String status) { + return HttpResponse.builder().statusCode(200) + .payload(payloadFromStringWithContentType( + replaceInstanceNameNetworkAndStatusOnResource("/instance_list.json", + instanceName, networkName, status), + "application/json")).build(); + } + + private HttpResponse getDiskResponseForInstance(String instanceName) { + return HttpResponse.builder().statusCode(200) + .payload(payloadFromStringWithContentType( + replaceDiskNameOnResource("/disk_get.json", instanceName + "-" + GCE_BOOT_DISK_SUFFIX), + "application/json")).build(); + } + + private String replaceDiskNameOnResource(String resourceName, String diskName) { + try { + return Strings2.toStringAndClose(this.getClass().getResourceAsStream(resourceName)) + .replace("testimage1", diskName); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + private String replaceInstanceNameNetworkAndStatusOnResource(String resourceName, String instanceName, + String networkName, String status) { + try { + return Strings2.toStringAndClose(this.getClass().getResourceAsStream(resourceName)).replace("test-0", + instanceName).replace("default", networkName).replace("RUNNING", status); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + private HttpRequest createDiskRequestForInstance(String instanceName) { + return HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks" + + "?sourceImage=https%3A//www.googleapis.com/compute/v1/projects/centos-cloud/global/images/gcel-12-04-v20121106") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromStringWithContentType("{\"name\":\"" + instanceName + "-" + GCE_BOOT_DISK_SUFFIX + "\"," + + "\"sizeGb\":10}", + MediaType.APPLICATION_JSON)).build(); + } + + private HttpRequest getDiskRequestForInstance(String instanceName) { + return HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/" + + instanceName + "-" + GCE_BOOT_DISK_SUFFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + } + + + + private HttpRequest createInstanceRequestForInstance(String instanceName, String groupName, + String networkName, String publicKey) { + return HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromStringWithContentType("{\"name\":\"" + instanceName + "\"," + + "\"machineType\":\"https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1\"," + + "\"serviceAccounts\":[]," + + "\"networkInterfaces\":[{\"network\":\"https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/" + networkName + "\"," + + "\"accessConfigs\":[{\"type\":\"ONE_TO_ONE_NAT\"}]}]," + + "\"disks\":[{\"mode\":\"READ_WRITE\",\"source\":\"https://www.googleapis.com/" + + "compute/v1/projects/myproject/zones/us-central1-a/disks/" + instanceName + + "-" + GCE_BOOT_DISK_SUFFIX + "\",\"deleteOnTerminate\":true,\"boot\":true,\"type\":\"PERSISTENT\"}]," + + "\"metadata\":{\"kind\":\"compute#metadata\",\"items\":[{\"key\":\"sshKeys\"," + + "\"value\":\"jclouds:" + + publicKey + " jclouds@localhost\"},{\"key\":\"jclouds-group\"," + + "\"value\":\"" + groupName + "\"},{\"key\":\"jclouds-image\",\"value\":\"https://www.googleapis" + + ".com/compute/v1/projects/centos-cloud/global/images/gcel-12-04-v20121106\"}," + + "{\"key\":\"jclouds-delete-boot-disk\",\"value\":\"true\"}]}}", + MediaType.APPLICATION_JSON)).build(); + } + + private HttpRequest getInstanceRequestForInstance(String instanceName) { + return HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/" + instanceName) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + } + + + @Override + protected Properties setupProperties() { + Properties overrides = super.setupProperties(); + overrides.put("google-compute-engine.identity", "myproject"); + try { + overrides.put("google-compute-engine.credential", toStringAndClose(getClass().getResourceAsStream("/testpk.pem"))); + } catch (IOException e) { + Throwables.propagate(e); + } + return overrides; + } + + @Test(enabled = false) + public void testThrowsAuthorizationException() throws Exception { + + Properties properties = new Properties(); + properties.setProperty("oauth.identity", "MOMMA"); + properties.setProperty("oauth.credential", "MiA"); + + ComputeService client = requestsSendResponses(ImmutableMap.of(), createModule(), + properties); + Template template = client.templateBuilder().build(); + Template toMatch = client.templateBuilder().imageId(template.getImage().getId()).build(); + assertEquals(toMatch.getImage(), template.getImage()); + } + + @Test + public void testTemplateMatch() throws Exception { + ImmutableMap requestResponseMap = ImmutableMap. + builder() + .put(requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE) + .put(GET_PROJECT_REQUEST, GET_PROJECT_RESPONSE) + .put(LIST_ZONES_REQ, LIST_ZONES_RESPONSE) + .put(LIST_PROJECT_IMAGES_REQUEST, LIST_PROJECT_IMAGES_RESPONSE) + .put(LIST_DEBIAN_IMAGES_REQUEST, LIST_DEBIAN_IMAGES_RESPONSE) + .put(LIST_CENTOS_IMAGES_REQUEST, LIST_CENTOS_IMAGES_RESPONSE) + .put(LIST_MACHINE_TYPES_REQUEST, LIST_MACHINE_TYPES_RESPONSE) + .put(LIST_CENTRAL1B_MACHINE_TYPES_REQUEST, LIST_CENTRAL1B_MACHINE_TYPES_RESPONSE) + .build(); + + ComputeService client = requestsSendResponses(requestResponseMap); + Template template = client.templateBuilder().build(); + Hardware defaultSize = client.templateBuilder().build().getHardware(); + + Hardware smallest = client.templateBuilder().smallest().build().getHardware(); + assertEquals(defaultSize, smallest); + + Hardware fastest = client.templateBuilder().fastest().build().getHardware(); + assertNotNull(fastest); + + assertEquals(client.listHardwareProfiles().size(), 5); + + Template toMatch = client.templateBuilder() + .imageId(template.getImage().getId()) + .build(); + assertEquals(toMatch.getImage(), template.getImage()); + } + + @Test + public void testNetworksAndFirewallDeletedWhenAllGroupNodesAreTerminated() throws IOException { + + HttpRequest deleteNodeRequest = HttpRequest.builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-delete-networks") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpRequest deleteFirewallRequest = HttpRequest.builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls/jclouds-test-delete") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpRequest getNetworkRequest = HttpRequest.builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/jclouds-test-delete") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse getNetworkResponse = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/GoogleComputeEngineServiceExpectTest/network_get.json")).build(); + + HttpRequest listFirewallsRequest = HttpRequest.builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse listFirewallsResponse = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/GoogleComputeEngineServiceExpectTest/firewall_list.json")).build(); + + HttpRequest deleteNetworkReqquest = HttpRequest.builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/jclouds-test-delete") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpRequest deleteDiskRequest = HttpRequest.builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/test") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + List orderedRequests = ImmutableList.builder() + .add(requestForScopes(COMPUTE_READONLY_SCOPE)) + .add(GET_PROJECT_REQUEST) + .add(getInstanceRequestForInstance("test-delete-networks")) + .add(LIST_ZONES_REQ) + .add(LIST_MACHINE_TYPES_REQUEST) + .add(LIST_PROJECT_IMAGES_REQUEST) + .add(LIST_DEBIAN_IMAGES_REQUEST) + .add(LIST_CENTOS_IMAGES_REQUEST) + .add(getInstanceRequestForInstance("test-delete-networks")) + .add(requestForScopes(COMPUTE_SCOPE)) + .add(deleteNodeRequest) + .add(GET_ZONE_OPERATION_REQUEST) + .add(deleteDiskRequest) + .add(GET_ZONE_OPERATION_REQUEST) + .add(getInstanceRequestForInstance("test-delete-networks")) + .add(LIST_INSTANCES_REQUEST) + .add(getNetworkRequest) + .add(listFirewallsRequest) + .add(deleteFirewallRequest) + .add(GET_GLOBAL_OPERATION_REQUEST) + .add(deleteNetworkReqquest) + .add(GET_GLOBAL_OPERATION_REQUEST) + .build(); + + + List orderedResponses = ImmutableList.builder() + .add(TOKEN_RESPONSE) + .add(GET_PROJECT_RESPONSE) + .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", Instance + .Status.RUNNING.name())) + .add(LIST_ZONES_SHORT_RESPONSE) + .add(LIST_MACHINE_TYPES_RESPONSE) + .add(LIST_PROJECT_IMAGES_RESPONSE) + .add(LIST_DEBIAN_IMAGES_RESPONSE) + .add(LIST_CENTOS_IMAGES_RESPONSE) + .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", Instance + .Status.RUNNING.name())) + .add(TOKEN_RESPONSE) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(GET_ZONE_OPERATION_RESPONSE) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(GET_ZONE_OPERATION_RESPONSE) + .add(getInstanceResponseForInstanceAndNetworkAndStatus("test-delete-networks", "test-network", Instance + .Status.TERMINATED.name())) + .add(getListInstancesResponseForSingleInstanceAndNetworkAndStatus("test-delete-networks", + "test-network", Instance + .Status.TERMINATED.name())) + .add(getNetworkResponse) + .add(listFirewallsResponse) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(GET_GLOBAL_OPERATION_RESPONSE) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(GET_GLOBAL_OPERATION_RESPONSE) + .build(); + + ComputeService client = orderedRequestsSendResponses(orderedRequests, orderedResponses); + client.destroyNode("us-central1-a/test-delete-networks"); + + } + + public void testListLocationsWhenResponseIs2xx() throws Exception { + + ImmutableMap requestResponseMap = ImmutableMap. + builder() + .put(requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE) + .put(GET_PROJECT_REQUEST, GET_PROJECT_RESPONSE) + .put(LIST_ZONES_REQ, LIST_ZONES_RESPONSE) + .put(LIST_INSTANCES_REQUEST, LIST_INSTANCES_RESPONSE) + .put(LIST_CENTRAL1B_INSTANCES_REQUEST, LIST_CENTRAL1B_INSTANCES_RESPONSE) + .put(LIST_PROJECT_IMAGES_REQUEST, LIST_PROJECT_IMAGES_RESPONSE) + .put(LIST_DEBIAN_IMAGES_REQUEST, LIST_DEBIAN_IMAGES_RESPONSE) + .put(LIST_CENTOS_IMAGES_REQUEST, LIST_CENTOS_IMAGES_RESPONSE) + .put(LIST_MACHINE_TYPES_REQUEST, LIST_MACHINE_TYPES_RESPONSE) + .put(LIST_CENTRAL1B_MACHINE_TYPES_REQUEST, LIST_CENTRAL1B_MACHINE_TYPES_RESPONSE) + .build(); + + ComputeService apiWhenServersExist = requestsSendResponses(requestResponseMap); + + Set locations = apiWhenServersExist.listAssignableLocations(); + + assertNotNull(locations); + assertEquals(locations.size(), 2); + assertEquals(locations.iterator().next().getId(), "us-central1-a"); + + assertNotNull(apiWhenServersExist.listNodes()); + assertEquals(apiWhenServersExist.listNodes().size(), 1); + assertEquals(apiWhenServersExist.listNodes().iterator().next().getId(), "us-central1-a/test-0"); + assertEquals(apiWhenServersExist.listNodes().iterator().next().getName(), "test-0"); + } + + @Test(dependsOnMethods = "testListLocationsWhenResponseIs2xx") + public void testCreateNodeWhenNetworkNorFirewallExistDoesNotExist() throws RunNodesException, IOException { + + + String payload = Strings2.toStringAndClose(InstanceApiExpectTest.class.getResourceAsStream("/instance_get.json")); + payload = payload.replace("test-0", "test-1"); + + HttpResponse getInstanceResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromStringWithContentType(payload, "application/json")).build(); + + HttpRequest getFirewallRequest = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls/jclouds-test-port-22") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpRequest insertFirewallRequest = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromStringWithContentType("{\"name\":\"jclouds-test-port-22\",\"network\":\"https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/jclouds-test\"," + + "\"sourceRanges\":[\"10.0.0.0/8\",\"0.0.0.0/0\"],\"sourceTags\":[\"aTag\"],\"targetTags\":[\"jclouds-test-port-22\"],\"allowed\":[{\"IPProtocol\":\"tcp\"," + + "\"ports\":[\"22\"]}," + + "{\"IPProtocol\":\"udp\",\"ports\":[\"22\"]}]}", + MediaType.APPLICATION_JSON)) + .build(); + + HttpRequest setTagsRequest = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/setTags") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromStringWithContentType("{\"items\":[\"jclouds-test-port-22\"],\"fingerprint\":\"abcd\"}", + MediaType.APPLICATION_JSON)) + .build(); + + List orderedRequests = ImmutableList.builder() + .add(requestForScopes(COMPUTE_READONLY_SCOPE)) + .add(GET_PROJECT_REQUEST) + .add(LIST_ZONES_REQ) + .add(LIST_PROJECT_IMAGES_REQUEST) + .add(LIST_DEBIAN_IMAGES_REQUEST) + .add(LIST_CENTOS_IMAGES_REQUEST) + .add(LIST_ZONES_REQ) + .add(LIST_MACHINE_TYPES_REQUEST) + .add(GET_NETWORK_REQUEST) + .add(GET_NETWORK_REQUEST) + .add(requestForScopes(COMPUTE_SCOPE)) + .add(INSERT_NETWORK_REQUEST) + .add(GET_GLOBAL_OPERATION_REQUEST) + .add(GET_NETWORK_REQUEST) + .add(getFirewallRequest) + .add(insertFirewallRequest) + .add(GET_GLOBAL_OPERATION_REQUEST) + .add(LIST_INSTANCES_REQUEST) + .add(LIST_MACHINE_TYPES_REQUEST) + .add(LIST_PROJECT_IMAGES_REQUEST) + .add(LIST_DEBIAN_IMAGES_REQUEST) + .add(LIST_CENTOS_IMAGES_REQUEST) + .add(createDiskRequestForInstance("test-1")) + .add(GET_ZONE_OPERATION_REQUEST) + .add(getDiskRequestForInstance("test-1")) + .add(createInstanceRequestForInstance("test-1", "test", "jclouds-test", openSshKey)) + .add(GET_ZONE_OPERATION_REQUEST) + .add(getInstanceRequestForInstance("test-1")) + .add(SET_TAGS_REQUEST) + .add(GET_ZONE_OPERATION_REQUEST) + .add(getInstanceRequestForInstance("test-1")) + .add(setTagsRequest) + .add(LIST_PROJECT_IMAGES_REQUEST) + .add(LIST_DEBIAN_IMAGES_REQUEST) + .add(LIST_CENTOS_IMAGES_REQUEST) + .add(setTagsRequest) + .build(); + + List orderedResponses = ImmutableList.builder() + .add(TOKEN_RESPONSE) + .add(GET_PROJECT_RESPONSE) + .add(LIST_ZONES_SHORT_RESPONSE) + .add(LIST_PROJECT_IMAGES_RESPONSE) + .add(LIST_DEBIAN_IMAGES_RESPONSE) + .add(LIST_CENTOS_IMAGES_RESPONSE) + .add(LIST_ZONES_SHORT_RESPONSE) + .add(LIST_MACHINE_TYPES_RESPONSE) + .add(HttpResponse.builder().statusCode(404).build()) + .add(HttpResponse.builder().statusCode(404).build()) + .add(TOKEN_RESPONSE) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(GET_GLOBAL_OPERATION_RESPONSE) + .add(GET_NETWORK_RESPONSE) + .add(HttpResponse.builder().statusCode(404).build()) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(GET_GLOBAL_OPERATION_RESPONSE) + .add(LIST_INSTANCES_RESPONSE) + .add(LIST_MACHINE_TYPES_RESPONSE) + .add(LIST_PROJECT_IMAGES_RESPONSE) + .add(LIST_DEBIAN_IMAGES_RESPONSE) + .add(LIST_CENTOS_IMAGES_RESPONSE) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(GET_ZONE_OPERATION_RESPONSE) + .add(getDiskResponseForInstance("test-1")) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(GET_ZONE_OPERATION_RESPONSE) + .add(getInstanceResponse) + .add(SET_TAGS_RESPONSE) + .add(GET_ZONE_OPERATION_RESPONSE) + .add(getInstanceResponse) + .add(SUCESSFULL_OPERATION_RESPONSE) + .add(LIST_PROJECT_IMAGES_RESPONSE) + .add(LIST_DEBIAN_IMAGES_RESPONSE) + .add(LIST_CENTOS_IMAGES_RESPONSE) + .add(SUCESSFULL_OPERATION_RESPONSE) + .build(); + + + ComputeService computeService = orderedRequestsSendResponses(orderedRequests, orderedResponses); + + GoogleComputeEngineTemplateOptions options = computeService.templateOptions().as(GoogleComputeEngineTemplateOptions.class); + options.tags(ImmutableSet.of("aTag")); + NodeMetadata node = getOnlyElement(computeService.createNodesInGroup("test", 1, options)); + assertEquals(node.getImageId(), "gcel-12-04-v20121106"); + } +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceLiveTest.java new file mode 100644 index 0000000000..2b5bdcd89d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceLiveTest.java @@ -0,0 +1,128 @@ +/* + * 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.googlecomputeengine.compute; + +import static com.google.common.collect.Iterables.contains; +import static org.jclouds.oauth.v2.OAuthTestUtils.setCredentialFromPemFile; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import java.util.Properties; +import java.util.Set; + +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.internal.BaseComputeServiceLiveTest; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.MachineType; +import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.TypeLiteral; + +@Test(groups = "live", singleThreaded = true) +public class GoogleComputeEngineServiceLiveTest extends BaseComputeServiceLiveTest { + + protected static final String DEFAULT_ZONE_NAME = "us-central1-a"; + + public GoogleComputeEngineServiceLiveTest() { + provider = "google-compute-engine"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setCredentialFromPemFile(props, provider + ".credential"); + return props; + } + + public void testListHardwareProfiles() throws Exception { + GoogleComputeEngineApi api = client.getContext().unwrapApi(GoogleComputeEngineApi.class); + Supplier userProject = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { + }, UserProject.class)); + ImmutableSet.Builder deprecatedMachineTypes = ImmutableSet.builder(); + for (MachineType machine : api.getMachineTypeApiForProject(userProject.get()) + .listInZone(DEFAULT_ZONE_NAME).concat()) { + if (machine.getDeprecated().isPresent()) { + deprecatedMachineTypes.add(machine.getId()); + } + } + ImmutableSet deprecatedMachineTypeIds = deprecatedMachineTypes.build(); + Set hardwareProfiles = client.listHardwareProfiles(); + System.out.println(hardwareProfiles.size()); + for (Hardware hardwareProfile : hardwareProfiles) { + System.out.println(hardwareProfile); + assertFalse(contains(deprecatedMachineTypeIds, hardwareProfile.getId())); + } + } + + /** + * Nodes may have additional metadata entries (particularly they may have an "sshKeys" entry) + */ + protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap userMetadata) { + assertTrue(node.getUserMetadata().keySet().containsAll(userMetadata.keySet())); + } + + // do not run until the auth exception problem is figured out. + @Test(enabled = false) + @Override + public void testCorrectAuthException() throws Exception { + } + + // reboot is not supported by GCE + @Test(enabled = true, dependsOnMethods = "testGet") + public void testReboot() throws Exception { + } + + // suspend/Resume is not supported by GCE + @Test(enabled = true, dependsOnMethods = "testReboot") + public void testSuspendResume() throws Exception { + } + + @Test(enabled = true, dependsOnMethods = "testSuspendResume") + public void testListNodesByIds() throws Exception { + super.testGetNodesWithDetails(); + } + + @Test(enabled = true, dependsOnMethods = "testSuspendResume") + @Override + public void testGetNodesWithDetails() throws Exception { + super.testGetNodesWithDetails(); + } + + @Test(enabled = true, dependsOnMethods = "testSuspendResume") + @Override + public void testListNodes() throws Exception { + super.testListNodes(); + } + + @Test(enabled = true, dependsOnMethods = {"testListNodes", "testGetNodesWithDetails", "testListNodesByIds"}) + @Override + public void testDestroyNodes() { + super.testDestroyNodes(); + } + + @Override + protected Module getSshModule() { + return new SshjSshClientModule(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtensionLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtensionLiveTest.java new file mode 100644 index 0000000000..588ef51661 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtensionLiveTest.java @@ -0,0 +1,28 @@ +/* + * 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.googlecomputeengine.compute.extensions; + +import org.jclouds.compute.extensions.internal.BaseSecurityGroupExtensionLiveTest; +import org.testng.annotations.Test; + +@Test(groups = "live", singleThreaded = true, testName = "GoogleComputeEngineSecurityGroupExtensionLiveTest") +public class GoogleComputeEngineSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest { + + public GoogleComputeEngineSecurityGroupExtensionLiveTest() { + provider = "google-compute-engine"; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermissionTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermissionTest.java new file mode 100644 index 0000000000..62f92600d8 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermissionTest.java @@ -0,0 +1,93 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.net.URI; +import java.util.Date; + +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; + +public class FirewallToIpPermissionTest { + + @Test + public void testApply() { + + Firewall fw = fwForTest(); + + FirewallToIpPermission converter = new FirewallToIpPermission(); + + Iterable perms = converter.apply(fw); + + assertEquals(Iterables.size(perms), 3, "There should be three IpPermissions but there is only " + Iterables.size(perms)); + + assertTrue(Iterables.any(perms, Predicates.and(hasProtocol(IpProtocol.TCP), + hasStartAndEndPort(1, 10))), "No permission found for TCP, ports 1-10"); + assertTrue(Iterables.any(perms, Predicates.and(hasProtocol(IpProtocol.TCP), + hasStartAndEndPort(33, 33))), "No permission found for TCP, port 33"); + assertTrue(Iterables.any(perms, hasProtocol(IpProtocol.ICMP)), + "No permission found for ICMP"); + } + + public static Firewall fwForTest() { + Firewall.Builder builder = Firewall.builder(); + + builder.addSourceRange("0.0.0.0/0"); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.TCP) + .addPortRange(1, 10).build()); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.TCP) + .addPort(33).build()); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.ICMP).build()); + builder.id("abcd"); + builder.selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test")); + builder.network(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test")); + builder.creationTimestamp(new Date()); + builder.name("jclouds-test"); + + return builder.build(); + } + + public static Predicate hasProtocol(final IpProtocol protocol) { + return new Predicate() { + + @Override + public boolean apply(IpPermission perm) { + return protocol.equals(perm.getIpProtocol()); + } + }; + } + + public static Predicate hasStartAndEndPort(final int startPort, final int endPort) { + return new Predicate() { + + @Override + public boolean apply(IpPermission perm) { + return startPort == perm.getFromPort() && endPort == perm.getToPort(); + } + }; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java new file mode 100644 index 0000000000..239cea5a11 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java @@ -0,0 +1,60 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; + +import java.net.URI; + +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.googlecomputeengine.domain.Image; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class GoogleComputeEngineImageToImageTest { + + Image.Builder imageBuilder = Image.builder() + .id("1234") + .selfLink(URI.create("http://test.com")) + .sourceType("RAW") + .description("") + .rawDisk(Image.RawDisk.builder().source("").containerType("TAR").build()); + + public void testArbitratyImageName() { + GoogleComputeEngineImageToImage imageToImage = new GoogleComputeEngineImageToImage(); + Image image = imageBuilder.name("arbitratyname").build(); + org.jclouds.compute.domain.Image transformed = imageToImage.apply(image); + assertEquals(transformed.getName(), image.getName()); + assertEquals(transformed.getId(), image.getName()); + assertEquals(transformed.getProviderId(), image.getId()); + assertSame(transformed.getOperatingSystem().getFamily(), OsFamily.LINUX); + } + + public void testWellFormedImageName() { + GoogleComputeEngineImageToImage imageToImage = new GoogleComputeEngineImageToImage(); + Image image = imageBuilder.name("ubuntu-12-04-v123123").build(); + org.jclouds.compute.domain.Image transformed = imageToImage.apply(image); + assertEquals(transformed.getName(), image.getName()); + assertEquals(transformed.getId(), image.getName()); + assertEquals(transformed.getProviderId(), image.getId()); + assertSame(transformed.getOperatingSystem().getFamily(), OsFamily.UBUNTU); + assertEquals(transformed.getOperatingSystem().getVersion(), "12.04"); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadataTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadataTest.java new file mode 100644 index 0000000000..dd2416ea2d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/InstanceInZoneToNodeMetadataTest.java @@ -0,0 +1,286 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static org.easymock.EasyMock.createMock; +import static org.testng.Assert.assertEquals; +import static org.jclouds.compute.domain.Image.Status.AVAILABLE; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.HardwareBuilder; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.domain.Processor; +import org.jclouds.compute.domain.Volume.Type; +import org.jclouds.compute.domain.VolumeBuilder; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.InstanceInZone; +import org.jclouds.googlecomputeengine.domain.Metadata; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; + +@Test(groups = "unit", testName = "InstanceInZoneToNodeMetadataTest") +public class InstanceInZoneToNodeMetadataTest { + + /** + * GroupNamingConvention that always returns the same name provided in the constructor. + * The predicates returned always evaluate to true. + * + */ + class FixedGroupNamingConvention implements GroupNamingConvention { + private final String name; + + public FixedGroupNamingConvention(final String name) { + this.name = name; + } + + @Override + public String sharedNameForGroup(final String group) { + return name; + } + + @Override + public String uniqueNameForGroup(final String group) { + return name; + } + + @Override + public String groupInUniqueNameOrNull(final String encoded) { + return name; + } + + @Override + public String groupInSharedNameOrNull(final String encoded) { + return name; + } + + @Override + public Predicate containsGroup(final String group) { + return new Predicate() { + @Override + public boolean apply(final String input) { + return true; + } + }; + } + + @Override + public Predicate containsAnyGroup() { + return new Predicate() { + @Override + public boolean apply(final String input) { + return true; + } + }; + } + + @Override + public String extractGroup(final String encoded) { + return name; + } + } + + private Instance instance; + + private Set hardwares; + + private Set images; + + private Set locations; + + private InstanceInZoneToNodeMetadata groupGroupNodeParser; + private InstanceInZoneToNodeMetadata groupNullNodeParser; + + @BeforeMethod + public final void setup() { + instance = Instance.builder() + .id("13051190678907570425") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-11-25T23:48:20.758")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-0")) + .description("desc") + .name("test-0") + .machineType(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/" + + "machineTypes/n1-standard-1")) + .status(Instance.Status.RUNNING) + .zone(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a")) + .addNetworkInterface( + Instance.NetworkInterface.builder() + .name("nic0") + .networkIP("10.240.121.115") + .network(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/default")) + .build()) + .addDisk( + Instance.PersistentAttachedDisk.builder() + .index(0) + .mode(Instance.PersistentAttachedDisk.Mode.READ_WRITE) + .deviceName("test") + .source(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/test")) + .boot(true) + .build()) + .tags(Instance.Tags.builder().fingerprint("abcd").addItem("aTag").addItem("Group-port-42").build()) + .metadata(Metadata.builder() + .items(ImmutableMap.of("aKey", "aValue", + "jclouds-image", + "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/gcel-12-04-v20121106", + "jclouds-delete-boot-disk", "true")) + .fingerprint("efgh") + .build()) + .addServiceAccount(Instance.ServiceAccount.builder().email("default").addScopes("myscope").build()) + .build(); + + images = ImmutableSet.of(new ImageBuilder() + .id("1") + .uri(URI.create("https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/" + + "gcel-12-04-v20121106")) + .providerId("1") + .name("mock image") + .status(AVAILABLE) + .operatingSystem( + OperatingSystem.builder().name("Ubuntu 14.04 x86_64").description("Ubuntu").family(OsFamily.UBUNTU) + .version("10.04").arch("x86_64").is64Bit(true).build()).build()); + + hardwares = ImmutableSet.of(new HardwareBuilder().id("my_id") + .uri(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/" + + "n1-standard-1")) + .providerId("1") + .name("mock hardware").processor(new Processor(1.0, 1.0)).ram(2048) + .volume(new VolumeBuilder().size(20f).type(Type.LOCAL).build()).build()); + + locations = ImmutableSet.of(new LocationBuilder() + .id("id") + .description("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a") + .scope(LocationScope.REGION) + .parent( + new LocationBuilder().id("0").description("mock parent location").scope(LocationScope.PROVIDER) + .build()).build()); + + groupGroupNodeParser = createNodeParser(hardwares, images, locations, "Group"); + groupNullNodeParser = createNodeParser(hardwares, images, locations, null); + } + + private InstanceInZoneToNodeMetadata createNodeParser(final Set hardware, final Set images, + final Set locations, final String groupName) { + Supplier> locationSupplier = new Supplier>() { + @Override + public Map get() { + return Maps.uniqueIndex(locations, new Function() { + @Override + public URI apply(final Location input) { + return URI.create(input.getDescription()); + } + }); + } + }; + + Supplier> hardwareSupplier = new Supplier>() { + @Override + public Map get() { + return Maps.uniqueIndex(hardware, new Function() { + @Override + public URI apply(final Hardware input) { + return input.getUri(); + } + }); + } + }; + + Supplier> imageSupplier = new Supplier>() { + @Override + public Map get() { + return Maps.uniqueIndex(images, new Function() { + @Override + public URI apply(final Image input) { + return input.getUri(); + } + }); + } + }; + + Supplier userProjectSupplier = new Supplier() { + @Override + public String get() { + return "userProject"; + } + }; + + GroupNamingConvention.Factory namingConventionFactory = + new GroupNamingConvention.Factory() { + @Override + public GroupNamingConvention createWithoutPrefix() { + return new FixedGroupNamingConvention(groupName); + } + + @Override + public GroupNamingConvention create() { + return new FixedGroupNamingConvention(groupName); + } + }; + + return new InstanceInZoneToNodeMetadata( + ImmutableMap.builder() + .put(Instance.Status.RUNNING, NodeMetadata.Status.PENDING).build(), + namingConventionFactory, + imageSupplier, + hardwareSupplier, + locationSupplier, + new FirewallTagNamingConvention.Factory(namingConventionFactory), + createMock(GoogleComputeEngineApi.class), + userProjectSupplier); + } + + @Test + public final void testTagFilteringWorks() { + InstanceInZone instanceInZone = new InstanceInZone(instance, "zoneId"); + NodeMetadata nodeMetadata = groupGroupNodeParser.apply(instanceInZone); + assertEquals(nodeMetadata.getId(), "id/test-0"); + assertEquals(nodeMetadata.getTags(), ImmutableSet.of( + "aTag" // "aTag" kept as a non firewall tag. + // "Group-port-42" filtered out as a firewall tag. + )); + } + + @Test + public final void testInstanceWithGroupNull() { + InstanceInZone instanceInZone = new InstanceInZone(instance, "zoneId"); + NodeMetadata nodeMetadata = groupNullNodeParser.apply(instanceInZone); + assertEquals(nodeMetadata.getId(), "id/test-0"); + assertEquals(nodeMetadata.getTags(), ImmutableSet.of("aTag", "Group-port-42")); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java new file mode 100644 index 0000000000..795c98998f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java @@ -0,0 +1,94 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.jclouds.googlecomputeengine.compute.functions.FirewallToIpPermissionTest.hasProtocol; +import static org.jclouds.googlecomputeengine.compute.functions.FirewallToIpPermissionTest.hasStartAndEndPort; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.net.URI; +import java.util.Date; + +import org.jclouds.collect.IterableWithMarkers; +import org.jclouds.collect.PagedIterables; +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.features.FirewallApi; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.googlecomputeengine.options.ListOptions.Builder; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +import com.google.common.base.Predicates; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +public class NetworkToSecurityGroupTest { + + @Test + public void testApply() { + Supplier projectSupplier = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + FirewallToIpPermission fwToPerm = new FirewallToIpPermission(); + + GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + FirewallApi fwApi = createMock(FirewallApi.class); + + ListOptions options = new Builder().filter("network eq .*/jclouds-test"); + expect(api.getFirewallApiForProject(projectSupplier.get())) + .andReturn(fwApi); + expect(fwApi.list(options)).andReturn(PagedIterables.of(IterableWithMarkers.from(ImmutableSet.of(FirewallToIpPermissionTest.fwForTest())))); + + replay(api, fwApi); + Network.Builder builder = Network.builder(); + + builder.id("abcd"); + builder.selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test")); + builder.creationTimestamp(new Date()); + builder.description("some description"); + builder.gatewayIPv4("1.2.3.4"); + builder.IPv4Range("0.0.0.0/0"); + builder.name("jclouds-test"); + + Network network = builder.build(); + + NetworkToSecurityGroup netToSg = new NetworkToSecurityGroup(fwToPerm, api, projectSupplier); + + SecurityGroup group = netToSg.apply(network); + + assertEquals(group.getId(), "jclouds-test"); + assertEquals(group.getUri(), URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test")); + assertEquals(group.getIpPermissions().size(), 3); + assertTrue(Iterables.any(group.getIpPermissions(), Predicates.and(hasProtocol(IpProtocol.TCP), + hasStartAndEndPort(1, 10))), "No permission found for TCP, ports 1-10"); + assertTrue(Iterables.any(group.getIpPermissions(), Predicates.and(hasProtocol(IpProtocol.TCP), + hasStartAndEndPort(33, 33))), "No permission found for TCP, port 33"); + assertTrue(Iterables.any(group.getIpPermissions(), hasProtocol(IpProtocol.ICMP)), + "No permission found for ICMP"); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java new file mode 100644 index 0000000000..cae3432e23 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java @@ -0,0 +1,136 @@ +/* + * 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.googlecomputeengine.compute.functions; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.util.Set; + +import org.easymock.EasyMock; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.domain.ComputeMetadata; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.internal.NodeMetadataImpl; +import org.jclouds.googlecomputeengine.compute.predicates.AllNodesInGroupTerminated; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +public class OrphanedGroupsFromDeadNodesTest { + + private static class IdAndGroupOnlyNodeMetadata extends NodeMetadataImpl { + + public IdAndGroupOnlyNodeMetadata(String id, String group, Status status) { + super(null, null, id, null, null, ImmutableMap.of(), ImmutableSet.of(), group, null, + null, null, status, null, 0, ImmutableSet.of(), ImmutableSet.of(), null, null); + } + } + + + @Test + public void testDetectsAllOrphanedGroupsWhenAllNodesTerminated() { + + Set deadNodesGroup1 = (Set) ImmutableSet.builder() + .add(new IdAndGroupOnlyNodeMetadata("a", "1", NodeMetadata.Status.TERMINATED)).build(); + + Set deadNodesGroup2 = (Set) ImmutableSet.builder() + .add(new IdAndGroupOnlyNodeMetadata("b", "2", NodeMetadata.Status.TERMINATED)).build(); + + Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); + + ComputeService mock = createMock(ComputeService.class); + expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) + .andReturn((Set) deadNodesGroup1).once(); + expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) + .andReturn((Set) deadNodesGroup2).once(); + + replay(mock); + + OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(new + AllNodesInGroupTerminated(mock)); + + Set orphanedGroups = orphanedGroupsFromDeadNodes.apply(allDeadNodes); + + assertSame(orphanedGroups.size(), 2); + assertTrue(orphanedGroups.contains("1")); + assertTrue(orphanedGroups.contains("2")); + } + + @Test + public void testDetectsAllOrphanedGroupsWhenSomeNodesTerminatedAndOtherMissing() { + + Set deadNodesGroup1 = (Set) ImmutableSet.builder() + .add(new IdAndGroupOnlyNodeMetadata("a", "1", NodeMetadata.Status.TERMINATED)).build(); + + Set deadNodesGroup2 = (Set) ImmutableSet.builder() + .add(new IdAndGroupOnlyNodeMetadata("b", "2", NodeMetadata.Status.TERMINATED)).build(); + + Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); + + ComputeService mock = createMock(ComputeService.class); + expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) + .andReturn((Set) deadNodesGroup1).once(); + expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) + .andReturn((Set) ImmutableSet.of()).once(); + + replay(mock); + + OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(new + AllNodesInGroupTerminated(mock)); + + Set orphanedGroups = orphanedGroupsFromDeadNodes.apply(allDeadNodes); + + assertSame(orphanedGroups.size(), 2); + assertTrue(orphanedGroups.contains("1")); + assertTrue(orphanedGroups.contains("2")); + } + + @Test + public void testDetectsAllOrphanedGroupsWhenSomeNodesAreAlive() { + + Set deadNodesGroup1 = (Set) ImmutableSet.builder() + .add(new IdAndGroupOnlyNodeMetadata("a", "1", NodeMetadata.Status.TERMINATED)).build(); + + Set deadNodesGroup2 = (Set) ImmutableSet.builder() + .add(new IdAndGroupOnlyNodeMetadata("b", "2", NodeMetadata.Status.RUNNING)).build(); + + Set allDeadNodes = Sets.union(deadNodesGroup1, deadNodesGroup2); + + ComputeService mock = createMock(ComputeService.class); + expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) + .andReturn((Set) deadNodesGroup1).once(); + expect(mock.listNodesDetailsMatching(EasyMock.>anyObject())) + .andReturn((Set) deadNodesGroup2).once(); + + replay(mock); + + OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(new + AllNodesInGroupTerminated(mock)); + + Set orphanedGroups = orphanedGroupsFromDeadNodes.apply(allDeadNodes); + + assertSame(orphanedGroups.size(), 1); + assertTrue(orphanedGroups.contains("1")); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreateTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreateTest.java new file mode 100644 index 0000000000..467995fe34 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreateTest.java @@ -0,0 +1,141 @@ +/* + * 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.googlecomputeengine.compute.loaders; + +import static com.google.common.base.Optional.fromNullable; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.features.GlobalOperationApi; +import org.jclouds.googlecomputeengine.features.NetworkApi; +import org.jclouds.googlecomputeengine.functions.CreateNetworkIfNeeded; +import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; + +public class FindNetworkOrCreateTest { + + @Test + public void testLoadExisting() { + final GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + final NetworkApi nwApi = createMock(NetworkApi.class); + + Network network = Network.builder().IPv4Range("0.0.0.0/0") + .id("abcd").name("this-network") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/this-network")) + .build(); + + final Supplier userProject = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + expect(api.getNetworkApiForProject(userProject.get())).andReturn(nwApi).atLeastOnce(); + + expect(nwApi.get("this-network")).andReturn(network); + + replay(api, nwApi); + + NetworkAndAddressRange input = new NetworkAndAddressRange("this-network", "0.0.0.0/0", null); + + GlobalOperationDonePredicate pred = new GlobalOperationDonePredicate(api, userProject); + + CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l); + + FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator, userProject); + + LoadingCache cache = CacheBuilder.newBuilder().build(loader); + + assertEquals(cache.getUnchecked(input), network); + + // Second call is to ensure we only need to make the API calls once. + assertEquals(cache.getUnchecked(input), network); + + verify(api, nwApi); + } + + @Test + public void testLoadNew() { + final GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + final NetworkApi nwApi = createMock(NetworkApi.class); + final GlobalOperationApi globalApi = createMock(GlobalOperationApi.class); + + Network network = Network.builder().IPv4Range("0.0.0.0/0") + .id("abcd").name("this-network") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/this-network")) + .build(); + + Operation createOp = createMock(Operation.class); + + final Supplier userProject = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + expect(api.getNetworkApiForProject(userProject.get())).andReturn(nwApi).atLeastOnce(); + expect(api.getGlobalOperationApiForProject(userProject.get())).andReturn(globalApi).atLeastOnce(); + + expect(nwApi.createInIPv4Range("this-network", "0.0.0.0/0")) + .andReturn(createOp); + expect(globalApi.get("create-op")).andReturn(createOp); + // pre-creation + expect(nwApi.get("this-network")).andReturn(null).times(2); + // post-creation + expect(nwApi.get("this-network")).andReturn(network); + + expect(createOp.getName()).andReturn("create-op"); + expect(createOp.getStatus()).andReturn(Operation.Status.DONE); + expect(createOp.getHttpError()).andReturn(fromNullable((HttpResponse)null)); + replay(api, nwApi, createOp, globalApi); + + NetworkAndAddressRange input = new NetworkAndAddressRange("this-network", "0.0.0.0/0", null); + + GlobalOperationDonePredicate pred = new GlobalOperationDonePredicate(api, userProject); + + CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l); + + FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator, userProject); + + LoadingCache cache = CacheBuilder.newBuilder().build(loader); + + assertEquals(cache.getUnchecked(input), network); + + // Second call is to ensure we only need to make the API calls once. + assertEquals(cache.getUnchecked(input), network); + + verify(api, nwApi, globalApi, createOp); + + } +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiExpectTest.java new file mode 100644 index 0000000000..1816b78f1a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiExpectTest.java @@ -0,0 +1,163 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseAddressListTest; +import org.jclouds.googlecomputeengine.parse.ParseAddressTest; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class AddressApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public void testGetAddressResponseIs2xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/address_get.json")).build(); + + AddressApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getAddressApiForProject("myproject"); + + assertEquals(api.getInRegion("us-central1", "test-ip1"), + new ParseAddressTest().expected()); + } + + public void testGetAddressResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + AddressApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getAddressApiForProject("myproject"); + + assertNull(api.getInRegion("us-central1", "test-ip1")); + } + + public void testInsertAddressResponseIs2xx() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/address_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertAddressResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/region_operation.json")).build(); + + AddressApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, + insertAddressResponse).getAddressApiForProject("myproject"); + + assertEquals(api.createInRegion("us-central1", "test-ip1"), new ParseOperationTest().expected()); + } + + public void testDeleteAddressResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/region_operation.json")).build(); + + AddressApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getAddressApiForProject("myproject"); + + assertEquals(api.deleteInRegion("us-central1", "test-ip1"), + new ParseOperationTest().expected()); + } + + public void testDeleteAddressResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + AddressApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getAddressApiForProject("myproject"); + + assertNull(api.deleteInRegion("us-central1", "test-ip1")); + } + + public void testListAddresssResponseIs2xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central1/addresses") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/address_list.json")).build(); + + AddressApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getAddressApiForProject("myproject"); + + assertEquals(api.listFirstPageInRegion("us-central1").toString(), + new ParseAddressListTest().expected().toString()); + } + + public void testListAddresssResponseIs4xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central1/addresses") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + AddressApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getAddressApiForProject("myproject"); + + assertTrue(api.listInRegion("us-central1").concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.java new file mode 100644 index 0000000000..c11d04e96f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.List; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Address; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Lists; + +public class AddressApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String ADDRESS_NAME = "address-api-live-test-address"; + private static final int TIME_WAIT = 30; + + private AddressApi api() { + return api.getAddressApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testInsertAddress() { + + assertRegionOperationDoneSucessfully(api().createInRegion(DEFAULT_REGION_NAME, ADDRESS_NAME), TIME_WAIT); + } + + @Test(groups = "live", dependsOnMethods = "testInsertAddress") + public void testGetAddress() { + Address address = api().getInRegion(DEFAULT_REGION_NAME, ADDRESS_NAME); + assertNotNull(address); + assertEquals(address.getName(), ADDRESS_NAME); + } + + @Test(groups = "live", dependsOnMethods = "testGetAddress") + public void testListAddress() { + + PagedIterable
addresss = api().listInRegion(DEFAULT_REGION_NAME, new ListOptions.Builder() + .filter("name eq " + ADDRESS_NAME)); + + List
addresssAsList = Lists.newArrayList(addresss.concat()); + + assertEquals(addresssAsList.size(), 1); + + } + + @Test(groups = "live", dependsOnMethods = "testListAddress") + public void testDeleteAddress() { + + assertRegionOperationDoneSucessfully(api().deleteInRegion(DEFAULT_REGION_NAME, ADDRESS_NAME), TIME_WAIT); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiExpectTest.java new file mode 100644 index 0000000000..6aaf8fa457 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiExpectTest.java @@ -0,0 +1,226 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseDiskListTest; +import org.jclouds.googlecomputeengine.parse.ParseDiskTest; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class DiskApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + public static final String IMAGE_URL = "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/images/foo"; + + public void testGetDiskResponseIs2xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/disk_get.json")).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getDiskApiForProject("myproject"); + + assertEquals(api.getInZone("us-central1-a", "testimage1"), + new ParseDiskTest().expected()); + } + + public void testGetDiskResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getDiskApiForProject("myproject"); + + assertNull(api.getInZone("us-central1-a", "testimage1")); + } + + public void testInsertDiskResponseIs2xx() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/disk_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertDiskResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, + insertDiskResponse).getDiskApiForProject("myproject"); + + assertEquals(api.createInZone("testimage1", 1, "us-central1-a"), new ParseOperationTest().expected()); + } + + public void testInsertDiskFromImageResponseIs2xx() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks" + + "?sourceImage=" + IMAGE_URL.replaceAll(":", "%3A")) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/disk_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertDiskResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, + insertDiskResponse).getDiskApiForProject("myproject"); + + assertEquals(api.createFromImageWithSizeInZone(IMAGE_URL, "testimage1", 1, "us-central1-a"), new ParseOperationTest().expected()); + } + + public void testCreateSnapshotResponseIs2xx() { + HttpRequest createSnapshotRequest = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks" + + "/testimage1/createSnapshot") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/disk_create_snapshot.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse createSnapshotResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, createSnapshotRequest, + createSnapshotResponse).getDiskApiForProject("myproject"); + + assertEquals(api.createSnapshotInZone("us-central1-a", "testimage1", "test-snap"), new ParseOperationTest().expected()); + } + + public void testCreateSnapshotResponseIs4xx() { + HttpRequest createSnapshotRequest = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks" + + "/testimage1/createSnapshot") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/disk_create_snapshot.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse createSnapshotResponse = HttpResponse.builder().statusCode(404).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, createSnapshotRequest, + createSnapshotResponse).getDiskApiForProject("myproject"); + + assertNull(api.createSnapshotInZone("us-central1-a", "testimage1", "test-snap")); + } + + public void testDeleteDiskResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getDiskApiForProject("myproject"); + + assertEquals(api.deleteInZone("us-central1-a", "testimage1"), + new ParseOperationTest().expected()); + } + + public void testDeleteDiskResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getDiskApiForProject("myproject"); + + assertNull(api.deleteInZone("us-central1-a", "testimage1")); + } + + public void testListDisksResponseIs2xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/disk_list.json")).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getDiskApiForProject("myproject"); + + assertEquals(api.listFirstPageInZone("us-central1-a").toString(), + new ParseDiskListTest().expected().toString()); + } + + public void testListDisksResponseIs4xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + DiskApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getDiskApiForProject("myproject"); + + assertTrue(api.listInZone("us-central1-a").concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java new file mode 100644 index 0000000000..bd26621411 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java @@ -0,0 +1,85 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.List; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Disk; +import org.jclouds.googlecomputeengine.domain.Project; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class DiskApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + public static final String DISK_NAME = "disk-api-live-test-disk"; + public static final int TIME_WAIT = 30; + public static final int sizeGb = 1; + + private DiskApi api() { + return api.getDiskApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testInsertDisk() { + Project project = api.getProjectApi().get(userProject.get()); + assertZoneOperationDoneSucessfully(api().createInZone(DISK_NAME, sizeGb, DEFAULT_ZONE_NAME), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testInsertDisk") + public void testGetDisk() { + + Disk disk = api().getInZone(DEFAULT_ZONE_NAME, DISK_NAME); + assertNotNull(disk); + assertDiskEquals(disk); + } + + @Test(groups = "live", dependsOnMethods = "testGetDisk") + public void testListDisk() { + + PagedIterable disks = api().listInZone(DEFAULT_ZONE_NAME, new ListOptions.Builder() + .filter("name eq " + DISK_NAME)); + + List disksAsList = Lists.newArrayList(disks.concat()); + + assertEquals(disksAsList.size(), 1); + + assertDiskEquals(Iterables.getOnlyElement(disksAsList)); + + } + + @Test(groups = "live", dependsOnMethods = "testListDisk") + public void testDeleteDisk() { + + assertZoneOperationDoneSucessfully(api().deleteInZone(DEFAULT_ZONE_NAME, DISK_NAME), TIME_WAIT); + } + + private void assertDiskEquals(Disk result) { + assertEquals(result.getName(), DISK_NAME); + assertEquals(result.getSizeGb(), sizeGb); + assertEquals(result.getZone(), getDefaultZoneUrl(userProject.get())); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiExpectTest.java new file mode 100644 index 0000000000..7a5759bc23 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiExpectTest.java @@ -0,0 +1,301 @@ +/* + * 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.googlecomputeengine.features; + +import static com.google.common.base.Joiner.on; +import static com.google.common.collect.Iterables.transform; +import static java.lang.String.format; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.jclouds.io.Payloads.newStringPayload; +import static org.jclouds.util.Strings2.toStringAndClose; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +import java.io.IOException; +import java.net.URI; +import java.util.Set; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.options.FirewallOptions; +import org.jclouds.googlecomputeengine.parse.ParseFirewallListTest; +import org.jclouds.googlecomputeengine.parse.ParseFirewallTest; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.io.Payload; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class FirewallApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final HttpRequest GET_FIREWALL_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls/jclouds-test") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static HttpResponse GET_FIREWALL_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/firewall_get.json")).build(); + + public void testGetFirewallResponseIs2xx() throws Exception { + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_FIREWALL_REQUEST, GET_FIREWALL_RESPONSE).getFirewallApiForProject("myproject"); + + assertEquals(api.get("jclouds-test"), new ParseFirewallTest().expected()); + } + + + public static Payload firewallPayloadFirewallOfName(String firewallName, + String networkName, + Set sourceRanges, + Set sourceTags, + Set targetTags, + Set portRanges) throws IOException { + Function addQuotes = new Function() { + @Override + public String apply(String input) { + return "\"" + input + "\""; + } + }; + + String ports = on(",").skipNulls().join(transform(portRanges, addQuotes)); + + Payload payload = newStringPayload( + format(toStringAndClose(FirewallApiExpectTest.class.getResourceAsStream("/firewall_insert.json")), + firewallName, + networkName, + on(",").skipNulls().join(transform(sourceRanges, addQuotes)), + on(",").skipNulls().join(transform(sourceTags, addQuotes)), + on(",").skipNulls().join(transform(targetTags, addQuotes)), + ports, + ports)); + payload.getContentMetadata().setContentType(MediaType.APPLICATION_JSON); + return payload; + } + + + public void testGetFirewallResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls/jclouds-test") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getFirewallApiForProject("myproject"); + + assertNull(api.get("jclouds-test")); + } + + public void testInsertFirewallResponseIs2xx() throws IOException { + + HttpRequest request = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(firewallPayloadFirewallOfName( + "myfw", + "default", + ImmutableSet.of("10.0.1.0/32"), + ImmutableSet.of("tag1"), + ImmutableSet.of("tag2"), + ImmutableSet.of("22", "23-24"))) + .build(); + + HttpResponse insertFirewallResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, request, insertFirewallResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.createInNetwork("myfw", URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/default"), + new FirewallOptions() + .addAllowedRule(Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(22) + .addPortRange(23, 24).build()) + .addSourceTag("tag1") + .addSourceRange("10.0.1.0/32") + .addTargetTag("tag2")), new ParseOperationTest().expected()); + + } + + public void testUpdateFirewallResponseIs2xx() throws IOException { + HttpRequest update = HttpRequest + .builder() + .method("PUT") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/myfw") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(firewallPayloadFirewallOfName( + "myfw", + "default", + ImmutableSet.of("10.0.1.0/32"), + ImmutableSet.of("tag1"), + ImmutableSet.of("tag2"), + ImmutableSet.of("22", "23-24"))) + .build(); + + HttpResponse updateFirewallResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, update, + updateFirewallResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.update("myfw", + new FirewallOptions() + .name("myfw") + .network(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/default")) + .addAllowedRule(Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(22) + .addPortRange(23, 24).build()) + .addSourceTag("tag1") + .addSourceRange("10.0.1.0/32") + .addTargetTag("tag2")), new ParseOperationTest().expected()); + } + + public void testPatchFirewallResponseIs2xx() throws IOException { + HttpRequest update = HttpRequest + .builder() + .method("PATCH") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/myfw") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(firewallPayloadFirewallOfName( + "myfw", + "default", + ImmutableSet.of("10.0.1.0/32"), + ImmutableSet.of("tag1"), + ImmutableSet.of("tag2"), + ImmutableSet.of("22", "23-24"))) + .build(); + + HttpResponse updateFirewallResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, update, + updateFirewallResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.patch("myfw", + new FirewallOptions() + .name("myfw") + .network(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/default")) + .addAllowedRule(Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(22) + .addPortRange(23, 24).build()) + .addSourceTag("tag1") + .addSourceRange("10.0.1.0/32") + .addTargetTag("tag2")), new ParseOperationTest().expected()); + } + + public void testDeleteFirewallResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls/default-allow-internal") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.delete("default-allow-internal"), + new ParseOperationTest().expected()); + } + + public void testDeleteFirewallResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls/default-allow-internal") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getFirewallApiForProject("myproject"); + + assertNull(api.delete("default-allow-internal")); + } + + public void testListFirewallsResponseIs2xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/firewall_list.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.listFirstPage().toString(), + new ParseFirewallListTest().expected().toString()); + } + + public void testListFirewallsResponseIs4xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getFirewallApiForProject("myproject"); + + assertTrue(api.list().concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java new file mode 100644 index 0000000000..24b52428e9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java @@ -0,0 +1,163 @@ +/* + * 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.googlecomputeengine.features; + +import static com.google.common.collect.Iterables.getOnlyElement; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.List; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.FirewallOptions; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; + +public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String FIREWALL_NAME = "firewall-api-live-test-firewall"; + private static final String FIREWALL_NETWORK_NAME = "firewall-api-live-test-network"; + private static final String IPV4_RANGE = "10.0.0.0/8"; + private static final int TIME_WAIT = 30; + + private FirewallApi api() { + return api.getFirewallApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testInsertFirewall() { + + // need to create the network first + assertGlobalOperationDoneSucessfully(api.getNetworkApiForProject(userProject.get()).createInIPv4Range + (FIREWALL_NETWORK_NAME, IPV4_RANGE), TIME_WAIT); + + FirewallOptions firewall = new FirewallOptions() + .addAllowedRule( + Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(22).build()) + .addSourceRange("10.0.0.0/8") + .addSourceTag("tag1") + .addTargetTag("tag2"); + + assertGlobalOperationDoneSucessfully(api().createInNetwork(FIREWALL_NAME, getNetworkUrl(userProject.get(), + FIREWALL_NETWORK_NAME), firewall), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testInsertFirewall") + public void testUpdateFirewall() { + + FirewallOptions firewall = new FirewallOptions() + .name(FIREWALL_NAME) + .network(getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME)) + .addSourceRange("10.0.0.0/8") + .addSourceTag("tag1") + .addTargetTag("tag2") + .allowedRules(ImmutableSet.of( + Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(23) + .build())); + + + assertGlobalOperationDoneSucessfully(api().update(FIREWALL_NAME, firewall), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testUpdateFirewall") + public void testPatchFirewall() { + + FirewallOptions firewall = new FirewallOptions() + .name(FIREWALL_NAME) + .network(getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME)) + .allowedRules(ImmutableSet.of( + Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(22) + .build(), + Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(23) + .build())) + .addSourceRange("10.0.0.0/8") + .addSourceTag("tag1") + .addTargetTag("tag2"); + + assertGlobalOperationDoneSucessfully(api().update(FIREWALL_NAME, firewall), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testPatchFirewall") + public void testGetFirewall() { + + FirewallOptions patchedFirewall = new FirewallOptions() + .name(FIREWALL_NAME) + .network(getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME)) + .allowedRules(ImmutableSet.of( + Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(22) + .build(), + Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(23) + .build())) + .addSourceRange("10.0.0.0/8") + .addSourceTag("tag1") + .addTargetTag("tag2"); + + Firewall firewall = api().get(FIREWALL_NAME); + assertNotNull(firewall); + assertFirewallEquals(firewall, patchedFirewall); + } + + @Test(groups = "live", dependsOnMethods = "testGetFirewall") + public void testListFirewall() { + + PagedIterable firewalls = api().list(new ListOptions.Builder() + .filter("name eq " + FIREWALL_NAME)); + + List firewallsAsList = Lists.newArrayList(firewalls.concat()); + + assertEquals(firewallsAsList.size(), 1); + + } + + @Test(groups = "live", dependsOnMethods = "testListFirewall") + public void testDeleteFirewall() { + + assertGlobalOperationDoneSucessfully(api().delete(FIREWALL_NAME), TIME_WAIT); + assertGlobalOperationDoneSucessfully(api.getNetworkApiForProject(userProject.get()).delete + (FIREWALL_NETWORK_NAME), TIME_WAIT); + } + + private void assertFirewallEquals(Firewall result, FirewallOptions expected) { + assertEquals(result.getName(), expected.getName()); + assertEquals(getOnlyElement(result.getSourceRanges()), getOnlyElement(expected.getSourceRanges())); + assertEquals(getOnlyElement(result.getSourceTags()), getOnlyElement(expected.getSourceTags())); + assertEquals(getOnlyElement(result.getTargetTags()), getOnlyElement(expected.getTargetTags())); + assertEquals(result.getAllowed(), expected.getAllowed()); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiExpectTest.java new file mode 100644 index 0000000000..7fac1d74f9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiExpectTest.java @@ -0,0 +1,158 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.googlecomputeengine.parse.ParseOperationListTest; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class GlobalOperationApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + private static final String OPERATIONS_URL_PREFIX = "https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/operations"; + + public static final HttpRequest GET_GLOBAL_OPERATION_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX + "/operation-1354084865060-4cf88735faeb8-bbbb12cb") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse GET_GLOBAL_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/global_operation.json")).build(); + + public void testGetOperationResponseIs2xx() throws Exception { + + GlobalOperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_GLOBAL_OPERATION_REQUEST, GET_GLOBAL_OPERATION_RESPONSE).getGlobalOperationApiForProject("myproject"); + + assertEquals(operationApi.get("operation-1354084865060-4cf88735faeb8-bbbb12cb"), + new ParseOperationTest().expected()); + } + + public void testGetOperationResponseIs4xx() throws Exception { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_GLOBAL_OPERATION_REQUEST, operationResponse).getGlobalOperationApiForProject("myproject"); + + assertNull(globalOperationApi.get("operation-1354084865060-4cf88735faeb8-bbbb12cb")); + } + + public void testDeleteOperationResponseIs2xx() throws Exception { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(204).build(); + + GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, operationResponse).getGlobalOperationApiForProject("myproject"); + + globalOperationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279"); + } + + public void testDeleteOperationResponseIs4xx() throws Exception { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, operationResponse).getGlobalOperationApiForProject("myproject"); + + globalOperationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279"); + } + + public void testLisOperationWithNoOptionsResponseIs2xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/global_operation_list.json")).build(); + + GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getGlobalOperationApiForProject("myproject"); + + assertEquals(globalOperationApi.listFirstPage().toString(), + new ParseOperationListTest().expected().toString()); + } + + public void testListOperationWithPaginationOptionsResponseIs2xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX + + "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" + + "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" + + "filter=" + + "status%20eq%20done&" + + "maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/global_operation_list.json")).build(); + + GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getGlobalOperationApiForProject("myproject"); + + assertEquals(globalOperationApi.listAtMarker("CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1Mj" + + "I0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz", + new ListOptions.Builder().filter("status eq done").maxResults(3)).toString(), + new ParseOperationListTest().expected().toString()); + } + + public void testListOperationWithPaginationOptionsResponseIs4xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getGlobalOperationApiForProject("myproject"); + + assertTrue(globalOperationApi.list().concat().isEmpty()); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiLiveTest.java new file mode 100644 index 0000000000..704df02ac1 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiLiveTest.java @@ -0,0 +1,91 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.features.ProjectApiLiveTest.addItemToMetadata; +import static org.jclouds.googlecomputeengine.features.ProjectApiLiveTest.deleteItemFromMetadata; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + +public class GlobalOperationApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String METADATA_ITEM_KEY = "operationLiveTestTestProp"; + private static final String METADATA_ITEM_VALUE = "operationLiveTestTestValue"; + private Operation addOperation; + private Operation deleteOperation; + + private GlobalOperationApi api() { + return api.getGlobalOperationApiForProject(userProject.get()); + } + + + @Test(groups = "live") + public void testCreateOperations() { + //create some operations by adding and deleting metadata items + // this will make sure there is stuff to listFirstPage + addOperation = assertGlobalOperationDoneSucessfully(addItemToMetadata(api.getProjectApi(), + userProject.get(), METADATA_ITEM_KEY, METADATA_ITEM_VALUE), 20); + deleteOperation = assertGlobalOperationDoneSucessfully(deleteItemFromMetadata(api + .getProjectApi(), userProject.get(), METADATA_ITEM_KEY), 20); + + assertNotNull(addOperation); + assertNotNull(deleteOperation); + } + + @Test(groups = "live", dependsOnMethods = "testCreateOperations") + public void testGetOperation() { + Operation operation = api().get(addOperation.getName()); + assertNotNull(operation); + assertOperationEquals(operation, this.addOperation); + } + + @Test(groups = "live", dependsOnMethods = "testCreateOperations") + public void testListOperationsWithFiltersAndPagination() { + PagedIterable operations = api().list(new ListOptions.Builder() + .filter("operationType eq setMetadata") + .maxResults(1)); + + // make sure that in spite of having only one result per page we get at least two results + final AtomicInteger counter = new AtomicInteger(); + operations.firstMatch(new Predicate>() { + + @Override + public boolean apply(IterableWithMarker input) { + counter.addAndGet(Iterables.size(input)); + return counter.get() == 2; + } + }); + } + + private void assertOperationEquals(Operation result, Operation expected) { + assertEquals(result.getName(), expected.getName()); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiExpectTest.java new file mode 100644 index 0000000000..6001c24cc9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiExpectTest.java @@ -0,0 +1,159 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseImageListTest; +import org.jclouds.googlecomputeengine.parse.ParseImageTest; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ImageApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final HttpRequest LIST_PROJECT_IMAGES_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_PROJECT_IMAGES_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/image_list.json")).build(); + + public static final HttpRequest LIST_CENTOS_IMAGES_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_CENTOS_IMAGES_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/image_list_single_page.json")).build(); + + public static final HttpRequest LIST_DEBIAN_IMAGES_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_DEBIAN_IMAGES_RESPONSE = + HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/image_list_empty.json")).build(); + + public void testGetImageResponseIs2xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120326") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_get.json")).build(); + + ImageApi imageApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getImageApiForProject("centos-cloud"); + + assertEquals(imageApi.get("centos-6-2-v20120326"), + new ParseImageTest().expected()); + } + + public void testGetImageResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120326") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + ImageApi imageApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getImageApiForProject("centos-cloud"); + + assertNull(imageApi.get("centos-6-2-v20120326")); + } + + public void testDeleteImageResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images/centos-6-2-v20120326") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + ImageApi imageApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getImageApiForProject("myproject"); + + assertEquals(imageApi.delete("centos-6-2-v20120326"), + new ParseOperationTest().expected()); + } + + public void testDeleteImageResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images/centos-6-2-v20120326") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + ImageApi imageApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getImageApiForProject("myproject"); + + assertNull(imageApi.delete("centos-6-2-v20120326")); + } + + public void testListImagesResponseIs2xx() { + + ImageApi imageApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_PROJECT_IMAGES_REQUEST, LIST_PROJECT_IMAGES_RESPONSE).getImageApiForProject + ("myproject"); + + assertEquals(imageApi.listFirstPage().toString(), + new ParseImageListTest().expected().toString()); + } + + public void testListImagesResponseIs4xx() { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + ImageApi imageApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_PROJECT_IMAGES_REQUEST, operationResponse).getImageApiForProject("myproject"); + + assertTrue(imageApi.list().concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java new file mode 100644 index 0000000000..a4922b47c0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java @@ -0,0 +1,74 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.util.Iterator; +import java.util.List; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class ImageApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private Image image; + + private ImageApi api() { + return api.getImageApiForProject("centos-cloud"); + } + + @Test(groups = "live") + public void testListImage() { + + PagedIterable images = api().list(new ListOptions.Builder().maxResults(1)); + + Iterator> pageIterator = images.iterator(); + assertTrue(pageIterator.hasNext()); + + IterableWithMarker singlePageIterator = pageIterator.next(); + List imageAsList = Lists.newArrayList(singlePageIterator); + + assertSame(imageAsList.size(), 1); + + this.image = Iterables.getOnlyElement(imageAsList); + } + + + @Test(groups = "live", dependsOnMethods = "testListImage") + public void testGetImage() { + Image image = api().get(this.image.getName()); + assertNotNull(image); + assertImageEquals(image, this.image); + } + + private void assertImageEquals(Image result, Image expected) { + assertEquals(result.getName(), expected.getName()); + } + +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java new file mode 100644 index 0000000000..f460de661e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java @@ -0,0 +1,410 @@ +/* + * 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.googlecomputeengine.features; + +import static java.net.URI.create; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.jclouds.googlecomputeengine.features.ProjectApiExpectTest.GET_PROJECT_REQUEST; +import static org.jclouds.googlecomputeengine.features.ProjectApiExpectTest.GET_PROJECT_RESPONSE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +import java.net.URI; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.InstanceTemplate; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions.DiskMode; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions.DiskType; +import org.jclouds.googlecomputeengine.parse.ParseInstanceListTest; +import org.jclouds.googlecomputeengine.parse.ParseInstanceSerialOutputTest; +import org.jclouds.googlecomputeengine.parse.ParseInstanceTest; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +@Test(groups = "unit") +public class InstanceApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final HttpRequest GET_INSTANCE_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + + public static final HttpResponse GET_INSTANCE_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/instance_get.json")).build(); + + public static final HttpRequest LIST_INSTANCES_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_INSTANCES_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/instance_list.json")).build(); + + public static final HttpRequest LIST_CENTRAL1B_INSTANCES_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-b/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_CENTRAL1B_INSTANCES_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/instance_list_central1b_empty.json")).build(); + + public static final HttpResponse CREATE_INSTANCE_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/zone_operation.json")).build(); + + + public void testGetInstanceResponseIs2xx() throws Exception { + + InstanceApi api = requestsSendResponses( + requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE, + GET_INSTANCE_REQUEST, GET_INSTANCE_RESPONSE).getInstanceApiForProject("myproject"); + + assertEquals(api.getInZone("us-central1-a", "test-1"), new ParseInstanceTest().expected()); + } + + public void testGetInstanceResponseIs4xx() throws Exception { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_INSTANCE_REQUEST, operationResponse).getInstanceApiForProject("myproject"); + + assertNull(api.getInZone("us-central1-a", "test-1")); + } + + public void testGetInstanceSerialPortOutput() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/serialPort") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/instance_serial_port.json")).build(); + + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.getSerialPortOutputInZone("us-central1-a", "test-1"), new ParseInstanceSerialOutputTest().expected()); + } + + public void testInsertInstanceResponseIs2xxNoOptions() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/instance_insert_simple.json", MediaType.APPLICATION_JSON)) + .build(); + + InstanceApi api = requestsSendResponses(ImmutableMap.of(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_PROJECT_REQUEST, GET_PROJECT_RESPONSE, + requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, + CREATE_INSTANCE_RESPONSE)).getInstanceApiForProject("myproject"); + + InstanceTemplate options = InstanceTemplate.builder().forMachineType("us-central1-a/n1-standard-1") + .addNetworkInterface(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/default")); + + assertEquals(api.createInZone("test-1", "us-central1-a", options), new ParseOperationTest().expected()); + } + + public void testInsertInstanceResponseIs2xxAllOptions() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/instance_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertInstanceResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + InstanceApi api = requestsSendResponses(ImmutableMap.of(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_PROJECT_REQUEST, GET_PROJECT_RESPONSE, + requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, insertInstanceResponse)).getInstanceApiForProject("myproject"); + + InstanceTemplate options = InstanceTemplate.builder().forMachineType("us-central1-a/n1-standard-1") + .addNetworkInterface(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/default"), Instance.NetworkInterface.AccessConfig.Type.ONE_TO_ONE_NAT) + .description("desc") + .addDisk(InstanceTemplate.PersistentDisk.Mode.READ_WRITE, + create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/test"), + true) + .addServiceAccount(Instance.ServiceAccount.builder().email("default").addScopes("myscope").build()) + .addMetadata("aKey", "aValue"); + + assertEquals(api.createInZone("test-0", "us-central1-a", options), + new ParseOperationTest().expected()); + } + + public void testDeleteInstanceResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.deleteInZone("us-central1-a", "test-1"), + new ParseOperationTest().expected()); + } + + public void testDeleteInstanceResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getInstanceApiForProject("myproject"); + + assertNull(api.deleteInZone("us-central1-a", "test-1")); + } + + public void testListInstancesResponseIs2xx() { + + InstanceApi api = requestsSendResponses( + requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE, + LIST_INSTANCES_REQUEST, LIST_INSTANCES_RESPONSE).getInstanceApiForProject("myproject"); + + assertEquals(api.listFirstPageInZone("us-central1-a").toString(), + new ParseInstanceListTest().expected().toString()); + } + + public void testListInstancesResponseIs4xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getInstanceApiForProject("myproject"); + + assertTrue(api.listInZone("us-central1-a").concat().isEmpty()); + } + + public void testSetInstanceMetadataResponseIs2xx() { + HttpRequest setMetadata = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/setMetadata") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/instance_set_metadata.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, setMetadata, setMetadataResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.setMetadataInZone("us-central1-a", "test-1", ImmutableMap.of("foo", "bar"), "efgh"), + new ParseOperationTest().expected()); + } + + public void testSetInstanceMetadataResponseIs4xx() { + HttpRequest setMetadata = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/setMetadata") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/instance_set_metadata.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, setMetadata, setMetadataResponse).getInstanceApiForProject("myproject"); + + assertNull(api.setMetadataInZone("us-central1-a", "test-1", ImmutableMap.of("foo", "bar"), "efgh")); + } + + public void testResetInstanceResponseIs2xx() { + HttpRequest reset = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/reset") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse resetResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, reset, resetResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.resetInZone("us-central1-a", "test-1"), + new ParseOperationTest().expected()); + } + + public void testResetInstanceResponseIs4xx() { + HttpRequest reset = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/reset") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse resetResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, reset, resetResponse).getInstanceApiForProject("myproject"); + + assertNull(api.resetInZone("us-central1-a", "test-1")); + } + + public void testAttachDiskResponseIs2xx() { + HttpRequest attach = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/attachDisk") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/instance_attach_disk.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse attachResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, attach, attachResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.attachDiskInZone("us-central1-a", "test-1", + new AttachDiskOptions() + .mode(DiskMode.READ_ONLY) + .source(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1")) + .type(DiskType.PERSISTENT)), + new ParseOperationTest().expected()); + } + + public void testAttachDiskResponseIs4xx() { + HttpRequest attach = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/attachDisk") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/instance_attach_disk.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse attachResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, attach, attachResponse).getInstanceApiForProject("myproject"); + + assertNull(api.attachDiskInZone("us-central1-a", "test-1", + new AttachDiskOptions() + .mode(DiskMode.READ_ONLY) + .source(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1")) + .type(DiskType.PERSISTENT))); + + } + + public void testDetachDiskResponseIs2xx() { + HttpRequest detach = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/detachDisk" + + "?deviceName=test-disk-1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .build(); + + HttpResponse detachResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation.json")).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, detach, detachResponse).getInstanceApiForProject("myproject"); + + assertEquals(api.detachDiskInZone("us-central1-a", "test-1", "test-disk-1"), + new ParseOperationTest().expected()); + } + + public void testDetachDiskResponseIs4xx() { + HttpRequest detach = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1/detachDisk" + + "?deviceName=test-disk-1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .build(); + + HttpResponse detachResponse = HttpResponse.builder().statusCode(404).build(); + + InstanceApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, detach, detachResponse).getInstanceApiForProject("myproject"); + + assertNull(api.detachDiskInZone("us-central1-a", "test-1", "test-disk-1")); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java new file mode 100644 index 0000000000..a781602538 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java @@ -0,0 +1,240 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.net.URI; +import java.util.List; +import java.util.Properties; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk; +import org.jclouds.googlecomputeengine.domain.Instance.PersistentAttachedDisk; +import org.jclouds.googlecomputeengine.domain.InstanceTemplate; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions.DiskMode; +import org.jclouds.googlecomputeengine.options.AttachDiskOptions.DiskType; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.inject.Module; + +public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String INSTANCE_NETWORK_NAME = "instance-api-live-test-network"; + private static final String INSTANCE_NAME = "instance-api-live-test-instance"; + private static final String BOOT_DISK_NAME = INSTANCE_NAME + "-boot-disk"; + private static final String DISK_NAME = "instance-live-test-disk"; + private static final String IPV4_RANGE = "10.0.0.0/8"; + private static final String METADATA_ITEM_KEY = "instanceLiveTestTestProp"; + private static final String METADATA_ITEM_VALUE = "instanceLiveTestTestValue"; + private static final String ATTACH_DISK_NAME = "instance-api-live-test-attach-disk"; + private static final String ATTACH_DISK_DEVICE_NAME = "attach-disk-1"; + + private static final int TIME_WAIT = 600; + + private InstanceTemplate instance; + + @Override + protected GoogleComputeEngineApi create(Properties props, Iterable modules) { + GoogleComputeEngineApi api = super.create(props, modules); + URI imageUri = api.getImageApiForProject("centos-cloud") + .list(new ListOptions.Builder().filter("name eq centos.*")) + .concat() + .filter(new Predicate() { + @Override + public boolean apply(Image input) { + // filter out all deprecated images + return !(input.getDeprecated().isPresent() && input.getDeprecated().get().getState().isPresent()); + } + }) + .first() + .get() + .getSelfLink(); + instance = InstanceTemplate.builder() + .forMachineType(getDefaultMachineTypeUrl(userProject.get())) + .addNetworkInterface(getNetworkUrl(userProject.get(), INSTANCE_NETWORK_NAME), + Instance.NetworkInterface.AccessConfig.Type.ONE_TO_ONE_NAT) + .addMetadata("mykey", "myvalue") + .description("a description") + .addDisk(InstanceTemplate.PersistentDisk.Mode.READ_WRITE, getDiskUrl(userProject.get(), BOOT_DISK_NAME), + null, true, true) + .addDisk(InstanceTemplate.PersistentDisk.Mode.READ_WRITE, getDiskUrl(userProject.get(), DISK_NAME)) + .image(imageUri); + + return api; + } + + private InstanceApi api() { + return api.getInstanceApiForProject(userProject.get()); + } + + private DiskApi diskApi() { + return api.getDiskApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testInsertInstance() { + + // need to create the network first + assertGlobalOperationDoneSucessfully(api.getNetworkApiForProject(userProject.get()).createInIPv4Range + (INSTANCE_NETWORK_NAME, IPV4_RANGE), TIME_WAIT); + + + assertZoneOperationDoneSucessfully(api.getDiskApiForProject(userProject.get()) + .createFromImageInZone(instance.getImage().toString(), + BOOT_DISK_NAME, + DEFAULT_ZONE_NAME), + TIME_WAIT); + + + assertZoneOperationDoneSucessfully(diskApi().createInZone + ("instance-live-test-disk", 10, DEFAULT_ZONE_NAME), TIME_WAIT); + + assertZoneOperationDoneSucessfully(api().createInZone(INSTANCE_NAME, DEFAULT_ZONE_NAME, instance), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testInsertInstance") + public void testGetInstance() { + + Instance instance = api().getInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME); + assertNotNull(instance); + assertInstanceEquals(instance, this.instance); + } + + @Test(groups = "live", dependsOnMethods = "testListInstance") + public void testSetMetadataForInstance() { + Instance originalInstance = api().getInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME); + assertZoneOperationDoneSucessfully(api().setMetadataInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME, + ImmutableMap.of(METADATA_ITEM_KEY, METADATA_ITEM_VALUE), + originalInstance.getMetadata().getFingerprint()), + TIME_WAIT); + + Instance modifiedInstance = api().getInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME); + + assertTrue(modifiedInstance.getMetadata().getItems().containsKey(METADATA_ITEM_KEY)); + assertEquals(modifiedInstance.getMetadata().getItems().get(METADATA_ITEM_KEY), + METADATA_ITEM_VALUE); + assertNotNull(modifiedInstance.getMetadata().getFingerprint()); + + } + + @Test(groups = "live", dependsOnMethods = "testSetMetadataForInstance") + public void testAttachDiskToInstance() { + assertZoneOperationDoneSucessfully(diskApi().createInZone(ATTACH_DISK_NAME, 1, DEFAULT_ZONE_NAME), TIME_WAIT); + + Instance originalInstance = api().getInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME); + assertZoneOperationDoneSucessfully(api().attachDiskInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME, + new AttachDiskOptions().type(DiskType.PERSISTENT) + .source(getDiskUrl(userProject.get(), ATTACH_DISK_NAME)) + .mode(DiskMode.READ_ONLY) + .deviceName(ATTACH_DISK_DEVICE_NAME)), + TIME_WAIT); + + Instance modifiedInstance = api().getInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME); + + assertTrue(modifiedInstance.getDisks().size() > originalInstance.getDisks().size()); + assertTrue(Iterables.any(modifiedInstance.getDisks(), new Predicate() { + + @Override + public boolean apply(AttachedDisk disk) { + return disk instanceof PersistentAttachedDisk && + ((PersistentAttachedDisk) disk).getDeviceName().isPresent() && + ((PersistentAttachedDisk) disk).getDeviceName().get().equals(ATTACH_DISK_DEVICE_NAME); + } + })); + } + + @Test(groups = "live", dependsOnMethods = "testAttachDiskToInstance") + public void testDetachDiskFromInstance() { + Instance originalInstance = api().getInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME); + assertZoneOperationDoneSucessfully(api().detachDiskInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME, + ATTACH_DISK_DEVICE_NAME), TIME_WAIT); + + Instance modifiedInstance = api().getInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME); + + assertTrue(modifiedInstance.getDisks().size() < originalInstance.getDisks().size()); + + assertZoneOperationDoneSucessfully(diskApi().deleteInZone(DEFAULT_ZONE_NAME, ATTACH_DISK_NAME), TIME_WAIT); + } + + @Test(groups = "live", dependsOnMethods = "testInsertInstance") + public void testListInstance() { + + PagedIterable instances = api().listInZone(DEFAULT_ZONE_NAME, new ListOptions.Builder() + .filter("name eq " + INSTANCE_NAME)); + + List instancesAsList = Lists.newArrayList(instances.concat()); + + assertEquals(instancesAsList.size(), 1); + + assertInstanceEquals(Iterables.getOnlyElement(instancesAsList), instance); + + } + + @Test(groups = "live", dependsOnMethods = "testDetachDiskFromInstance") + public void testResetInstance() { + assertZoneOperationDoneSucessfully(api().resetInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME), + TIME_WAIT); + } + + @Test(groups = "live", dependsOnMethods = "testResetInstance") + public void testDeleteInstance() { + + assertZoneOperationDoneSucessfully(api().deleteInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME), TIME_WAIT); + assertZoneOperationDoneSucessfully(api.getDiskApiForProject(userProject.get()).deleteInZone(DEFAULT_ZONE_NAME, DISK_NAME), + TIME_WAIT); + assertZoneOperationDoneSucessfully(api.getDiskApiForProject(userProject.get()).deleteInZone(DEFAULT_ZONE_NAME, BOOT_DISK_NAME), + TIME_WAIT); + assertGlobalOperationDoneSucessfully(api.getNetworkApiForProject(userProject.get()).delete + (INSTANCE_NETWORK_NAME), TIME_WAIT); + } + + private void assertInstanceEquals(Instance result, InstanceTemplate expected) { + assertEquals(result.getName(), expected.getName()); + assertEquals(result.getMetadata().getItems(), expected.getMetadata()); + } + + @AfterClass(groups = { "integration", "live" }) + protected void tearDownContext() { + try { + waitZoneOperationDone(api().deleteInZone(DEFAULT_ZONE_NAME, INSTANCE_NAME), TIME_WAIT); + waitZoneOperationDone(api.getDiskApiForProject(userProject.get()).deleteInZone(DEFAULT_ZONE_NAME, DISK_NAME), + TIME_WAIT); + waitZoneOperationDone(api.getDiskApiForProject(userProject.get()).deleteInZone(DEFAULT_ZONE_NAME, BOOT_DISK_NAME), + TIME_WAIT); + waitGlobalOperationDone(api.getNetworkApiForProject(userProject.get()).delete + (INSTANCE_NETWORK_NAME), TIME_WAIT); + } catch (Exception e) { + // we don't really care about any exception here, so just delete away. + } + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/MachineTypeApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/MachineTypeApiExpectTest.java new file mode 100644 index 0000000000..35dec083ca --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/MachineTypeApiExpectTest.java @@ -0,0 +1,113 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseMachineTypeListTest; +import org.jclouds.googlecomputeengine.parse.ParseMachineTypeTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class MachineTypeApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final HttpRequest LIST_MACHINE_TYPES_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_MACHINE_TYPES_RESPONSE = HttpResponse.builder() + .statusCode(200) + .payload(staticPayloadFromResource("/machinetype_list.json")) + .build(); + + public static final HttpRequest LIST_CENTRAL1B_MACHINE_TYPES_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b/machineTypes") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_CENTRAL1B_MACHINE_TYPES_RESPONSE = HttpResponse.builder() + .statusCode(200) + .payload(staticPayloadFromResource("/machinetype_list_central1b.json")) + .build(); + + public void testGetMachineTypeResponseIs2xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/machinetype.json")).build(); + + MachineTypeApi machineTypeApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getMachineTypeApiForProject("myproject"); + + assertEquals(machineTypeApi.getInZone("us-central1-a", "n1-standard-1"), + new ParseMachineTypeTest().expected()); + } + + public void testGetMachineTypeResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + MachineTypeApi machineTypeApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getMachineTypeApiForProject("myproject"); + + assertNull(machineTypeApi.getInZone("us-central1-a", "n1-standard-1")); + } + + public void testListMachineTypeNoOptionsResponseIs2xx() throws Exception { + + MachineTypeApi machineTypeApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_MACHINE_TYPES_REQUEST, LIST_MACHINE_TYPES_RESPONSE).getMachineTypeApiForProject + ("myproject"); + + assertEquals(machineTypeApi.listFirstPageInZone("us-central1-a").toString(), + new ParseMachineTypeListTest().expected().toString()); + } + + public void testLisOperationWithPaginationOptionsResponseIs4xx() { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + MachineTypeApi machineTypeApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_MACHINE_TYPES_REQUEST, operationResponse).getMachineTypeApiForProject("myproject"); + + assertTrue(machineTypeApi.listInZone("us-central1-a").concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/MachineTypeApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/MachineTypeApiLiveTest.java new file mode 100644 index 0000000000..d9d00a1a45 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/MachineTypeApiLiveTest.java @@ -0,0 +1,73 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.util.Iterator; +import java.util.List; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.MachineType; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class MachineTypeApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private MachineType machineType; + + private MachineTypeApi api() { + return api.getMachineTypeApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testListMachineType() { + + PagedIterable machineTypes = api().listInZone(DEFAULT_ZONE_NAME, new ListOptions.Builder() + .maxResults(1)); + + Iterator> pageIterator = machineTypes.iterator(); + assertTrue(pageIterator.hasNext()); + + IterableWithMarker singlePageIterator = pageIterator.next(); + List machineTypeAsList = Lists.newArrayList(singlePageIterator); + + assertSame(machineTypeAsList.size(), 1); + + this.machineType = Iterables.getOnlyElement(machineTypeAsList); + } + + + @Test(groups = "live", dependsOnMethods = "testListMachineType") + public void testGetMachineType() { + MachineType machineType = api().getInZone(DEFAULT_ZONE_NAME, this.machineType.getName()); + assertNotNull(machineType); + assertMachineTypeEquals(machineType, this.machineType); + } + + private void assertMachineTypeEquals(MachineType result, MachineType expected) { + assertEquals(result.getName(), expected.getName()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiExpectTest.java new file mode 100644 index 0000000000..1b2d73b770 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiExpectTest.java @@ -0,0 +1,164 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseNetworkListTest; +import org.jclouds.googlecomputeengine.parse.ParseNetworkTest; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class NetworkApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final HttpRequest GET_NETWORK_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse GET_NETWORK_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/network_get.json")).build(); + + public void testGetNetworkResponseIs2xx() throws Exception { + + NetworkApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_NETWORK_REQUEST, GET_NETWORK_RESPONSE).getNetworkApiForProject("myproject"); + + assertEquals(api.get("jclouds-test"), + new ParseNetworkTest().expected()); + } + + public void testGetNetworkResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + NetworkApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getNetworkApiForProject("myproject"); + + assertNull(api.get("jclouds-test")); + } + + public void testInsertNetworkResponseIs2xx() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/networks") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/network_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertNetworkResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + NetworkApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, + insertNetworkResponse).getNetworkApiForProject("myproject"); + + assertEquals(api.createInIPv4Range("test-network", "10.0.0.0/8"), new ParseOperationTest().expected()); + } + + public void testDeleteNetworkResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/jclouds-test") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + NetworkApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getNetworkApiForProject("myproject"); + + assertEquals(api.delete("jclouds-test"), + new ParseOperationTest().expected()); + } + + public void testDeleteNetworkResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/jclouds-test") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + NetworkApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getNetworkApiForProject("myproject"); + + assertNull(api.delete("jclouds-test")); + } + + public void testListNetworksResponseIs2xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/network_list.json")).build(); + + NetworkApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getNetworkApiForProject("myproject"); + + assertEquals(api.listFirstPage().toString(), + new ParseNetworkListTest().expected().toString()); + } + + public void testListNetworksResponseIs4xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + NetworkApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getNetworkApiForProject("myproject"); + + assertTrue(api.list().concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java new file mode 100644 index 0000000000..5b6aa619f1 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java @@ -0,0 +1,83 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.List; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class NetworkApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String NETWORK_NAME = "network-api-live-test-network"; + private static final String IPV4_RANGE = "10.0.0.0/8"; + private static final int TIME_WAIT = 10; + + private NetworkApi api() { + return api.getNetworkApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testInsertNetwork() { + + assertGlobalOperationDoneSucessfully(api().createInIPv4Range(NETWORK_NAME, IPV4_RANGE), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testInsertNetwork") + public void testGetNetwork() { + + Network network = api().get(NETWORK_NAME); + assertNotNull(network); + assertNetworkEquals(network); + } + + @Test(groups = "live", dependsOnMethods = "testGetNetwork") + public void testListNetwork() { + + PagedIterable networks = api().list(new ListOptions.Builder() + .filter("name eq " + NETWORK_NAME)); + + List networksAsList = Lists.newArrayList(networks.concat()); + + assertEquals(networksAsList.size(), 1); + + assertNetworkEquals(Iterables.getOnlyElement(networksAsList)); + + } + + @Test(groups = "live", dependsOnMethods = "testListNetwork") + public void testDeleteNetwork() { + + assertGlobalOperationDoneSucessfully(api().delete(NETWORK_NAME), TIME_WAIT); + } + + private void assertNetworkEquals(Network result) { + assertEquals(result.getName(), NETWORK_NAME); + assertEquals(result.getIPv4Range(), IPV4_RANGE); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiExpectTest.java new file mode 100644 index 0000000000..45e9f6c680 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiExpectTest.java @@ -0,0 +1,96 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.GoogleComputeEngineConstants; +import org.jclouds.googlecomputeengine.domain.Metadata; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseMetadataTest; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.googlecomputeengine.parse.ParseProjectTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + + +@Test(groups = "unit") +public class ProjectApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final String PROJECTS_URL_PREFIX = "https://www.googleapis.com/compute/v1/projects"; + + public static final HttpRequest GET_PROJECT_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint(PROJECTS_URL_PREFIX + "/myproject") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse GET_PROJECT_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/project.json")).build(); + + public void testGetProjectResponseIs2xx() throws Exception { + ProjectApi api = requestsSendResponses(requestForScopes(GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_PROJECT_REQUEST, + GET_PROJECT_RESPONSE).getProjectApi(); + + assertEquals(api.get("myproject"), new ParseProjectTest().expected()); + } + + public void testGetProjectResponseIs4xx() throws Exception { + HttpRequest getProjectRequest = HttpRequest + .builder() + .method("GET") + .endpoint(PROJECTS_URL_PREFIX + "/myproject") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse getProjectResponse = HttpResponse.builder().statusCode(404).build(); + + ProjectApi api = requestsSendResponses(requestForScopes(GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, getProjectRequest, + getProjectResponse).getProjectApi(); + + assertNull(api.get("myproject")); + } + + public void testSetCommonInstanceMetadata() { + HttpRequest setMetadata = HttpRequest + .builder() + .method("POST") + .endpoint(PROJECTS_URL_PREFIX + "/myproject/setCommonInstanceMetadata") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/metadata.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/global_operation.json")).build(); + + ProjectApi api = requestsSendResponses(requestForScopes(GoogleComputeEngineConstants.COMPUTE_SCOPE), + TOKEN_RESPONSE, setMetadata, + setMetadataResponse).getProjectApi(); + Metadata expected = new ParseMetadataTest().expected(); + assertEquals(api.setCommonInstanceMetadata("myproject", expected.getItems(), expected.getFingerprint()), + new ParseOperationTest().expected()); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java new file mode 100644 index 0000000000..150b58ce9e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java @@ -0,0 +1,123 @@ +/* + * 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.googlecomputeengine.features; + + +import static com.google.common.base.Predicates.equalTo; +import static com.google.common.base.Predicates.not; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Project; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +/** + */ +public class ProjectApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String METADATA_ITEM_KEY = "projectLiveTestTestProp"; + private static final String METADATA_ITEM_VALUE = "projectLiveTestTestValue"; + + private ProjectApi projectApi() { + return api.getProjectApi(); + } + + private Project project; + private int initialMetadataSize; + private String initialFingerprint; + + @Test(groups = "live") + public void testGetProjectWhenExists() { + this.project = projectApi().get(userProject.get()); + assertNotNull(project); + assertNotNull(project.getId()); + assertNotNull(project.getName()); + } + + @Test(groups = "live") + public void testGetProjectWhenNotExists() { + Project project = projectApi().get("momma"); + assertNull(project); + } + + @Test(groups = "live", dependsOnMethods = "testGetProjectWhenExists") + public void addItemToMetadata() { + this.initialMetadataSize = project.getCommonInstanceMetadata().getItems().size(); + this.initialFingerprint = this.project.getCommonInstanceMetadata().getFingerprint(); + assertGlobalOperationDoneSucessfully(addItemToMetadata(projectApi(), userProject.get(), METADATA_ITEM_KEY, + METADATA_ITEM_VALUE), 20); + this.project = projectApi().get(userProject.get()); + assertNotNull(project); + assertTrue(this.project.getCommonInstanceMetadata().getItems().containsKey(METADATA_ITEM_KEY), + this.project.toString()); + assertEquals(this.project.getCommonInstanceMetadata().getItems().get(METADATA_ITEM_KEY), + METADATA_ITEM_VALUE); + assertNotNull(this.project.getCommonInstanceMetadata().getFingerprint()); + } + + @Test(groups = "live", dependsOnMethods = "addItemToMetadata") + public void testDeleteItemFromMetadata() { + assertGlobalOperationDoneSucessfully(deleteItemFromMetadata(projectApi(), userProject.get(), METADATA_ITEM_KEY), 20); + this.project = projectApi().get(userProject.get()); + assertNotNull(project); + assertFalse(project.getCommonInstanceMetadata().getItems().containsKey(METADATA_ITEM_KEY)); + assertSame(this.project.getCommonInstanceMetadata().getItems().size(), initialMetadataSize); + assertEquals(this.project.getCommonInstanceMetadata().getFingerprint(), initialFingerprint); + } + + /** + * Adds an item to the Project's metadata + *

+ * Beyond it's use here it is also used as a cheap way of generating Operations to both test the OperationApi and + * the pagination system. + */ + public static Operation addItemToMetadata(ProjectApi projectApi, String projectName, String key, String value) { + Project project = projectApi.get(projectName); + assertNotNull(project); + ImmutableMap.Builder metadataBuilder = ImmutableMap.builder(); + metadataBuilder.putAll(project.getCommonInstanceMetadata().getItems()); + metadataBuilder.put(key, value); + return projectApi.setCommonInstanceMetadata(projectName, metadataBuilder.build(), + project.getCommonInstanceMetadata().getFingerprint()); + } + + /** + * Deletes an item from the Project's metadata + *

+ * Beyond it's use here it is also used as a cheap way of generating Operation's to both test the OperationApi and + * the pagination system. + */ + public static Operation deleteItemFromMetadata(ProjectApi projectApi, String projectName, String key) { + Project project = projectApi.get(projectName); + assertNotNull(project); + ImmutableMap.Builder metadataBuilder = ImmutableMap.builder(); + metadataBuilder.putAll(Maps.filterKeys(project.getCommonInstanceMetadata().getItems(), not(equalTo(key)))); + return projectApi.setCommonInstanceMetadata(projectName, metadataBuilder.build(), + project.getCommonInstanceMetadata().getFingerprint()); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiExpectTest.java new file mode 100644 index 0000000000..f4e32cb11c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiExpectTest.java @@ -0,0 +1,94 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseRegionListTest; +import org.jclouds.googlecomputeengine.parse.ParseRegionTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class RegionApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final String REGIONS_URL_PREFIX = "https://www.googleapis.com/compute/v1/projects/myproject/regions"; + + public static final HttpRequest GET_REGION_REQ = HttpRequest + .builder() + .method("GET") + .endpoint(REGIONS_URL_PREFIX + "/us-central1") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpRequest LIST_REGIONS_REQ = HttpRequest + .builder() + .method("GET") + .endpoint(REGIONS_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_REGIONS_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/region_list.json")).build(); + + public void testGetRegionResponseIs2xx() throws Exception { + + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/region_get.json")).build(); + + RegionApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_REGION_REQ, operationResponse).getRegionApiForProject("myproject"); + + assertEquals(api.get("us-central1"), + new ParseRegionTest().expected()); + } + + public void testGetRegionResponseIs4xx() throws Exception { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + RegionApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_REGION_REQ, operationResponse).getRegionApiForProject("myproject"); + + assertNull(api.get("us-central1")); + } + + public void testListRegionNoOptionsResponseIs2xx() throws Exception { + + RegionApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_REGIONS_REQ, LIST_REGIONS_RESPONSE).getRegionApiForProject("myproject"); + + assertEquals(api.listFirstPage().toString(), + new ParseRegionListTest().expected().toString()); + } + + public void testListRegionWithPaginationOptionsResponseIs4xx() { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + RegionApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_REGIONS_REQ, operationResponse).getRegionApiForProject("myproject"); + + assertTrue(api.list().concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiLiveTest.java new file mode 100644 index 0000000000..6558f3638f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionApiLiveTest.java @@ -0,0 +1,74 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.util.Iterator; +import java.util.List; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Region; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class RegionApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private Region region; + + private RegionApi api() { + return api.getRegionApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testListRegion() { + + PagedIterable regions = api().list(new ListOptions.Builder() + .maxResults(1)); + + Iterator> pageIterator = regions.iterator(); + assertTrue(pageIterator.hasNext()); + + IterableWithMarker singlePageIterator = pageIterator.next(); + List regionAsList = Lists.newArrayList(singlePageIterator); + + assertSame(regionAsList.size(), 1); + + this.region = Iterables.getOnlyElement(regionAsList); + } + + + @Test(groups = "live", dependsOnMethods = "testListRegion") + public void testGetRegion() { + Region region = api().get(this.region.getName()); + assertNotNull(region); + assertRegionEquals(region, this.region); + } + + private void assertRegionEquals(Region result, Region expected) { + assertEquals(result.getName(), expected.getName()); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiExpectTest.java new file mode 100644 index 0000000000..70b9edab24 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiExpectTest.java @@ -0,0 +1,195 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import java.net.URI; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class RegionOperationApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + private static final String OPERATIONS_URL_PREFIX = "https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central1/operations"; + + private static final String DELETE_OPERATIONS_URL_PREFIX = "https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central1/operations"; + + public static final HttpRequest GET_OPERATION_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX + "/operation-1354084865060-4cf88735faeb8-bbbb12cb") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse GET_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/region_operation.json")).build(); + + private Operation expected() { + SimpleDateFormatDateService dateService = new SimpleDateFormatDateService(); + return Operation.builder().id("13053095055850848306") + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central1/operations/operation-1354084865060-4cf88735faeb8" + + "-bbbb12cb")) + .name("operation-1354084865060-4cf88735faeb8-bbbb12cb") + .targetLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central1/addresses/test-address")) + .targetId("13053094017547040099") + .status(Operation.Status.DONE) + .user("user@developer.gserviceaccount.com") + .progress(100) + .insertTime(dateService.iso8601DateParse("2012-11-28T06:41:05.060")) + .startTime(dateService.iso8601DateParse("2012-11-28T06:41:05.142")) + .endTime(dateService.iso8601DateParse("2012-11-28T06:41:06.142")) + .operationType("insert") + .region(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1")) + .build(); + } + + private ListPage expectedList() { + return ListPage.builder() + .kind(Resource.Kind.OPERATION_LIST) + .id("projects/myproject/regions/us-central1/operations") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/operations")) + .addItem(expected()) + .build(); + } + + public void testGetOperationResponseIs2xx() throws Exception { + + RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_OPERATION_REQUEST, GET_OPERATION_RESPONSE).getRegionOperationApiForProject("myproject"); + + assertEquals(regionOperationApi.getInRegion("us-central1", "operation-1354084865060-4cf88735faeb8-bbbb12cb"), + expected()); + } + + public void testGetOperationResponseIs4xx() throws Exception { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_OPERATION_REQUEST, operationResponse).getRegionOperationApiForProject("myproject"); + + assertNull(regionOperationApi.getInRegion("us-central1", "operation-1354084865060-4cf88735faeb8-bbbb12cb")); + } + + public void testDeleteOperationResponseIs2xx() throws Exception { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint(DELETE_OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(204).build(); + + RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, operationResponse).getRegionOperationApiForProject("myproject"); + + regionOperationApi.deleteInRegion("us-central1", "operation-1352178598164-4cdcc9d031510-4aa46279"); + } + + public void testDeleteOperationResponseIs4xx() throws Exception { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint(DELETE_OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, operationResponse).getRegionOperationApiForProject("myproject"); + + regionOperationApi.deleteInRegion("us-central1", "operation-1352178598164-4cdcc9d031510-4aa46279"); + } + + public void testLisOperationWithNoOptionsResponseIs2xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/region_operation_list.json")).build(); + + RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getRegionOperationApiForProject("myproject"); + + assertEquals(regionOperationApi.listFirstPageInRegion("us-central1").toString(), + expectedList().toString()); + } + + public void testListOperationWithPaginationOptionsResponseIs2xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX + + "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" + + "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" + + "filter=" + + "status%20eq%20done&" + + "maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/region_operation_list.json")).build(); + + RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getRegionOperationApiForProject("myproject"); + + assertEquals(regionOperationApi.listAtMarkerInRegion("us-central1", "CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1Mj" + + "I0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz", + new ListOptions.Builder().filter("status eq done").maxResults(3)).toString(), + expectedList().toString()); + } + + public void testListOperationWithPaginationOptionsResponseIs4xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getRegionOperationApiForProject("myproject"); + + assertTrue(regionOperationApi.listInRegion("us-central1").concat().isEmpty()); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiLiveTest.java new file mode 100644 index 0000000000..118d8791e2 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiLiveTest.java @@ -0,0 +1,91 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + +public class RegionOperationApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String ADDRESS_NAME = "region-operations-api-live-test-address"; + private Operation addOperation; + private Operation deleteOperation; + + private RegionOperationApi api() { + return api.getRegionOperationApiForProject(userProject.get()); + } + + private AddressApi addressApi() { + return api.getAddressApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testCreateOperations() { + //create some operations by adding and deleting metadata items + // this will make sure there is stuff to listFirstPage + addOperation = assertRegionOperationDoneSucessfully(addressApi().createInRegion(DEFAULT_REGION_NAME, + ADDRESS_NAME), 20); + deleteOperation = assertRegionOperationDoneSucessfully(addressApi().deleteInRegion(DEFAULT_REGION_NAME, + ADDRESS_NAME), 20); + + assertNotNull(addOperation); + assertNotNull(deleteOperation); + } + + @Test(groups = "live", dependsOnMethods = "testCreateOperations") + public void testGetOperation() { + Operation operation = api().getInRegion(DEFAULT_REGION_NAME, addOperation.getName()); + assertNotNull(operation); + assertOperationEquals(operation, this.addOperation); + } + + @Test(groups = "live", dependsOnMethods = "testCreateOperations") + public void testListOperationsWithFiltersAndPagination() { + PagedIterable operations = api().listInRegion(DEFAULT_REGION_NAME, new ListOptions.Builder() +// .filter("operationType eq insert") + .maxResults(1)); + + // make sure that in spite of having only one result per page we get at least two results + final AtomicInteger counter = new AtomicInteger(); + operations.firstMatch(new Predicate>() { + + @Override + public boolean apply(IterableWithMarker input) { + counter.addAndGet(Iterables.size(input)); + return counter.get() == 2; + } + }); + } + + private void assertOperationEquals(Operation result, Operation expected) { + assertEquals(result.getName(), expected.getName()); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiExpectTest.java new file mode 100644 index 0000000000..6e9fa6e799 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiExpectTest.java @@ -0,0 +1,175 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +import java.net.URI; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.options.RouteOptions; +import org.jclouds.googlecomputeengine.parse.ParseOperationTest; +import org.jclouds.googlecomputeengine.parse.ParseRouteListTest; +import org.jclouds.googlecomputeengine.parse.ParseRouteTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class RouteApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public void testGetRouteResponseIs2xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/routes/default-route-c99ebfbed0e1f375") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/route_get.json")).build(); + + RouteApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getRouteApiForProject("myproject"); + + assertEquals(api.get("default-route-c99ebfbed0e1f375"), + new ParseRouteTest().expected()); + } + + public void testGetRouteResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/routes/default-route-c99ebfbed0e1f375") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + RouteApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getRouteApiForProject("myproject"); + + assertNull(api.get("default-route-c99ebfbed0e1f375")); + } + + public void testInsertRouteResponseIs2xx() { + HttpRequest insert = HttpRequest + .builder() + + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1/projects/myproject/global/routes") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/route_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertRouteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/global_operation.json")).build(); + + RouteApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, + insertRouteResponse).getRouteApiForProject("myproject"); + + assertEquals(api.createInNetwork("default-route-c99ebfbed0e1f375", + URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default"), + new RouteOptions().addTag("fooTag") + .addTag("barTag") + .description("Default route to the virtual network.") + .destRange("10.240.0.0/16") + .priority(1000) + .nextHopNetwork(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default")) + ), new ParseOperationTest().expected()); + } + + public void testDeleteRouteResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/routes/default-route-c99ebfbed0e1f375") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/global_operation.json")).build(); + + RouteApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getRouteApiForProject("myproject"); + + assertEquals(api.delete("default-route-c99ebfbed0e1f375"), + new ParseOperationTest().expected()); + } + + public void testDeleteRouteResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/routes/default-route-c99ebfbed0e1f375") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + RouteApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getRouteApiForProject("myproject"); + + assertNull(api.delete("default-route-c99ebfbed0e1f375")); + } + + public void testListRoutesResponseIs2xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/routes") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/route_list.json")).build(); + + RouteApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getRouteApiForProject("myproject"); + + assertEquals(api.listFirstPage().toString(), + new ParseRouteListTest().expected().toString()); + } + + public void testListRoutesResponseIs4xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/routes") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + RouteApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getRouteApiForProject("myproject"); + + assertTrue(api.list().concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java new file mode 100644 index 0000000000..8875e7e419 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java @@ -0,0 +1,96 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.List; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Route; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.googlecomputeengine.options.RouteOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class RouteApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String DEST_RANGE = "20.10.0.0/16"; + private static final String IPV4_RANGE = "10.0.0.0/8"; + private static final String ROUTE_NAME = "route-api-live-test-route"; + private static final String ROUTE_NETWORK_NAME = "route-api-live-test-network"; + public static final int TIME_WAIT = 30; + + private RouteApi api() { + return api.getRouteApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testInsertRoute() { + assertGlobalOperationDoneSucessfully(api.getNetworkApiForProject(userProject.get()).createInIPv4Range + (ROUTE_NETWORK_NAME, IPV4_RANGE), TIME_WAIT); + assertGlobalOperationDoneSucessfully(api().createInNetwork(ROUTE_NAME, + getNetworkUrl(userProject.get(), ROUTE_NETWORK_NAME), + new RouteOptions().addTag("footag") + .addTag("bartag") + .description("RouteApi Live Test") + .destRange(DEST_RANGE) + .priority(1000) + .nextHopGateway(getGatewayUrl(userProject.get(), DEFAULT_GATEWAY_NAME))), + TIME_WAIT); + } + + @Test(groups = "live", dependsOnMethods = "testInsertRoute") + public void testGetRoute() { + Route route = api().get(ROUTE_NAME); + + assertNotNull(route); + assertRouteEquals(route); + } + + @Test(groups = "live", dependsOnMethods = "testGetRoute") + public void testListRoute() { + + PagedIterable routes = api().list(new ListOptions() + .filter("name eq " + ROUTE_NAME)); + + List routesAsList = Lists.newArrayList(routes.concat()); + + assertEquals(routesAsList.size(), 1); + + assertRouteEquals(Iterables.getOnlyElement(routesAsList)); + + } + + @Test(groups = "live", dependsOnMethods = "testListRoute") + public void testDeleteRoute() { + assertGlobalOperationDoneSucessfully(api().delete(ROUTE_NAME), TIME_WAIT); + assertGlobalOperationDoneSucessfully(api.getNetworkApiForProject(userProject.get()) + .delete(ROUTE_NETWORK_NAME), TIME_WAIT); + } + + private void assertRouteEquals(Route result) { + assertEquals(result.getName(), ROUTE_NAME); + assertEquals(result.getDestRange(), DEST_RANGE); + assertEquals(result.getNextHopGateway().orNull(), getGatewayUrl(userProject.get(), DEFAULT_GATEWAY_NAME)); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiExpectTest.java new file mode 100644 index 0000000000..4caedc552e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiExpectTest.java @@ -0,0 +1,94 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseSnapshotListTest; +import org.jclouds.googlecomputeengine.parse.ParseSnapshotTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class SnapshotApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final String SNAPSHOT_URL_PREFIX = "https://www.googleapis.com/compute/v1/projects/myproject/global/snapshots"; + + public static final HttpRequest GET_SNAPSHOT_REQ = HttpRequest + .builder() + .method("GET") + .endpoint(SNAPSHOT_URL_PREFIX + "/test-snap") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpRequest LIST_SNAPSHOTS_REQ = HttpRequest + .builder() + .method("GET") + .endpoint(SNAPSHOT_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_SNAPSHOTS_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/snapshot_list.json")).build(); + + public void testGetSnapshotResponseIs2xx() throws Exception { + + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/snapshot_get.json")).build(); + + SnapshotApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_SNAPSHOT_REQ, operationResponse).getSnapshotApiForProject("myproject"); + + assertEquals(api.get("test-snap"), + new ParseSnapshotTest().expected()); + } + + public void testGetSnapshotResponseIs4xx() throws Exception { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + SnapshotApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_SNAPSHOT_REQ, operationResponse).getSnapshotApiForProject("myproject"); + + assertNull(api.get("test-snap")); + } + + public void testListSnapshotNoOptionsResponseIs2xx() throws Exception { + + SnapshotApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_SNAPSHOTS_REQ, LIST_SNAPSHOTS_RESPONSE).getSnapshotApiForProject("myproject"); + + assertEquals(api.listFirstPage().toString(), + new ParseSnapshotListTest().expected().toString()); + } + + public void testListSnapshotWithPaginationOptionsResponseIs4xx() { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + SnapshotApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_SNAPSHOTS_REQ, operationResponse).getSnapshotApiForProject("myproject"); + + assertTrue(api.list().concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java new file mode 100644 index 0000000000..3f833a9a0a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java @@ -0,0 +1,92 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.features.DiskApiLiveTest.TIME_WAIT; +import static org.testng.Assert.assertEquals; + +import java.util.List; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Disk; +import org.jclouds.googlecomputeengine.domain.Snapshot; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class SnapshotApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String DISK_NAME = "snapshot-api-live-test-disk"; + private static final String SNAPSHOT_NAME = "snapshot-api-live-test-snapshot"; + + private Disk disk; + private SnapshotApi api() { + return api.getSnapshotApiForProject(userProject.get()); + } + + private DiskApi diskApi() { + return api.getDiskApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testCreateSnapshot() { + assertZoneOperationDoneSucessfully(diskApi().createInZone(DISK_NAME, 1, DEFAULT_ZONE_NAME), TIME_WAIT); + disk = diskApi().getInZone(DEFAULT_ZONE_NAME, DISK_NAME); + + assertZoneOperationDoneSucessfully(diskApi().createSnapshotInZone(DEFAULT_ZONE_NAME, DISK_NAME, SNAPSHOT_NAME), + TIME_WAIT); + } + + @Test(groups = "live", dependsOnMethods = "testCreateSnapshot") + public void testGetSnapshot() { + Snapshot snapshot = api().get(SNAPSHOT_NAME); + + assertEquals(snapshot.getName(), SNAPSHOT_NAME); + assertSnapshotEquals(snapshot); + } + + @Test(groups = "live", dependsOnMethods = "testGetSnapshot") + public void testListSnapshot() { + + PagedIterable snapshots = api().list(new ListOptions.Builder() + .filter("name eq " + SNAPSHOT_NAME)); + + List snapshotsAsList = Lists.newArrayList(snapshots.concat()); + + assertEquals(snapshotsAsList.size(), 1); + + assertSnapshotEquals(Iterables.getOnlyElement(snapshotsAsList)); + } + + @Test(groups = "live", dependsOnMethods = "testListSnapshot") + public void testDeleteDisk() { + + assertZoneOperationDoneSucessfully(diskApi().deleteInZone(DEFAULT_ZONE_NAME, DISK_NAME), TIME_WAIT); + assertGlobalOperationDoneSucessfully(api().delete(SNAPSHOT_NAME), TIME_WAIT); + } + + private void assertSnapshotEquals(Snapshot result) { + assertEquals(result.getName(), SNAPSHOT_NAME); + assertEquals(result.getSourceDisk().orNull(), disk.getSelfLink()); + assertEquals(result.getSizeGb(), disk.getSizeGb()); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneApiExpectTest.java new file mode 100644 index 0000000000..0a26bd6978 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneApiExpectTest.java @@ -0,0 +1,97 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.parse.ParseZoneListTest; +import org.jclouds.googlecomputeengine.parse.ParseZoneTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ZoneApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public static final String ZONES_URL_PREFIX = "https://www.googleapis.com/compute/v1/projects/myproject/zones"; + + public static final HttpRequest GET_ZONE_REQ = HttpRequest + .builder() + .method("GET") + .endpoint(ZONES_URL_PREFIX + "/us-central1-a") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpRequest LIST_ZONES_REQ = HttpRequest + .builder() + .method("GET") + .endpoint(ZONES_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse LIST_ZONES_SHORT_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/zone_list_short.json")).build(); + + public static final HttpResponse LIST_ZONES_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/zone_list.json")).build(); + + public void testGetZoneResponseIs2xx() throws Exception { + + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_get.json")).build(); + + ZoneApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_ZONE_REQ, operationResponse).getZoneApiForProject("myproject"); + + assertEquals(api.get("us-central1-a"), + new ParseZoneTest().expected()); + } + + public void testGetZoneResponseIs4xx() throws Exception { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + ZoneApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_ZONE_REQ, operationResponse).getZoneApiForProject("myproject"); + + assertNull(api.get("us-central1-a")); + } + + public void testListZoneNoOptionsResponseIs2xx() throws Exception { + + ZoneApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_ZONES_REQ, LIST_ZONES_RESPONSE).getZoneApiForProject("myproject"); + + assertEquals(api.listFirstPage().toString(), + new ParseZoneListTest().expected().toString()); + } + + public void testListZoneWithPaginationOptionsResponseIs4xx() { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + ZoneApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, LIST_ZONES_REQ, operationResponse).getZoneApiForProject("myproject"); + + assertTrue(api.list().concat().isEmpty()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneApiLiveTest.java new file mode 100644 index 0000000000..934e93aba8 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneApiLiveTest.java @@ -0,0 +1,74 @@ +/* + * 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.googlecomputeengine.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.util.Iterator; +import java.util.List; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class ZoneApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private Zone zone; + + private ZoneApi api() { + return api.getZoneApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testListZone() { + + PagedIterable zones = api().list(new ListOptions.Builder() + .maxResults(1)); + + Iterator> pageIterator = zones.iterator(); + assertTrue(pageIterator.hasNext()); + + IterableWithMarker singlePageIterator = pageIterator.next(); + List zoneAsList = Lists.newArrayList(singlePageIterator); + + assertSame(zoneAsList.size(), 1); + + this.zone = Iterables.getOnlyElement(zoneAsList); + } + + + @Test(groups = "live", dependsOnMethods = "testListZone") + public void testGetZone() { + Zone zone = api().get(this.zone.getName()); + assertNotNull(zone); + assertZoneEquals(zone, this.zone); + } + + private void assertZoneEquals(Zone result, Zone expected) { + assertEquals(result.getName(), expected.getName()); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiExpectTest.java new file mode 100644 index 0000000000..fc23e1b79a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiExpectTest.java @@ -0,0 +1,193 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import java.net.URI; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ZoneOperationApiExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + private static final String OPERATIONS_URL_PREFIX = "https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/operations"; + + public static final HttpRequest GET_ZONE_OPERATION_REQUEST = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX + "/operation-1354084865060-4cf88735faeb8-bbbb12cb") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + public static final HttpResponse GET_ZONE_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200) + .payload(staticPayloadFromResource("/zone_operation.json")).build(); + + private Operation expected() { + SimpleDateFormatDateService dateService = new SimpleDateFormatDateService(); + return Operation.builder().id("13053095055850848306") + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8" + + "-bbbb12cb")) + .name("operation-1354084865060-4cf88735faeb8-bbbb12cb") + .targetLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance")) + .targetId("13053094017547040099") + .status(Operation.Status.DONE) + .user("user@developer.gserviceaccount.com") + .progress(100) + .insertTime(dateService.iso8601DateParse("2012-11-28T06:41:05.060")) + .startTime(dateService.iso8601DateParse("2012-11-28T06:41:05.142")) + .endTime(dateService.iso8601DateParse("2012-11-28T06:41:06.142")) + .operationType("insert") + .zone(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a")) + .build(); + } + + private ListPage expectedList() { + return ListPage.builder() + .kind(Resource.Kind.OPERATION_LIST) + .id("projects/myproject/zones/us-central1-a/operations") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations")) + .addItem(expected()) + .build(); + } + + public void testGetOperationResponseIs2xx() throws Exception { + + ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_ZONE_OPERATION_REQUEST, GET_ZONE_OPERATION_RESPONSE).getZoneOperationApiForProject("myproject"); + + assertEquals(zoneOperationApi.getInZone("us-central1-a", "operation-1354084865060-4cf88735faeb8-bbbb12cb"), + expected()); + } + + public void testGetOperationResponseIs4xx() throws Exception { + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, GET_ZONE_OPERATION_REQUEST, operationResponse).getZoneOperationApiForProject("myproject"); + + assertNull(zoneOperationApi.getInZone("us-central1-a", "operation-1354084865060-4cf88735faeb8-bbbb12cb")); + } + + public void testDeleteOperationResponseIs2xx() throws Exception { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(204).build(); + + ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, operationResponse).getZoneOperationApiForProject("myproject"); + + zoneOperationApi.deleteInZone("us-central1-a", "operation-1352178598164-4cdcc9d031510-4aa46279"); + } + + public void testDeleteOperationResponseIs4xx() throws Exception { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, operationResponse).getZoneOperationApiForProject("myproject"); + + zoneOperationApi.deleteInZone("us-central1-a", "operation-1352178598164-4cdcc9d031510-4aa46279"); + } + + public void testListOperationWithNoOptionsResponseIs2xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation_list.json")).build(); + + ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getZoneOperationApiForProject("myproject"); + + assertEquals(zoneOperationApi.listFirstPageInZone("us-central1-a").toString(), + expectedList().toString()); + } + + public void testListOperationWithPaginationOptionsResponseIs2xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX + + "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" + + "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" + + "filter=" + + "status%20eq%20done&" + + "maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/zone_operation_list.json")).build(); + + ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getZoneOperationApiForProject("myproject"); + + assertEquals(zoneOperationApi.listAtMarkerInZone("us-central1-a", + "CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1Mj" + + "I0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz", + new ListOptions.Builder().filter("status eq done").maxResults(3)).toString(), + expectedList().toString()); + } + + public void testListOperationWithPaginationOptionsResponseIs4xx() { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint(OPERATIONS_URL_PREFIX) + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getZoneOperationApiForProject("myproject"); + + assertTrue(zoneOperationApi.listInZone("us-central1-a").concat().isEmpty()); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiLiveTest.java new file mode 100644 index 0000000000..4d30272d63 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiLiveTest.java @@ -0,0 +1,90 @@ +/* + * 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.googlecomputeengine.features; + +import static org.jclouds.googlecomputeengine.features.DiskApiLiveTest.TIME_WAIT; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + +public class ZoneOperationApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { + + private static final String DISK_NAME = "zone-operations-api-live-test-disk"; + private Operation addOperation; + private Operation deleteOperation; + + private ZoneOperationApi api() { + return api.getZoneOperationApiForProject(userProject.get()); + } + + private DiskApi diskApi() { + return api.getDiskApiForProject(userProject.get()); + } + + @Test(groups = "live") + public void testCreateOperations() { + //create some operations by creating and deleting a disk + // this will make sure there is stuff to listFirstPage + addOperation = assertZoneOperationDoneSucessfully(diskApi().createInZone(DISK_NAME, 1, DEFAULT_ZONE_NAME), TIME_WAIT); + deleteOperation = assertZoneOperationDoneSucessfully(diskApi().deleteInZone(DEFAULT_ZONE_NAME, DISK_NAME), TIME_WAIT); + + assertNotNull(addOperation); + assertNotNull(deleteOperation); + } + + @Test(groups = "live", dependsOnMethods = "testCreateOperations") + public void testGetOperation() { + Operation operation = api().getInZone(DEFAULT_ZONE_NAME, addOperation.getName()); + assertNotNull(operation); + assertOperationEquals(operation, this.addOperation); + } + + @Test(groups = "live", dependsOnMethods = "testCreateOperations") + public void testListOperationsWithFiltersAndPagination() { + PagedIterable operations = api().listInZone(DEFAULT_ZONE_NAME, new ListOptions.Builder() +// .filter("operationType eq insert") + .maxResults(1)); + + // make sure that in spite of having only one result per page we get at least two results + final AtomicInteger counter = new AtomicInteger(); + operations.firstMatch(new Predicate>() { + + @Override + public boolean apply(IterableWithMarker input) { + counter.addAndGet(Iterables.size(input)); + return counter.get() == 2; + } + }); + } + + private void assertOperationEquals(Operation result, Operation expected) { + assertEquals(result.getName(), expected.getName()); + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeededTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeededTest.java new file mode 100644 index 0000000000..292f9d4e27 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeededTest.java @@ -0,0 +1,132 @@ +/* + * 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.googlecomputeengine.functions; + +import static com.google.common.base.Optional.fromNullable; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.features.GlobalOperationApi; +import org.jclouds.googlecomputeengine.features.NetworkApi; +import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; + +public class CreateNetworkIfNeededTest { + + @Test + public void testApply() { + final GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + final NetworkApi nwApi = createMock(NetworkApi.class); + final GlobalOperationApi globalApi = createMock(GlobalOperationApi.class); + + Network network = Network.builder().IPv4Range("0.0.0.0/0") + .id("abcd").name("this-network") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/this-network")) + .build(); + + Operation createOp = createMock(Operation.class); + + final Supplier userProject = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + expect(api.getNetworkApiForProject(userProject.get())).andReturn(nwApi).atLeastOnce(); + expect(api.getGlobalOperationApiForProject(userProject.get())).andReturn(globalApi).atLeastOnce(); + + expect(nwApi.createInIPv4Range("this-network", "0.0.0.0/0")) + .andReturn(createOp); + expect(globalApi.get("create-op")).andReturn(createOp); + expect(nwApi.get("this-network")).andReturn(null); + expect(nwApi.get("this-network")).andReturn(network); + + expect(createOp.getName()).andReturn("create-op"); + expect(createOp.getStatus()).andReturn(Operation.Status.DONE); + expect(createOp.getHttpError()).andReturn(fromNullable((HttpResponse)null)); + replay(api, nwApi, createOp, globalApi); + + NetworkAndAddressRange input = new NetworkAndAddressRange("this-network", "0.0.0.0/0", null); + + GlobalOperationDonePredicate pred = new GlobalOperationDonePredicate(api, userProject); + + CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l); + + assertEquals(creator.apply(input), network); + + verify(api, nwApi, globalApi, createOp); + } + + @Test + public void testApplyWithGateway() { + final GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + final NetworkApi nwApi = createMock(NetworkApi.class); + final GlobalOperationApi globalApi = createMock(GlobalOperationApi.class); + + Network network = Network.builder().IPv4Range("0.0.0.0/0") + .id("abcd").name("this-network").gatewayIPv4("1.2.3.4") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/this-network")) + .build(); + + Operation createOp = createMock(Operation.class); + + final Supplier userProject = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + expect(api.getNetworkApiForProject(userProject.get())).andReturn(nwApi).atLeastOnce(); + expect(api.getGlobalOperationApiForProject(userProject.get())).andReturn(globalApi).atLeastOnce(); + + expect(nwApi.createInIPv4RangeWithGateway("this-network", "0.0.0.0/0", "1.2.3.4")) + .andReturn(createOp); + expect(globalApi.get("create-op")).andReturn(createOp); + expect(nwApi.get("this-network")).andReturn(null); + expect(nwApi.get("this-network")).andReturn(network); + + expect(createOp.getName()).andReturn("create-op"); + expect(createOp.getStatus()).andReturn(Operation.Status.DONE); + expect(createOp.getHttpError()).andReturn(fromNullable((HttpResponse)null)); + replay(api, nwApi, createOp, globalApi); + + NetworkAndAddressRange input = new NetworkAndAddressRange("this-network", "0.0.0.0/0", "1.2.3.4"); + + GlobalOperationDonePredicate pred = new GlobalOperationDonePredicate(api, userProject); + + CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l); + + assertEquals(creator.apply(input), network); + + verify(api, nwApi, globalApi, createOp); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/handlers/GoogleComputeEngineErrorHandlerTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/handlers/GoogleComputeEngineErrorHandlerTest.java new file mode 100644 index 0000000000..1d88d5a912 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/handlers/GoogleComputeEngineErrorHandlerTest.java @@ -0,0 +1,92 @@ +/* + * 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.googlecomputeengine.handlers; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reportMatcher; +import static org.easymock.EasyMock.verify; + +import java.net.URI; + +import org.easymock.IArgumentMatcher; +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "GoogleComputeErrorHandlerTest") +public class GoogleComputeEngineErrorHandlerTest { + + @Test + public void test409MakesIllegalStateException() { + assertCodeMakes( + "POST", + URI.create("https://www.googleapis.com/compute/v1"), + 409, + "HTTP/1.1 409 Conflict", + "\"{\"code\":\"InvalidState\",\"message\":\"An incompatible transition has already been queued for this" + + " resource\"}\"", + IllegalStateException.class); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content, + Class expected) { + assertCodeMakes(method, uri, statusCode, message, "application/json", content, expected); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType, + String content, Class expected) { + + GoogleComputeEngineErrorHandler function = new GoogleComputeEngineErrorHandler(); + + HttpCommand command = createMock(HttpCommand.class); + HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build(); + HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build(); + response.getPayload().getContentMetadata().setContentType(contentType); + + expect(command.getCurrentRequest()).andReturn(request).atLeastOnce(); + command.setException(classEq(expected)); + + replay(command); + + function.handleError(command, response); + + verify(command); + } + + public static Exception classEq(final Class in) { + reportMatcher(new IArgumentMatcher() { + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("classEq("); + buffer.append(in); + buffer.append(")"); + } + + @Override + public boolean matches(Object arg) { + return arg.getClass() == in; + } + + }); + return null; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiExpectTest.java new file mode 100644 index 0000000000..1766de88cf --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiExpectTest.java @@ -0,0 +1,31 @@ +/* + * 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.googlecomputeengine.internal; + +import java.util.Properties; + +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; + +public class BaseGoogleComputeEngineApiExpectTest extends BaseGoogleComputeEngineExpectTest { + + @Override + protected Properties setupProperties() { + Properties properties = super.setupProperties(); + properties.put("google-compute-engine.identity", "myproject"); + return properties; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java new file mode 100644 index 0000000000..2c018ebcbc --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java @@ -0,0 +1,160 @@ +/* + * 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.googlecomputeengine.internal; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.jclouds.util.Predicates2.retry; +import static org.testng.Assert.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.net.URI; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicReference; + +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Operation; + +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.util.concurrent.Atomics; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + + +public class BaseGoogleComputeEngineApiLiveTest extends BaseApiLiveTest { + + protected static final String API_URL_PREFIX = "https://www.googleapis.com/compute/v1/projects/"; + protected static final String ZONE_API_URL_SUFFIX = "/zones/"; + protected static final String DEFAULT_ZONE_NAME = "us-central1-a"; + + protected static final String REGION_API_URL_SUFFIX = "/region/"; + protected static final String DEFAULT_REGION_NAME = "us-central1"; + + protected static final String NETWORK_API_URL_SUFFIX = "/global/networks/"; + protected static final String DEFAULT_NETWORK_NAME = "live-test-network"; + + protected static final String MACHINE_TYPE_API_URL_SUFFIX = "/machineTypes/"; + protected static final String DEFAULT_MACHINE_TYPE_NAME = "n1-standard-1"; + + protected static final String GATEWAY_API_URL_SUFFIX = "/global/gateways/"; + protected static final String DEFAULT_GATEWAY_NAME = "default-internet-gateway"; + + protected static final String GOOGLE_PROJECT = "google"; + + protected Supplier userProject; + protected Predicate> globalOperationDonePredicate; + protected Predicate> regionOperationDonePredicate; + protected Predicate> zoneOperationDonePredicate; + + + public BaseGoogleComputeEngineApiLiveTest() { + provider = "google-compute-engine"; + } + + protected GoogleComputeEngineApi create(Properties props, Iterable modules) { + Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); + userProject = injector.getInstance(Key.get(new TypeLiteral>() { + }, UserProject.class)); + globalOperationDonePredicate = injector.getInstance(Key.get(new TypeLiteral>>() { + }, Names.named("global"))); + regionOperationDonePredicate = injector.getInstance(Key.get(new TypeLiteral>>() { + }, Names.named("region"))); + zoneOperationDonePredicate = injector.getInstance(Key.get(new TypeLiteral>>() { + }, Names.named("zone"))); + return injector.getInstance(GoogleComputeEngineApi.class); + } + + protected Operation assertGlobalOperationDoneSucessfully(Operation operation, long maxWaitSeconds) { + operation = waitGlobalOperationDone(operation, maxWaitSeconds); + assertEquals(operation.getStatus(), Operation.Status.DONE); + assertTrue(operation.getErrors().isEmpty()); + return operation; + } + + protected Operation waitGlobalOperationDone(Operation operation, long maxWaitSeconds) { + return waitOperationDone(globalOperationDonePredicate, operation, maxWaitSeconds); + } + + protected Operation assertRegionOperationDoneSucessfully(Operation operation, long maxWaitSeconds) { + operation = waitRegionOperationDone(operation, maxWaitSeconds); + assertEquals(operation.getStatus(), Operation.Status.DONE); + assertTrue(operation.getErrors().isEmpty()); + return operation; + } + + protected Operation waitRegionOperationDone(Operation operation, long maxWaitSeconds) { + return waitOperationDone(regionOperationDonePredicate, operation, maxWaitSeconds); + } + + protected Operation assertZoneOperationDoneSucessfully(Operation operation, long maxWaitSeconds) { + operation = waitZoneOperationDone(operation, maxWaitSeconds); + assertEquals(operation.getStatus(), Operation.Status.DONE); + assertTrue(operation.getErrors().isEmpty()); + return operation; + } + + protected Operation waitZoneOperationDone(Operation operation, long maxWaitSeconds) { + return waitOperationDone(zoneOperationDonePredicate, operation, maxWaitSeconds); + } + + protected URI getDefaultZoneUrl(String project) { + return getZoneUrl(project, DEFAULT_ZONE_NAME); + } + + protected URI getZoneUrl(String project, String zone) { + return URI.create(API_URL_PREFIX + project + ZONE_API_URL_SUFFIX + zone); + } + + protected URI getDefaultNetworkUrl(String project) { + return getNetworkUrl(project, DEFAULT_NETWORK_NAME); + } + + protected URI getNetworkUrl(String project, String network) { + return URI.create(API_URL_PREFIX + project + NETWORK_API_URL_SUFFIX + network); + } + + protected URI getGatewayUrl(String project, String gateway) { + return URI.create(API_URL_PREFIX + project + GATEWAY_API_URL_SUFFIX + gateway); + } + + protected URI getDefaultMachineTypeUrl(String project) { + return getMachineTypeUrl(project, DEFAULT_MACHINE_TYPE_NAME); + } + + protected URI getMachineTypeUrl(String project, String machineType) { + return URI.create(API_URL_PREFIX + project + ZONE_API_URL_SUFFIX + + DEFAULT_ZONE_NAME + MACHINE_TYPE_API_URL_SUFFIX + machineType); + } + + protected URI getDiskUrl(String project, String diskName) { + return URI.create(API_URL_PREFIX + project + ZONE_API_URL_SUFFIX + + DEFAULT_ZONE_NAME + "/disks/" + diskName); + } + + protected static Operation waitOperationDone(Predicate> operationDonePredicate, + Operation operation, long maxWaitSeconds) { + AtomicReference operationReference = Atomics.newReference(operation); + retry(operationDonePredicate, maxWaitSeconds, 1, SECONDS).apply(operationReference); + return operationReference.get(); + } +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineExpectTest.java new file mode 100644 index 0000000000..47a42458c9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineExpectTest.java @@ -0,0 +1,195 @@ +/* + * 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.googlecomputeengine.internal; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.base.Throwables.propagate; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.jclouds.crypto.Pems.privateKeySpec; +import static org.jclouds.crypto.Pems.publicKeySpec; +import static org.jclouds.crypto.PemsTest.PRIVATE_KEY; +import static org.jclouds.crypto.PemsTest.PUBLIC_KEY; + +import java.io.IOException; +import java.net.URI; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.collect.PagedIterables; +import org.jclouds.crypto.Crypto; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.io.Payload; +import org.jclouds.oauth.v2.OAuthConstants; +import org.jclouds.oauth.v2.config.OAuthProperties; +import org.jclouds.rest.internal.BaseRestApiExpectTest; +import org.jclouds.ssh.SshKeys; +import org.jclouds.util.Strings2; + +import com.google.common.base.Joiner; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.io.ByteSource; +import com.google.inject.Binder; +import com.google.inject.Module; +import com.google.inject.TypeLiteral; + +public class BaseGoogleComputeEngineExpectTest extends BaseRestApiExpectTest { + + private static final String header = "{\"alg\":\"none\",\"typ\":\"JWT\"}"; + + private static final String CLAIMS_TEMPLATE = "{" + + "\"iss\":\"myproject\"," + + "\"scope\":\"%s\"," + + "\"aud\":\"https://accounts.google.com/o/oauth2/token\"," + + "\"exp\":3600," + + "\"iat\":0}"; + + protected static final String TOKEN = "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M"; + + protected static final HttpResponse TOKEN_RESPONSE = HttpResponse.builder().statusCode(200).payload( + payloadFromString("{\n" + + " \"access_token\" : \"" + TOKEN + "\",\n" + + " \"token_type\" : \"Bearer\",\n" + + " \"expires_in\" : 3600\n" + + "}")).build(); + + protected String openSshKey; + + + public BaseGoogleComputeEngineExpectTest() { + provider = "google-compute-engine"; + } + + @Override + protected Module createModule() { + + + return new Module() { + @Override + public void configure(Binder binder) { + // Predicatable time + binder.bind(new TypeLiteral>() {}).toInstance(Suppliers.ofInstance(0L)); + try { + KeyFactory keyfactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyfactory.generatePrivate(privateKeySpec(ByteSource.wrap( + PRIVATE_KEY.getBytes(UTF_8)))); + PublicKey publicKey = keyfactory.generatePublic(publicKeySpec(ByteSource.wrap(PUBLIC_KEY.getBytes(UTF_8)))); + KeyPair keyPair = new KeyPair(publicKey, privateKey); + openSshKey = SshKeys.encodeAsOpenSSH(RSAPublicKey.class.cast(publicKey)); + final Crypto crypto = createMock(Crypto.class); + KeyPairGenerator rsaKeyPairGenerator = createMock(KeyPairGenerator.class); + final SecureRandom secureRandom = createMock(SecureRandom.class); + expect(crypto.rsaKeyPairGenerator()).andReturn(rsaKeyPairGenerator).anyTimes(); + rsaKeyPairGenerator.initialize(2048, secureRandom); + expectLastCall().anyTimes(); + expect(rsaKeyPairGenerator.genKeyPair()).andReturn(keyPair).anyTimes(); + replay(crypto, rsaKeyPairGenerator, secureRandom); + binder.bind(Crypto.class).toInstance(crypto); + binder.bind(SecureRandom.class).toInstance(secureRandom); + } catch (NoSuchAlgorithmException e) { + propagate(e); + } catch (InvalidKeySpecException e) { + propagate(e); + } catch (IOException e) { + propagate(e); + } + // predictable node names + final AtomicInteger suffix = new AtomicInteger(); + binder.bind(new TypeLiteral>() { + }).toInstance(new Supplier() { + @Override + public String get() { + return suffix.getAndIncrement() + ""; + } + }); + } + }; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + // use no sig algorithm for expect tests (means no credential is required either) + props.put(OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM, OAuthConstants.NO_ALGORITHM); + return props; + } + + @Override + protected HttpRequestComparisonType compareHttpRequestAsType(HttpRequest input) { + HttpRequestComparisonType reqType = HttpRequestComparisonType.DEFAULT; + if (input.getPayload() != null) { + if (input.getPayload().getContentMetadata().getContentType().equals(MediaType.APPLICATION_JSON)) { + reqType = HttpRequestComparisonType.JSON; + } + } + return reqType; + } + + protected HttpRequest requestForScopes(String... scopes) { + String claims = String.format(CLAIMS_TEMPLATE, Joiner.on(",").join(scopes)); + + String payload = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" + + // Base64 Encoded Header + "assertion=" + base64Url().omitPadding().encode(header.getBytes(UTF_8)) + "." + + // Base64 Encoded Claims + base64Url().omitPadding().encode(claims.getBytes(UTF_8)) + "."; + + return HttpRequest.builder() + .method("POST") + .endpoint(URI.create("https://accounts.google.com/o/oauth2/token")) + .addHeader("Accept", MediaType.APPLICATION_JSON) + .payload(payloadFromStringWithContentType(payload, "application/x-www-form-urlencoded")) + .build(); + } + + /** + * Parse tests don't apply @Transform so we need to apply the transformation to PagedIterable on the result of + * expected() + */ + protected PagedIterable toPagedIterable(ListPage list) { + return PagedIterables.of(list); + } + + protected static Payload staticPayloadFromResource(String resource) { + try { + return payloadFromString(Strings2.toStringAndClose(BaseGoogleComputeEngineExpectTest.class.getResourceAsStream + (resource))); + } catch (IOException e) { + throw propagate(e); + } + } + + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineParseTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineParseTest.java new file mode 100644 index 0000000000..aba1fc386f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineParseTest.java @@ -0,0 +1,33 @@ +/* + * 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.googlecomputeengine.internal; + +import org.jclouds.googlecomputeengine.config.GoogleComputeEngineParserModule; +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.json.config.GsonModule; + +import com.google.inject.Guice; +import com.google.inject.Injector; + +public abstract class BaseGoogleComputeEngineParseTest extends BaseItemParserTest { + + @Override + protected Injector injector() { + return Guice.createInjector(new GsonModule(), new GoogleComputeEngineParserModule()); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineServiceContextExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineServiceContextExpectTest.java new file mode 100644 index 0000000000..1b65fc1b92 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineServiceContextExpectTest.java @@ -0,0 +1,49 @@ +/* + * 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.googlecomputeengine.internal; + +import java.util.Properties; + +import org.jclouds.apis.ApiMetadata; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApiMetadata; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; + +import com.google.common.base.Function; +import com.google.inject.Module; + +public abstract class BaseGoogleComputeEngineServiceContextExpectTest extends BaseGoogleComputeEngineExpectTest implements + Function { + + + @Override + public T createClient(Function fn, Module module, Properties props) { + return apply(createComputeServiceContext(fn, module, props)); + } + + private ComputeServiceContext createComputeServiceContext(Function fn, Module module, + Properties props) { + return createInjector(fn, module, props).getInstance(ComputeServiceContext.class); + } + + @Override + protected ApiMetadata createApiMetadata() { + return new GoogleComputeEngineApiMetadata(); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineServiceExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineServiceExpectTest.java new file mode 100644 index 0000000000..23fa49ea06 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineServiceExpectTest.java @@ -0,0 +1,28 @@ +/* + * 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.googlecomputeengine.internal; + +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceContext; + +public class BaseGoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngineServiceContextExpectTest { + + @Override + public ComputeService apply(ComputeServiceContext input) { + return input.getComputeService(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseAddressListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseAddressListTest.java new file mode 100644 index 0000000000..8140a18e4e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseAddressListTest.java @@ -0,0 +1,61 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Address; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Resource.Kind; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseAddressListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/address_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage

expected() { + return ListPage.
builder() + .kind(Kind.ADDRESS_LIST) + .id("projects/myproject/regions/us-central1/addresses") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses")) + .items(ImmutableSet.of(new ParseAddressTest().expected(), + Address.builder() + .id("4881363978908129158") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2013-07-26T14:08:21.552-07:00")) + .status("RESERVED") + .region(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1")) + .name("test-ip2") + .description("") + .address("173.255.118.115") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip2")) + .build()) + ).build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseAddressTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseAddressTest.java new file mode 100644 index 0000000000..dd3c3ed039 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseAddressTest.java @@ -0,0 +1,51 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Address; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ParseAddressTest extends BaseGoogleComputeEngineParseTest
{ + + @Override + public String resource() { + return "/address_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Address expected() { + return Address.builder() + .id("4439373783165447583") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2013-07-26T13:57:20.204-07:00")) + .status("RESERVED") + .region(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1")) + .name("test-ip1") + .description("") + .address("173.255.115.190") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip1")) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseDiskListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseDiskListTest.java new file mode 100644 index 0000000000..4e0cd43284 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseDiskListTest.java @@ -0,0 +1,61 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Disk; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseDiskListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/disk_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.DISK_LIST) + .id("projects/myproject/zones/us-central1-a/disks") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks")) + .items(ImmutableSet.of(Disk.builder() + .id("13050421646334304115") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-11-25T01:38:48.306")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1")) + .name("testimage1") + .sizeGb(1) + .zone(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a")) + .status("READY") + .build()) + ).build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseDiskTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseDiskTest.java new file mode 100644 index 0000000000..fe4c2bc783 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseDiskTest.java @@ -0,0 +1,50 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Disk; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ParseDiskTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/disk_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Disk expected() { + return Disk.builder() + .id("13050421646334304115") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-11-25T01:38:48.306")) + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1")) + .name("testimage1") + .sizeGb(1) + .zone(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a")) + .status("READY") + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallListTest.java new file mode 100644 index 0000000000..a1fc1594b0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallListTest.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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseFirewallListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/firewall_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.FIREWALL_LIST) + .id("projects/google/firewalls") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/google/global/firewalls")) + .items(ImmutableSet.of( + new ParseFirewallTest().expected() + , Firewall.builder() + .id("12862241067393040785") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-04-13T03:05:04.365")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/google/global/firewalls/default-ssh")) + .name("default-ssh") + .description("SSH allowed from anywhere") + .network(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/google/global/networks/default")) + .addSourceRange("0.0.0.0/0") + .addAllowed(Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPort(22).build()) + .build() + )) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallTest.java new file mode 100644 index 0000000000..37fc794427 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallTest.java @@ -0,0 +1,60 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ParseFirewallTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/firewall_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Firewall expected() { + return Firewall.builder() + .id("12862241031274216284") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-04-13T03:05:02.855")) + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test")) + .name("jclouds-test") + .description("Internal traffic from default allowed") + .network(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test")) + .addSourceRange("10.0.0.0/8") + .addAllowed(Firewall.Rule.builder() + .IpProtocol(IpProtocol.TCP) + .addPortRange(1, 65535).build()) + .addAllowed(Firewall.Rule.builder() + .IpProtocol(IpProtocol.UDP) + .addPortRange(1, 65535).build()) + .addAllowed(Firewall.Rule.builder() + .IpProtocol(IpProtocol.ICMP).build()) + .build(); + + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseImageListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseImageListTest.java new file mode 100644 index 0000000000..1a364f6af2 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseImageListTest.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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Deprecated; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseImageListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/image_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.IMAGE_LIST) + .id("projects/centos-cloud/global/images") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images")) + .items(ImmutableSet.of(Image.builder() + .id("12941197498378735318") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-07-16T22:16:13.468")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120326")) + .name("centos-6-2-v20120326") + .description("DEPRECATED. CentOS 6.2 image; Created Mon, 26 Mar 2012 21:19:09 +0000") + .sourceType("RAW") + .deprecated(Deprecated.builder() + .state("DEPRECATED") + .replacement(URI.create("https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-v20130104")) + .build()) + .rawDisk( + Image.RawDisk.builder() + .source("") + .containerType("TAR") + .build() + ).build() + + )) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseImageTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseImageTest.java new file mode 100644 index 0000000000..99cfd6f6fe --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseImageTest.java @@ -0,0 +1,55 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ParseImageTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/image_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Image expected() { + return Image.builder() + .id("12941197498378735318") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-07-16T22:16:13.468")) + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-2" + + "-v20120326")) + .name("centos-6-2-v20120326") + .description("DEPRECATED. CentOS 6.2 image; Created Mon, 26 Mar 2012 21:19:09 +0000") + .sourceType("RAW") + .rawDisk( + Image.RawDisk.builder() + .source("") + .containerType("TAR") + .build() + ).build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceListTest.java new file mode 100644 index 0000000000..ad6041b44a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceListTest.java @@ -0,0 +1,48 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; + +import com.google.common.collect.ImmutableSet; + +public class ParseInstanceListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/instance_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.INSTANCE_LIST) + .id("projects/myproject/zones/us-central1-a/instances") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances")) + .items(ImmutableSet.of(new ParseInstanceTest().expected())) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceSerialOutputTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceSerialOutputTest.java new file mode 100644 index 0000000000..f44baa1d08 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceSerialOutputTest.java @@ -0,0 +1,38 @@ +/* + * 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.googlecomputeengine.parse; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; + +public class ParseInstanceSerialOutputTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/instance_serial_port.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Instance.SerialPortOutput expected() { + return Instance.SerialPortOutput.builder() + .contents("console output").build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceTest.java new file mode 100644 index 0000000000..18255acac8 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseInstanceTest.java @@ -0,0 +1,81 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.Metadata; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; + +import com.google.common.collect.ImmutableMap; + +public class ParseInstanceTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/instance_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Instance expected() { + return Instance.builder() + .id("13051190678907570425") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-11-25T23:48:20.758")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-0")) + .description("desc") + .name("test-0") + .machineType(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1" + + "-standard-1")) + .status(Instance.Status.RUNNING) + .zone(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a")) + .addNetworkInterface( + Instance.NetworkInterface.builder() + .name("nic0") + .networkIP("10.240.121.115") + .network(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/networks/default")) + .build() + ) + .addDisk( + Instance.PersistentAttachedDisk.builder() + .index(0) + .mode(Instance.PersistentAttachedDisk.Mode.READ_WRITE) + .deviceName("test") + .source(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/disks/test")) + .boot(true) + .build() + ) + .tags(Instance.Tags.builder().fingerprint("abcd").addItem("aTag").build()) + .metadata(Metadata.builder() + .items(ImmutableMap.of("aKey", "aValue", + "jclouds-image", + "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/gcel-12-04-v20121106", + "jclouds-delete-boot-disk", "true")) + .fingerprint("efgh") + .build()) + .addServiceAccount(Instance.ServiceAccount.builder().email("default").addScopes("myscope").build()) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMachineTypeListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMachineTypeListTest.java new file mode 100644 index 0000000000..ace1ca8ffc --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMachineTypeListTest.java @@ -0,0 +1,94 @@ +/* + * 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.googlecomputeengine.parse; + +import static org.jclouds.googlecomputeengine.domain.Resource.Kind.MACHINE_TYPE_LIST; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.MachineType; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; + +public class ParseMachineTypeListTest extends BaseGoogleComputeEngineParseTest> { + + + @Override + public String resource() { + return "/machinetype_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + SimpleDateFormatDateService dateService = new SimpleDateFormatDateService(); + return ListPage.builder() + .kind(MACHINE_TYPE_LIST) + .id("projects/myproject/machineTypes") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes")) + .addItem(MachineType.builder() + .id("4618642685664990776") + .creationTimestamp(dateService.iso8601DateParse("2013-04-25T13:32:49.088-07:00")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/f1-micro")) + .zone("us-central1-a") + .name("f1-micro") + .description("1 vCPU (shared physical core) and 0.6 GB RAM") + .guestCpus(1) + .memoryMb(614) + .imageSpaceGb(0) + .maximumPersistentDisks(4) + .maximumPersistentDisksSizeGb(3072) + .build()) + .addItem(MachineType.builder() + .id("12907738072351752276") + .creationTimestamp(dateService.iso8601DateParse("2012-06-07T20:48:14.670")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1")) + .zone("us-central1-a") + .name("n1-standard-1") + .description("1 vCPU, 3.75 GB RAM, and a 10 GB ephemeral root disk") + .guestCpus(1) + .memoryMb(3840) + .imageSpaceGb(10) + .maximumPersistentDisks(16) + .maximumPersistentDisksSizeGb(128) + .build()) + .addItem(MachineType.builder() + .id("12908560709887590691") + .creationTimestamp(dateService.iso8601DateParse("2012-06-07T20:51:19.936")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-8-d")) + .zone("us-central1-a") + .name("n1-standard-8-d") + .description("8 vCPUs, 30 GB RAM, a 10 GB ephemeral root disk, " + + "and 2 extra 1770 GB ephemeral disks") + .guestCpus(8) + .memoryMb(30720) + .imageSpaceGb(10) + .addScratchDisk(1770) + .addScratchDisk(1770) + .maximumPersistentDisks(16) + .maximumPersistentDisksSizeGb(1024) + .build()) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMachineTypeTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMachineTypeTest.java new file mode 100644 index 0000000000..2995c3584f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMachineTypeTest.java @@ -0,0 +1,57 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.MachineType; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; + +public class ParseMachineTypeTest extends BaseGoogleComputeEngineParseTest { + + + @Override + public String resource() { + return "/machinetype.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public MachineType expected() { + SimpleDateFormatDateService dateService = new SimpleDateFormatDateService(); + return MachineType.builder() + .id("12907738072351752276") + .creationTimestamp(dateService.iso8601DateParse("2012-06-07T20:48:14.670")) + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1" + + "-standard-1")) + .zone("us-central1-a") + .name("n1-standard-1") + .description("1 vCPU, 3.75 GB RAM, and a 10 GB ephemeral root disk") + .guestCpus(1) + .memoryMb(3840) + .imageSpaceGb(10) + .addScratchDisk(1770) + .addScratchDisk(1770) + .maximumPersistentDisks(16) + .maximumPersistentDisksSizeGb(128) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMetadataTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMetadataTest.java new file mode 100644 index 0000000000..877bc31a6d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseMetadataTest.java @@ -0,0 +1,45 @@ +/* + * 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.googlecomputeengine.parse; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.Metadata; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +@Test(groups = "unit") +public class ParseMetadataTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/metadata.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Metadata expected() { + return new Metadata("efgh", + ImmutableMap.builder() + .put("propA", "valueA") + .put("propB", "valueB") + .build()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseNetworkListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseNetworkListTest.java new file mode 100644 index 0000000000..61d56ba0f8 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseNetworkListTest.java @@ -0,0 +1,49 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; + +import com.google.common.collect.ImmutableSet; + +public class ParseNetworkListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/network_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.NETWORK_LIST) + .id("projects/myproject/networks") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/networks")) + .items(ImmutableSet.of(new ParseNetworkTest().expected())) + .build(); + + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseNetworkTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseNetworkTest.java new file mode 100644 index 0000000000..cd0fdcf8de --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseNetworkTest.java @@ -0,0 +1,48 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; + +public class ParseNetworkTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/network_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Network expected() { + return Network.builder() + .id("13024414170909937976") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-10-24T20:13:19.967")) + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/networks/jclouds-test")) + .name("default") + .description("Default network for the project") + .IPv4Range("10.0.0.0/8") + .gatewayIPv4("10.0.0.1") + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationListTest.java new file mode 100644 index 0000000000..ec407a384d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationListTest.java @@ -0,0 +1,46 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; + +public class ParseOperationListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/global_operation_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.OPERATION_LIST) + .id("projects/myproject/global/operations") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/operations")) + .addItem(new ParseOperationTest().expected()) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.java new file mode 100644 index 0000000000..cb561bf1d7 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ParseOperationTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/global_operation.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Operation expected() { + SimpleDateFormatDateService dateService = new SimpleDateFormatDateService(); + return Operation.builder().id("13053095055850848306") + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/operations/operation-1354084865060-4cf88735faeb8" + + "-bbbb12cb")) + .name("operation-1354084865060-4cf88735faeb8-bbbb12cb") + .targetLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/firewalls/jclouds-test-delete")) + .targetId("13053094017547040099") + .status(Operation.Status.DONE) + .user("user@developer.gserviceaccount.com") + .progress(100) + .insertTime(dateService.iso8601DateParse("2012-11-28T06:41:05.060")) + .startTime(dateService.iso8601DateParse("2012-11-28T06:41:05.142")) + .endTime(dateService.iso8601DateParse("2012-11-28T06:41:06.142")) + .operationType("insert") + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseProjectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseProjectTest.java new file mode 100644 index 0000000000..3e549df4bf --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseProjectTest.java @@ -0,0 +1,67 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; +import java.util.Date; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.Metadata; +import org.jclouds.googlecomputeengine.domain.Project; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +@Test(groups = "unit") +public class ParseProjectTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/project.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Project expected() { + return Project.builder() + .id("13024414184846275913") + .creationTimestamp(new Date(Long.parseLong("1351109596252"))) + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject")) + .name("myproject") + .description("") + .commonInstanceMetadata(Metadata.builder() + .items(ImmutableMap.builder() + .put("propA", "valueA") + .put("propB", "valueB") + .build()) + .fingerprint("efgh") + .build()) + .addQuota("INSTANCES", 0, 8) + .addQuota("CPUS", 0, 8) + .addQuota("EPHEMERAL_ADDRESSES", 0, 8) + .addQuota("DISKS", 0, 8) + .addQuota("DISKS_TOTAL_GB", 0, 100) + .addQuota("SNAPSHOTS", 0, 1000) + .addQuota("NETWORKS", 1, 5) + .addQuota("FIREWALLS", 2, 100) + .addQuota("IMAGES", 0, 100) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseQuotaTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseQuotaTest.java new file mode 100644 index 0000000000..894dd0e578 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseQuotaTest.java @@ -0,0 +1,39 @@ +/* + * 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.googlecomputeengine.parse; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.googlecomputeengine.domain.Quota; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ParseQuotaTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/quota.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Quota expected() { + return Quota.builder().metric("INSTANCES").usage(0.0).limit(8.0).build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionListTest.java new file mode 100644 index 0000000000..8dfdea1aa6 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionListTest.java @@ -0,0 +1,72 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Region; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseRegionListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/region_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.REGION_LIST) + .id("projects/myproject/regions") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions")) + .items(ImmutableSet.of( + new ParseRegionTest().expected(), + Region.builder() + .id("6396763663251190992") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse + ("2013-07-08T14:40:37.939-07:00")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/regions/us-central2")) + .name("us-central2") + .description("us-central2") + .status(Region.Status.UP) + .zone(URI.create("https://www.googleapis.com/compute/v1/zones/us-central2-a")) + .addQuota("INSTANCES", 0, 8) + .addQuota("CPUS", 0, 8) + .addQuota("EPHEMERAL_ADDRESSES", 0, 8) + .addQuota("DISKS", 0, 8) + .addQuota("DISKS_TOTAL_GB", 0, 100) + .addQuota("SNAPSHOTS", 0, 1000) + .addQuota("NETWORKS", 1, 5) + .addQuota("FIREWALLS", 2, 100) + .addQuota("IMAGES", 0, 100) + .build())) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionTest.java new file mode 100644 index 0000000000..fab9915298 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRegionTest.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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Region; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseRegionTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/region_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Region expected() { + return Region.builder() + .id("12912210600542709766") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2013-07-08T14:40:37.939-07:00")) + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1")) + .name("us-central1") + .description("us-central1") + .status(Region.Status.UP) + .zones(ImmutableSet.of(URI.create("https://www.googleapis.com/compute/v1/zones/us-central1-a"), + URI.create("https://www.googleapis.com/compute/v1/zones/us-central1-b"))) + .addQuota("INSTANCES", 0, 8) + .addQuota("CPUS", 0, 8) + .addQuota("EPHEMERAL_ADDRESSES", 0, 8) + .addQuota("DISKS", 0, 8) + .addQuota("DISKS_TOTAL_GB", 0, 100) + .addQuota("SNAPSHOTS", 0, 1000) + .addQuota("NETWORKS", 1, 5) + .addQuota("FIREWALLS", 2, 100) + .addQuota("IMAGES", 0, 100) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRouteListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRouteListTest.java new file mode 100644 index 0000000000..3a378aa7c4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRouteListTest.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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Resource.Kind; +import org.jclouds.googlecomputeengine.domain.Route; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseRouteListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/route_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Kind.ROUTE_LIST) + .id("projects/myproject/global/routes") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/routes")) + .items(ImmutableSet.of(new ParseRouteTest().expected(), + Route.builder() + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/routes/default-route-fc92a41ecb5a8d17")) + .id("507025480040058551") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2013-07-08T14:40:38.502-07:00")) + .name("default-route-fc92a41ecb5a8d17") + .description("Default route to the Internet.") + .network(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default")) + .destRange("0.0.0.0/0") + .priority(1000) + .nextHopGateway(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/gateways/default-internet-gateway")) + .build()) + ).build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRouteTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRouteTest.java new file mode 100644 index 0000000000..5ffd84535f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseRouteTest.java @@ -0,0 +1,56 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Route; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseRouteTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/route_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Route expected() { + return Route.builder() + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/routes/default-route-c99ebfbed0e1f375")) + .id("7241926205630356071") + .name("default-route-c99ebfbed0e1f375") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2013-07-08T14:40:38.502-07:00")) + .description("Default route to the virtual network.") + .network(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default")) + .destRange("10.240.0.0/16") + .priority(1000) + .nextHopNetwork(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default")) + .tags(ImmutableSet.of("fooTag", "barTag")) + .build(); + + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseSnapshotListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseSnapshotListTest.java new file mode 100644 index 0000000000..f52aa3f876 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseSnapshotListTest.java @@ -0,0 +1,64 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Resource.Kind; +import org.jclouds.googlecomputeengine.domain.Snapshot; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseSnapshotListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/snapshot_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Kind.SNAPSHOT_LIST) + .id("projects/myproject/global/snapshots") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/snapshots")) + .items(ImmutableSet.of( + new ParseSnapshotTest().expected(), Snapshot.builder() + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/snapshots/test-snap2")) + .id("13895715048576107883") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse + ("2013-07-26T12:57:01.927-07:00")) + .status("READY") + .sizeGb(10) + .sourceDisk(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1")) + .name("test-snap2") + .description("") + .sourceDiskId("8243603669926824540") + .build())) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseSnapshotTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseSnapshotTest.java new file mode 100644 index 0000000000..f3e7a013d9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseSnapshotTest.java @@ -0,0 +1,52 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Snapshot; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ParseSnapshotTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/snapshot_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Snapshot expected() { + return Snapshot.builder() + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/snapshots/test-snap")) + .id("9734455566806191190") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2013-07-26T12:54:23.173-07:00")) + .status("READY") + .sizeGb(10) + .sourceDisk(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1")) + .name("test-snap") + .description("") + .sourceDiskId("8243603669926824540") + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneListTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneListTest.java new file mode 100644 index 0000000000..54fe1a26e3 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneListTest.java @@ -0,0 +1,70 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.ListPage; +import org.jclouds.googlecomputeengine.domain.Resource; +import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +@Test(groups = "unit") +public class ParseZoneListTest extends BaseGoogleComputeEngineParseTest> { + + @Override + public String resource() { + return "/zone_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.ZONE_LIST) + .id("projects/myproject/zones") + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones")) + .items(ImmutableSet.of( + new ParseZoneTest().expected() + , Zone.builder() + .id("13024414164050619686") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse + ("2012-10-24T20:13:19.271")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1/projects/myproject/zones/us-central1-b")) + .name("us-central1-b") + .description("us-central1-b") + .status(Zone.Status.UP) + .addMaintenanceWindow(Zone.MaintenanceWindow.builder() + .name("2013-02-17-planned-outage") + .description("maintenance zone") + .beginTime(new SimpleDateFormatDateService().iso8601DateParse + ("2013-02-17T08:00:00.000")) + .endTime(new SimpleDateFormatDateService().iso8601DateParse + ("2013-03-03T08:00:00.000")) + .build()) + .build())) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneTest.java new file mode 100644 index 0000000000..48cdbfc8c2 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneTest.java @@ -0,0 +1,55 @@ +/* + * 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.googlecomputeengine.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.testng.annotations.Test; + +@Test(groups = "unit") +public class ParseZoneTest extends BaseGoogleComputeEngineParseTest { + + @Override + public String resource() { + return "/zone_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Zone expected() { + return Zone.builder() + .id("13020128040171887099") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-10-19T16:42:54.131")) + .selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a")) + .name("us-central1-a") + .description("us-central1-a") + .status(Zone.Status.DOWN) + .addMaintenanceWindow(Zone.MaintenanceWindow.builder() + .name("2012-11-10-planned-outage") + .description("maintenance zone") + .beginTime(new SimpleDateFormatDateService().iso8601DateParse("2012-11-10T20:00:00.000")) + .endTime(new SimpleDateFormatDateService().iso8601DateParse("2012-12-02T20:00:00.000")) + .build()) + .build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java new file mode 100644 index 0000000000..58ed81cd6b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java @@ -0,0 +1,162 @@ +/* + * 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.googlecomputeengine.predicates; + +import static org.jclouds.googlecomputeengine.compute.functions.FirewallToIpPermissionTest.fwForTest; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.equalsIpPermission; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.hasPortRange; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.hasProtocol; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.hasSourceRange; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.hasSourceTag; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.providesIpPermission; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.net.URI; +import java.util.Date; + +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +import com.google.common.collect.Range; + +@Test(groups = "unit") +public class NetworkFirewallPredicatesTest { + + public static Firewall getFwForTestSourceTags() { + Firewall.Builder builder = Firewall.builder(); + + builder.network(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test")); + builder.selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test")); + builder.addSourceTag("tag-1"); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.TCP) + .addPortRange(1, 10).build()); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.TCP) + .addPort(33).build()); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.ICMP).build()); + builder.id("abcd"); + builder.creationTimestamp(new Date()); + builder.name("jclouds-test"); + + return builder.build(); + } + + public static Firewall getFwForTestSourceTagsExact() { + Firewall.Builder builder = Firewall.builder(); + + builder.network(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test")); + builder.selfLink(URI.create("https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test")); + builder.addSourceTag("tag-1"); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.TCP) + .addPortRange(1, 10).build()); + builder.id("abcd"); + builder.creationTimestamp(new Date()); + builder.name("jclouds-test"); + + return builder.build(); + } + + @Test + public void testHasProtocol() { + assertTrue(hasProtocol(IpProtocol.TCP).apply(fwForTest()), + "Firewall " + fwForTest() + " should contain a TCP rule."); + } + + @Test + public void testHasProtocolFails() { + assertFalse(hasProtocol(IpProtocol.UDP).apply(fwForTest()), + "Firewall " + fwForTest() + " should NOT contain a UDP rule."); + } + + @Test + public void testHasPortRange() { + assertTrue(hasPortRange(Range.closed(2, 9)).apply(fwForTest()), + "Firewall " + fwForTest() + " should contain the port range 2-9."); + } + + @Test + public void testHasPortRangeFails() { + assertFalse(hasPortRange(Range.closed(11, 15)).apply(fwForTest()), + "Firewall " + fwForTest() + " should NOT contain the port range 11-15."); + } + + @Test + public void testHasSourceTag() { + assertTrue(hasSourceTag("tag-1").apply(getFwForTestSourceTags()), + "Firewall " + getFwForTestSourceTags() + " should contain the source tag 'tag-1'."); + } + + @Test + public void testHasSourceTagFails() { + assertFalse(hasSourceTag("tag-1").apply(fwForTest()), + "Firewall " + fwForTest() + " should NOT contain the source tag 'tag-1'."); + } + + @Test + public void testHasSourceRange() { + assertTrue(hasSourceRange("0.0.0.0/0").apply(fwForTest()), + "Firewall " + fwForTest() + " should contain the source range '0.0.0.0/0'."); + } + + @Test + public void testHasSourceRangeFails() { + assertFalse(hasSourceRange("0.0.0.0/0").apply(getFwForTestSourceTags()), + "Firewall " + getFwForTestSourceTags() + " should NOT contain the source range '0.0.0.0/0'."); + } + + @Test + public void testEqualsIpPermission() { + IpPermission perm = IpPermission.builder().groupId("tag-1") + .fromPort(1).toPort(10).ipProtocol(IpProtocol.TCP).build(); + + assertTrue(equalsIpPermission(perm).apply(getFwForTestSourceTagsExact()), + "Firewall " + getFwForTestSourceTagsExact() + " should match IpPermission " + perm + " but does not."); + } + + @Test + public void testEqualsIpPermissionFails() { + IpPermission perm = IpPermission.builder().groupId("tag-1") + .fromPort(1).toPort(10).ipProtocol(IpProtocol.TCP).build(); + + assertFalse(equalsIpPermission(perm).apply(getFwForTestSourceTags()), + "Firewall " + getFwForTestSourceTags() + " should not match IpPermission " + perm + " but does."); + } + + @Test + public void testProvidesIpPermission() { + IpPermission perm = IpPermission.builder().groupId("tag-1") + .fromPort(1).toPort(10).ipProtocol(IpProtocol.TCP).build(); + + assertTrue(providesIpPermission(perm).apply(getFwForTestSourceTagsExact()), + "Firewall " + getFwForTestSourceTagsExact() + " should provide IpPermission " + perm + " but does not."); + + assertTrue(providesIpPermission(perm).apply(getFwForTestSourceTags()), + "Firewall " + getFwForTestSourceTags() + " should inexactly provide IpPermission " + perm + " but does not."); + } + + @Test + public void testProvidesIpPermissionFails() { + IpPermission perm = IpPermission.builder().groupId("tag-1") + .fromPort(1).toPort(10).ipProtocol(IpProtocol.TCP).build(); + + assertFalse(providesIpPermission(perm).apply(fwForTest()), + "Firewall " + fwForTest() + " should not provide IpPermission " + perm + " but does."); + } +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java new file mode 100644 index 0000000000..d6ea17f60d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java @@ -0,0 +1,38 @@ +/* + * 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.oauth.v2; + +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; +import org.jclouds.View; +import org.jclouds.apis.internal.BaseApiMetadataTest; +import org.testng.annotations.Test; + +/** + * Tests that OAuthApiMetadata is properly registered in ServiceLoader + *

+ *

+ * META-INF/services/org.jclouds.apis.ApiMetadata
+ * 
+ */ +@Test(groups = "unit") +public class OAuthApiMetadataTest extends BaseApiMetadataTest { + + public OAuthApiMetadataTest() { + super(new OAuthApiMetadata(), ImmutableSet.>of()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java new file mode 100644 index 0000000000..28879a98ce --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -0,0 +1,75 @@ +/* + * 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.oauth.v2; + +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.io.Files; + +import java.io.File; +import java.io.IOException; +import java.util.Properties; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; + +/** + * Utils for OAuth tests. + */ +public class OAuthTestUtils { + + public static Properties defaultProperties(Properties properties) { + try { + properties = properties == null ? new Properties() : properties; + properties.put("oauth.identity", "foo"); + properties.put("oauth.credential", + Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read()); + properties.put("oauth.endpoint", "http://localhost:5000/o/oauth2/token"); + properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); + return properties; + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + public static String setCredentialFromPemFile(Properties overrides, String key) { + String val = null; + String credentialFromFile = null; + String testKey = "test." + key; + + if (System.getProperties().containsKey(testKey)) { + val = System.getProperty(testKey); + } + checkNotNull(val, String.format("the property %s must be set (pem private key path)", testKey)); + + try { + credentialFromFile = Files.toString(new File(val), Charsets.UTF_8); + } catch (IOException e) { + throw Throwables.propagate(e); + } + overrides.setProperty(key, credentialFromFile); + return credentialFromFile; + } + + public static String getMandatoryProperty(Properties properties, String key) { + checkNotNull(properties); + checkNotNull(key); + String value = properties.getProperty(key); + return checkNotNull(value, String.format("mandatory property %s or test.%s was not present", key, key)); + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java new file mode 100644 index 0000000000..2008e5dddd --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java @@ -0,0 +1,99 @@ +/* + * 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.oauth.v2.features; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.testng.Assert.assertEquals; + +import java.net.URI; +import java.util.Properties; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.oauth.v2.OAuthApi; +import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.internal.BaseOAuthApiExpectTest; +import org.testng.annotations.Test; + +/** + * Tests that a token requess is well formed. + */ +@Test(groups = "unit") +public class OAuthApiExpectTest extends BaseOAuthApiExpectTest { + + private static final String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; + + private static final String claims = "{\"iss\":\"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer" + + ".gserviceaccount.com\"," + + "\"scope\":\"https://www.googleapis.com/auth/prediction\",\"aud\":\"https://accounts.google" + + ".com/o/oauth2/token\",\"exp\":1328573381,\"iat\":1328569781}"; + + private static final Token TOKEN = new Token.Builder().accessToken + ("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M").tokenType("Bearer").expiresIn(3600).build(); + + private static final ClaimSet CLAIM_SET = new ClaimSet.Builder().addClaim("iss", + "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer" + + ".gserviceaccount.com") + .addClaim("scope", "https://www.googleapis.com/auth/prediction") + .addClaim("aud", "https://accounts.google.com/o/oauth2/token") + .expirationTime(1328573381) + .emissionTime(1328569781).build(); + + private static final Header HEADER = new Header.Builder().signerAlgorithm("RS256").type("JWT").build(); + + private static final String URL_ENCODED_TOKEN_REQUEST = + "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" + + // Base64 Encoded Header + "assertion=" + base64Url().omitPadding().encode(header.getBytes(UTF_8)) + "." + + // Base64 Encoded Claims + base64Url().omitPadding().encode(claims.getBytes(UTF_8)) + "." + + // Base64 encoded {header}.{claims} signature (using SHA256) + "W2Lesr_98AzVYiMbzxFqmwcOjpIWlwqkC6pNn1fXND9oSDNNnFhy-AAR6DKH-x9ZmxbY80" + + "R5fH-OCeWumXlVgceKN8Z2SmgQsu8ElTpypQA54j_5j8vUImJ5hsOUYPeyF1U2BUzZ3L5g" + + "03PXBA0YWwRU9E1ChH28dQBYuGiUmYw"; + + private static final HttpRequest TOKEN_REQUEST = HttpRequest.builder() + .method("POST") + .endpoint(URI.create("http://localhost:5000/o/oauth2/token")) + .addHeader("Accept", MediaType.APPLICATION_JSON) + .payload(payloadFromStringWithContentType(URL_ENCODED_TOKEN_REQUEST, "application/x-www-form-urlencoded")) + .build(); + + private static final HttpResponse TOKEN_RESPONSE = HttpResponse.builder().statusCode(200).payload( + payloadFromString("{\n" + + " \"access_token\" : \"1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M\",\n" + + " \"token_type\" : \"Bearer\",\n" + + " \"expires_in\" : 3600\n" + + "}")).build(); + + @Override + protected Properties setupProperties() { + return OAuthTestUtils.defaultProperties(super.setupProperties()); + } + + public void testGenerateJWTRequest() { + OAuthApi api = requestSendsResponse(TOKEN_REQUEST, TOKEN_RESPONSE); + assertEquals(api.authenticate(new TokenRequest(HEADER, CLAIM_SET)), TOKEN); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java new file mode 100644 index 0000000000..4ac59508a4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java @@ -0,0 +1,80 @@ +/* + * 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.oauth.v2.features; + +import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.oauth.v2.OAuthTestUtils.getMandatoryProperty; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.Properties; + +import org.jclouds.oauth.v2.OAuthConstants; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.internal.BaseOAuthApiLiveTest; +import org.testng.annotations.Test; + +/** + * A live test for authentication. Requires the following properties to be set: + * - test.oauth.endpoint + * - test.oauth.identity + * - test.oauth.credential + * - test.jclouds.oauth.audience + * - test.jclouds.oauth.scopes + * - test.jclouds.oauth.signature-or-mac-algorithm + */ +@Test(groups = "live", singleThreaded = true) +public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { + + private Properties properties; + + @Override + protected Properties setupProperties() { + properties = super.setupProperties(); + return properties; + + } + + @Test(groups = "live", singleThreaded = true) + public void testAuthenticateJWTToken() throws Exception { + assertTrue(properties != null, "properties were not set"); + String signatureAlgorithm = getMandatoryProperty(properties, SIGNATURE_OR_MAC_ALGORITHM); + checkState(OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureAlgorithm) + , String.format("Algorithm not supported: " + signatureAlgorithm)); + + Header header = Header.builder().signerAlgorithm(signatureAlgorithm).type("JWT").build(); + + String scopes = getMandatoryProperty(properties, SCOPES); + String audience = getMandatoryProperty(properties, AUDIENCE); + + long now = nowInSeconds(); + + ClaimSet claimSet = ClaimSet.builder().addClaim("aud", audience).addClaim("scope", scopes).addClaim("iss", + identity).emissionTime(now).expirationTime(now + 3600).build(); + + TokenRequest tokenRequest = TokenRequest.builder().header(header).claimSet(claimSet).build(); + Token token = api.authenticate(tokenRequest); + + assertNotNull(token, "no token when authenticating " + tokenRequest); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java new file mode 100644 index 0000000000..e3794d6943 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java @@ -0,0 +1,61 @@ +/* + * 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.oauth.v2.functions; + +import static com.google.common.base.Suppliers.ofInstance; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.io.File; +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; + +import org.jclouds.domain.Credentials; +import org.jclouds.oauth.v2.domain.OAuthCredentials; +import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; +import org.testng.annotations.Test; + +/** + * Test loading the credentials by extracting a pk from a PKCS12 keystore. + */ +@Test(groups = "unit") +public class OAuthCredentialsFromPKTest { + + public static OAuthCredentials loadOAuthCredentials() throws IOException, NoSuchAlgorithmException, + CertificateException, InvalidKeySpecException { + OAuthCredentialsSupplier loader = new OAuthCredentialsSupplier(ofInstance(new Credentials("foo", + Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read())), + new OAuthCredentialsForCredentials("RS256"), "RS256"); + return loader.get(); + } + + + public void testLoadPKString() throws IOException, NoSuchAlgorithmException, KeyStoreException, + CertificateException, UnrecoverableKeyException, InvalidKeySpecException { + OAuthCredentials creds = loadOAuthCredentials(); + assertNotNull(creds); + assertEquals(creds.identity, "foo"); + assertNotNull(creds.privateKey); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java new file mode 100644 index 0000000000..2b3d094f40 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java @@ -0,0 +1,55 @@ +/* + * 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.oauth.v2.functions; + +import com.google.common.base.Suppliers; +import org.jclouds.domain.Credentials; +import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.rest.AuthorizationException; +import org.testng.annotations.Test; + +import java.util.Properties; + +import static org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; +import static org.testng.Assert.assertNotNull; + +@Test(groups = "unit") +public class OAuthCredentialsSupplierTest { + + @Test(expectedExceptions = AuthorizationException.class) + public void testAuthorizationExceptionIsThrownOnBadKeys() { + OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA", + "MIA")), new OAuthCredentialsForCredentials("RS256"), "RS256"); + supplier.get(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testGSEChildExceptionsPropagateAsAuthorizationException() { + OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA", + "MIA")), new OAuthCredentialsForCredentials("MOMMA"), "MOMMA"); + supplier.get(); + } + + public void testCredentialsAreLoadedOnRightAlgoAndCredentials() { + Properties propertied = OAuthTestUtils.defaultProperties(new Properties()); + Credentials validCredentials = new Credentials(propertied.getProperty("oauth.identity"), + propertied.getProperty("oauth.credential")); + OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(validCredentials), + new OAuthCredentialsForCredentials("RS256"), "RS256"); + assertNotNull(supplier.get()); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java new file mode 100644 index 0000000000..2a64822ce6 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java @@ -0,0 +1,61 @@ +/* + * 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.oauth.v2.functions; +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.base.Suppliers.ofInstance; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.testng.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertEquals; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; + +import org.testng.annotations.Test; + +/** + * Tests the SignOrProduceMacForToken + */ +@Test(groups = "unit") +public class SignerFunctionTest { + + private static final String PAYLOAD = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.\n" + + "eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZ" + + "GV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2ds" + + "ZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2x" + + "lLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ"; + + private static final String SHA256withRSA_PAYLOAD_SIGNATURE_RESULT = + "bmQrCv4gjkLWDK1JNJni74_kPiSDUMF_FImgqKJMUIgkDX1m2Sg3bH1yjF-cjBN7CvfAscnageo" + + "GtL2TGbwoTjJgUO5Yy0esavUUF-mBQHQtSw-2nL-9TNyM4SNi6fHPbgr83GGKOgA86r" + + "I9-nj3oUGd1fQty2k4Lsd-Zdkz6es"; + + + public void testSignPayload() throws InvalidKeyException, IOException, NoSuchAlgorithmException, + CertificateException, InvalidKeySpecException { + SignOrProduceMacForToken signer = new SignOrProduceMacForToken("RS256", + ofInstance(OAuthCredentialsFromPKTest + .loadOAuthCredentials())); + signer.loadSignatureOrMacOrNone(); + byte[] payloadSignature = signer.apply(PAYLOAD.getBytes(UTF_8)); + assertNotNull(payloadSignature); + + assertEquals(base64Url().omitPadding().encode(payloadSignature), SHA256withRSA_PAYLOAD_SIGNATURE_RESULT); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java new file mode 100644 index 0000000000..255c5c7f65 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java @@ -0,0 +1,92 @@ +/* + * 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.oauth.v2.handlers; + +import org.easymock.IArgumentMatcher; +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import java.net.URI; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reportMatcher; +import static org.easymock.EasyMock.verify; + +@Test(groups = "unit") +public class OAuthErrorHandlerTest { + + @Test + public void test409MakesIllegalStateException() { + assertCodeMakes( + "POST", + URI.create("http://oauth.org"), + 409, + "HTTP/1.1 409 Conflict", + "\"{\"code\":\"InvalidState\",\"message\":\"An incompatible transition has already been queued for this" + + " resource\"}\"", + IllegalStateException.class); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content, + Class expected) { + assertCodeMakes(method, uri, statusCode, message, "application/json", content, expected); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType, + String content, Class expected) { + + OAuthErrorHandler function = new OAuthErrorHandler(); + + HttpCommand command = createMock(HttpCommand.class); + HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build(); + HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build(); + response.getPayload().getContentMetadata().setContentType(contentType); + + expect(command.getCurrentRequest()).andReturn(request).atLeastOnce(); + command.setException(classEq(expected)); + + replay(command); + + function.handleError(command, response); + + verify(command); + } + + public static Exception classEq(final Class in) { + reportMatcher(new IArgumentMatcher() { + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("classEq("); + buffer.append(in); + buffer.append(")"); + } + + @Override + public boolean matches(Object arg) { + return arg.getClass() == in; + } + + }); + return null; + } + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java new file mode 100644 index 0000000000..f6d938a868 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java @@ -0,0 +1,40 @@ +/* + * 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.oauth.v2.internal; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.testng.Assert.assertTrue; + +import org.testng.annotations.Test; + +/** + * Tests that the Base64 implementations used to Base64 encode the tokens are Url safe. + */ +@Test(groups = "unit") +public class Base64UrlSafeTest { + + public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + + "=?*qwertyuiopº´WERTYUIOPªàsdfghjklç~ASDFGHJKLÇ^ZXCVBNM;:_@€"; + + public void testUsedBase64IsUrlSafe() { + String encoded = base64Url().omitPadding().encode(STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING.getBytes(UTF_8)); + assertTrue(!encoded.contains("+")); + assertTrue(!encoded.contains("/")); + assertTrue(!encoded.endsWith("=")); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java new file mode 100644 index 0000000000..a44bad175d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java @@ -0,0 +1,23 @@ +/* + * 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.oauth.v2.internal; + +import org.jclouds.oauth.v2.OAuthApi; + +public class BaseOAuthApiExpectTest extends BaseOAuthExpectTest { + +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java new file mode 100644 index 0000000000..ee1149002b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java @@ -0,0 +1,56 @@ +/* + * 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.oauth.v2.internal; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.oauth.v2.OAuthTestUtils.setCredentialFromPemFile; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; + +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.oauth.v2.OAuthApi; +import org.testng.annotations.Test; + + +@Test(groups = "live") +public class BaseOAuthApiLiveTest extends BaseApiLiveTest { + + public BaseOAuthApiLiveTest() { + provider = "oauth"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setCredentialFromPemFile(props, "oauth.credential"); + checkNotNull(setIfTestSystemPropertyPresent(props, "oauth.endpoint"), "test.oauth.endpoint must be set"); + checkNotNull(setIfTestSystemPropertyPresent(props, AUDIENCE), "test.jclouds.oauth.audience must be set"); + setIfTestSystemPropertyPresent(props, SCOPES); + setIfTestSystemPropertyPresent(props, SIGNATURE_OR_MAC_ALGORITHM); + return props; + } + + protected long nowInSeconds() { + return TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + +} + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java new file mode 100644 index 0000000000..aefdcdd934 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java @@ -0,0 +1,110 @@ +/* + * 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.oauth.v2.internal; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.testng.Assert.assertNotNull; + +import java.io.Closeable; +import java.util.Properties; + +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.oauth.v2.OAuthApi; +import org.jclouds.oauth.v2.OAuthConstants; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.reflect.TypeToken; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; + +/** + * A base test of oauth authenticated rest providers. Providers must set the following properties: + *

+ * - oauth.endpoint + * - oauth.audience + * - oauth.signature-or-mac-algorithm + *

+ * - oauth.scopes is provided by the subclass + *

+ * This test asserts that a provider can authenticate with oauth for a given scope, or more simply + * that authentication/authorization is working. + */ + +@Test(groups = "live") +public abstract class BaseOAuthAuthenticatedApiLiveTest extends BaseApiLiveTest { + + protected abstract String getScopes(); + + private OAuthApi oauthApi; + + public void testAuthenticate() { + // obtain the necessary properties from the context + String signatureAlgorithm = checkNotNull(propFunction.apply(SIGNATURE_OR_MAC_ALGORITHM), + SIGNATURE_OR_MAC_ALGORITHM); + + checkState(OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureAlgorithm) + , String.format("Algorithm not supported: " + signatureAlgorithm)); + + String audience = checkNotNull(propFunction.apply(AUDIENCE), AUDIENCE); + + // obtain the scopes from the subclass + String scopes = getScopes(); + + Header header = Header.builder().signerAlgorithm(signatureAlgorithm).type("JWT").build(); + + long now = SECONDS.convert(System.currentTimeMillis(), MILLISECONDS); + + ClaimSet claimSet = ClaimSet.builder() + .addClaim("aud", audience) + .addClaim("scope", scopes) + .addClaim("iss", identity) + .emissionTime(now) + .expirationTime(now + 3600).build(); + + TokenRequest tokenRequest = TokenRequest.builder().header(header).claimSet(claimSet).build(); + + Token token = oauthApi.authenticate(tokenRequest); + + assertNotNull(token, "no token when authenticating " + tokenRequest); + } + + @SuppressWarnings({ "unchecked", "serial" }) + protected A create(Properties props, Iterable modules) { + Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); + propFunction = injector.getInstance(ValueOfConfigurationKeyOrNull.class); + try { + oauthApi = injector.getInstance(OAuthApi.class); + } catch (Exception e) { + throw new IllegalStateException("Provider has no OAuthApi bound. Was the OAuthAuthenticationModule added?"); + } + return (A) injector.getInstance(Key.get(new TypeToken(getClass()) { + }.getType())); + } + + private Function propFunction; +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java new file mode 100644 index 0000000000..18fe151ea5 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java @@ -0,0 +1,26 @@ +/* + * 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.oauth.v2.internal; + +import org.jclouds.rest.internal.BaseRestApiExpectTest; + +public class BaseOAuthExpectTest extends BaseRestApiExpectTest { + + public BaseOAuthExpectTest() { + provider = "oauth"; + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java new file mode 100644 index 0000000000..fa3307fd7e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java @@ -0,0 +1,69 @@ +/* + * 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.oauth.v2.json; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; + +import org.jclouds.ContextBuilder; +import org.jclouds.http.HttpRequest; +import org.jclouds.oauth.v2.OAuthApiMetadata; +import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.domain.TokenRequestFormat; +import org.jclouds.util.Strings2; +import org.testng.annotations.Test; + +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; + +@Test(groups = "unit") +public class JWTTokenRequestFormatTest { + public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + + "=?*qwertyuiopº´WERTYUIOPªàsdfghjklç~ASDFGHJKLÇ^ZXCVBNM;:_@€"; + + public void testPayloadIsUrlSafe() throws IOException { + + TokenRequestFormat tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides + (OAuthTestUtils.defaultProperties(null)).build().utils() + .injector().getInstance(TokenRequestFormat.class); + Header header = new Header.Builder().signerAlgorithm("a").type("b").build(); + ClaimSet claimSet = new ClaimSet.Builder().addClaim("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING) + .build(); + TokenRequest tokenRequest = new TokenRequest.Builder().claimSet(claimSet).header(header).build(); + HttpRequest request = tokenRequestFormat.formatRequest(HttpRequest.builder().method("GET").endpoint + ("http://localhost").build(), tokenRequest); + + assertNotNull(request.getPayload()); + + String payload = Strings2.toStringAndClose(request.getPayload().getInput()); + + // make sure the paylod is in the format {header}.{claims}.{signature} + Iterable parts = Splitter.on(".").split(payload); + + assertSame(Iterables.size(parts), 3); + + assertTrue(!payload.contains("+")); + assertTrue(!payload.contains("/")); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java new file mode 100644 index 0000000000..bcaa9e4a48 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java @@ -0,0 +1,40 @@ +/* + * 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.oauth.v2.parse; + +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.oauth.v2.domain.Token; +import org.testng.annotations.Test; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +@Test(groups = "unit") +public class ParseTokenTest extends BaseItemParserTest { + + @Override + public String resource() { + return "/tokenResponse.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Token expected() { + return Token.builder().expiresIn(3600).tokenType("Bearer").accessToken + ("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M").build(); + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/GoogleComputeEngineServiceExpectTest/firewall_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/GoogleComputeEngineServiceExpectTest/firewall_list.json new file mode 100644 index 0000000000..c965349447 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/GoogleComputeEngineServiceExpectTest/firewall_list.json @@ -0,0 +1,37 @@ +{ + "kind": "compute#firewallList", + "id": "projects/google/firewalls", + "selfLink": "https://www.googleapis.com/compute/v1/projects/google/global/firewalls", + "items": [ + { + + "kind": "compute#firewall", + "id": "12862241031274216284", + "creationTimestamp": "2012-04-13T03:05:02.855", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test-delete", + "name": "jclouds-test-delete", + "description": "Internal traffic from default allowed", + "network": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test-delete", + "sourceRanges": [ + "10.0.0.0/8" + ], + "allowed": [ + { + "IPProtocol": "tcp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "udp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "icmp" + } + ] + } + ] +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/GoogleComputeEngineServiceExpectTest/network_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/GoogleComputeEngineServiceExpectTest/network_get.json new file mode 100644 index 0000000000..e9308f0b91 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/GoogleComputeEngineServiceExpectTest/network_get.json @@ -0,0 +1,10 @@ +{ + "kind": "compute#network", + "id": "13024414170909937976", + "creationTimestamp": "2012-10-24T20:13:19.967", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test-delete", + "name": "jclouds-test-delete", + "description": "Default network for the project", + "IPv4Range": "10.0.0.0/8", + "gatewayIPv4": "10.0.0.1" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_get.json new file mode 100644 index 0000000000..f93e497bb6 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_get.json @@ -0,0 +1,12 @@ +{ + + "kind": "compute#address", + "id": "4439373783165447583", + "creationTimestamp": "2013-07-26T13:57:20.204-07:00", + "status": "RESERVED", + "region": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1", + "name": "test-ip1", + "description": "", + "address": "173.255.115.190", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip1" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_insert.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_insert.json new file mode 100644 index 0000000000..4bccf63d5f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_insert.json @@ -0,0 +1 @@ +{"name":"test-ip1"} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_list.json new file mode 100644 index 0000000000..cbfa9d58ff --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/address_list.json @@ -0,0 +1,31 @@ +{ + "kind": "compute#addressList", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses", + "id": "projects/myproject/regions/us-central1/addresses", + "items": [ + { + + "kind": "compute#address", + "id": "4439373783165447583", + "creationTimestamp": "2013-07-26T13:57:20.204-07:00", + "status": "RESERVED", + "region": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1", + "name": "test-ip1", + "description": "", + "address": "173.255.115.190", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip1" + }, + { + + "kind": "compute#address", + "id": "4881363978908129158", + "creationTimestamp": "2013-07-26T14:08:21.552-07:00", + "status": "RESERVED", + "region": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1", + "name": "test-ip2", + "description": "", + "address": "173.255.118.115", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-ip2" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_create_snapshot.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_create_snapshot.json new file mode 100644 index 0000000000..6499744ea0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_create_snapshot.json @@ -0,0 +1 @@ +{"name":"test-snap"} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_get.json new file mode 100644 index 0000000000..88ddd54667 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_get.json @@ -0,0 +1,10 @@ +{ + "kind": "compute#disk", + "id": "13050421646334304115", + "creationTimestamp": "2012-11-25T01:38:48.306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1", + "name": "testimage1", + "sizeGb": "1", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "status": "READY" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_insert.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_insert.json new file mode 100644 index 0000000000..8699cdd81b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_insert.json @@ -0,0 +1 @@ +{"name":"testimage1","sizeGb":1} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_list.json new file mode 100644 index 0000000000..bdca33d699 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/disk_list.json @@ -0,0 +1,17 @@ +{ + "kind": "compute#diskList", + "id": "projects/myproject/zones/us-central1-a/disks", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks", + "items": [ + { + "kind": "compute#disk", + "id": "13050421646334304115", + "creationTimestamp": "2012-11-25T01:38:48.306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1", + "name": "testimage1", + "sizeGb": "1", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "status": "READY" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_get.json new file mode 100644 index 0000000000..74ced7447f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_get.json @@ -0,0 +1,30 @@ +{ + + "kind": "compute#firewall", + "id": "12862241031274216284", + "creationTimestamp": "2012-04-13T03:05:02.855", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test", + "name": "jclouds-test", + "description": "Internal traffic from default allowed", + "network": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test", + "sourceRanges": [ + "10.0.0.0/8" + ], + "allowed": [ + { + "IPProtocol": "tcp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "udp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "icmp" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_insert.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_insert.json new file mode 100644 index 0000000000..fabe1bddd5 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_insert.json @@ -0,0 +1 @@ +{"name":"%s","network":"https://www.googleapis.com/compute/v1/projects/myproject/global/networks/%s","sourceRanges":[%s],"sourceTags":[%s],"targetTags":[%s],"allowed":[{"IPProtocol":"tcp","ports":[%s]}]} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_list.json new file mode 100644 index 0000000000..ab7d0b7f7b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/firewall_list.json @@ -0,0 +1,58 @@ +{ + "kind": "compute#firewallList", + "id": "projects/google/firewalls", + "selfLink": "https://www.googleapis.com/compute/v1/projects/google/global/firewalls", + "items": [ + { + + "kind": "compute#firewall", + "id": "12862241031274216284", + "creationTimestamp": "2012-04-13T03:05:02.855", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test", + "name": "jclouds-test", + "description": "Internal traffic from default allowed", + "network": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/jclouds-test", + "sourceRanges": [ + "10.0.0.0/8" + ], + "allowed": [ + { + "IPProtocol": "tcp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "udp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "icmp" + } + ] + }, + { + + "kind": "compute#firewall", + "id": "12862241067393040785", + "creationTimestamp": "2012-04-13T03:05:04.365", + "selfLink": "https://www.googleapis.com/compute/v1/projects/google/global/firewalls/default-ssh", + "name": "default-ssh", + "description": "SSH allowed from anywhere", + "network": "https://www.googleapis.com/compute/v1/projects/google/global/networks/default", + "sourceRanges": [ + "0.0.0.0/0" + ], + "allowed": [ + { + "IPProtocol": "tcp", + "ports": [ + "22" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/global_operation.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/global_operation.json new file mode 100644 index 0000000000..17d7748301 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/global_operation.json @@ -0,0 +1,15 @@ +{ + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test-delete", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "endTime": "2012-11-28T06:41:06.142", + "operationType": "insert" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/global_operation_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/global_operation_list.json new file mode 100644 index 0000000000..32b881ad39 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/global_operation_list.json @@ -0,0 +1,22 @@ +{ + "kind": "compute#operationList", + "id": "projects/myproject/global/operations", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/operations", + "items": [ + { + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/jclouds-test-delete", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "endTime": "2012-11-28T06:41:06.142", + "operationType": "insert" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_get.json new file mode 100644 index 0000000000..23cb0d202f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_get.json @@ -0,0 +1,13 @@ +{ + "kind": "compute#image", + "id": "12941197498378735318", + "creationTimestamp": "2012-07-16T22:16:13.468", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120326", + "name": "centos-6-2-v20120326", + "description": "DEPRECATED. CentOS 6.2 image; Created Mon, 26 Mar 2012 21:19:09 +0000", + "sourceType": "RAW", + "rawDisk": { + "source": "", + "containerType": "TAR" + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_insert.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_insert.json new file mode 100644 index 0000000000..fd030a74ca --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_insert.json @@ -0,0 +1,4 @@ +{"sourceType": "RAW", "rawDisk": { + "source": "https://storage.googleapis.com/mybuket/myimage.image.tar.gz", + "containerType": "TAR" +}, "kind": "compute#image", "name": "myimage"} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list.json new file mode 100644 index 0000000000..6010f5a38c --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list.json @@ -0,0 +1,24 @@ +{ + "kind": "compute#imageList", + "id": "projects/centos-cloud/global/images", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images", + "items": [ + { + "kind": "compute#image", + "id": "12941197498378735318", + "creationTimestamp": "2012-07-16T22:16:13.468", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120326", + "name": "centos-6-2-v20120326", + "description": "DEPRECATED. CentOS 6.2 image; Created Mon, 26 Mar 2012 21:19:09 +0000", + "sourceType": "RAW", + "deprecated": { + "state": "DEPRECATED", + "replacement": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-v20130104" + }, + "rawDisk": { + "source": "", + "containerType": "TAR" + } + } + ] +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_empty.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_empty.json new file mode 100644 index 0000000000..f082e082bd --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_empty.json @@ -0,0 +1,6 @@ +{ + "kind": "compute#imageList", + "id": "projects/debian-cloud/global/images", + "selfLink": "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images", + "items": [ ] +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_multiple_page_1.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_multiple_page_1.json new file mode 100644 index 0000000000..3ffcfd5e7d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_multiple_page_1.json @@ -0,0 +1,55 @@ +{ + "kind": "compute#imageList", + "id": "projects/centos-cloud/global/images", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images", + "nextPageToken": "CgVJTUFHRRIbZ29vZ2xlLmNlbnRvcy02LTItdjIwMTIwNjIx", + "items": [ + { + "kind": "compute#image", + "id": "12941197498378735318", + "creationTimestamp": "2012-07-16T15:16:13.468-07:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120326", + "name": "centos-6-2-v20120326", + "description": "DEPRECATED. CentOS 6.2 image; Created Mon, 26 Mar 2012 21:19:09 +0000", + "sourceType": "RAW", + "deprecated": { + "state": "DELETED", + "replacement": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-v20130104" + }, + "rawDisk": { + "source": "", + "containerType": "TAR" + } + }, + { + "kind": "compute#image", + "id": "12894486577628239762", + "creationTimestamp": "2012-05-21T13:15:37.215-07:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120503", + "name": "centos-6-2-v20120503", + "description": "CentOS 6.2; Created Wed, 09 May 2012 11:55:54 +0000", + "sourceType": "RAW", + "rawDisk": { + "source": "", + "containerType": "TAR" + } + }, + { + "kind": "compute#image", + "id": "12917726455664967299", + "creationTimestamp": "2012-06-18T11:05:30.664-07:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120611", + "name": "centos-6-2-v20120611", + "description": "CentOS 6.2; Created Mon, 11 Jun 2012 13:15:44 +0000", + "sourceType": "RAW", + "deprecated": { + "state": "DEPRECATED", + "replacement": "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-20130509" + }, + "rawDisk": { + "source": "", + "containerType": "TAR" + } + } + ] +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_multiple_page_2.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_multiple_page_2.json new file mode 100644 index 0000000000..b7b736ae77 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_multiple_page_2.json @@ -0,0 +1,47 @@ +{ + "kind": "compute#imageList", + "id": "projects/centos-cloud/global/images", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images", + "nextPageToken": "CgVJTUFHRRIbZ29vZ2xlLmdjZWwtMTAtMDQtdjIwMTIxMTA2", + "items": [ + { + "kind": "compute#image", + "id": "12920641029336858796", + "creationTimestamp": "2012-06-21T22:59:56.392-07:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-2-v20120621", + "name": "centos-6-2-v20120621", + "description": "CentOS 6.2; Created Thu, 21 Jun 2012 14:22:21 +0000", + "sourceType": "RAW", + "rawDisk": { + "source": "", + "containerType": "TAR" + } + }, + { + "kind": "compute#image", + "id": "12994279803511049620", + "creationTimestamp": "2012-09-18T08:52:47.584-07:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-v20120912", + "name": "centos-6-v20120912", + "description": "CentOS 6; Created Wed, 12 Sep 2012 00:00:00 +0000", + "sourceType": "RAW", + "rawDisk": { + "source": "", + "containerType": "TAR" + } + }, + { + "kind": "compute#image", + "id": "13037720516378381209", + "creationTimestamp": "2012-11-09T11:40:41.079-08:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-6-v20121106", + "name": "centos-6-v20121106", + "description": "SCSI-enabled CentOS 6; Created Tue, 06 Nov 2012 00:00:00 +0000", + "sourceType": "RAW", + "rawDisk": { + "source": "", + "containerType": "TAR" + } + } + ] +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_single_page.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_single_page.json new file mode 100644 index 0000000000..4136f46d36 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/image_list_single_page.json @@ -0,0 +1,50 @@ +{ + "kind": "compute#imageList", + "id": "projects/centos-cloud/global/images", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images", + "items": [ + { + "kind": "compute#image", + "id": "13037722963789596520", + "creationTimestamp": "2012-11-09T11:43:28.749-08:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/gcel-10-04-v20121106", + "name": "gcel-10-04-v20121106", + "description": "SCSI-enabled GCEL 10.04 LTS; Created Tue, 06 Nov 2012 00:00:00 +0000", + "sourceType": "RAW", + "rawDisk": { + "source": "", + "containerType": "TAR" + } + }, + { + "kind": "compute#image", + "id": "13037721421359523565", + "creationTimestamp": "2012-11-09T11:40:51.994-08:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/gcel-12-04-v20121106", + "name": "gcel-12-04-v20121106", + "description": "SCSI-enabled GCEL 12.04 LTS; Created Tue, 06 Nov 2012 00:00:00 +0000", + "sourceType": "RAW", + "rawDisk": { + "source": "", + "containerType": "TAR" + } + }, + { + "kind": "compute#image", + "id": "12941198995845323366", + "creationTimestamp": "2012-07-16T15:18:50.405-07:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/ubuntu-10-04-v20110728", + "name": "ubuntu-10-04-v20110728", + "description": "DEPRECATED. GCEL 10.04 LTS; Created Thu, 28 Jul 2011 16:45:51 +0000", + "sourceType": "RAW", + "deprecated": { + "state": "DELETED", + "replacement": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/gcel-10-04-v20130104" + }, + "rawDisk": { + "source": "", + "containerType": "TAR" + } + } + ] +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_add_access_config.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_add_access_config.json new file mode 100644 index 0000000000..fe4fcf0228 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_add_access_config.json @@ -0,0 +1,11 @@ +POST https://www.googleapis.com/compute/v1/projects/jclouds-gce/zones/us-central1-a/instances/test-instance/addAccessConfig?network_interface=nic0&key={YOUR_API_KEY} + +Content-Type: application/json +Authorization: Bearer ya29.AHES6ZRyNKVHwnMPUvZitAuA8mR8b0lcWh1bMI5UQ5bgsJ4j +X-JavaScript-User-Agent: Google APIs Explorer + +{ +"name": "config1", +"natIP": "10.0.1.1", +"type": "ONE_TO_ONE_NAT" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_attach_disk.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_attach_disk.json new file mode 100644 index 0000000000..8fc35bcd0a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_attach_disk.json @@ -0,0 +1,6 @@ +{ + "type": "PERSISTENT", + "mode": "READ_ONLY", + "source": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1", + "boot": false +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_get.json new file mode 100644 index 0000000000..c38ae7779e --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_get.json @@ -0,0 +1,62 @@ +{ + "kind": "compute#instance", + "id": "13051190678907570425", + "description": "desc", + "creationTimestamp": "2012-11-25T23:48:20.758", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-0", + "name": "test-0", + "machineType": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1", + "status": "RUNNING", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "networkInterfaces": [ + { + "kind": "compute#instanceNetworkInterface", + "name": "nic0", + "networkIP": "10.240.121.115", + "network": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default" + } + ], + "disks": [ + { + "kind": "compute#instanceDisk", + "type": "PERSISTENT", + "mode": "READ_WRITE", + "deviceName": "test", + "source": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/test", + "index": 0, + "boot": true + } + ], + "serviceAccounts": [ + { + "kind": "compute#serviceAccount", + "email": "default", + "scopes": [ + "myscope" + ] + } + ], + "metadata": { + "items": [ + { + "key": "aKey", + "value": "aValue" + }, + { + "key": "jclouds-image", + "value": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/gcel-12-04-v20121106" + }, + { + "key": "jclouds-delete-boot-disk", + "value": "true" + } + ], + "fingerprint": "efgh" + }, + "tags": { + "items": [ + "aTag" + ], + "fingerprint": "abcd" + } +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_insert.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_insert.json new file mode 100644 index 0000000000..0ce3c53927 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_insert.json @@ -0,0 +1 @@ +{"name":"test-0","description":"desc","machineType":"https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1","serviceAccounts":[{"email":"default","scopes":["myscope"]}],"networkInterfaces":[{"network":"https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default","accessConfigs":[{"type":"ONE_TO_ONE_NAT"}]}],"disks":[{"mode":"READ_WRITE","source":"https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/test","deleteOnTerminate":true,"boot":false,"type":"PERSISTENT"}],"metadata":{"kind":"compute#metadata","items":[{"key":"aKey","value":"aValue"}]}} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_insert_simple.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_insert_simple.json new file mode 100644 index 0000000000..038e7f8b43 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_insert_simple.json @@ -0,0 +1 @@ +{"name":"test-1","machineType":"https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1","serviceAccounts":[],"networkInterfaces":[{"network":"https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default","accessConfigs":[]}]} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_list.json new file mode 100644 index 0000000000..7e9595c52f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_list.json @@ -0,0 +1,69 @@ +{ + "kind": "compute#instanceList", + "id": "projects/myproject/zones/us-central1-a/instances", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances", + "items": [ + { + "kind": "compute#instance", + "id": "13051190678907570425", + "description": "desc", + "creationTimestamp": "2012-11-25T23:48:20.758", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-0", + "name": "test-0", + "machineType": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1", + "status": "RUNNING", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "networkInterfaces": [ + { + "kind": "compute#instanceNetworkInterface", + "name": "nic0", + "networkIP": "10.240.121.115", + "network": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default" + } + ], + "disks": [ + { + "kind": "compute#instanceDisk", + "type": "PERSISTENT", + "mode": "READ_WRITE", + "deviceName": "test", + "source": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/test", + "index": 0, + "boot": true + } + ], + "serviceAccounts": [ + { + "kind": "compute#serviceAccount", + "email": "default", + "scopes": [ + "myscope" + ] + } + ], + "metadata": { + "items": [ + { + "key": "aKey", + "value": "aValue" + }, + { + "key": "jclouds-image", + "value": "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/gcel-12-04-v20121106" + }, + { + "key": "jclouds-delete-boot-disk", + "value": "true" + } + ], + "fingerprint": "efgh" + }, + "tags": { + "items": [ + "aTag" + ], + "fingerprint": "abcd" + } + } + ] +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_list_central1b_empty.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_list_central1b_empty.json new file mode 100644 index 0000000000..51c8793c08 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_list_central1b_empty.json @@ -0,0 +1,6 @@ +{ + "kind": "compute#instanceList", + "id": "projects/myproject/zones/us-central1-b/instances", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b/instances", + "items": [ ] +} diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_serial_port.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_serial_port.json new file mode 100644 index 0000000000..03280cca8b --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_serial_port.json @@ -0,0 +1,4 @@ +{ + "kind": "compute#serialPortOutput", + "contents": "console output" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_set_metadata.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_set_metadata.json new file mode 100644 index 0000000000..b39e983bde --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/instance_set_metadata.json @@ -0,0 +1,10 @@ +{ + "items": [ + { + "key": "foo", + "value": "bar" + } + ], + "fingerprint": "efgh", + "kind": "compute#metadata" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/logback.xml b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/logback.xml new file mode 100644 index 0000000000..864a5a52de --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/logback.xml @@ -0,0 +1,83 @@ + + + + + target/test-data/jclouds.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-wire.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-compute.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-ssh.log + + + %d %-5p [%c] [%thread] %m%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype.json new file mode 100644 index 0000000000..01692b33ff --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype.json @@ -0,0 +1,22 @@ +{ + "kind": "compute#machineType", + "id": "12907738072351752276", + "creationTimestamp": "2012-06-07T20:48:14.670", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1", + "name": "n1-standard-1", + "description": "1 vCPU, 3.75 GB RAM, and a 10 GB ephemeral root disk", + "guestCpus": 1, + "memoryMb": 3840, + "imageSpaceGb": 10, + "scratchDisks": [ + { + "diskGb": 1770 + }, + { + "diskGb": 1770 + } + ], + "maximumPersistentDisks": 16, + "maximumPersistentDisksSizeGb": "128", + "zone": "us-central1-a" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list.json new file mode 100644 index 0000000000..9acb7e0cde --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list.json @@ -0,0 +1,57 @@ +{ + "kind": "compute#machineTypeList", + "id": "projects/myproject/machineTypes", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes", + "items": [ + { + "kind": "compute#machineType", + "id": "4618642685664990776", + "creationTimestamp": "2013-04-25T13:32:49.088-07:00", + "name": "f1-micro", + "description": "1 vCPU (shared physical core) and 0.6 GB RAM", + "guestCpus": 1, + "memoryMb": 614, + "imageSpaceGb": 0, + "maximumPersistentDisks": 4, + "maximumPersistentDisksSizeGb": "3072", + "zone": "us-central1-a", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/f1-micro" + }, + { + "kind": "compute#machineType", + "id": "12907738072351752276", + "creationTimestamp": "2012-06-07T20:48:14.670", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-1", + "name": "n1-standard-1", + "description": "1 vCPU, 3.75 GB RAM, and a 10 GB ephemeral root disk", + "guestCpus": 1, + "memoryMb": 3840, + "imageSpaceGb": 10, + "maximumPersistentDisks": 16, + "maximumPersistentDisksSizeGb": "128", + "zone": "us-central1-a" + }, + { + "kind": "compute#machineType", + "id": "12908560709887590691", + "creationTimestamp": "2012-06-07T20:51:19.936", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/machineTypes/n1-standard-8-d", + "name": "n1-standard-8-d", + "description": "8 vCPUs, 30 GB RAM, a 10 GB ephemeral root disk, and 2 extra 1770 GB ephemeral disks", + "guestCpus": 8, + "memoryMb": 30720, + "imageSpaceGb": 10, + "scratchDisks": [ + { + "diskGb": 1770 + }, + { + "diskGb": 1770 + } + ], + "maximumPersistentDisks": 16, + "maximumPersistentDisksSizeGb": "1024", + "zone": "us-central1-a" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list_central1b.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list_central1b.json new file mode 100644 index 0000000000..fe5974a7a6 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list_central1b.json @@ -0,0 +1,43 @@ +{ + "kind": "compute#machineTypeList", + "selfLink": "https://www.googleapis.com/compute/v1/projects/abayer-jclouds-test1/zones/us-central1-b/machineTypes", + "id": "projects/abayer-jclouds-test1/zones/us-central1-b/machineTypes", + "items": [ + { + "kind": "compute#machineType", + "id": "12907738072351752276", + "creationTimestamp": "2012-06-07T20:48:14.670", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b/machineTypes/n1-standard-0", + "name": "n1-standard-0", + "description": "1 vCPU, 3.75 GB RAM, and a 10 GB ephemeral root disk", + "guestCpus": 1, + "memoryMb": 3840, + "imageSpaceGb": 10, + "maximumPersistentDisks": 16, + "maximumPersistentDisksSizeGb": "128", + "zone": "us-central1-b" + }, + { + "kind": "compute#machineType", + "id": "12908560709887590691", + "creationTimestamp": "2012-06-07T20:51:19.936", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b/machineTypes/n1-standard-8-d", + "name": "n1-standard-8-d", + "description": "8 vCPUs, 30 GB RAM, a 10 GB ephemeral root disk, and 2 extra 1770 GB ephemeral disks", + "guestCpus": 8, + "memoryMb": 30720, + "imageSpaceGb": 10, + "scratchDisks": [ + { + "diskGb": 1770 + }, + { + "diskGb": 1770 + } + ], + "maximumPersistentDisks": 16, + "maximumPersistentDisksSizeGb": "1024", + "zone": "us-central1-b" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list_central1b_empty.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list_central1b_empty.json new file mode 100644 index 0000000000..73fe582435 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/machinetype_list_central1b_empty.json @@ -0,0 +1,6 @@ +{ + "kind": "compute#machineTypeList", + "id": "projects/myproject/zones/us-central1-b/machineTypes", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b/machineTypes", + "items": [] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/metadata.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/metadata.json new file mode 100644 index 0000000000..5014270a68 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/metadata.json @@ -0,0 +1 @@ +{"kind":"compute#metadata","items":[{"key":"propA","value":"valueA"},{"key":"propB","value":"valueB"}],"fingerprint":"efgh"} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_get.json new file mode 100644 index 0000000000..4a7a9cc2f8 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_get.json @@ -0,0 +1,10 @@ +{ + "kind": "compute#network", + "id": "13024414170909937976", + "creationTimestamp": "2012-10-24T20:13:19.967", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/networks/jclouds-test", + "name": "default", + "description": "Default network for the project", + "IPv4Range": "10.0.0.0/8", + "gatewayIPv4": "10.0.0.1" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_insert.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_insert.json new file mode 100644 index 0000000000..55e8331fc5 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_insert.json @@ -0,0 +1 @@ +{"name":"test-network","IPv4Range":"10.0.0.0/8"} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_list.json new file mode 100644 index 0000000000..1d15f6e200 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/network_list.json @@ -0,0 +1,18 @@ +{ + "kind": "compute#networkList", + "id": "projects/myproject/networks", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/networks", + "items": [ + { + + "kind": "compute#network", + "id": "13024414170909937976", + "creationTimestamp": "2012-10-24T20:13:19.967", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/networks/jclouds-test", + "name": "default", + "description": "Default network for the project", + "IPv4Range": "10.0.0.0/8", + "gatewayIPv4": "10.0.0.1" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation.json new file mode 100644 index 0000000000..7ca83c8c5d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation.json @@ -0,0 +1,17 @@ +{ + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "endTime": "2012-11-28T06:41:06.142", + "operationType": "insert", + "region": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation_error.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation_error.json new file mode 100644 index 0000000000..157f786b46 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation_error.json @@ -0,0 +1,26 @@ +{ + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "httpErrorStatusCode": 400, + "httpErrorMessage": "BAD REQUEST", + "error": { + "errors": [ + { + "code": "RESOURCE_ALREADY_EXISTS", + "message": "The resource 'projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance' already exists" + } + ] + }, + "operationType": "insert", + "region": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation_list.json new file mode 100644 index 0000000000..c83980d2e4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/operation_list.json @@ -0,0 +1,24 @@ +{ + "kind": "compute#operationList", + "id": "projects/myproject/operations", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/operations", + "items": [ + { + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "endTime": "2012-11-28T06:41:06.142", + "operationType": "insert", + "region": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/project.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/project.json new file mode 100644 index 0000000000..c195062227 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/project.json @@ -0,0 +1,69 @@ +{ + "kind": "compute#project", + "id": "13024414184846275913", + "creationTimestamp": "2012-10-24T20:13:16.252", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject", + "name": "myproject", + "description": "", + "commonInstanceMetadata": { + "kind": "compute#metadata", + "items": [ + { + "key": "propA", + "value": "valueA" + }, + { + "key": "propB", + "value": "valueB" + } + ], + "fingerprint": "efgh" + }, + "quotas": [ + { + "metric": "INSTANCES", + "usage": 0, + "limit": 8 + }, + { + "metric": "CPUS", + "usage": 0, + "limit": 8 + }, + { + "metric": "EPHEMERAL_ADDRESSES", + "usage": 0, + "limit": 8 + }, + { + "metric": "DISKS", + "usage": 0, + "limit": 8 + }, + { + "metric": "DISKS_TOTAL_GB", + "usage": 0, + "limit": 100 + }, + { + "metric": "SNAPSHOTS", + "usage": 0, + "limit": 1000 + }, + { + "metric": "NETWORKS", + "usage": 1, + "limit": 5 + }, + { + "metric": "FIREWALLS", + "usage": 2, + "limit": 100 + }, + { + "metric": "IMAGES", + "usage": 0, + "limit": 100 + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/quota.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/quota.json new file mode 100644 index 0000000000..b631ab33dd --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/quota.json @@ -0,0 +1,5 @@ +{ + "metric": "INSTANCES", + "usage": 0, + "limit": 8 +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_get.json new file mode 100644 index 0000000000..069865d2a6 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_get.json @@ -0,0 +1,60 @@ +{ + "kind": "compute#region", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1", + "id": "12912210600542709766", + "creationTimestamp": "2013-07-08T14:40:37.939-07:00", + "name": "us-central1", + "description": "us-central1", + "status": "UP", + "zones": [ + "https://www.googleapis.com/compute/v1/zones/us-central1-a", + "https://www.googleapis.com/compute/v1/zones/us-central1-b" + ], + "quotas": [ + { + "metric": "INSTANCES", + "usage": 0, + "limit": 8 + }, + { + "metric": "CPUS", + "usage": 0, + "limit": 8 + }, + { + "metric": "EPHEMERAL_ADDRESSES", + "usage": 0, + "limit": 8 + }, + { + "metric": "DISKS", + "usage": 0, + "limit": 8 + }, + { + "metric": "DISKS_TOTAL_GB", + "usage": 0, + "limit": 100 + }, + { + "metric": "SNAPSHOTS", + "usage": 0, + "limit": 1000 + }, + { + "metric": "NETWORKS", + "usage": 1, + "limit": 5 + }, + { + "metric": "FIREWALLS", + "usage": 2, + "limit": 100 + }, + { + "metric": "IMAGES", + "usage": 0, + "limit": 100 + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_list.json new file mode 100644 index 0000000000..ae0673e9d0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_list.json @@ -0,0 +1,126 @@ +{ + "kind": "compute#regionList", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions", + "id": "projects/myproject/regions", + "items": [ + { + "kind": "compute#region", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1", + "id": "12912210600542709766", + "creationTimestamp": "2013-07-08T14:40:37.939-07:00", + "name": "us-central1", + "description": "us-central1", + "status": "UP", + "zones": [ + "https://www.googleapis.com/compute/v1/zones/us-central1-a", + "https://www.googleapis.com/compute/v1/zones/us-central1-b" + ], + "quotas": [ + { + "metric": "INSTANCES", + "usage": 0, + "limit": 8 + }, + { + "metric": "CPUS", + "usage": 0, + "limit": 8 + }, + { + "metric": "EPHEMERAL_ADDRESSES", + "usage": 0, + "limit": 8 + }, + { + "metric": "DISKS", + "usage": 0, + "limit": 8 + }, + { + "metric": "DISKS_TOTAL_GB", + "usage": 0, + "limit": 100 + }, + { + "metric": "SNAPSHOTS", + "usage": 0, + "limit": 1000 + }, + { + "metric": "NETWORKS", + "usage": 1, + "limit": 5 + }, + { + "metric": "FIREWALLS", + "usage": 2, + "limit": 100 + }, + { + "metric": "IMAGES", + "usage": 0, + "limit": 100 + } + ] + }, + { + "kind": "compute#region", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central2", + "id": "6396763663251190992", + "creationTimestamp": "2013-07-08T14:40:37.939-07:00", + "name": "us-central2", + "description": "us-central2", + "status": "UP", + "zones": [ + "https://www.googleapis.com/compute/v1/zones/us-central2-a" + ], + "quotas": [ + { + "metric": "INSTANCES", + "usage": 0, + "limit": 8 + }, + { + "metric": "CPUS", + "usage": 0, + "limit": 8 + }, + { + "metric": "EPHEMERAL_ADDRESSES", + "usage": 0, + "limit": 8 + }, + { + "metric": "DISKS", + "usage": 0, + "limit": 8 + }, + { + "metric": "DISKS_TOTAL_GB", + "usage": 0, + "limit": 100 + }, + { + "metric": "SNAPSHOTS", + "usage": 0, + "limit": 1000 + }, + { + "metric": "NETWORKS", + "usage": 1, + "limit": 5 + }, + { + "metric": "FIREWALLS", + "usage": 2, + "limit": 100 + }, + { + "metric": "IMAGES", + "usage": 0, + "limit": 100 + } + ] + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_operation.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_operation.json new file mode 100644 index 0000000000..67ac27d04d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_operation.json @@ -0,0 +1,16 @@ +{ + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-address", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "endTime": "2012-11-28T06:41:06.142", + "operationType": "insert", + "region": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_operation_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_operation_list.json new file mode 100644 index 0000000000..8a6d619ca8 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/region_operation_list.json @@ -0,0 +1,23 @@ +{ + "kind": "compute#operationList", + "id": "projects/myproject/regions/us-central1/operations", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/operations", + "items": [ + { + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/addresses/test-address", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "endTime": "2012-11-28T06:41:06.142", + "operationType": "insert", + "region": "https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_get.json new file mode 100644 index 0000000000..be544f278d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_get.json @@ -0,0 +1,14 @@ +{ + + "kind": "compute#route", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/routes/default-route-c99ebfbed0e1f375", + "id": "7241926205630356071", + "creationTimestamp": "2013-07-08T14:40:38.502-07:00", + "name": "default-route-c99ebfbed0e1f375", + "description": "Default route to the virtual network.", + "network": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default", + "destRange": "10.240.0.0/16", + "priority": 1000, + "nextHopNetwork": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default", + "tags": [ "fooTag", "barTag" ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_insert.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_insert.json new file mode 100644 index 0000000000..68fff7d983 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_insert.json @@ -0,0 +1 @@ +{"name":"default-route-c99ebfbed0e1f375","description":"Default route to the virtual network.","network":"https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default","destRange":"10.240.0.0/16","priority":1000,"nextHopNetwork":"https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default","tags":["fooTag","barTag"]} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_list.json new file mode 100644 index 0000000000..5126ff1068 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/route_list.json @@ -0,0 +1,34 @@ +{ + "kind": "compute#routeList", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/routes", + "id": "projects/myproject/global/routes", + "items": [ + { + + "kind": "compute#route", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/routes/default-route-c99ebfbed0e1f375", + "id": "7241926205630356071", + "creationTimestamp": "2013-07-08T14:40:38.502-07:00", + "name": "default-route-c99ebfbed0e1f375", + "description": "Default route to the virtual network.", + "network": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default", + "destRange": "10.240.0.0/16", + "priority": 1000, + "nextHopNetwork": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default", + "tags": [ "fooTag", "barTag" ] + }, + { + + "kind": "compute#route", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/routes/default-route-fc92a41ecb5a8d17", + "id": "507025480040058551", + "creationTimestamp": "2013-07-08T14:40:38.502-07:00", + "name": "default-route-fc92a41ecb5a8d17", + "description": "Default route to the Internet.", + "network": "https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default", + "destRange": "0.0.0.0/0", + "priority": 1000, + "nextHopGateway": "https://www.googleapis.com/compute/v1/projects/myproject/global/gateways/default-internet-gateway" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/snapshot_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/snapshot_get.json new file mode 100644 index 0000000000..3ba287f5d4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/snapshot_get.json @@ -0,0 +1,13 @@ +{ + + "kind": "compute#snapshot", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/snapshots/test-snap", + "id": "9734455566806191190", + "creationTimestamp": "2013-07-26T12:54:23.173-07:00", + "status": "READY", + "diskSizeGb": "10", + "sourceDisk": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1", + "name": "test-snap", + "description": "", + "sourceDiskId": "8243603669926824540" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/snapshot_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/snapshot_list.json new file mode 100644 index 0000000000..431460f294 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/snapshot_list.json @@ -0,0 +1,33 @@ +{ + "kind": "compute#snapshotList", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/snapshots", + "id": "projects/myproject/global/snapshots", + "items": [ + { + + "kind": "compute#snapshot", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/snapshots/test-snap", + "id": "9734455566806191190", + "creationTimestamp": "2013-07-26T12:54:23.173-07:00", + "status": "READY", + "diskSizeGb": "10", + "sourceDisk": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1", + "name": "test-snap", + "description": "", + "sourceDiskId": "8243603669926824540" + }, + { + + "kind": "compute#snapshot", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/snapshots/test-snap2", + "id": "13895715048576107883", + "creationTimestamp": "2013-07-26T12:57:01.927-07:00", + "status": "READY", + "diskSizeGb": "10", + "sourceDisk": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/disks/testimage1", + "name": "test-snap2", + "description": "", + "sourceDiskId": "8243603669926824540" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/tag_insert.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/tag_insert.json new file mode 100644 index 0000000000..61ade71a24 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/tag_insert.json @@ -0,0 +1 @@ +{"items":["aTag"],"fingerprint":"abcd"} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/testpk.pem b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/testpk.pem new file mode 100644 index 0000000000..1443074c78 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/testpk.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQCwqwzakEPP+U9vx9JCuMHebFIVQZ4Sjaj2RU9dJ6YT2s3u7dC6 +/0fGM5xm4fXmSHqyGC6PC8weQSkxnSpbU+R4jMWPM8ML4TIr5wP0avbg+wy3+WWI +of0MN7YHkCfqpaaiKiMw7niK1y07YvxJN8LX1xLpE7aXgIpn6L/qtJdHnQIDAQAB +AoGBAIAHlcsW3W3smPrC7sdXqXeNPHcXFH0RmC7Qz9EMmLiuyqqqQagitFsYr/GH +M3Ltd611BNi5jfUm97ly0m1ZAKp/nkTMVhfKfRIVsBDHtjQHcUOR9tr0LslptmaN +TG0bovbUohe5KwOqMK4YOjUQbInChVBrf7VrNQtv8e0eShdpAkEA3lzLP9QYfP1i +C4iYXqS7cgMDrs3qujC7PoyB54maen+Uvgyau1ZJpKMzXYkORPcYk+b71bl9jF80 +U+7LDnJjPwJBAMtksvL1V8DC5DYL43497JW4KBN4YZ3K7YWx/9gkvc3Q9VdXiUGu +6WKjmcbmsPI/jFdeO71uy934N8qEXLJcyiMCQQCTNKcxWD3l8PCJZiJI9ZFKBwjX +Hmb4X+51mBsfpw7nbbKQplOBFbynC4ujrmoN6e8RaubpNGUTGqvPrNQsejmNAkEA +lUDEAH4BczaQ+QgoXI9ceVG2NvNzzrMHMcC5Ggd8MPhR0VIvKsAMC5I6WjcXSe1Q +Mxy3gf84Ix7u8fHHhCuLOQJAQRhrlXiQUk4cJumNhjza5/+KtaV4FPbEQi+qcWE6 +tGoHPEBfbXyUdcUD4ae8X1W0yri0BuyVNaOCpGCBRIhPZA== +-----END RSA PRIVATE KEY----- diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/tokenResponse.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/tokenResponse.json new file mode 100644 index 0000000000..6717a550e9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/tokenResponse.json @@ -0,0 +1,5 @@ +{ + "access_token" : "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", + "token_type" : "Bearer", + "expires_in" : 3600 +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_get.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_get.json new file mode 100644 index 0000000000..50cb3755f9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_get.json @@ -0,0 +1,17 @@ +{ + "kind": "compute#zone", + "id": "13020128040171887099", + "creationTimestamp": "2012-10-19T16:42:54.131", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "name": "us-central1-a", + "description": "us-central1-a", + "status": "DOWN", + "maintenanceWindows": [ + { + "name": "2012-11-10-planned-outage", + "description": "maintenance zone", + "beginTime": "2012-11-10T20:00:00.000", + "endTime": "2012-12-02T20:00:00.000" + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_list.json new file mode 100644 index 0000000000..ee4e17b9c3 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_list.json @@ -0,0 +1,41 @@ +{ + "kind": "compute#zoneList", + "id": "projects/myproject/zones", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones", + "items": [ + { + "kind": "compute#zone", + "id": "13020128040171887099", + "creationTimestamp": "2012-10-19T16:42:54.131", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "name": "us-central1-a", + "description": "us-central1-a", + "status": "DOWN", + "maintenanceWindows": [ + { + "name": "2012-11-10-planned-outage", + "description": "maintenance zone", + "beginTime": "2012-11-10T20:00:00.000", + "endTime": "2012-12-02T20:00:00.000" + } + ] + }, + { + "kind": "compute#zone", + "id": "13024414164050619686", + "creationTimestamp": "2012-10-24T20:13:19.271", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-b", + "name": "us-central1-b", + "description": "us-central1-b", + "status": "UP", + "maintenanceWindows": [ + { + "name": "2013-02-17-planned-outage", + "description": "maintenance zone", + "beginTime": "2013-02-17T08:00:00.000", + "endTime": "2013-03-03T08:00:00.000" + } + ] + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_list_short.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_list_short.json new file mode 100644 index 0000000000..711af99238 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_list_short.json @@ -0,0 +1,24 @@ +{ + "kind": "compute#zoneList", + "id": "projects/myproject/zones", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones", + "items": [ + { + "kind": "compute#zone", + "id": "13020128040171887099", + "creationTimestamp": "2012-10-19T16:42:54.131", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a", + "name": "us-central1-a", + "description": "us-central1-a", + "status": "DOWN", + "maintenanceWindows": [ + { + "name": "2012-11-10-planned-outage", + "description": "maintenance zone", + "beginTime": "2012-11-10T20:00:00.000", + "endTime": "2012-12-02T20:00:00.000" + } + ] + } + ] +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation.json new file mode 100644 index 0000000000..c0c5b561f1 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation.json @@ -0,0 +1,16 @@ +{ + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "endTime": "2012-11-28T06:41:06.142", + "operationType": "insert", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation_error.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation_error.json new file mode 100644 index 0000000000..d6d054a548 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation_error.json @@ -0,0 +1,25 @@ +{ + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "httpErrorStatusCode": 400, + "httpErrorMessage": "BAD REQUEST", + "error": { + "errors": [ + { + "code": "RESOURCE_ALREADY_EXISTS", + "message": "The resource 'projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance' already exists" + } + ] + }, + "operationType": "insert", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a" +} \ No newline at end of file diff --git a/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation_list.json b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation_list.json new file mode 100644 index 0000000000..77f1656af4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.0-stratos/src/test/resources/zone_operation_list.json @@ -0,0 +1,23 @@ +{ + "kind": "compute#operationList", + "id": "projects/myproject/zones/us-central1-a/operations", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations", + "items": [ + { + "kind": "compute#operation", + "id": "13053095055850848306", + "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb", + "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb", + "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance", + "targetId": "13053094017547040099", + "status": "DONE", + "user": "user@developer.gserviceaccount.com", + "progress": 100, + "insertTime": "2012-11-28T06:41:05.060", + "startTime": "2012-11-28T06:41:05.142", + "endTime": "2012-11-28T06:41:06.142", + "operationType": "insert", + "zone": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a" + } + ] +} \ No newline at end of file diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 5c9a1b0674..c37076a1f3 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -37,6 +37,7 @@ jclouds/apis/ec2/1.8.0-stratos jclouds/apis/openstack-nova/1.8.0-stratos jclouds/apis/docker/1.8.0-stratos + jclouds/apis/gce/1.8.0-stratos jclouds/provider/aws-ec2/1.8.0-stratos org.wso2.carbon.ui diff --git a/features/cloud-controller/org.apache.stratos.cloud.controller.feature/pom.xml b/features/cloud-controller/org.apache.stratos.cloud.controller.feature/pom.xml index 253a8b9dd9..c957844d1f 100644 --- a/features/cloud-controller/org.apache.stratos.cloud.controller.feature/pom.xml +++ b/features/cloud-controller/org.apache.stratos.cloud.controller.feature/pom.xml @@ -165,6 +165,11 @@ vcloud 1.8.0-stratos + + org.apache.stratos + gce + 1.8.0-stratos + com.google.code.gson gson @@ -299,6 +304,7 @@ org.apache.stratos:ec2:1.8.0-stratos org.apache.stratos:openstack-nova:1.8.0-stratos org.apache.stratos:vcloud:1.8.0-stratos + org.apache.stratos:gce:1.8.0-stratos org.apache.stratos:docker:1.8.0-stratos org.apache.commons:commons-compress:1.5 com.jamesmurty.utils.wso2:java-xmlbuilder:0.4.wso2v1 diff --git a/tools/puppet3-agent/config-gce.sh b/tools/puppet3-agent/config-gce.sh new file mode 100644 index 0000000000..0c1cbc7462 --- /dev/null +++ b/tools/puppet3-agent/config-gce.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# -------------------------------------------------------------- +# +# 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. +# +# -------------------------------------------------------------- +shopt -s nocasematch +ECHO=`which echo` +RM=`which rm` +READ=`which read` +TR=`which tr` +HEAD=`which head` +WGET=`which wget` +MKDIR=`which mkdir` +GREP=`which grep` +SED=`which sed` +CP=`which cp` +MV=`which mv` +CURL=`which curl` + +HOSTSFILE=/etc/hosts +DATE=`date +%d%m%y%S` +RANDOMNUMBER="`${TR} -c -d 0-9 < /dev/urandom | ${HEAD} -c 4`${DATE}" + +function valid_ip() +{ + local ip=$1 + local stat=1 + + if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + OIFS=$IFS + IFS='.' + ip=($ip) + IFS=$OIFS + [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ + && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] + stat=$? + fi + return $stat +} + +read -p "This script will install and configure puppet agent, do you want to continue [y/n]" answer +if [[ $answer = y ]] ; then + + ${CP} -f ${HOSTSFILE} /etc/hosts.tmp + ${MKDIR} -p /tmp/payload + ${CURL} "http://metadata.google.internal/computeMetadata/v1/instance/attributes/stratos_usermetadata" \ + -H "Metadata-Flavor: Google" > /tmp/payload/launch-params + + read -p "Please provide stratos service-name:" SERVICE_NAME + if [[ -z $SERVICE_NAME ]]; then + echo "service is empty!. Base image will be created." + SERVICE_NAME=default + fi + + read -p "Please provide puppet master IP:" PUPPET_IP + if ! valid_ip $PUPPET_IP ; then + echo "invalid IP address format!" + exit -1 + fi + + read -p "Please provide puppet master hostname [puppet.stratos.org]:" DOMAIN + DOMAIN=${DOMAIN:-puppet.stratos.org} + #essential to have PUPPET_HOSTNAME at the end in order to auto-sign the certs + + #read -p "Please provide stratos deployment:" DEPLOYMENT + #DEPLOYMENT=${DEPLOYMENT:-default} + DEPLOYMENT="default" + + NODEID="${RANDOMNUMBER}.${DEPLOYMENT}.${SERVICE_NAME}" + + ${ECHO} -e "\nNode Id ${NODEID}\n" + ${ECHO} -e "\nDomain ${DOMAIN}\n" + + ARGS=("-n${NODEID}" "-d${DOMAIN}" "-s${PUPPET_IP}") + ${ECHO} "\nRunning puppet installation with arguments: ${ARGS[@]}" + /root/bin/puppetinstall/puppetinstall "${ARGS[@]}" + ${RM} /mnt/apache-stratos-cartridge-agent-4.0.0/wso2carbon.lck + ${GREP} -q '/root/bin/init.sh > /tmp/puppet_log' /etc/rc.local || ${SED} -i 's/exit 0$/\/root\/bin\/init.sh \> \/tmp\/puppet_log\nexit 0/' /etc/rc.local + ${RM} -rf /tmp/* + ${RM} -rf /var/lib/puppet/ssl/* + ${MV} -f /etc/hosts.tmp ${HOSTSFILE} + +fi + +# END diff --git a/tools/puppet3-agent/init-gce.sh b/tools/puppet3-agent/init-gce.sh new file mode 100644 index 0000000000..0ca816ffcd --- /dev/null +++ b/tools/puppet3-agent/init-gce.sh @@ -0,0 +1,146 @@ +#!/bin/bash +# -------------------------------------------------------------- +# +# 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. +# +# -------------------------------------------------------------- + +MKDIR=`which mkdir` +UNZIP=`which unzip` +ECHO=`which echo` +FIND=`which find` +GREP=`which grep` +RM=`which rm` +XARGS=`which xargs` +SED=`which sed` +CUT=`which cut` +AWK=`which awk` +IFCONFIG=`which ifconfig` +HOSTNAME=`which hostname` +SLEEP=`which sleep` +TR=`which tr` +HEAD=`which head` +WGET=`which wget` +PUPPETD=`which puppet` +AGENT="agent" +PUPPETAGENT="${PUPPETD} ${AGENT}" +CURL=`which curl` + +COMMAND="${PUPPETAGENT} -vt" +IP=`${IFCONFIG} eth0 | ${GREP} -e "inet addr" | ${AWK} '{print $2}' | ${CUT} -d ':' -f 2` +LOG=/tmp/puppet-init.log + +HOSTSFILE=/etc/hosts +HOSTNAMEFILE=/etc/hostname +PUPPETCONF=/etc/puppet/puppet.conf + +read_master() { + ${COMMAND} +} + + +is_public_ip_assigned() { + +while true +do + # Reading the internal ip assigned + ${CURL} "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip" \ + -H "Metadata-Flavor: Google" > public-ipv4 + if [ ! -f public-ipv4 ] + then + echo "Public ipv4 file not found. Sleep and retry" >> $LOG + sleep 2; + continue; + else + echo "public-ipv4 file is available. Read value" >> $LOG + # Here means file is available. Read the file + read -r ip> $LOG + + if [ -z "$ip" ] + then + echo "File is empty. Retry...." >> $LOG + sleep 2 + rm public-ipv4 + continue + else + echo "public ip is assigned. value is [$ip]. Remove file" >> $LOG + rm public-ipv4 + break + fi + fi +done +} + + +DATE=`date +%d%m%y%S` +RANDOMNUMBER="`${TR} -c -d 0-9 < /dev/urandom | ${HEAD} -c 4`${DATE}" + +if [ ! -d /tmp/payload ]; then + + ## Check whether the public ip is assigned + is_public_ip_assigned + + echo "Public ip have assigned. Continue.." >> $LOG + + ## Clean old poop + ${ECHO} "Removing all existing certificates .." + #${FIND} /var/lib/puppet -type f -print0 | ${XARGS} -0r ${RM} + + ${MKDIR} -p /tmp/payload + ${CURL} "http://metadata.google.internal/computeMetadata/v1/instance/attributes/stratos_usermetadata" \ + -H "Metadata-Flavor: Google" > /tmp/payload/launch-params + + cd /tmp/payload + SERVICE_NAME=`sed 's/,/\n/g' launch-params | grep SERVICE_NAME | cut -d "=" -f 2` + DEPLOYMENT=`sed 's/,/\n/g' launch-params | grep DEPLOYMENT | cut -d "=" -f 2` + INSTANCE_HOSTNAME=`sed 's/,/\n/g' launch-params | grep HOSTNAME | cut -d "=" -f 2` + PUPPET_IP=`sed 's/,/\n/g' launch-params | grep PUPPET_IP | cut -d "=" -f 2` + PUPPET_HOSTNAME=`sed 's/,/\n/g' launch-params | grep PUPPET_HOSTNAME | cut -d "=" -f 2` + PUPPET_ENV=`sed 's/,/\n/g' launch-params | grep PUPPET_ENV | cut -d "=" -f 2` + NODEID="${RANDOMNUMBER}.${DEPLOYMENT}.${SERVICE_NAME}" + #essential to have PUPPET_HOSTNAME at the end in order to auto-sign the certs + DOMAIN="${PUPPET_HOSTNAME}" + ${ECHO} -e "\nNode Id ${NODEID}\n" + ${ECHO} -e "\nDomain ${DOMAIN}\n" + sed -i "s/server=.*/server=${PUPPET_HOSTNAME}/g" ${PUPPETCONF} + /etc/init.d/puppet restart + ARGS=("-n${NODEID}" "-d${DOMAIN}" "-s${PUPPET_IP}") + HOST="${NODEID}.${DOMAIN}" + ${HOSTNAME} ${HOST} + ${ECHO} "${HOST}" > ${HOSTNAMEFILE} + ${ECHO} "${PUPPET_IP} ${PUPPET_HOSTNAME}" >> ${HOSTSFILE} + ${ECHO} "127.0.0.1 ${HOST}" >> ${HOSTSFILE} + /etc/init.d/hostname start + + PUPPET=`which puppet` + PUPPETAGENT="${PUPPET} agent" + RUNPUPPET="${PUPPETAGENT} -vt" + + ${SLEEP} 5 + + ${PUPPETAGENT} --enable + + ${RUNPUPPET} + + ${PUPPETAGENT} --disable + ${ECHO} -e "Initialization completed successfully." + +fi + +# END + diff --git a/tools/stratos-installer/conf/setup.conf b/tools/stratos-installer/conf/setup.conf index 1fa114bfa3..70af4e151e 100644 --- a/tools/stratos-installer/conf/setup.conf +++ b/tools/stratos-installer/conf/setup.conf @@ -94,6 +94,10 @@ export vcloud_identity="stratos" # vCloud login user export vcloud_credential="password" # vCloud login password export vcloud_jclouds_endpoint="https://vcloud/api" +# GCE +export gce_provider_enabled=false +export gce_identity="" +export gce_credential="" # Database configuration # ---------------------------------------------------------------------------- diff --git a/tools/stratos-installer/config/all/repository/conf/cloud-controller.xml b/tools/stratos-installer/config/all/repository/conf/cloud-controller.xml index b71a1fe7be..5b4c289684 100644 --- a/tools/stratos-installer/config/all/repository/conf/cloud-controller.xml +++ b/tools/stratos-installer/config/all/repository/conf/cloud-controller.xml @@ -85,5 +85,13 @@ + + org.apache.stratos.cloud.controller.iaases.GCEIaas + google-compute-engine + GCE_IDENTITY + GCE_CREDENTIAL + > + + diff --git a/tools/stratos-installer/ec2.sh b/tools/stratos-installer/ec2.sh index cf38b83fa5..848286621f 100755 --- a/tools/stratos-installer/ec2.sh +++ b/tools/stratos-installer/ec2.sh @@ -62,6 +62,8 @@ ${SED} -i "s@OPENSTACK_PROVIDER_START@!--@g" repository/conf/cloud-controller.xm ${SED} -i "s@OPENSTACK_PROVIDER_END@--@g" repository/conf/cloud-controller.xml ${SED} -i "s@VCLOUD_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml ${SED} -i "s@VCLOUD_PROVIDER_END@--@g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_PROVIDER_END@--@g" repository/conf/cloud-controller.xml popd diff --git a/tools/stratos-installer/gce.sh b/tools/stratos-installer/gce.sh new file mode 100755 index 0000000000..3cd90399fe --- /dev/null +++ b/tools/stratos-installer/gce.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# ---------------------------------------------------------------------------- +# +# 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. +# +# ---------------------------------------------------------------------------- +# +# This script is invoked by setup.sh for configuring OpenStack IaaS information. +# ---------------------------------------------------------------------------- + +# Die on any error: +set -e + +# General commands +if [ "$(uname)" == "Darwin" ]; then + # Do something under Mac OS X platform + SED=`which gsed` && : || (echo "Command 'gsed' is not installed."; exit 10;) +else + # Do something else under some other platform + SED=`which sed` && : || (echo "Command 'sed' is not installed."; exit 10;) +fi + +SLEEP=60 +export LOG=$log_path/stratos-gce.log + +source "./conf/setup.conf" + +stratos_extract_path=$1 + +if [[ ! -d $log_path ]]; then + mkdir -p $log_path +fi + +pushd $stratos_extract_path + +echo "Set vCloud provider specific info in repository/conf/cloud-controller.xml" >> $LOG + +${SED} -i "s@VCLOUD_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml +${SED} -i "s@VCLOUD_PROVIDER_END@--@g" repository/conf/cloud-controller.xml +${SED} -i "s@EC2_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml +${SED} -i "s@EC2_PROVIDER_END@--@g" repository/conf/cloud-controller.xml +${SED} -i "s@OPENSTACK_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml +${SED} -i "s@OPENSTACK_PROVIDER_END@--@g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_PROVIDER_START@@g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_IDENTITY@${gce_identity//@/\\@}@g" repository/conf/cloud-controller.xml +# first replace the newlines in $gce_credential to newline, then add that in the place where +# GCE_CREDENTIAL is found in the xml file +${SED} -i "s@GCE_CREDENTIAL@${gce_credential//$'\n'/\\n}@g" repository/conf/cloud-controller.xml +${SED} -i "s/GCE_PROJECTNAME/$gce_projectname/g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_PROVIDER_END@@g" repository/conf/cloud-controller.xml + +popd diff --git a/tools/stratos-installer/openstack.sh b/tools/stratos-installer/openstack.sh index 8f71a7b6c6..ad75cb8bf5 100755 --- a/tools/stratos-installer/openstack.sh +++ b/tools/stratos-installer/openstack.sh @@ -61,5 +61,7 @@ ${SED} -i "s@EC2_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml ${SED} -i "s@EC2_PROVIDER_END@--@g" repository/conf/cloud-controller.xml ${SED} -i "s@VCLOUD_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml ${SED} -i "s@VCLOUD_PROVIDER_END@--@g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_PROVIDER_END@--@g" repository/conf/cloud-controller.xml popd diff --git a/tools/stratos-installer/setup.sh b/tools/stratos-installer/setup.sh index f889151d66..5a02de24d7 100755 --- a/tools/stratos-installer/setup.sh +++ b/tools/stratos-installer/setup.sh @@ -191,7 +191,8 @@ function cc_related_popup() { } function cc_conf_validate() { - if [[ $ec2_provider_enabled = "false" && $openstack_provider_enabled = "false" && $vcloud_provider_enabled = "false" ]]; then + if [[ $ec2_provider_enabled = "false" && $openstack_provider_enabled = "false" && $vcloud_provider_enabled = "false" \ + && $gce_provider_enabled = "false" ]]; then echo "Please enable at least one of the IaaS providers in conf/setup.conf file" exit 1 fi @@ -213,6 +214,12 @@ function cc_conf_validate() { exit 1 fi fi + if [[ $gce_provider_enabled = "true" ]]; then + if [[ ( -z $gce_identity || -z $gce_credential ) ]]; then + echo "Please set GCE configuration information in conf/setup.conf file" + exit 1 + fi + fi } # Setup cc @@ -233,6 +240,9 @@ function cc_setup() { if [[ $vcloud_provider_enabled = true ]]; then ./vcloud.sh $stratos_extract_path fi + if [[ $gce_provider_enabled = true ]]; then + ./gce.sh $stratos_extract_path + fi pushd $stratos_extract_path diff --git a/tools/stratos-installer/vcloud.sh b/tools/stratos-installer/vcloud.sh index ba4893dbea..ee9a0829d7 100755 --- a/tools/stratos-installer/vcloud.sh +++ b/tools/stratos-installer/vcloud.sh @@ -59,5 +59,7 @@ ${SED} -i "s@EC2_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml ${SED} -i "s@EC2_PROVIDER_END@--@g" repository/conf/cloud-controller.xml ${SED} -i "s@OPENSTACK_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml ${SED} -i "s@OPENSTACK_PROVIDER_END@--@g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_PROVIDER_START@!--@g" repository/conf/cloud-controller.xml +${SED} -i "s@GCE_PROVIDER_END@--@g" repository/conf/cloud-controller.xml popd