From 04a05c89750772d2877a5ccb994e378768aa9ebf Mon Sep 17 00:00:00 2001 From: Daryl Walleck Date: Mon, 16 Apr 2018 17:52:36 -0500 Subject: [PATCH 1/6] Re-created OpenStack project as a .NET Standard class lib --- .gitignore | 1 + .../AuthenticatedHttpClientFactory.cs | 29 + .../AuthenticatedMessageHandler.cs | 47 + .../Authentication/IAuthenticationProvider.cs | 37 + src/OpenStack/Authentication/NamespaceDoc.cs | 13 + src/OpenStack/Authentication/ServiceType.cs | 99 + .../v2/Serialization/SnapshotStatus.cs | 37 + .../v2/Serialization/VolumeStatus.cs | 67 + .../BlockStorage/v2/SnapshotStatus.cs | 7 + src/OpenStack/BlockStorage/v2/VolumeStatus.cs | 7 + .../ComputeOperationFailedException.cs | 28 + src/OpenStack/Compute/NamespaceDoc.cs | 17 + .../Actions/AssociateFloatingIPRequest.cs | 33 + .../v2_1/Actions/RebootServerRequest.cs | 18 + .../Compute/v2_1/Actions/RebootType.cs | 8 + .../v2_1/Actions/RescueServerRequest.cs | 24 + .../v2_1/Actions/SnapshotServerRequest.cs | 35 + src/OpenStack/Compute/v2_1/AddressType.cs | 8 + src/OpenStack/Compute/v2_1/ComputeService.cs | 536 ++++ .../Compute/v2_1/ComputeServiceExtensions.cs | 500 +++ .../Compute/v2_1/DiskConfiguration.cs | 8 + src/OpenStack/Compute/v2_1/Flavor.cs | 49 + .../Compute/v2_1/FlavorExtensions.cs | 18 + .../Compute/v2_1/FlavorListOptions.cs | 30 + src/OpenStack/Compute/v2_1/FlavorReference.cs | 36 + src/OpenStack/Compute/v2_1/FlavorSummary.cs | 16 + src/OpenStack/Compute/v2_1/IPProtocol.cs | 8 + src/OpenStack/Compute/v2_1/Image.cs | 129 + src/OpenStack/Compute/v2_1/ImageExtensions.cs | 49 + .../Compute/v2_1/ImageListOptions.cs | 55 + src/OpenStack/Compute/v2_1/ImageMetadata.cs | 90 + .../Compute/v2_1/ImageMetadataExtensions.cs | 30 + src/OpenStack/Compute/v2_1/ImageReference.cs | 70 + src/OpenStack/Compute/v2_1/ImageSummary.cs | 16 + src/OpenStack/Compute/v2_1/ImageType.cs | 8 + src/OpenStack/Compute/v2_1/KeyPair.cs | 24 + .../Compute/v2_1/KeyPairDefinition.cs | 31 + .../Compute/v2_1/KeyPairExtensions.cs | 18 + src/OpenStack/Compute/v2_1/KeyPairRequest.cs | 27 + src/OpenStack/Compute/v2_1/KeyPairResponse.cs | 17 + src/OpenStack/Compute/v2_1/KeyPairSummary.cs | 48 + src/OpenStack/Compute/v2_1/NamespaceDoc.cs | 13 + .../v2_1/Operator/ComputeServiceExtensions.cs | 36 + .../v2_1/Operator/EvacuateServerRequest.cs | 39 + .../Compute/v2_1/Operator/NamespaceDoc.cs | 12 + .../Compute/v2_1/Operator/ServerExtensions.cs | 23 + .../Compute/v2_1/Operator/ServiceQuotas.cs | 108 + src/OpenStack/Compute/v2_1/RemoteConsole.cs | 25 + .../Compute/v2_1/RemoteConsoleType.cs | 9 + src/OpenStack/Compute/v2_1/SchedulerHints.cs | 73 + src/OpenStack/Compute/v2_1/SecurityGroup.cs | 68 + .../Compute/v2_1/SecurityGroupDefinition.cs | 31 + .../Compute/v2_1/SecurityGroupExtensions.cs | 42 + .../Compute/v2_1/SecurityGroupReference.cs | 64 + .../Compute/v2_1/SecurityGroupRule.cs | 87 + .../v2_1/SecurityGroupRuleDefinition.cs | 56 + .../Compute/v2_1/Serialization/AddressType.cs | 22 + .../Compute/v2_1/Serialization/ComputeApi.cs | 2260 ++++++++++++++ .../v2_1/Serialization/DiskConfiguration.cs | 22 + .../v2_1/Serialization/FlavorCollection.cs | 35 + .../v2_1/Serialization/ImageCollection.cs | 35 + .../Compute/v2_1/Serialization/ImageType.cs | 27 + .../v2_1/Serialization/KeyPairCollection.cs | 25 + .../v2_1/Serialization/KeyPairConverter.cs | 50 + .../Compute/v2_1/Serialization/RebootType.cs | 22 + .../v2_1/Serialization/RemoteConsoleType.cs | 37 + .../Serialization/SecurityGroupCollection.cs | 23 + .../Serialization/ServerActionCollection.cs | 25 + .../Serialization/ServerAddressCollection.cs | 18 + .../Serialization/ServerBlockDeviceType.cs | 27 + .../v2_1/Serialization/ServerCollection.cs | 35 + .../ServerCreateDefinitionConverter.cs | 41 + .../v2_1/Serialization/ServerEventStatus.cs | 18 + .../Serialization/ServerGroupCollection.cs | 23 + .../v2_1/Serialization/ServerStatus.cs | 103 + .../Serialization/ServerVolumeCollection.cs | 25 + .../v2_1/Serialization/VolumeCollection.cs | 25 + .../Serialization/VolumeSnapshotCollection.cs | 24 + src/OpenStack/Compute/v2_1/Server.cs | 286 ++ src/OpenStack/Compute/v2_1/ServerAction.cs | 67 + .../Compute/v2_1/ServerActionExtensions.cs | 18 + .../Compute/v2_1/ServerActionSummary.cs | 66 + src/OpenStack/Compute/v2_1/ServerAddress.cs | 41 + .../Compute/v2_1/ServerBlockDeviceMapping.cs | 62 + .../Compute/v2_1/ServerBlockDeviceType.cs | 8 + .../Compute/v2_1/ServerCreateDefinition.cs | 172 ++ .../Compute/v2_1/ServerEventStatus.cs | 8 + .../Compute/v2_1/ServerExtensions.cs | 206 ++ src/OpenStack/Compute/v2_1/ServerGroup.cs | 61 + .../Compute/v2_1/ServerGroupDefinition.cs | 30 + .../Compute/v2_1/ServerGroupExtensions.cs | 18 + .../Compute/v2_1/ServerListOptions.cs | 64 + src/OpenStack/Compute/v2_1/ServerMetadata.cs | 89 + .../Compute/v2_1/ServerMetadataExtensions.cs | 30 + .../Compute/v2_1/ServerNetworkDefinition.cs | 28 + src/OpenStack/Compute/v2_1/ServerReference.cs | 226 ++ src/OpenStack/Compute/v2_1/ServerStatus.cs | 8 + src/OpenStack/Compute/v2_1/ServerSummary.cs | 16 + .../Compute/v2_1/ServerUpdateDefinition.cs | 43 + src/OpenStack/Compute/v2_1/ServerVolume.cs | 40 + .../Compute/v2_1/ServerVolumeDefinition.cs | 29 + .../Compute/v2_1/ServerVolumeExtensions.cs | 23 + .../Compute/v2_1/ServerVolumeReference.cs | 90 + src/OpenStack/Compute/v2_1/ServiceLimits.cs | 225 ++ src/OpenStack/Compute/v2_1/Volume.cs | 171 ++ .../Compute/v2_1/VolumeDefinition.cs | 57 + .../Compute/v2_1/VolumeExtensions.cs | 52 + src/OpenStack/Compute/v2_1/VolumeSnapshot.cs | 113 + .../Compute/v2_1/VolumeSnapshotDefinition.cs | 46 + .../Compute/v2_1/VolumeSnapshotExtensions.cs | 18 + src/OpenStack/Compute/v2_2/ComputeApi.cs | 19 + src/OpenStack/Compute/v2_2/ComputeService.cs | 45 + .../Compute/v2_2/ComputeServiceExtensions.cs | 24 + src/OpenStack/Compute/v2_2/KeyPair.cs | 12 + .../Compute/v2_2/KeyPairDefinition.cs | 20 + src/OpenStack/Compute/v2_2/KeyPairType.cs | 16 + src/OpenStack/Compute/v2_2/RemoteConsole.cs | 7 + .../Compute/v2_2/RemoteConsoleType.cs | 9 + .../v2_2/Serialization/ServerCollection.cs | 16 + src/OpenStack/Compute/v2_2/Server.cs | 7 + .../Compute/v2_2/ServerListOptions.cs | 6 + src/OpenStack/Compute/v2_2/ServerReference.cs | 6 + src/OpenStack/Compute/v2_2/ServerStatus.cs | 6 + src/OpenStack/Compute/v2_6/ComputeApi.cs | 51 + src/OpenStack/Compute/v2_6/ComputeService.cs | 48 + .../Compute/v2_6/ComputeServiceExtensions.cs | 18 + src/OpenStack/Compute/v2_6/Console.cs | 25 + src/OpenStack/Compute/v2_6/ConsoleProtocol.cs | 39 + src/OpenStack/Compute/v2_6/KeyPair.cs | 7 + .../Compute/v2_6/KeyPairDefinition.cs | 28 + src/OpenStack/Compute/v2_6/KeyPairType.cs | 16 + .../Compute/v2_6/RemoteConsoleType.cs | 6 + .../v2_6/Serialization/ServerCollection.cs | 16 + src/OpenStack/Compute/v2_6/Server.cs | 27 + .../Compute/v2_6/ServerListOptions.cs | 6 + src/OpenStack/Compute/v2_6/ServerReference.cs | 6 + src/OpenStack/Compute/v2_6/ServerStatus.cs | 6 + .../v1/ContentDeliveryNetworkService.cs | 304 ++ ...ContentDeliveryNetworkServiceExtensions.cs | 179 ++ .../ContentDeliveryNetworks/v1/Flavor.cs | 32 + .../v1/FlavorCollection.cs | 28 + .../v1/IContentDeliveryNetworkService.cs | 150 + .../v1/NamespaceDoc.cs | 13 + .../ContentDeliveryNetworks/v1/Provider.cs | 25 + .../ContentDeliveryNetworks/v1/Service.cs | 76 + .../v1/ServiceCache.cs | 48 + .../v1/ServiceCacheRule.cs | 34 + .../v1/ServiceCollection.cs | 25 + .../v1/ServiceDefinition.cs | 77 + .../v1/ServiceDomain.cs | 32 + .../v1/ServiceError.cs | 17 + .../v1/ServiceOperationFailedException.cs | 55 + .../v1/ServiceOrigin.cs | 49 + .../v1/ServiceOriginRule.cs | 34 + .../v1/ServiceProtocol.cs | 21 + .../v1/ServiceRestriction.cs | 35 + .../v1/ServiceRestrictionRule.cs | 34 + .../v1/ServiceStatus.cs | 43 + src/OpenStack/Core/AsyncCompletionOption.cs | 24 + src/OpenStack/Core/BackoffPolicy.cs | 63 + src/OpenStack/Core/Caching/ICache`1.cs | 41 + src/OpenStack/Core/Caching/NamespaceDoc.cs | 14 + src/OpenStack/Core/Caching/UserAccessCache.cs | 126 + .../BasicReadOnlyCollectionPage`1.cs | 55 + .../Core/Collections/NamespaceDoc.cs | 13 + .../Collections/ReadOnlyCollectionPage`1.cs | 108 + src/OpenStack/Core/Compat/Funcs.cs | 53 + .../Core/Compat/ISafeSerializationData.cs | 17 + .../Core/Compat/IStructuralComparable.cs | 72 + .../Core/Compat/IStructuralEquatable.cs | 57 + src/OpenStack/Core/Compat/Tuple.cs | 222 ++ src/OpenStack/Core/Compat/Tuples.cs | 1280 ++++++++ src/OpenStack/Core/CoreTaskExtensions.cs | 712 +++++ .../Core/Domain/AuthenticationRequirement.cs | 56 + .../Core/Domain/AuthenticationType.cs | 82 + src/OpenStack/Core/Domain/CloudIdentity.cs | 47 + .../Core/Domain/CloudIdentityWithProject.cs | 38 + src/OpenStack/Core/Domain/CloudNetwork.cs | 39 + src/OpenStack/Core/Domain/Container.cs | 49 + src/OpenStack/Core/Domain/ContainerCDN.cs | 111 + src/OpenStack/Core/Domain/ContainerObject.cs | 54 + .../Converters/IPAddressDetailsConverter.cs | 137 + .../IPAddressNoneIsNullSimpleConverter.cs | 32 + .../Converters/IPAddressSimpleConverter.cs | 30 + .../Core/Domain/Converters/NamespaceDoc.cs | 18 + .../PhysicalAddressSimpleConverter.cs | 46 + .../Converters/SimpleStringJsonConverter`1.cs | 80 + .../Core/Domain/DiskConfiguration.cs | 101 + src/OpenStack/Core/Domain/Endpoint.cs | 62 + src/OpenStack/Core/Domain/EndpointTemplate.cs | 64 + .../Core/Domain/EndpointTemplateId.cs | 45 + src/OpenStack/Core/Domain/ExtendedEndpoint.cs | 37 + .../Core/Domain/ExtensibleJsonObject.cs | 390 +++ src/OpenStack/Core/Domain/Flavor.cs | 35 + src/OpenStack/Core/Domain/FlavorDetails.cs | 100 + src/OpenStack/Core/Domain/FlavorId.cs | 41 + src/OpenStack/Core/Domain/HomeDocument.cs | 36 + src/OpenStack/Core/Domain/IPAddressList.cs | 48 + src/OpenStack/Core/Domain/IdentityToken.cs | 64 + src/OpenStack/Core/Domain/ImageId.cs | 41 + src/OpenStack/Core/Domain/ImageState.cs | 129 + src/OpenStack/Core/Domain/ImageType.cs | 85 + src/OpenStack/Core/Domain/Link.cs | 48 + .../Domain/Mapping/IJsonObjectMapper`1.cs | 23 + .../Core/Domain/Mapping/IObjectMapper`2.cs | 41 + .../Core/Domain/Mapping/NamespaceDoc.cs | 14 + src/OpenStack/Core/Domain/Metadata.cs | 19 + src/OpenStack/Core/Domain/NamespaceDoc.cs | 13 + src/OpenStack/Core/Domain/NetworkId.cs | 41 + src/OpenStack/Core/Domain/NewServer.cs | 51 + src/OpenStack/Core/Domain/NewUser.cs | 78 + src/OpenStack/Core/Domain/ObjectStore.cs | 23 + src/OpenStack/Core/Domain/Personality.cs | 133 + src/OpenStack/Core/Domain/PowerState.cs | 106 + src/OpenStack/Core/Domain/ProjectId.cs | 40 + .../Core/Domain/ProviderStateBase`1.cs | 29 + src/OpenStack/Core/Domain/Queues/Claim.cs | 304 ++ src/OpenStack/Core/Domain/Queues/ClaimId.cs | 42 + .../Core/Domain/Queues/CloudQueue.cs | 79 + src/OpenStack/Core/Domain/Queues/Message.cs | 36 + src/OpenStack/Core/Domain/Queues/MessageId.cs | 42 + .../Core/Domain/Queues/MessageStatistics.cs | 77 + src/OpenStack/Core/Domain/Queues/Message`1.cs | 75 + .../Core/Domain/Queues/MessagesEnqueued.cs | 103 + .../Core/Domain/Queues/NamespaceDoc.cs | 13 + .../Domain/Queues/QueueMessagesStatistics.cs | 118 + src/OpenStack/Core/Domain/Queues/QueueName.cs | 42 + .../Core/Domain/Queues/QueueStatistics.cs | 43 + .../Core/Domain/Queues/QueuedMessage.cs | 129 + .../Core/Domain/Queues/QueuedMessageList.cs | 52 + .../Core/Domain/Queues/QueuedMessageListId.cs | 44 + src/OpenStack/Core/Domain/RebootType.cs | 86 + src/OpenStack/Core/Domain/ResourceHints.cs | 298 ++ src/OpenStack/Core/Domain/ResourceObject.cs | 112 + src/OpenStack/Core/Domain/Role.cs | 52 + src/OpenStack/Core/Domain/Server.cs | 492 +++ src/OpenStack/Core/Domain/ServerAddresses.cs | 50 + src/OpenStack/Core/Domain/ServerBase.cs | 487 +++ src/OpenStack/Core/Domain/ServerId.cs | 41 + src/OpenStack/Core/Domain/ServerImage.cs | 312 ++ src/OpenStack/Core/Domain/ServerState.cs | 309 ++ src/OpenStack/Core/Domain/ServerVolume.cs | 46 + src/OpenStack/Core/Domain/ServiceCatalog.cs | 64 + src/OpenStack/Core/Domain/SimpleServer.cs | 38 + .../Core/Domain/SimpleServerImage.cs | 225 ++ src/OpenStack/Core/Domain/Snapshot.cs | 69 + src/OpenStack/Core/Domain/SnapshotState.cs | 121 + src/OpenStack/Core/Domain/Status.cs | 42 + src/OpenStack/Core/Domain/TaskState.cs | 461 +++ src/OpenStack/Core/Domain/Tenant.cs | 28 + src/OpenStack/Core/Domain/User.cs | 94 + src/OpenStack/Core/Domain/UserAccess.cs | 65 + src/OpenStack/Core/Domain/UserCredential.cs | 50 + src/OpenStack/Core/Domain/UserDetails.cs | 78 + src/OpenStack/Core/Domain/VirtualInterface.cs | 46 + .../Core/Domain/VirtualInterfaceAddress.cs | 48 + .../Core/Domain/VirtualMachineState.cs | 189 ++ src/OpenStack/Core/Domain/Volume.cs | 101 + src/OpenStack/Core/Domain/VolumeState.cs | 181 ++ src/OpenStack/Core/Domain/VolumeType.cs | 29 + .../Core/Exceptions/CDNNotEnabledException.cs | 60 + .../Core/Exceptions/CidrFormatException.cs | 45 + .../Core/Exceptions/ContainerNameException.cs | 46 + .../Exceptions/ContainerNotEmptyException.cs | 61 + .../ImageEnteredErrorStateException.cs | 63 + .../InvalidCloudIdentityException.cs | 37 + src/OpenStack/Core/Exceptions/NamespaceDoc.cs | 14 + .../Exceptions/NoDefaultRegionSetException.cs | 36 + .../Core/Exceptions/ObjectNameException.cs | 46 + .../Response/BadServiceRequestException.cs | 37 + .../Response/ItemNotFoundException.cs | 37 + .../Response/MethodNotImplementedException.cs | 37 + .../Core/Exceptions/Response/NamespaceDoc.cs | 13 + .../Exceptions/Response/ResponseException.cs | 101 + .../Response/ServiceConflictException.cs | 37 + .../Response/ServiceFaultException.cs | 37 + .../Response/ServiceLimitReachedException.cs | 37 + .../Response/ServiceUnavailableException.cs | 37 + .../Response/UserNotAuthorizedException.cs | 38 + .../ServerEnteredErrorStateException.cs | 63 + .../SnapshotEnteredErrorStateException.cs | 63 + .../Core/Exceptions/TTLLengthException.cs | 44 + .../Exceptions/UserAuthenticationException.cs | 37 + .../Exceptions/UserAuthorizationException.cs | 40 + .../VolumeEnteredErrorStateException.cs | 63 + src/OpenStack/Core/ExtensibleEnum`1.cs | 97 + src/OpenStack/Core/HttpStatusCodeParser.cs | 105 + src/OpenStack/Core/IBackoffPolicy.cs | 28 + src/OpenStack/Core/IEncodeDecodeProvider.cs | 26 + .../Core/IObjectStorageMetadataProcessor.cs | 37 + src/OpenStack/Core/IStatusParser.cs | 23 + src/OpenStack/Core/InternalTaskExtensions.cs | 57 + .../LegacyAuthenticationProviderHelper.cs | 49 + src/OpenStack/Core/NamespaceDoc.cs | 13 + .../TaskCompletionSourceExtensions.cs | 39 + .../TaskExtrasExtensions.cs | 37 + .../TaskFactoryExtensions_Common.cs | 16 + ...askFactoryExtensions_ContinueWhenAllAny.cs | 26 + .../TaskFactoryExtensions_Delayed.cs | 63 + .../TaskFactoryExtensions_From.cs | 25 + .../Core/Providers/IBlockStorageProvider.cs | 493 +++ .../Core/Providers/IComputeProvider.cs | 1765 +++++++++++ .../Core/Providers/IIdentityProvider.cs | 330 ++ .../Core/Providers/IIdentityService.cs | 68 + .../Core/Providers/INetworksProvider.cs | 116 + .../Core/Providers/IObjectStorageProvider.cs | 1639 ++++++++++ .../Core/Providers/IQueueingService.cs | 555 ++++ src/OpenStack/Core/Providers/NamespaceDoc.cs | 15 + .../Providers/OpenStackIdentityProvider.cs | 136 + .../Core/ReadOnlyCollectionPageExtensions.cs | 104 + src/OpenStack/Core/ResourceIdentifier`1.cs | 155 + src/OpenStack/Core/ResponseExtensions.cs | 85 + src/OpenStack/Core/RestWebHeaderCollection.cs | 83 + .../Synchronous/AutoScaleServiceExtensions.cs | 816 +++++ .../Core/Synchronous/ClaimExtensions.cs | 86 + .../Synchronous/DatabaseServiceExtensions.cs | 1006 +++++++ .../Core/Synchronous/DnsServiceExtensions.cs | 964 ++++++ .../LoadBalancerServiceExtensions.cs | 2238 ++++++++++++++ .../MonitoringServiceExtensions.cs | 2572 ++++++++++++++++ .../Core/Synchronous/NamespaceDoc.cs | 18 + .../Synchronous/QueueingServiceExtensions.cs | 869 ++++++ ...OnlyCollectionPageSynchronousExtensions.cs | 83 + src/OpenStack/Core/UriPart.cs | 52 + src/OpenStack/Core/UriUtility.cs | 392 +++ .../Core/Validators/IBlockStorageValidator.cs | 22 + .../Validators/IHttpResponseCodeValidator.cs | 23 + .../Core/Validators/INetworksValidator.cs | 21 + .../Validators/IObjectStorageValidator.cs | 29 + src/OpenStack/Core/Validators/NamespaceDoc.cs | 14 + src/OpenStack/Core/WebRequestExtensions.cs | 124 + .../Exceptions/IdentityRequiredException.cs | 33 + .../Exceptions/RegionRequiredException.cs | 31 + .../Exceptions/ResourceErrorException.cs | 26 + .../Exceptions/UserAuthenticationException.cs | 37 + .../Extensions/EnumerableExtensions.cs | 19 + src/OpenStack/Extensions/FlurlExtensions.cs | 136 + .../Extensions/HttpHeadersExtensions.cs | 17 + .../HttpRequestMessageExtensions.cs | 25 + src/OpenStack/Extensions/TaskExtensions.cs | 27 + src/OpenStack/Extensions/TypeExtensions.cs | 63 + src/OpenStack/Flurl/PreparedRequest.cs | 152 + src/OpenStack/Icons/openstack_net_logo.png | Bin 0 -> 3746 bytes src/OpenStack/Identifier.cs | 133 + src/OpenStack/Images/v2/ImageStatus.cs | 8 + .../Images/v2/Serialization/ImageStatus.cs | 27 + src/OpenStack/NamespaceDoc.cs | 28 + src/OpenStack/Networking/IPVersion.cs | 18 + src/OpenStack/Networking/NamespaceDoc.cs | 13 + src/OpenStack/Networking/v2/AllocationPool.cs | 59 + src/OpenStack/Networking/v2/AllowedAddress.cs | 71 + src/OpenStack/Networking/v2/HostRoute.cs | 59 + .../Networking/v2/IPAddressAssociation.cs | 100 + src/OpenStack/Networking/v2/IPProtocol.cs | 8 + .../Networking/v2/Layer3/ExternalGateway.cs | 37 + .../v2/Layer3/ExternalGatewayDefinition.cs | 38 + .../Networking/v2/Layer3/FloatingIP.cs | 100 + .../v2/Layer3/FloatingIPCreateDefinition.cs | 37 + .../v2/Layer3/FloatingIPExtensions.cs | 23 + .../v2/Layer3/FloatingIPListOptions.cs | 56 + .../Networking/v2/Layer3/FloatingIPStatus.cs | 6 + .../v2/Layer3/FloatingIPUpdateDefinition.cs | 18 + .../NetworkingService_Layer3_Extensions.cs | 234 ++ src/OpenStack/Networking/v2/Layer3/Router.cs | 117 + .../v2/Layer3/RouterCreateDefinition.cs | 24 + .../Networking/v2/Layer3/RouterExtensions.cs | 41 + .../Networking/v2/Layer3/RouterListOptions.cs | 32 + .../Networking/v2/Layer3/RouterStatus.cs | 6 + .../v2/Layer3/RouterUpdateDefinition.cs | 37 + .../Networking/v2/Layer3/SecurityGroup.cs | 43 + .../v2/Layer3/SecurityGroupListOptions.cs | 26 + .../Networking/v2/Layer3/SecurityGroupRule.cs | 82 + .../v2/Layer3/SecurityGroupRuleListOptions.cs | 26 + src/OpenStack/Networking/v2/NamespaceDoc.cs | 13 + src/OpenStack/Networking/v2/Network.cs | 65 + .../Networking/v2/NetworkDefinition.cs | 26 + src/OpenStack/Networking/v2/NetworkStatus.cs | 6 + .../Networking/v2/NetworkingApiBuilder.cs | 890 ++++++ .../Networking/v2/NetworkingService.cs | 195 ++ .../v2/NetworkingServiceExtensions.cs | 241 ++ .../Networking/v2/Operator/NamespaceDoc.cs | 12 + .../v2/Operator/NetworkDefinition.cs | 14 + src/OpenStack/Networking/v2/Port.cs | 46 + .../Networking/v2/PortCreateDefinition.cs | 69 + .../Networking/v2/PortListOptions.cs | 56 + src/OpenStack/Networking/v2/PortStatus.cs | 6 + .../Networking/v2/PortUpdateDefinition.cs | 41 + .../v2/Serialization/DHCPOptionsConverter.cs | 113 + .../v2/Serialization/FloatingIPCollection.cs | 26 + .../Networking/v2/Serialization/IPProtocol.cs | 27 + .../v2/Serialization/NetworkCollection.cs | 30 + .../NetworkDefinitionCollection.cs | 18 + .../v2/Serialization/NetworkResourceStatus.cs | 27 + .../v2/Serialization/PortCollection.cs | 30 + .../Serialization/PortDefinitionCollection.cs | 18 + .../v2/Serialization/RouterCollection.cs | 26 + .../Serialization/SecurityGroupCollection.cs | 32 + .../SecurityGroupRuleCollection.cs | 32 + .../v2/Serialization/SubnetCollection.cs | 30 + .../SubnetDefinitionCollection.cs | 18 + .../v2/Serialization/TrafficDirection.cs | 22 + src/OpenStack/Networking/v2/Subnet.cs | 34 + .../Networking/v2/SubnetCreateDefinition.cs | 49 + .../Networking/v2/SubnetUpdateDefinition.cs | 60 + .../Networking/v2/TrafficDirection.cs | 8 + src/OpenStack/OpenStack.csproj | 21 + src/OpenStack/OpenStackNet.cs | 302 ++ src/OpenStack/Page.cs | 23 + src/OpenStack/PageExtensions.cs | 18 + src/OpenStack/PageOptions.cs | 45 + .../Providers/Hp/HpIdentityProvider.cs | 198 ++ src/OpenStack/Providers/Hp/NamespaceDoc.cs | 14 + .../Hp/PredefinedHpIdentityEndpoints.cs | 42 + .../Rackspace/CloudAutoScaleProvider.cs | 840 ++++++ .../Rackspace/CloudBlockStorageProvider.cs | 511 ++++ .../Rackspace/CloudDatabasesProvider.cs | 1222 ++++++++ .../Providers/Rackspace/CloudDnsProvider.cs | 1369 +++++++++ .../Rackspace/CloudFilesMetadataProcessor.cs | 90 + .../Providers/Rackspace/CloudFilesProvider.cs | 2597 ++++++++++++++++ .../Rackspace/CloudIdentityProvider.cs | 1173 ++++++++ .../Rackspace/CloudLoadBalancerProvider.cs | 2671 +++++++++++++++++ .../Rackspace/CloudMonitoringProvider.cs | 2103 +++++++++++++ .../Rackspace/CloudNetworksProvider.cs | 231 ++ .../Rackspace/CloudQueuesProvider.cs | 860 ++++++ .../Rackspace/CloudServersProvider.cs | 1543 ++++++++++ .../Rackspace/EncodeDecodeProvider.cs | 48 + .../Exceptions/BulkDeletionException.cs | 74 + .../Exceptions/InvalidETagException.cs | 32 + .../Exceptions/InvalidVolumeSizeException.cs | 58 + .../Rackspace/Exceptions/NamespaceDoc.cs | 13 + .../Rackspace/ExtendedJsonRestServices.cs | 70 + .../Providers/Rackspace/IAutoScaleService.cs | 445 +++ .../Providers/Rackspace/IDatabaseService.cs | 554 ++++ .../Providers/Rackspace/IDnsService.cs | 679 +++++ .../IExtendedCloudIdentityProvider.cs | 380 +++ .../Rackspace/ILoadBalancerService.cs | 1417 +++++++++ .../Providers/Rackspace/IMonitoringService.cs | 1435 +++++++++ .../Providers/Rackspace/IProviderFactory`2.cs | 20 + .../Providers/Rackspace/IRackspaceProvider.cs | 18 + .../Providers/Rackspace/NamespaceDoc.cs | 14 + .../Rackspace/Objects/ArchiveFormat.cs | 102 + .../Rackspace/Objects/AuthDetails.cs | 17 + .../Objects/AutoScale/ActiveServer.cs | 67 + .../AutoScale/GenericLaunchConfiguration.cs | 39 + .../Objects/AutoScale/GroupConfiguration.cs | 168 ++ .../Rackspace/Objects/AutoScale/GroupState.cs | 142 + .../Objects/AutoScale/LaunchConfiguration.cs | 56 + .../AutoScale/LaunchConfiguration`1.cs | 73 + .../Rackspace/Objects/AutoScale/LaunchType.cs | 76 + .../Objects/AutoScale/LoadBalancerArgument.cs | 83 + .../Objects/AutoScale/NamespaceDoc.cs | 14 + .../AutoScale/NewWebhookConfiguration.cs | 55 + .../Rackspace/Objects/AutoScale/Policy.cs | 63 + .../Objects/AutoScale/PolicyConfiguration.cs | 324 ++ .../Rackspace/Objects/AutoScale/PolicyId.cs | 42 + .../Rackspace/Objects/AutoScale/PolicyType.cs | 100 + .../Objects/AutoScale/ScalingGroup.cs | 80 + .../AutoScale/ScalingGroupConfiguration.cs | 37 + .../AutoScale/ScalingGroupConfiguration`1.cs | 120 + .../Objects/AutoScale/ScalingGroupId.cs | 42 + .../Objects/AutoScale/ServerArgument.cs | 217 ++ .../AutoScale/ServerLaunchArguments.cs | 104 + .../AutoScale/ServerLaunchConfiguration.cs | 37 + .../AutoScale/ServerNetworkArgument.cs | 60 + .../AutoScale/UpdateWebhookConfiguration.cs | 79 + .../Rackspace/Objects/AutoScale/Webhook.cs | 63 + .../Objects/AutoScale/WebhookConfiguration.cs | 83 + .../Rackspace/Objects/AutoScale/WebhookId.cs | 42 + .../Objects/BulkDeletionFailedObject.cs | 51 + .../Rackspace/Objects/BulkDeletionResults.cs | 43 + .../Rackspace/Objects/Credentials.cs | 61 + .../Rackspace/Objects/Databases/Backup.cs | 165 + .../Objects/Databases/BackupConfiguration.cs | 103 + .../Rackspace/Objects/Databases/BackupId.cs | 42 + .../Objects/Databases/BackupStatus.cs | 126 + .../Rackspace/Objects/Databases/Database.cs | 42 + .../Databases/DatabaseConfiguration.cs | 105 + .../Objects/Databases/DatabaseFlavor.cs | 125 + .../Objects/Databases/DatabaseInstance.cs | 184 ++ .../DatabaseInstanceConfiguration.cs | 139 + .../Objects/Databases/DatabaseInstanceId.cs | 42 + .../Databases/DatabaseInstanceStatus.cs | 162 + .../Objects/Databases/DatabaseName.cs | 42 + .../Objects/Databases/DatabaseUser.cs | 24 + .../Databases/DatabaseVolumeConfiguration.cs | 83 + .../Rackspace/Objects/Databases/FlavorId.cs | 42 + .../Rackspace/Objects/Databases/FlavorRef.cs | 42 + .../Objects/Databases/NamespaceDoc.cs | 14 + .../Objects/Databases/RestorePoint.cs | 54 + .../Rackspace/Objects/Databases/RootUser.cs | 60 + .../Databases/UpdateUserConfiguration.cs | 96 + .../Objects/Databases/UserConfiguration.cs | 207 ++ .../Rackspace/Objects/Databases/UserName.cs | 126 + .../Rackspace/Objects/Dns/DnsChange.cs | 91 + .../Rackspace/Objects/Dns/DnsConfiguration.cs | 74 + .../Rackspace/Objects/Dns/DnsDomain.cs | 274 ++ .../Rackspace/Objects/Dns/DnsDomainChange.cs | 161 + .../Rackspace/Objects/Dns/DnsDomainChanges.cs | 125 + .../Objects/Dns/DnsDomainConfiguration.cs | 326 ++ .../Dns/DnsDomainRecordConfiguration.cs | 195 ++ .../Dns/DnsDomainRecordUpdateConfiguration.cs | 186 ++ .../Dns/DnsDomainUpdateConfiguration.cs | 130 + .../Rackspace/Objects/Dns/DnsDomains.cs | 57 + .../Providers/Rackspace/Objects/Dns/DnsJob.cs | 193 ++ .../Rackspace/Objects/Dns/DnsJobStatus.cs | 113 + .../Rackspace/Objects/Dns/DnsJob`1.cs | 50 + .../Rackspace/Objects/Dns/DnsNameserver.cs | 49 + .../Rackspace/Objects/Dns/DnsRateLimit.cs | 139 + .../Objects/Dns/DnsRateLimitPattern.cs | 97 + .../Rackspace/Objects/Dns/DnsRateLimitUnit.cs | 88 + .../Rackspace/Objects/Dns/DnsRateLimits.cs | 55 + .../Rackspace/Objects/Dns/DnsRecord.cs | 220 ++ .../Rackspace/Objects/Dns/DnsRecordType.cs | 161 + .../Rackspace/Objects/Dns/DnsRecordsList.cs | 52 + .../Rackspace/Objects/Dns/DnsServiceLimits.cs | 74 + .../Rackspace/Objects/Dns/DnsSubdomain.cs | 154 + .../Objects/Dns/DnsSubdomainConfiguration.cs | 109 + .../Objects/Dns/DnsSubdomainsList.cs | 52 + .../Objects/Dns/DnsUpdateConfiguration.cs | 74 + .../Rackspace/Objects/Dns/DomainId.cs | 42 + .../Rackspace/Objects/Dns/ExportedDomain.cs | 72 + .../Providers/Rackspace/Objects/Dns/JobId.cs | 42 + .../Rackspace/Objects/Dns/LimitType.cs | 103 + .../Rackspace/Objects/Dns/NamespaceDoc.cs | 13 + .../Rackspace/Objects/Dns/RecordId.cs | 42 + .../Rackspace/Objects/Dns/SerializedDomain.cs | 88 + .../Objects/Dns/SerializedDomainFormat.cs | 75 + .../Providers/Rackspace/Objects/Domain.cs | 42 + .../Objects/LoadBalancers/AccessType.cs | 90 + .../LoadBalancers/ConnectionHealthMonitor.cs | 43 + .../LoadBalancers/ConnectionThrottles.cs | 146 + .../LoadBalancers/CustomHealthMonitor.cs | 22 + .../Objects/LoadBalancers/HealthMonitor.cs | 160 + .../LoadBalancers/HealthMonitorType.cs | 101 + .../Objects/LoadBalancers/LoadBalancer.cs | 194 ++ .../LoadBalancers/LoadBalancerCluster.cs | 43 + .../LoadBalancerConfiguration.cs | 73 + .../LoadBalancerConfiguration`1.cs | 403 +++ .../LoadBalancers/LoadBalancerEnabledFlag.cs | 86 + .../Objects/LoadBalancers/LoadBalancerId.cs | 42 + .../LoadBalancers/LoadBalancerMetadataItem.cs | 106 + .../LoadBalancerSslConfiguration.cs | 198 ++ .../LoadBalancers/LoadBalancerStatistics.cs | 111 + .../LoadBalancers/LoadBalancerStatus.cs | 160 + .../LoadBalancers/LoadBalancerTimestamp.cs | 44 + .../LoadBalancers/LoadBalancerUpdate.cs | 158 + .../LoadBalancers/LoadBalancerUsage.cs | 268 ++ .../LoadBalancers/LoadBalancerUsageId.cs | 42 + .../LoadBalancerVirtualAddress.cs | 171 ++ .../LoadBalancerVirtualAddressType.cs | 101 + .../LoadBalancers/LoadBalancingAlgorithm.cs | 132 + .../LoadBalancers/LoadBalancingProtocol.cs | 87 + .../Objects/LoadBalancers/MetadataId.cs | 42 + .../Objects/LoadBalancers/NamespaceDoc.cs | 13 + .../Objects/LoadBalancers/NetworkItem.cs | 125 + .../Objects/LoadBalancers/NetworkItemId.cs | 42 + .../Rackspace/Objects/LoadBalancers/Node.cs | 66 + .../Objects/LoadBalancers/NodeCondition.cs | 107 + .../LoadBalancers/NodeConfiguration.cs | 195 ++ .../Rackspace/Objects/LoadBalancers/NodeId.cs | 42 + .../Objects/LoadBalancers/NodeServiceEvent.cs | 260 ++ .../LoadBalancers/NodeServiceEventCategory.cs | 66 + .../LoadBalancers/NodeServiceEventId.cs | 42 + .../LoadBalancers/NodeServiceEventSeverity.cs | 66 + .../LoadBalancers/NodeServiceEventType.cs | 66 + .../Objects/LoadBalancers/NodeStatus.cs | 77 + .../Objects/LoadBalancers/NodeType.cs | 89 + .../Objects/LoadBalancers/NodeUpdate.cs | 97 + .../Request/AddLoadBalancerMetadataRequest.cs | 31 + .../LoadBalancers/Request/AddNodesRequest.cs | 24 + .../Request/CreateAccessListRequest.cs | 24 + .../Request/CreateLoadBalancerRequest.cs | 22 + .../LoadBalancers/Request/NamespaceDoc.cs | 14 + ...SetLoadBalancerConnectionLoggingRequest.cs | 16 + .../SetLoadBalancerContentCachingRequest.cs | 16 + .../SetLoadBalancerErrorPageRequest.cs | 16 + .../UpdateLoadBalancerMetadataItemRequest.cs | 49 + .../Request/UpdateLoadBalancerNodeRequest.cs | 42 + .../Request/UpdateLoadBalancerRequest.cs | 18 + .../Response/GetAccessListResponse.cs | 36 + ...etLoadBalancerConnectionLoggingResponse.cs | 38 + .../GetLoadBalancerContentCachingResponse.cs | 38 + .../GetLoadBalancerErrorPageResponse.cs | 74 + .../GetLoadBalancerMetadataItemResponse.cs | 35 + .../Response/GetLoadBalancerNodeResponse.cs | 32 + .../Response/GetLoadBalancerResponse.cs | 32 + ...GetLoadBalancerSslConfigurationResponse.cs | 32 + .../Response/ListAllowedDomainsResponse.cs | 92 + .../ListLoadBalancerMetadataResponse.cs | 48 + .../Response/ListLoadBalancerNodesResponse.cs | 48 + .../ListLoadBalancerThrottlesResponse.cs | 43 + .../Response/ListLoadBalancerUsageResponse.cs | 47 + .../Response/ListLoadBalancersResponse.cs | 47 + .../ListLoadBalancingAlgorithmsResponse.cs | 72 + .../ListLoadBalancingProtocolsResponse.cs | 47 + .../Response/ListNodeServiceEventsResponse.cs | 47 + .../Response/ListVirtualAddressesResponse.cs | 36 + .../LoadBalancers/Response/NamespaceDoc.cs | 14 + .../LoadBalancers/SessionPersistence.cs | 107 + .../LoadBalancers/SessionPersistenceType.cs | 92 + .../Objects/LoadBalancers/VirtualAddressId.cs | 42 + .../LoadBalancers/WebServerHealthMonitor.cs | 184 ++ .../Mapping/BulkDeletionResultMapper.cs | 60 + .../Rackspace/Objects/Mapping/NamespaceDoc.cs | 15 + .../Monitoring/AccountConfiguration.cs | 115 + .../Rackspace/Objects/Monitoring/Agent.cs | 61 + .../Objects/Monitoring/AgentConnection.cs | 155 + .../Objects/Monitoring/AgentConnectionId.cs | 42 + .../Rackspace/Objects/Monitoring/AgentId.cs | 42 + .../Objects/Monitoring/AgentToken.cs | 60 + .../Monitoring/AgentTokenConfiguration.cs | 52 + .../Objects/Monitoring/AgentTokenId.cs | 42 + .../Rackspace/Objects/Monitoring/Alarm.cs | 77 + .../Objects/Monitoring/AlarmChangelog.cs | 129 + .../Objects/Monitoring/AlarmChangelogId.cs | 42 + .../Objects/Monitoring/AlarmConfiguration.cs | 166 + .../Rackspace/Objects/Monitoring/AlarmData.cs | 78 + .../Objects/Monitoring/AlarmExample.cs | 136 + .../Objects/Monitoring/AlarmExampleField.cs | 77 + .../Objects/Monitoring/AlarmExampleId.cs | 42 + .../Rackspace/Objects/Monitoring/AlarmId.cs | 42 + .../AlarmNotificationHistoryItem.cs | 176 ++ .../AlarmNotificationHistoryItemId.cs | 42 + .../Objects/Monitoring/AlarmState.cs | 100 + .../Objects/Monitoring/AlarmStateHistory.cs | 164 + .../Rackspace/Objects/Monitoring/Audit.cs | 287 ++ .../Rackspace/Objects/Monitoring/AuditId.cs | 42 + .../Objects/Monitoring/BoundAlarmExample.cs | 47 + .../Rackspace/Objects/Monitoring/Check.cs | 98 + .../Objects/Monitoring/CheckConfiguration.cs | 303 ++ .../Rackspace/Objects/Monitoring/CheckData.cs | 257 ++ .../Objects/Monitoring/CheckDetails.cs | 86 + .../Rackspace/Objects/Monitoring/CheckId.cs | 42 + .../Objects/Monitoring/CheckMetricType.cs | 100 + .../Objects/Monitoring/CheckTarget.cs | 67 + .../Objects/Monitoring/CheckTargetId.cs | 42 + .../Rackspace/Objects/Monitoring/CheckType.cs | 82 + .../Objects/Monitoring/CheckTypeId.cs | 345 +++ .../Objects/Monitoring/CheckTypeType.cs | 88 + .../Monitoring/ConnectionCheckDetails.cs | 55 + .../Objects/Monitoring/CpuCheckDetails.cs | 31 + .../Objects/Monitoring/CpuInformation.cs | 290 ++ .../Rackspace/Objects/Monitoring/DataPoint.cs | 135 + .../Monitoring/DataPointGranularity.cs | 136 + .../Objects/Monitoring/DataPointStatistic.cs | 124 + .../Monitoring/DateTimeOffsetExtensions.cs | 74 + .../Objects/Monitoring/DiskCheckDetails.cs | 68 + .../Objects/Monitoring/DiskInformation.cs | 173 ++ .../Objects/Monitoring/DnsCheckDetails.cs | 96 + .../Monitoring/EmailNotificationDetails.cs | 67 + .../Rackspace/Objects/Monitoring/Entity.cs | 72 + .../Objects/Monitoring/EntityConfiguration.cs | 147 + .../Rackspace/Objects/Monitoring/EntityId.cs | 42 + .../Objects/Monitoring/EntityOverview.cs | 107 + .../Monitoring/FilesystemCheckDetails.cs | 68 + .../Monitoring/FilesystemInformation.cs | 197 ++ .../Monitoring/FtpBannerCheckDetails.cs | 45 + .../Objects/Monitoring/GenericCheckDetails.cs | 73 + .../Monitoring/GenericNotificationDetails.cs | 73 + .../Objects/Monitoring/HostInformationType.cs | 168 ++ .../Objects/Monitoring/HostInformation`1.cs | 62 + .../Objects/Monitoring/HttpCheckDetails.cs | 263 ++ .../Monitoring/ImapBannerCheckDetails.cs | 46 + .../Monitoring/LoadAverageCheckDetails.cs | 31 + .../Objects/Monitoring/LoginInformation.cs | 96 + .../Objects/Monitoring/MemoryCheckDetails.cs | 31 + .../Objects/Monitoring/MemoryInformation.cs | 203 ++ .../Rackspace/Objects/Monitoring/Metric.cs | 52 + .../Objects/Monitoring/MetricName.cs | 42 + .../Objects/Monitoring/MonitoringAccount.cs | 47 + .../Objects/Monitoring/MonitoringAccountId.cs | 42 + .../Objects/Monitoring/MonitoringLimits.cs | 144 + .../Objects/Monitoring/MonitoringZone.cs | 112 + .../Objects/Monitoring/MonitoringZoneId.cs | 42 + .../Monitoring/MssqlBannerCheckDetails.cs | 46 + .../Monitoring/MysqlBannerCheckDetails.cs | 46 + .../Objects/Monitoring/NamespaceDoc.cs | 13 + .../Objects/Monitoring/NetworkCheckDetails.cs | 68 + .../Monitoring/NetworkInterfaceInformation.cs | 408 +++ .../Monitoring/NewAlarmConfiguration.cs | 53 + .../Monitoring/NewCheckConfiguration.cs | 88 + .../Monitoring/NewEntityConfiguration.cs | 50 + .../NewNotificationConfiguration.cs | 58 + .../NewNotificationPlanConfiguration.cs | 54 + .../Objects/Monitoring/Notification.cs | 78 + .../Objects/Monitoring/NotificationAttempt.cs | 61 + .../Monitoring/NotificationConfiguration.cs | 143 + .../Objects/Monitoring/NotificationData.cs | 61 + .../Objects/Monitoring/NotificationDetails.cs | 54 + .../Objects/Monitoring/NotificationId.cs | 42 + .../Objects/Monitoring/NotificationPlan.cs | 79 + .../NotificationPlanConfiguration.cs | 187 ++ .../Objects/Monitoring/NotificationPlanId.cs | 42 + .../Objects/Monitoring/NotificationResult.cs | 156 + .../Objects/Monitoring/NotificationType.cs | 65 + .../Monitoring/NotificationTypeField.cs | 77 + .../Objects/Monitoring/NotificationTypeId.cs | 90 + .../PagerDutyNotificationDetails.cs | 67 + .../Objects/Monitoring/PingCheckDetails.cs | 65 + .../Objects/Monitoring/PluginCheckDetails.cs | 121 + .../Objects/Monitoring/Pop3CheckDetails.cs | 46 + .../PostgresqlBannerCheckDetails.cs | 46 + .../Objects/Monitoring/ProcessInformation.cs | 409 +++ .../Monitoring/ReadOnlyCollectionPage`2.cs | 111 + .../SecureConnectionCheckDetails.cs | 52 + .../Monitoring/SmtpBannerCheckDetails.cs | 46 + .../Objects/Monitoring/SmtpCheckDetails.cs | 140 + .../Objects/Monitoring/SshCheckDetails.cs | 45 + .../Objects/Monitoring/SystemInformation.cs | 112 + .../Objects/Monitoring/TargetResolverType.cs | 88 + .../Objects/Monitoring/TcpCheckDetails.cs | 103 + .../Monitoring/TelnetBannerCheckDetails.cs | 65 + .../Monitoring/TestAlarmConfiguration.cs | 98 + .../Objects/Monitoring/TraceRoute.cs | 49 + .../Monitoring/TraceRouteConfiguration.cs | 98 + .../Objects/Monitoring/TraceRouteHop.cs | 138 + .../Objects/Monitoring/TransactionId.cs | 41 + .../Monitoring/UpdateAlarmConfiguration.cs | 44 + .../Monitoring/UpdateCheckConfiguration.cs | 68 + .../Monitoring/UpdateEntityConfiguration.cs | 47 + .../UpdateNotificationConfiguration.cs | 48 + .../UpdateNotificationPlanConfiguration.cs | 51 + .../Monitoring/WebhookNotificationDetails.cs | 67 + .../Objects/Monitoring/WebhookToken.cs | 42 + .../Rackspace/Objects/NamespaceDoc.cs | 13 + .../Rackspace/Objects/Queues/NamespaceDoc.cs | 13 + .../Queues/Request/ClaimMessagesRequest.cs | 28 + .../Objects/Queues/Request/NamespaceDoc.cs | 14 + .../ListCloudQueueMessagesResponse.cs | 52 + .../Response/ListCloudQueuesResponse.cs | 45 + .../Objects/Queues/Response/NamespaceDoc.cs | 14 + .../Objects/RackspaceCloudIdentity.cs | 52 + .../Objects/Request/AddRoleRequest.cs | 35 + .../AddServiceCatalogEndpointRequest.cs | 75 + .../Objects/Request/AddUserRequest.cs | 35 + .../Request/AttachServerVolumeRequest.cs | 86 + .../Rackspace/Objects/Request/AuthRequest.cs | 46 + .../ChangeServerAdminPasswordRequest.cs | 64 + .../Request/ConfirmServerResizeRequest.cs | 18 + .../CreateCloudBlockStorageSnapshotDetails.cs | 65 + .../CreateCloudBlockStorageSnapshotRequest.cs | 34 + .../CreateCloudBlockStorageVolumeDetails.cs | 70 + .../CreateCloudBlockStorageVolumeRequest.cs | 34 + .../Request/CreateCloudNetworkRequest.cs | 34 + .../Request/CreateCloudNetworksDetails.cs | 58 + .../Request/CreateServerImageDetails.cs | 47 + .../Request/CreateServerImageRequest.cs | 34 + .../Objects/Request/CreateServerRequest.cs | 166 + .../Request/CreateVirtualInterfaceRequest.cs | 70 + .../Rackspace/Objects/Request/NamespaceDoc.cs | 14 + .../Objects/Request/PasswordCredential.cs | 65 + .../Rackspace/Objects/Request/Personality.cs | 121 + .../Objects/Request/RescueServerRequest.cs | 18 + .../Request/RevertServerResizeRequest.cs | 18 + .../Objects/Request/ServerRebootDetails.cs | 40 + .../Objects/Request/ServerRebootRequest.cs | 34 + .../Objects/Request/ServerRebuildDetails.cs | 136 + .../Objects/Request/ServerRebuildRequest.cs | 34 + .../Objects/Request/ServerResizeDetails.cs | 67 + .../Objects/Request/ServerResizeRequest.cs | 34 + .../Objects/Request/SetPasswordRequest.cs | 52 + .../Objects/Request/UnrescueServerRequest.cs | 18 + .../Request/UpdateMetadataItemRequest.cs | 48 + .../Objects/Request/UpdateMetadataRequest.cs | 36 + .../Objects/Request/UpdateServerRequest.cs | 97 + .../Request/UpdateUserCredentialRequest.cs | 52 + .../Objects/Request/UpdateUserRequest.cs | 38 + .../Response/AuthenticationResponse.cs | 21 + .../Objects/Response/BulkDeleteResponse.cs | 32 + .../Objects/Response/CloudNetworkResponse.cs | 21 + .../Objects/Response/CreateServerResponse.cs | 20 + .../Objects/Response/ExtractArchiveError.cs | 65 + .../Response/ExtractArchiveResponse.cs | 132 + .../Objects/Response/FlavorDetailsResponse.cs | 20 + .../GetCloudBlockStorageSnapshotResponse.cs | 21 + .../GetCloudBlockStorageVolumeResponse.cs | 21 + .../GetCloudBlockStorageVolumeTypeResponse.cs | 20 + .../Objects/Response/GetEndpointResponse.cs | 52 + .../Response/GetImageDetailsResponse.cs | 20 + .../Objects/Response/ListAddressesResponse.cs | 20 + .../Response/ListCloudNetworksResponse.cs | 20 + .../Objects/Response/ListEndpointsResponse.cs | 22 + .../Response/ListFlavorDetailsResponse.cs | 20 + .../Objects/Response/ListFlavorsResponse.cs | 20 + .../Response/ListImagesDetailsResponse.cs | 20 + .../Objects/Response/ListImagesResponse.cs | 20 + .../Objects/Response/ListServersResponse.cs | 26 + .../Objects/Response/ListSnapshotResponse.cs | 20 + .../Response/ListVirtualInterfacesResponse.cs | 22 + .../Objects/Response/ListVolumeResponse.cs | 20 + .../Response/ListVolumeTypeResponse.cs | 20 + .../Objects/Response/MetaDataResponse.cs | 20 + .../Objects/Response/MetadataItemResponse.cs | 21 + .../Objects/Response/NamespaceDoc.cs | 14 + .../Objects/Response/NewUserResponse.cs | 21 + .../Response/PasswordCredentialResponse.cs | 21 + .../Objects/Response/RescueServerResponse.cs | 20 + .../Objects/Response/RoleResponse.cs | 21 + .../Objects/Response/RolesResponse.cs | 27 + .../Objects/Response/ServerDetailsResponse.cs | 22 + .../Response/ServerVolumeListResponse.cs | 21 + .../Objects/Response/ServerVolumeResponse.cs | 21 + .../Objects/Response/TenantsResponse.cs | 20 + .../Response/UserCredentialResponse.cs | 21 + .../Response/UserImpersonationResponse.cs | 43 + .../Objects/Response/UserResponse.cs | 28 + .../Objects/Response/UsersResponse.cs | 20 + .../Providers/Rackspace/ProviderBase`1.cs | 1405 +++++++++ .../RackspaceImpersonationIdentity.cs | 21 + .../Validators/CloudBlockStorageValidator.cs | 40 + .../Validators/CloudFilesValidator.cs | 58 + .../Validators/CloudNetworksValidator.cs | 74 + .../Validators/HttpResponseCodeValidator.cs | 66 + .../Rackspace/Validators/NamespaceDoc.cs | 14 + .../Rackspace/WebRequestEventArgs.cs | 44 + .../Rackspace/WebResponseEventArgs.cs | 44 + .../Serialization/DefaultJsonConverter.cs | 76 + src/OpenStack/Serialization/IHaveExtraData.cs | 45 + src/OpenStack/Serialization/IPageBuilder.cs | 17 + src/OpenStack/Serialization/IPageLink.cs | 12 + .../Serialization/IQueryStringBuilder.cs | 11 + .../Serialization/IServiceResource.cs | 139 + .../Serialization/IdentifierConverter.cs | 40 + .../JsonConverterWithConstructorAttribute.cs | 63 + .../OpenStackContractResolver.cs | 67 + src/OpenStack/Serialization/Page.cs | 76 + src/OpenStack/Serialization/PageLink.cs | 38 + .../Serialization/ResourceCollection.cs | 61 + src/OpenStack/Serialization/ResourceStatus.cs | 9 + .../Serialization/RootWrapperConverter.cs | 75 + .../Serialization/ServiceEndpoint.cs | 329 ++ .../Serialization/StringEnumeration.cs | 106 + .../StringEnumerationConverter.cs | 32 + .../TimeSpanInSecondsConverter.cs | 32 + .../Serialization/TolerantEnumConverter.cs | 65 + src/OpenStack/Testing/HttpTest.cs | 84 + src/OpenStack/Testing/NamespaceDoc.cs | 12 + src/corelib/OpenStack.csproj | 1265 -------- src/openstack.net.sln | 19 +- .../OpenStack.IntegrationTests.csproj | 6 +- src/testing/unit/OpenStack.UnitTests.csproj | 6 +- 840 files changed, 95554 insertions(+), 1274 deletions(-) create mode 100644 src/OpenStack/Authentication/AuthenticatedHttpClientFactory.cs create mode 100644 src/OpenStack/Authentication/AuthenticatedMessageHandler.cs create mode 100644 src/OpenStack/Authentication/IAuthenticationProvider.cs create mode 100644 src/OpenStack/Authentication/NamespaceDoc.cs create mode 100644 src/OpenStack/Authentication/ServiceType.cs create mode 100644 src/OpenStack/BlockStorage/v2/Serialization/SnapshotStatus.cs create mode 100644 src/OpenStack/BlockStorage/v2/Serialization/VolumeStatus.cs create mode 100644 src/OpenStack/BlockStorage/v2/SnapshotStatus.cs create mode 100644 src/OpenStack/BlockStorage/v2/VolumeStatus.cs create mode 100644 src/OpenStack/Compute/ComputeOperationFailedException.cs create mode 100644 src/OpenStack/Compute/NamespaceDoc.cs create mode 100644 src/OpenStack/Compute/v2_1/Actions/AssociateFloatingIPRequest.cs create mode 100644 src/OpenStack/Compute/v2_1/Actions/RebootServerRequest.cs create mode 100644 src/OpenStack/Compute/v2_1/Actions/RebootType.cs create mode 100644 src/OpenStack/Compute/v2_1/Actions/RescueServerRequest.cs create mode 100644 src/OpenStack/Compute/v2_1/Actions/SnapshotServerRequest.cs create mode 100644 src/OpenStack/Compute/v2_1/AddressType.cs create mode 100644 src/OpenStack/Compute/v2_1/ComputeService.cs create mode 100644 src/OpenStack/Compute/v2_1/ComputeServiceExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/DiskConfiguration.cs create mode 100644 src/OpenStack/Compute/v2_1/Flavor.cs create mode 100644 src/OpenStack/Compute/v2_1/FlavorExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/FlavorListOptions.cs create mode 100644 src/OpenStack/Compute/v2_1/FlavorReference.cs create mode 100644 src/OpenStack/Compute/v2_1/FlavorSummary.cs create mode 100644 src/OpenStack/Compute/v2_1/IPProtocol.cs create mode 100644 src/OpenStack/Compute/v2_1/Image.cs create mode 100644 src/OpenStack/Compute/v2_1/ImageExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/ImageListOptions.cs create mode 100644 src/OpenStack/Compute/v2_1/ImageMetadata.cs create mode 100644 src/OpenStack/Compute/v2_1/ImageMetadataExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/ImageReference.cs create mode 100644 src/OpenStack/Compute/v2_1/ImageSummary.cs create mode 100644 src/OpenStack/Compute/v2_1/ImageType.cs create mode 100644 src/OpenStack/Compute/v2_1/KeyPair.cs create mode 100644 src/OpenStack/Compute/v2_1/KeyPairDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/KeyPairExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/KeyPairRequest.cs create mode 100644 src/OpenStack/Compute/v2_1/KeyPairResponse.cs create mode 100644 src/OpenStack/Compute/v2_1/KeyPairSummary.cs create mode 100644 src/OpenStack/Compute/v2_1/NamespaceDoc.cs create mode 100644 src/OpenStack/Compute/v2_1/Operator/ComputeServiceExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/Operator/EvacuateServerRequest.cs create mode 100644 src/OpenStack/Compute/v2_1/Operator/NamespaceDoc.cs create mode 100644 src/OpenStack/Compute/v2_1/Operator/ServerExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/Operator/ServiceQuotas.cs create mode 100644 src/OpenStack/Compute/v2_1/RemoteConsole.cs create mode 100644 src/OpenStack/Compute/v2_1/RemoteConsoleType.cs create mode 100644 src/OpenStack/Compute/v2_1/SchedulerHints.cs create mode 100644 src/OpenStack/Compute/v2_1/SecurityGroup.cs create mode 100644 src/OpenStack/Compute/v2_1/SecurityGroupDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/SecurityGroupExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/SecurityGroupReference.cs create mode 100644 src/OpenStack/Compute/v2_1/SecurityGroupRule.cs create mode 100644 src/OpenStack/Compute/v2_1/SecurityGroupRuleDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/AddressType.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ComputeApi.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/DiskConfiguration.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/FlavorCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ImageCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ImageType.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/KeyPairCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/KeyPairConverter.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/RebootType.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/RemoteConsoleType.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/SecurityGroupCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerActionCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerAddressCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerBlockDeviceType.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerCreateDefinitionConverter.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerEventStatus.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerGroupCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerStatus.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/ServerVolumeCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/VolumeCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Serialization/VolumeSnapshotCollection.cs create mode 100644 src/OpenStack/Compute/v2_1/Server.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerAction.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerActionExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerActionSummary.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerAddress.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerBlockDeviceMapping.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerBlockDeviceType.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerCreateDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerEventStatus.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerGroup.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerGroupDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerGroupExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerListOptions.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerMetadata.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerMetadataExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerNetworkDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerReference.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerStatus.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerSummary.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerUpdateDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerVolume.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerVolumeDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerVolumeExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/ServerVolumeReference.cs create mode 100644 src/OpenStack/Compute/v2_1/ServiceLimits.cs create mode 100644 src/OpenStack/Compute/v2_1/Volume.cs create mode 100644 src/OpenStack/Compute/v2_1/VolumeDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/VolumeExtensions.cs create mode 100644 src/OpenStack/Compute/v2_1/VolumeSnapshot.cs create mode 100644 src/OpenStack/Compute/v2_1/VolumeSnapshotDefinition.cs create mode 100644 src/OpenStack/Compute/v2_1/VolumeSnapshotExtensions.cs create mode 100644 src/OpenStack/Compute/v2_2/ComputeApi.cs create mode 100644 src/OpenStack/Compute/v2_2/ComputeService.cs create mode 100644 src/OpenStack/Compute/v2_2/ComputeServiceExtensions.cs create mode 100644 src/OpenStack/Compute/v2_2/KeyPair.cs create mode 100644 src/OpenStack/Compute/v2_2/KeyPairDefinition.cs create mode 100644 src/OpenStack/Compute/v2_2/KeyPairType.cs create mode 100644 src/OpenStack/Compute/v2_2/RemoteConsole.cs create mode 100644 src/OpenStack/Compute/v2_2/RemoteConsoleType.cs create mode 100644 src/OpenStack/Compute/v2_2/Serialization/ServerCollection.cs create mode 100644 src/OpenStack/Compute/v2_2/Server.cs create mode 100644 src/OpenStack/Compute/v2_2/ServerListOptions.cs create mode 100644 src/OpenStack/Compute/v2_2/ServerReference.cs create mode 100644 src/OpenStack/Compute/v2_2/ServerStatus.cs create mode 100644 src/OpenStack/Compute/v2_6/ComputeApi.cs create mode 100644 src/OpenStack/Compute/v2_6/ComputeService.cs create mode 100644 src/OpenStack/Compute/v2_6/ComputeServiceExtensions.cs create mode 100644 src/OpenStack/Compute/v2_6/Console.cs create mode 100644 src/OpenStack/Compute/v2_6/ConsoleProtocol.cs create mode 100644 src/OpenStack/Compute/v2_6/KeyPair.cs create mode 100644 src/OpenStack/Compute/v2_6/KeyPairDefinition.cs create mode 100644 src/OpenStack/Compute/v2_6/KeyPairType.cs create mode 100644 src/OpenStack/Compute/v2_6/RemoteConsoleType.cs create mode 100644 src/OpenStack/Compute/v2_6/Serialization/ServerCollection.cs create mode 100644 src/OpenStack/Compute/v2_6/Server.cs create mode 100644 src/OpenStack/Compute/v2_6/ServerListOptions.cs create mode 100644 src/OpenStack/Compute/v2_6/ServerReference.cs create mode 100644 src/OpenStack/Compute/v2_6/ServerStatus.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ContentDeliveryNetworkService.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceExtensions.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/Flavor.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/FlavorCollection.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/IContentDeliveryNetworkService.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/NamespaceDoc.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/Provider.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/Service.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceCache.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceCacheRule.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceCollection.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceDefinition.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceDomain.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceError.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceOperationFailedException.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceOrigin.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceOriginRule.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceProtocol.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceRestriction.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceRestrictionRule.cs create mode 100644 src/OpenStack/ContentDeliveryNetworks/v1/ServiceStatus.cs create mode 100644 src/OpenStack/Core/AsyncCompletionOption.cs create mode 100644 src/OpenStack/Core/BackoffPolicy.cs create mode 100644 src/OpenStack/Core/Caching/ICache`1.cs create mode 100644 src/OpenStack/Core/Caching/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Caching/UserAccessCache.cs create mode 100644 src/OpenStack/Core/Collections/BasicReadOnlyCollectionPage`1.cs create mode 100644 src/OpenStack/Core/Collections/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Collections/ReadOnlyCollectionPage`1.cs create mode 100644 src/OpenStack/Core/Compat/Funcs.cs create mode 100644 src/OpenStack/Core/Compat/ISafeSerializationData.cs create mode 100644 src/OpenStack/Core/Compat/IStructuralComparable.cs create mode 100644 src/OpenStack/Core/Compat/IStructuralEquatable.cs create mode 100644 src/OpenStack/Core/Compat/Tuple.cs create mode 100644 src/OpenStack/Core/Compat/Tuples.cs create mode 100644 src/OpenStack/Core/CoreTaskExtensions.cs create mode 100644 src/OpenStack/Core/Domain/AuthenticationRequirement.cs create mode 100644 src/OpenStack/Core/Domain/AuthenticationType.cs create mode 100644 src/OpenStack/Core/Domain/CloudIdentity.cs create mode 100644 src/OpenStack/Core/Domain/CloudIdentityWithProject.cs create mode 100644 src/OpenStack/Core/Domain/CloudNetwork.cs create mode 100644 src/OpenStack/Core/Domain/Container.cs create mode 100644 src/OpenStack/Core/Domain/ContainerCDN.cs create mode 100644 src/OpenStack/Core/Domain/ContainerObject.cs create mode 100644 src/OpenStack/Core/Domain/Converters/IPAddressDetailsConverter.cs create mode 100644 src/OpenStack/Core/Domain/Converters/IPAddressNoneIsNullSimpleConverter.cs create mode 100644 src/OpenStack/Core/Domain/Converters/IPAddressSimpleConverter.cs create mode 100644 src/OpenStack/Core/Domain/Converters/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Domain/Converters/PhysicalAddressSimpleConverter.cs create mode 100644 src/OpenStack/Core/Domain/Converters/SimpleStringJsonConverter`1.cs create mode 100644 src/OpenStack/Core/Domain/DiskConfiguration.cs create mode 100644 src/OpenStack/Core/Domain/Endpoint.cs create mode 100644 src/OpenStack/Core/Domain/EndpointTemplate.cs create mode 100644 src/OpenStack/Core/Domain/EndpointTemplateId.cs create mode 100644 src/OpenStack/Core/Domain/ExtendedEndpoint.cs create mode 100644 src/OpenStack/Core/Domain/ExtensibleJsonObject.cs create mode 100644 src/OpenStack/Core/Domain/Flavor.cs create mode 100644 src/OpenStack/Core/Domain/FlavorDetails.cs create mode 100644 src/OpenStack/Core/Domain/FlavorId.cs create mode 100644 src/OpenStack/Core/Domain/HomeDocument.cs create mode 100644 src/OpenStack/Core/Domain/IPAddressList.cs create mode 100644 src/OpenStack/Core/Domain/IdentityToken.cs create mode 100644 src/OpenStack/Core/Domain/ImageId.cs create mode 100644 src/OpenStack/Core/Domain/ImageState.cs create mode 100644 src/OpenStack/Core/Domain/ImageType.cs create mode 100644 src/OpenStack/Core/Domain/Link.cs create mode 100644 src/OpenStack/Core/Domain/Mapping/IJsonObjectMapper`1.cs create mode 100644 src/OpenStack/Core/Domain/Mapping/IObjectMapper`2.cs create mode 100644 src/OpenStack/Core/Domain/Mapping/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Domain/Metadata.cs create mode 100644 src/OpenStack/Core/Domain/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Domain/NetworkId.cs create mode 100644 src/OpenStack/Core/Domain/NewServer.cs create mode 100644 src/OpenStack/Core/Domain/NewUser.cs create mode 100644 src/OpenStack/Core/Domain/ObjectStore.cs create mode 100644 src/OpenStack/Core/Domain/Personality.cs create mode 100644 src/OpenStack/Core/Domain/PowerState.cs create mode 100644 src/OpenStack/Core/Domain/ProjectId.cs create mode 100644 src/OpenStack/Core/Domain/ProviderStateBase`1.cs create mode 100644 src/OpenStack/Core/Domain/Queues/Claim.cs create mode 100644 src/OpenStack/Core/Domain/Queues/ClaimId.cs create mode 100644 src/OpenStack/Core/Domain/Queues/CloudQueue.cs create mode 100644 src/OpenStack/Core/Domain/Queues/Message.cs create mode 100644 src/OpenStack/Core/Domain/Queues/MessageId.cs create mode 100644 src/OpenStack/Core/Domain/Queues/MessageStatistics.cs create mode 100644 src/OpenStack/Core/Domain/Queues/Message`1.cs create mode 100644 src/OpenStack/Core/Domain/Queues/MessagesEnqueued.cs create mode 100644 src/OpenStack/Core/Domain/Queues/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Domain/Queues/QueueMessagesStatistics.cs create mode 100644 src/OpenStack/Core/Domain/Queues/QueueName.cs create mode 100644 src/OpenStack/Core/Domain/Queues/QueueStatistics.cs create mode 100644 src/OpenStack/Core/Domain/Queues/QueuedMessage.cs create mode 100644 src/OpenStack/Core/Domain/Queues/QueuedMessageList.cs create mode 100644 src/OpenStack/Core/Domain/Queues/QueuedMessageListId.cs create mode 100644 src/OpenStack/Core/Domain/RebootType.cs create mode 100644 src/OpenStack/Core/Domain/ResourceHints.cs create mode 100644 src/OpenStack/Core/Domain/ResourceObject.cs create mode 100644 src/OpenStack/Core/Domain/Role.cs create mode 100644 src/OpenStack/Core/Domain/Server.cs create mode 100644 src/OpenStack/Core/Domain/ServerAddresses.cs create mode 100644 src/OpenStack/Core/Domain/ServerBase.cs create mode 100644 src/OpenStack/Core/Domain/ServerId.cs create mode 100644 src/OpenStack/Core/Domain/ServerImage.cs create mode 100644 src/OpenStack/Core/Domain/ServerState.cs create mode 100644 src/OpenStack/Core/Domain/ServerVolume.cs create mode 100644 src/OpenStack/Core/Domain/ServiceCatalog.cs create mode 100644 src/OpenStack/Core/Domain/SimpleServer.cs create mode 100644 src/OpenStack/Core/Domain/SimpleServerImage.cs create mode 100644 src/OpenStack/Core/Domain/Snapshot.cs create mode 100644 src/OpenStack/Core/Domain/SnapshotState.cs create mode 100644 src/OpenStack/Core/Domain/Status.cs create mode 100644 src/OpenStack/Core/Domain/TaskState.cs create mode 100644 src/OpenStack/Core/Domain/Tenant.cs create mode 100644 src/OpenStack/Core/Domain/User.cs create mode 100644 src/OpenStack/Core/Domain/UserAccess.cs create mode 100644 src/OpenStack/Core/Domain/UserCredential.cs create mode 100644 src/OpenStack/Core/Domain/UserDetails.cs create mode 100644 src/OpenStack/Core/Domain/VirtualInterface.cs create mode 100644 src/OpenStack/Core/Domain/VirtualInterfaceAddress.cs create mode 100644 src/OpenStack/Core/Domain/VirtualMachineState.cs create mode 100644 src/OpenStack/Core/Domain/Volume.cs create mode 100644 src/OpenStack/Core/Domain/VolumeState.cs create mode 100644 src/OpenStack/Core/Domain/VolumeType.cs create mode 100644 src/OpenStack/Core/Exceptions/CDNNotEnabledException.cs create mode 100644 src/OpenStack/Core/Exceptions/CidrFormatException.cs create mode 100644 src/OpenStack/Core/Exceptions/ContainerNameException.cs create mode 100644 src/OpenStack/Core/Exceptions/ContainerNotEmptyException.cs create mode 100644 src/OpenStack/Core/Exceptions/ImageEnteredErrorStateException.cs create mode 100644 src/OpenStack/Core/Exceptions/InvalidCloudIdentityException.cs create mode 100644 src/OpenStack/Core/Exceptions/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Exceptions/NoDefaultRegionSetException.cs create mode 100644 src/OpenStack/Core/Exceptions/ObjectNameException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/BadServiceRequestException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/ItemNotFoundException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/MethodNotImplementedException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/ResponseException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/ServiceConflictException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/ServiceFaultException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/ServiceLimitReachedException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/ServiceUnavailableException.cs create mode 100644 src/OpenStack/Core/Exceptions/Response/UserNotAuthorizedException.cs create mode 100644 src/OpenStack/Core/Exceptions/ServerEnteredErrorStateException.cs create mode 100644 src/OpenStack/Core/Exceptions/SnapshotEnteredErrorStateException.cs create mode 100644 src/OpenStack/Core/Exceptions/TTLLengthException.cs create mode 100644 src/OpenStack/Core/Exceptions/UserAuthenticationException.cs create mode 100644 src/OpenStack/Core/Exceptions/UserAuthorizationException.cs create mode 100644 src/OpenStack/Core/Exceptions/VolumeEnteredErrorStateException.cs create mode 100644 src/OpenStack/Core/ExtensibleEnum`1.cs create mode 100644 src/OpenStack/Core/HttpStatusCodeParser.cs create mode 100644 src/OpenStack/Core/IBackoffPolicy.cs create mode 100644 src/OpenStack/Core/IEncodeDecodeProvider.cs create mode 100644 src/OpenStack/Core/IObjectStorageMetadataProcessor.cs create mode 100644 src/OpenStack/Core/IStatusParser.cs create mode 100644 src/OpenStack/Core/InternalTaskExtensions.cs create mode 100644 src/OpenStack/Core/LegacyAuthenticationProviderHelper.cs create mode 100644 src/OpenStack/Core/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/ParallelExtensionsExtras/TaskCompletionSourceExtensions.cs create mode 100644 src/OpenStack/Core/ParallelExtensionsExtras/TaskExtrasExtensions.cs create mode 100644 src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_Common.cs create mode 100644 src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_ContinueWhenAllAny.cs create mode 100644 src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_Delayed.cs create mode 100644 src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_From.cs create mode 100644 src/OpenStack/Core/Providers/IBlockStorageProvider.cs create mode 100644 src/OpenStack/Core/Providers/IComputeProvider.cs create mode 100644 src/OpenStack/Core/Providers/IIdentityProvider.cs create mode 100644 src/OpenStack/Core/Providers/IIdentityService.cs create mode 100644 src/OpenStack/Core/Providers/INetworksProvider.cs create mode 100644 src/OpenStack/Core/Providers/IObjectStorageProvider.cs create mode 100644 src/OpenStack/Core/Providers/IQueueingService.cs create mode 100644 src/OpenStack/Core/Providers/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Providers/OpenStackIdentityProvider.cs create mode 100644 src/OpenStack/Core/ReadOnlyCollectionPageExtensions.cs create mode 100644 src/OpenStack/Core/ResourceIdentifier`1.cs create mode 100644 src/OpenStack/Core/ResponseExtensions.cs create mode 100644 src/OpenStack/Core/RestWebHeaderCollection.cs create mode 100644 src/OpenStack/Core/Synchronous/AutoScaleServiceExtensions.cs create mode 100644 src/OpenStack/Core/Synchronous/ClaimExtensions.cs create mode 100644 src/OpenStack/Core/Synchronous/DatabaseServiceExtensions.cs create mode 100644 src/OpenStack/Core/Synchronous/DnsServiceExtensions.cs create mode 100644 src/OpenStack/Core/Synchronous/LoadBalancerServiceExtensions.cs create mode 100644 src/OpenStack/Core/Synchronous/MonitoringServiceExtensions.cs create mode 100644 src/OpenStack/Core/Synchronous/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/Synchronous/QueueingServiceExtensions.cs create mode 100644 src/OpenStack/Core/Synchronous/ReadOnlyCollectionPageSynchronousExtensions.cs create mode 100644 src/OpenStack/Core/UriPart.cs create mode 100644 src/OpenStack/Core/UriUtility.cs create mode 100644 src/OpenStack/Core/Validators/IBlockStorageValidator.cs create mode 100644 src/OpenStack/Core/Validators/IHttpResponseCodeValidator.cs create mode 100644 src/OpenStack/Core/Validators/INetworksValidator.cs create mode 100644 src/OpenStack/Core/Validators/IObjectStorageValidator.cs create mode 100644 src/OpenStack/Core/Validators/NamespaceDoc.cs create mode 100644 src/OpenStack/Core/WebRequestExtensions.cs create mode 100644 src/OpenStack/Exceptions/IdentityRequiredException.cs create mode 100644 src/OpenStack/Exceptions/RegionRequiredException.cs create mode 100644 src/OpenStack/Exceptions/ResourceErrorException.cs create mode 100644 src/OpenStack/Exceptions/UserAuthenticationException.cs create mode 100644 src/OpenStack/Extensions/EnumerableExtensions.cs create mode 100644 src/OpenStack/Extensions/FlurlExtensions.cs create mode 100644 src/OpenStack/Extensions/HttpHeadersExtensions.cs create mode 100644 src/OpenStack/Extensions/HttpRequestMessageExtensions.cs create mode 100644 src/OpenStack/Extensions/TaskExtensions.cs create mode 100644 src/OpenStack/Extensions/TypeExtensions.cs create mode 100644 src/OpenStack/Flurl/PreparedRequest.cs create mode 100644 src/OpenStack/Icons/openstack_net_logo.png create mode 100644 src/OpenStack/Identifier.cs create mode 100644 src/OpenStack/Images/v2/ImageStatus.cs create mode 100644 src/OpenStack/Images/v2/Serialization/ImageStatus.cs create mode 100644 src/OpenStack/NamespaceDoc.cs create mode 100644 src/OpenStack/Networking/IPVersion.cs create mode 100644 src/OpenStack/Networking/NamespaceDoc.cs create mode 100644 src/OpenStack/Networking/v2/AllocationPool.cs create mode 100644 src/OpenStack/Networking/v2/AllowedAddress.cs create mode 100644 src/OpenStack/Networking/v2/HostRoute.cs create mode 100644 src/OpenStack/Networking/v2/IPAddressAssociation.cs create mode 100644 src/OpenStack/Networking/v2/IPProtocol.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/ExternalGateway.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/ExternalGatewayDefinition.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/FloatingIP.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/FloatingIPCreateDefinition.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/FloatingIPExtensions.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/FloatingIPListOptions.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/FloatingIPStatus.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/FloatingIPUpdateDefinition.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/NetworkingService_Layer3_Extensions.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/Router.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/RouterCreateDefinition.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/RouterExtensions.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/RouterListOptions.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/RouterStatus.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/RouterUpdateDefinition.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/SecurityGroup.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/SecurityGroupListOptions.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/SecurityGroupRule.cs create mode 100644 src/OpenStack/Networking/v2/Layer3/SecurityGroupRuleListOptions.cs create mode 100644 src/OpenStack/Networking/v2/NamespaceDoc.cs create mode 100644 src/OpenStack/Networking/v2/Network.cs create mode 100644 src/OpenStack/Networking/v2/NetworkDefinition.cs create mode 100644 src/OpenStack/Networking/v2/NetworkStatus.cs create mode 100644 src/OpenStack/Networking/v2/NetworkingApiBuilder.cs create mode 100644 src/OpenStack/Networking/v2/NetworkingService.cs create mode 100644 src/OpenStack/Networking/v2/NetworkingServiceExtensions.cs create mode 100644 src/OpenStack/Networking/v2/Operator/NamespaceDoc.cs create mode 100644 src/OpenStack/Networking/v2/Operator/NetworkDefinition.cs create mode 100644 src/OpenStack/Networking/v2/Port.cs create mode 100644 src/OpenStack/Networking/v2/PortCreateDefinition.cs create mode 100644 src/OpenStack/Networking/v2/PortListOptions.cs create mode 100644 src/OpenStack/Networking/v2/PortStatus.cs create mode 100644 src/OpenStack/Networking/v2/PortUpdateDefinition.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/DHCPOptionsConverter.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/FloatingIPCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/IPProtocol.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/NetworkCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/NetworkDefinitionCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/NetworkResourceStatus.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/PortCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/PortDefinitionCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/RouterCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/SecurityGroupCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/SecurityGroupRuleCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/SubnetCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/SubnetDefinitionCollection.cs create mode 100644 src/OpenStack/Networking/v2/Serialization/TrafficDirection.cs create mode 100644 src/OpenStack/Networking/v2/Subnet.cs create mode 100644 src/OpenStack/Networking/v2/SubnetCreateDefinition.cs create mode 100644 src/OpenStack/Networking/v2/SubnetUpdateDefinition.cs create mode 100644 src/OpenStack/Networking/v2/TrafficDirection.cs create mode 100644 src/OpenStack/OpenStack.csproj create mode 100644 src/OpenStack/OpenStackNet.cs create mode 100644 src/OpenStack/Page.cs create mode 100644 src/OpenStack/PageExtensions.cs create mode 100644 src/OpenStack/PageOptions.cs create mode 100644 src/OpenStack/Providers/Hp/HpIdentityProvider.cs create mode 100644 src/OpenStack/Providers/Hp/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Hp/PredefinedHpIdentityEndpoints.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudAutoScaleProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudBlockStorageProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudDatabasesProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudDnsProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudFilesMetadataProcessor.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudFilesProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudIdentityProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudLoadBalancerProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudMonitoringProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudNetworksProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudQueuesProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/CloudServersProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/Exceptions/BulkDeletionException.cs create mode 100644 src/OpenStack/Providers/Rackspace/Exceptions/InvalidETagException.cs create mode 100644 src/OpenStack/Providers/Rackspace/Exceptions/InvalidVolumeSizeException.cs create mode 100644 src/OpenStack/Providers/Rackspace/Exceptions/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/ExtendedJsonRestServices.cs create mode 100644 src/OpenStack/Providers/Rackspace/IAutoScaleService.cs create mode 100644 src/OpenStack/Providers/Rackspace/IDatabaseService.cs create mode 100644 src/OpenStack/Providers/Rackspace/IDnsService.cs create mode 100644 src/OpenStack/Providers/Rackspace/IExtendedCloudIdentityProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/ILoadBalancerService.cs create mode 100644 src/OpenStack/Providers/Rackspace/IMonitoringService.cs create mode 100644 src/OpenStack/Providers/Rackspace/IProviderFactory`2.cs create mode 100644 src/OpenStack/Providers/Rackspace/IRackspaceProvider.cs create mode 100644 src/OpenStack/Providers/Rackspace/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/ArchiveFormat.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AuthDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ActiveServer.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/GenericLaunchConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/GroupConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/GroupState.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchConfiguration`1.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/LoadBalancerArgument.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/NewWebhookConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/Policy.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroup.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupConfiguration`1.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerArgument.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerLaunchArguments.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerLaunchConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerNetworkArgument.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/UpdateWebhookConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/Webhook.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/WebhookConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/AutoScale/WebhookId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/BulkDeletionFailedObject.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/BulkDeletionResults.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Credentials.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/Backup.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/BackupConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/BackupId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/BackupStatus.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/Database.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseFlavor.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstance.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceStatus.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseName.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseUser.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseVolumeConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/FlavorId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/FlavorRef.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/RestorePoint.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/RootUser.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/UpdateUserConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/UserConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Databases/UserName.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsChange.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomain.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainChange.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainChanges.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainRecordConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainRecordUpdateConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainUpdateConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomains.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJob.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJobStatus.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJob`1.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsNameserver.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimit.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimitPattern.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimitUnit.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimits.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecord.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecordType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecordsList.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsServiceLimits.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomain.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomainConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomainsList.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DnsUpdateConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/DomainId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/ExportedDomain.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/JobId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/LimitType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/RecordId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/SerializedDomain.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Dns/SerializedDomainFormat.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Domain.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/AccessType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/ConnectionHealthMonitor.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/ConnectionThrottles.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/CustomHealthMonitor.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/HealthMonitor.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/HealthMonitorType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancer.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerCluster.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration`1.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerEnabledFlag.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerMetadataItem.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerSslConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerStatistics.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerStatus.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerTimestamp.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUpdate.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUsage.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUsageId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerVirtualAddress.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerVirtualAddressType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancingAlgorithm.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancingProtocol.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/MetadataId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NetworkItem.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NetworkItemId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Node.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeCondition.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEvent.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventCategory.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventSeverity.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeStatus.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeUpdate.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/AddLoadBalancerMetadataRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/AddNodesRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/CreateAccessListRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/CreateLoadBalancerRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerConnectionLoggingRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerContentCachingRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerErrorPageRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerMetadataItemRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerNodeRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetAccessListResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerConnectionLoggingResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerContentCachingResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerErrorPageResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerMetadataItemResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerNodeResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerSslConfigurationResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListAllowedDomainsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerMetadataResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerNodesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerThrottlesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerUsageResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancersResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancingAlgorithmsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancingProtocolsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListNodeServiceEventsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListVirtualAddressesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/SessionPersistence.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/SessionPersistenceType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/VirtualAddressId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/WebServerHealthMonitor.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Mapping/BulkDeletionResultMapper.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Mapping/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AccountConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/Agent.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentConnection.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentConnectionId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentToken.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentTokenConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentTokenId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/Alarm.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmChangelog.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmChangelogId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmData.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExample.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExampleField.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExampleId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmNotificationHistoryItem.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmNotificationHistoryItemId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmState.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmStateHistory.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/Audit.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/AuditId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/BoundAlarmExample.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/Check.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckData.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckMetricType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTarget.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTargetId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTypeId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTypeType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/ConnectionCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CpuCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/CpuInformation.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPoint.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPointGranularity.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPointStatistic.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/DateTimeOffsetExtensions.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/DiskCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/DiskInformation.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/DnsCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/EmailNotificationDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/Entity.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityOverview.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/FilesystemCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/FilesystemInformation.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/FtpBannerCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/GenericCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/GenericNotificationDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/HostInformationType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/HostInformation`1.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/HttpCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/ImapBannerCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/LoadAverageCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/LoginInformation.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MemoryCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MemoryInformation.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/Metric.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MetricName.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringAccount.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringAccountId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringLimits.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringZone.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringZoneId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MssqlBannerCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/MysqlBannerCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NetworkCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NetworkInterfaceInformation.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewAlarmConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewCheckConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewEntityConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewNotificationConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewNotificationPlanConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/Notification.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationAttempt.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationData.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlan.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlanConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlanId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationResult.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationTypeField.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationTypeId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/PagerDutyNotificationDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/PingCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/PluginCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/Pop3CheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/PostgresqlBannerCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/ProcessInformation.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/ReadOnlyCollectionPage`2.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/SecureConnectionCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/SmtpBannerCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/SmtpCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/SshCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/SystemInformation.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/TargetResolverType.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/TcpCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/TelnetBannerCheckDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/TestAlarmConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRoute.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRouteConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRouteHop.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/TransactionId.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateAlarmConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateCheckConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateEntityConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateNotificationConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateNotificationPlanConfiguration.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/WebhookNotificationDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Monitoring/WebhookToken.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Queues/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Queues/Request/ClaimMessagesRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Queues/Request/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Queues/Response/ListCloudQueueMessagesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Queues/Response/ListCloudQueuesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Queues/Response/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/RackspaceCloudIdentity.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/AddRoleRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/AddServiceCatalogEndpointRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/AddUserRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/AttachServerVolumeRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/AuthRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/ChangeServerAdminPasswordRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/ConfirmServerResizeRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageSnapshotDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageSnapshotRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageVolumeDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageVolumeRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudNetworkRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudNetworksDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerImageDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerImageRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/CreateVirtualInterfaceRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/PasswordCredential.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/Personality.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/RescueServerRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/RevertServerResizeRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebootDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebootRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebuildDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebuildRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/ServerResizeDetails.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/ServerResizeRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/SetPasswordRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/UnrescueServerRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/UpdateMetadataItemRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/UpdateMetadataRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/UpdateServerRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/UpdateUserCredentialRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Request/UpdateUserRequest.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/AuthenticationResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/BulkDeleteResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/CloudNetworkResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/CreateServerResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ExtractArchiveError.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ExtractArchiveResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/FlavorDetailsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageSnapshotResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageVolumeResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageVolumeTypeResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/GetEndpointResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/GetImageDetailsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListAddressesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListCloudNetworksResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListEndpointsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListFlavorDetailsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListFlavorsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListImagesDetailsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListImagesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListServersResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListSnapshotResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListVirtualInterfacesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListVolumeResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ListVolumeTypeResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/MetaDataResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/MetadataItemResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/NewUserResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/PasswordCredentialResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/RescueServerResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/RoleResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/RolesResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ServerDetailsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ServerVolumeListResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/ServerVolumeResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/TenantsResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/UserCredentialResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/UserImpersonationResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/UserResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/Objects/Response/UsersResponse.cs create mode 100644 src/OpenStack/Providers/Rackspace/ProviderBase`1.cs create mode 100644 src/OpenStack/Providers/Rackspace/RackspaceImpersonationIdentity.cs create mode 100644 src/OpenStack/Providers/Rackspace/Validators/CloudBlockStorageValidator.cs create mode 100644 src/OpenStack/Providers/Rackspace/Validators/CloudFilesValidator.cs create mode 100644 src/OpenStack/Providers/Rackspace/Validators/CloudNetworksValidator.cs create mode 100644 src/OpenStack/Providers/Rackspace/Validators/HttpResponseCodeValidator.cs create mode 100644 src/OpenStack/Providers/Rackspace/Validators/NamespaceDoc.cs create mode 100644 src/OpenStack/Providers/Rackspace/WebRequestEventArgs.cs create mode 100644 src/OpenStack/Providers/Rackspace/WebResponseEventArgs.cs create mode 100644 src/OpenStack/Serialization/DefaultJsonConverter.cs create mode 100644 src/OpenStack/Serialization/IHaveExtraData.cs create mode 100644 src/OpenStack/Serialization/IPageBuilder.cs create mode 100644 src/OpenStack/Serialization/IPageLink.cs create mode 100644 src/OpenStack/Serialization/IQueryStringBuilder.cs create mode 100644 src/OpenStack/Serialization/IServiceResource.cs create mode 100644 src/OpenStack/Serialization/IdentifierConverter.cs create mode 100644 src/OpenStack/Serialization/JsonConverterWithConstructorAttribute.cs create mode 100644 src/OpenStack/Serialization/OpenStackContractResolver.cs create mode 100644 src/OpenStack/Serialization/Page.cs create mode 100644 src/OpenStack/Serialization/PageLink.cs create mode 100644 src/OpenStack/Serialization/ResourceCollection.cs create mode 100644 src/OpenStack/Serialization/ResourceStatus.cs create mode 100644 src/OpenStack/Serialization/RootWrapperConverter.cs create mode 100644 src/OpenStack/Serialization/ServiceEndpoint.cs create mode 100644 src/OpenStack/Serialization/StringEnumeration.cs create mode 100644 src/OpenStack/Serialization/StringEnumerationConverter.cs create mode 100644 src/OpenStack/Serialization/TimeSpanInSecondsConverter.cs create mode 100644 src/OpenStack/Serialization/TolerantEnumConverter.cs create mode 100644 src/OpenStack/Testing/HttpTest.cs create mode 100644 src/OpenStack/Testing/NamespaceDoc.cs delete mode 100644 src/corelib/OpenStack.csproj diff --git a/.gitignore b/.gitignore index a4f6e5283..6eb900ded 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.DS_Store #Visual Studio files +.vs/ *.[Oo]bj *.user *.aps diff --git a/src/OpenStack/Authentication/AuthenticatedHttpClientFactory.cs b/src/OpenStack/Authentication/AuthenticatedHttpClientFactory.cs new file mode 100644 index 000000000..da27f2aab --- /dev/null +++ b/src/OpenStack/Authentication/AuthenticatedHttpClientFactory.cs @@ -0,0 +1,29 @@ +using System.Net.Http; +using Flurl; +using Flurl.Http; +using Flurl.Http.Configuration; + +namespace OpenStack.Authentication +{ + /// + /// Instructs Flurl to use an for all requests. + /// + /// + public class AuthenticatedHttpClientFactory : DefaultHttpClientFactory + { + /// + public override HttpClient CreateClient(Url url, HttpMessageHandler handler) + { + return new HttpClient(handler) + { + Timeout = FlurlHttp.GlobalSettings.DefaultTimeout + }; + } + + /// + public override HttpMessageHandler CreateMessageHandler() + { + return new AuthenticatedMessageHandler(base.CreateMessageHandler()); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Authentication/AuthenticatedMessageHandler.cs b/src/OpenStack/Authentication/AuthenticatedMessageHandler.cs new file mode 100644 index 000000000..3d75dc6bd --- /dev/null +++ b/src/OpenStack/Authentication/AuthenticatedMessageHandler.cs @@ -0,0 +1,47 @@ +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Flurl.Http; +using Flurl.Http.Configuration; + +namespace OpenStack.Authentication +{ + /// + /// Used by Flurl for all requests. Understands how to authenticate and retry when a token expires. + /// + /// + internal class AuthenticatedMessageHandler : FlurlMessageHandler + { + public AuthenticatedMessageHandler(HttpMessageHandler innerHandler) + : base(innerHandler) + { } + + public IAuthenticationProvider AuthenticationProvider; + + protected async override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if(AuthenticationProvider == null) + return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); + + string token = await AuthenticationProvider.GetToken(cancellationToken).ConfigureAwait(false); + request.Headers.SetAuthToken(token); + + try + { + return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); + } + catch (FlurlHttpException ex) + { + if (ex.Call.HttpStatus != HttpStatusCode.Unauthorized) + throw; + } + + // Retry with a new token + var retryRequest = request.Copy(); + var retryToken = await AuthenticationProvider.GetToken(cancellationToken).ConfigureAwait(false); + retryRequest.Headers.SetAuthToken(retryToken); + return await base.SendAsync(retryRequest, cancellationToken).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Authentication/IAuthenticationProvider.cs b/src/OpenStack/Authentication/IAuthenticationProvider.cs new file mode 100644 index 000000000..02dd94b9d --- /dev/null +++ b/src/OpenStack/Authentication/IAuthenticationProvider.cs @@ -0,0 +1,37 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace OpenStack.Authentication +{ + /// + /// Provides authentication functionality to any service implementations. + /// + public interface IAuthenticationProvider + { + /// + /// Gets the endpoints for the specified service. + /// + /// Uses a region specific endpoint if available, otherwise returns the global endpoint. + /// + /// + /// Type of the service. + /// The region. + /// if set to true [use internal URL]. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The user does not have access to the service or it does not exist. + /// or + /// The user does not have access to the service endpoint in the specified region. + /// + /// No region was specified and the {0} service does not provide a region-independent endpoint. + /// The requested endpoint. + Task GetEndpoint(IServiceType serviceType, string region, bool useInternalUrl, CancellationToken cancellationToken); + + /// + /// Gets an authentication token for the user. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// An authentication token. + Task GetToken(CancellationToken cancellationToken); + } +} diff --git a/src/OpenStack/Authentication/NamespaceDoc.cs b/src/OpenStack/Authentication/NamespaceDoc.cs new file mode 100644 index 000000000..fb3bfe6f8 --- /dev/null +++ b/src/OpenStack/Authentication/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace OpenStack.Authentication +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines provider-independent + /// interfaces and implementations related to authentication. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Authentication/ServiceType.cs b/src/OpenStack/Authentication/ServiceType.cs new file mode 100644 index 000000000..6862a822a --- /dev/null +++ b/src/OpenStack/Authentication/ServiceType.cs @@ -0,0 +1,99 @@ +using System; + +namespace OpenStack.Authentication +{ + /// + /// + public class ServiceType : IServiceType + { + /// + /// Initializes a new instance of the class. + /// + /// The value of "type" found in the service catalog. + protected ServiceType(string type) + { + Type = type; + } + + /// + public string Type { get; private set; } + + #region Equality + + /// + /// Determines if this instance is equal to the specified instance. + /// + /// The other instance to which this instance should be compared. + /// If the two instances are equal. + protected bool Equals(ServiceType other) + { + return string.Equals(Type, other.Type, StringComparison.OrdinalIgnoreCase); + } + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + var other = obj as ServiceType; + return other != null && Equals(other); + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + return Type.GetHashCode(); + } + + /// + public static bool operator ==(ServiceType left, ServiceType right) + { + return Equals(left, right); + } + + /// + public static bool operator !=(ServiceType left, ServiceType right) + { + return !Equals(left, right); + } + + #endregion + + /// + /// The Compute service + /// + public static readonly ServiceType Compute = new ServiceType("compute"); + + /// + /// The Content Delivery Network (CDN) service + /// + public static readonly ServiceType ContentDeliveryNetwork = new ServiceType("cdn"); + + /// + /// The Networking service + /// + public static readonly ServiceType Networking = new ServiceType("network"); + } + + /// + /// Provides identifying information to select the appropriate service from the catalog. + /// + public interface IServiceType + { + /// + /// The type used to identity the service in the service catalog. + /// + string Type { get; } + } +} diff --git a/src/OpenStack/BlockStorage/v2/Serialization/SnapshotStatus.cs b/src/OpenStack/BlockStorage/v2/Serialization/SnapshotStatus.cs new file mode 100644 index 000000000..9f04de9b3 --- /dev/null +++ b/src/OpenStack/BlockStorage/v2/Serialization/SnapshotStatus.cs @@ -0,0 +1,37 @@ +using OpenStack.Serialization; + +namespace OpenStack.BlockStorage.v2.Serialization +{ + /// + /// Volume snapshot status. + /// + /// + public class SnapshotStatus : ResourceStatus + where T : SnapshotStatus, new() + { + /// + /// The snapshot is being created. + /// + public static readonly T Creating = new T {DisplayName = "creating"}; + + /// + /// The snapshot is ready to use. + /// + public static readonly T Available = new T {DisplayName = "available"}; + + /// + /// The snapshot is being deleted. + /// + public static readonly T Deleting = new T {DisplayName = "deleting"}; + + /// + /// A snapshot creation error occurred. + /// + public static readonly T Error = new T {DisplayName = "error", IsError = true}; + + /// + /// A snapshot deletion error occurred. + /// + public static readonly T ErrorDeleting = new T {DisplayName = "error_deleting", IsError = true}; + } +} diff --git a/src/OpenStack/BlockStorage/v2/Serialization/VolumeStatus.cs b/src/OpenStack/BlockStorage/v2/Serialization/VolumeStatus.cs new file mode 100644 index 000000000..014c56769 --- /dev/null +++ b/src/OpenStack/BlockStorage/v2/Serialization/VolumeStatus.cs @@ -0,0 +1,67 @@ +using OpenStack.Serialization; + +namespace OpenStack.BlockStorage.v2.Serialization +{ + /// + /// Volume status. + /// + /// + public class VolumeStatus : ResourceStatus + where T : VolumeStatus, new() + { + /// + /// The volume is being created. + /// + public static readonly T Creating = new T {DisplayName = "creating"}; + + /// + /// The volume is ready to attach to an instance. + /// + public static readonly T Available = new T {DisplayName = "available"}; + + /// + /// The volume is attaching to an instance. + /// + public static readonly T Attaching = new T {DisplayName = "attaching"}; + + /// + /// The volume is attached to an instance. + /// + public static readonly T InUse = new T {DisplayName = "in-use"}; + + /// + /// The volume is being deleted. + /// + public static readonly T Deleting = new T {DisplayName = "deleting"}; + + /// + /// A volume creation error occurred. + /// + public static readonly T Error = new T {DisplayName = "error", IsError = true}; + + /// + /// A volume deletion error occurred. + /// + public static readonly T ErrorDeleting = new T {DisplayName = "error_deleting", IsError = true}; + + /// + /// A backup restoration error occurred. + /// + public static readonly T ErrorRestoring = new T {DisplayName = "error_restoring", IsError = true}; + + /// + /// An error occurred while attempting to extend a volume. + /// + public static readonly T ErrorExtending = new T {DisplayName = "error_extending", IsError = true}; + + /// + /// The volume is being backed up. + /// + public static readonly T BackingUp = new T {DisplayName = "backing-up"}; + + /// + /// A backup is being restored to the volume. + /// + public static readonly T RestoringBackup = new T {DisplayName = "restoring-backup"}; + } +} diff --git a/src/OpenStack/BlockStorage/v2/SnapshotStatus.cs b/src/OpenStack/BlockStorage/v2/SnapshotStatus.cs new file mode 100644 index 000000000..04cd118c7 --- /dev/null +++ b/src/OpenStack/BlockStorage/v2/SnapshotStatus.cs @@ -0,0 +1,7 @@ +namespace OpenStack.BlockStorage.v2 +{ + /// + public class SnapshotStatus : Serialization.SnapshotStatus + { + } +} diff --git a/src/OpenStack/BlockStorage/v2/VolumeStatus.cs b/src/OpenStack/BlockStorage/v2/VolumeStatus.cs new file mode 100644 index 000000000..a71f4a8ed --- /dev/null +++ b/src/OpenStack/BlockStorage/v2/VolumeStatus.cs @@ -0,0 +1,7 @@ +namespace OpenStack.BlockStorage.v2 +{ + /// + public class VolumeStatus : Serialization.VolumeStatus + { + } +} diff --git a/src/OpenStack/Compute/ComputeOperationFailedException.cs b/src/OpenStack/Compute/ComputeOperationFailedException.cs new file mode 100644 index 000000000..d0f353b72 --- /dev/null +++ b/src/OpenStack/Compute/ComputeOperationFailedException.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json; + +namespace OpenStack.Compute +{ + /// + /// The exception that is thrown when a Compute service operation (Create, Delete, Update) fails. + /// + /// + [Serializable] + public sealed class ComputeOperationFailedException : Exception + { + /// + public ComputeOperationFailedException() + { } + + /// + public ComputeOperationFailedException(string message) + : base(message) + { } + + /// + private ComputeOperationFailedException(SerializationInfo info, StreamingContext context) : base(info, context) + { } + } +} diff --git a/src/OpenStack/Compute/NamespaceDoc.cs b/src/OpenStack/Compute/NamespaceDoc.cs new file mode 100644 index 000000000..5db825a6b --- /dev/null +++ b/src/OpenStack/Compute/NamespaceDoc.cs @@ -0,0 +1,17 @@ +namespace OpenStack.Compute +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace contains the supported versions of + /// the Compute (Nova) OpenStack API. + /// + /// See the Nova API History for each version's release notes. + /// + /// + /// Nova API History + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Compute/v2_1/Actions/AssociateFloatingIPRequest.cs b/src/OpenStack/Compute/v2_1/Actions/AssociateFloatingIPRequest.cs new file mode 100644 index 000000000..470778ffa --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Actions/AssociateFloatingIPRequest.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Associates a floating IP address to a server. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "addFloatingIp")] + public class AssociateFloatingIPRequest + { + /// + /// Initializes a new instance of the class. + /// + /// The floating ip address. + public AssociateFloatingIPRequest(string floatingIPAddress) + { + FloatingIPAddress = floatingIPAddress; + } + + /// + /// The floating IP address. + /// + [JsonProperty("address")] + public string FloatingIPAddress { get; set; } + + /// + /// The fixed IP address with which you want to associate the floating IP address. + /// + [JsonProperty("fixed_address")] + public string FixedIPAddress { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Actions/RebootServerRequest.cs b/src/OpenStack/Compute/v2_1/Actions/RebootServerRequest.cs new file mode 100644 index 000000000..70e660767 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Actions/RebootServerRequest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Reboots a server. + /// + [JsonConverterWithConstructor(typeof (RootWrapperConverter), "reboot")] + public class RebootServerRequest + { + /// + /// The type of reboot to perform. The default, if unspecified, is a soft reboot. + /// + [JsonProperty("type")] + public RebootType Type { get; set; } = RebootType.Soft; + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Actions/RebootType.cs b/src/OpenStack/Compute/v2_1/Actions/RebootType.cs new file mode 100644 index 000000000..31f3f9bb4 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Actions/RebootType.cs @@ -0,0 +1,8 @@ +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + public class RebootType : RebootType + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Actions/RescueServerRequest.cs b/src/OpenStack/Compute/v2_1/Actions/RescueServerRequest.cs new file mode 100644 index 000000000..e0ed6f778 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Actions/RescueServerRequest.cs @@ -0,0 +1,24 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Puts a server in rescue mode and changes its status to RESCUE. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "rescue")] + public class RescueServerRequest + { + /// + /// The password for the rescued instance. If you omit this parameter, the operation generates a new password. + /// + [JsonProperty("adminPass")] + public string AdminPassword { get; set; } + + /// + /// The image identifier to use to rescue your server instance. + /// + [JsonProperty("rescue_image_ref")] + public Identifier ImageId { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Actions/SnapshotServerRequest.cs b/src/OpenStack/Compute/v2_1/Actions/SnapshotServerRequest.cs new file mode 100644 index 000000000..656f2164a --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Actions/SnapshotServerRequest.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Snapshots a server. + /// + [JsonConverterWithConstructor(typeof (RootWrapperConverter), "createImage")] + public class SnapshotServerRequest + { + /// + /// Initializes a new instance of the class. + /// + /// The snapshot name. + public SnapshotServerRequest(string name) + { + Name = name; + Metadata = new Dictionary(); + } + + /// + /// The snapshot name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Additional snapshot image metadata. + /// + [JsonProperty("metadata")] + public IDictionary Metadata { get; set; } + } +} diff --git a/src/OpenStack/Compute/v2_1/AddressType.cs b/src/OpenStack/Compute/v2_1/AddressType.cs new file mode 100644 index 000000000..9cccddd58 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/AddressType.cs @@ -0,0 +1,8 @@ +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + public class AddressType : AddressType + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ComputeService.cs b/src/OpenStack/Compute/v2_1/ComputeService.cs new file mode 100644 index 000000000..6173aac61 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ComputeService.cs @@ -0,0 +1,536 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using OpenStack.Authentication; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Images.v2; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// The OpenStack Compute Service. + /// + /// OpenStack Compute API v2.1 Overview + public class ComputeService + { + /// + internal readonly ComputeApi _computeApi; + + /// + /// Initializes a new instance of the class. + /// + /// The authentication provider. + /// The region. + /// if set to true uses the internal URLs specified in the ServiceCatalog, otherwise the public URLs are used. + public ComputeService(IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl = false) + { + _computeApi = new ComputeApi(ServiceType.Compute, authenticationProvider, region, useInternalUrl); + } + + #region Servers + + /// + public Task GetServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetServerAsync(serverId, cancellationToken); + } + + /// + public Task GetServerMetadataAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetServerMetadataAsync(serverId, cancellationToken); + } + + /// + public Task GetServerMetadataItemAsync(Identifier serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetServerMetadataItemAsync(serverId, key, cancellationToken); + } + + /// + public Task CreateServerAsync(ServerCreateDefinition server, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateServerAsync(server, cancellationToken); + } + + /// + public Task CreateServerMetadataAsync(Identifier serverId, string key, string value, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateServerMetadataAsync(serverId, key, value, cancellationToken); + } + + /// + public Task WaitForServerStatusAsync(Identifier serverId, ServerStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.WaitForServerStatusAsync(serverId, status, refreshDelay, timeout, progress, cancellationToken); + } + + /// + public Task WaitForServerStatusAsync(Identifier serverId, IEnumerable statuses, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.WaitForServerStatusAsync(serverId, statuses, refreshDelay, timeout, progress, cancellationToken); + } + + /// + public async Task> ListServerSummariesAsync(ServerListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListServerSummariesAsync(options, cancellationToken).ConfigureAwait(false); + } + + /// + public async Task> ListServersAsync(ServerListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListServersAsync(options, cancellationToken).ConfigureAwait(false); + } + + /// + public Task UpdateServerAsync(Identifier serverid, ServerUpdateDefinition server, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.UpdateServerAsync(serverid, server, cancellationToken); + } + + /// + public Task UpdateServerMetadataAsync(Identifier serverId, ServerMetadata metadata, bool overwrite = false, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.UpdateServerMetadataAsync(serverId, metadata, overwrite, cancellationToken); + } + + /// + public Task DeleteServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteServerAsync(serverId, cancellationToken); + } + + /// + public Task DeleteServerMetadataAsync(Identifier serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteServerMetadataAsync(serverId, key, cancellationToken); + } + + /// + public Task WaitUntilServerIsDeletedAsync(Identifier serverId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.WaitUntilServerIsDeletedAsync(serverId, null, refreshDelay, timeout, progress, cancellationToken); + } + + /// + public Task SnapshotServerAsync(Identifier serverId, SnapshotServerRequest request, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.SnapshotServerAsync(serverId, request, cancellationToken); + } + + /// + public Task StartServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.StartServerAsync(serverId, cancellationToken); + } + + /// + public Task StopServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.StopServerAsync(serverId, cancellationToken); + } + + /// + public Task SuspendServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.SuspendServerAsync(serverId, cancellationToken); + } + + /// + public Task ResumeServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.ResumeServerAsync(serverId, cancellationToken); + } + + /// + public Task RebootServerAsync(Identifier serverId, RebootServerRequest request = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.RebootServerAsync(serverId, request, cancellationToken); + } + + /// + public virtual Task GetVncConsoleAync(Identifier serverId, RemoteConsoleType type, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetVncConsoleAsync(serverId, type, cancellationToken); + } + + /// + public virtual Task GetSpiceConsoleAync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetSpiceConsoleAsync(serverId, RemoteConsoleType.SpiceHtml5, cancellationToken); + } + + /// + public virtual Task GetSerialConsoleAync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetSerialConsoleAsync(serverId, RemoteConsoleType.Serial, cancellationToken); + } + + /// + public virtual Task GetRdpConsoleAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetRdpConsoleAsync(serverId, RemoteConsoleType.RdpHtml5, cancellationToken); + } + + /// + public virtual Task GetConsoleOutputAsync(Identifier serverId, int length = -1, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetConsoleOutputAsync(serverId, length, cancellationToken); + } + + /// + public virtual Task RescueServerAsync(Identifier serverId, RescueServerRequest request = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.RescueServerAsync(serverId, request, cancellationToken); + } + + /// + public virtual Task UnrescueServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.UnrescueServerAsync(serverId, cancellationToken); + } + + /// + public virtual Task ResizeServerAsync(Identifier serverId, Identifier flavorId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.ResizeServerAsync(serverId, flavorId, cancellationToken); + } + + /// + public virtual Task ConfirmResizeServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.ConfirmResizeServerAsync(serverId, cancellationToken); + } + + /// + public virtual Task CancelResizeServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CancelResizeServerAsync(serverId, cancellationToken); + } + + /// + public virtual Task AssociateFloatingIPAddressAsync(Identifier serverId, AssociateFloatingIPRequest request, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.AssociateFloatingIPAsync(serverId, request, cancellationToken); + } + + /// + public virtual Task DisassociateFloatingIPAsync(Identifier serverId, string floatingIPAddress, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DisassociateFloatingIPAsync(serverId, floatingIPAddress, cancellationToken); + } + + /// + public virtual async Task> ListServerActionSummariesAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListServerActionSummariesAsync(serverId, cancellationToken).ConfigureAwait(false); + } + + /// + public virtual Task GetServerActionAsync(Identifier serverId, Identifier actionId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetServerActionAsync(serverId, actionId, cancellationToken); + } + #endregion + + #region Flavors + + /// + public Task GetFlavorAsync(Identifier flavorId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetFlavorAsync(flavorId, cancellationToken); + } + + /// + public async Task> ListFlavorSummariesAsync(FlavorListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListFlavorSummariesAsync(options, cancellationToken).ConfigureAwait(false); + } + + /// + public async Task> ListFlavorsAsync(FlavorListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListFlavorsAsync(options, cancellationToken).ConfigureAwait(false); + } + + #endregion + + #region Images + + /// + public Task GetImageAsync(Identifier imageId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetImageAsync(imageId, cancellationToken); + } + + /// + public Task GetImageMetadataAsync(Identifier imageId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetImageMetadataAsync(imageId, cancellationToken); + } + + /// + public Task GetImageMetadataItemAsync(Identifier imageId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetImageMetadataItemAsync(imageId, key, cancellationToken); + } + + /// + public Task WaitForImageStatusAsync(Identifier imageId, ImageStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.WaitForImageStatusAsync(imageId, status, refreshDelay, timeout, progress, cancellationToken); + } + + /// + public Task CreateImageMetadataAsync(Identifier imageId, string key, string value, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateImageMetadataAsync(imageId, key, value, cancellationToken); + } + + /// + public async Task> ListImageSummariesAsync(ImageListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListImageSummariesAsync(options, cancellationToken).ConfigureAwait(false); + } + + /// + public async Task> ListImagesAsync(ImageListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListImagesAsync(options, cancellationToken).ConfigureAwait(false); + } + + /// + public Task UpdateImageMetadataAsync(Identifier imageId, ImageMetadata metadata, bool overwrite = false, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.UpdateImageMetadataAsync(imageId, metadata, overwrite, cancellationToken); + } + + /// + public Task DeleteImageAsync(Identifier imageId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteImageAsync(imageId, cancellationToken); + } + + /// + public Task DeleteImageMetadataAsync(Identifier imageId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteImageMetadataAsync(imageId, key, cancellationToken); + } + + /// + public Task WaitUntilImageIsDeletedAsync(Identifier imageId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.WaitUntilImageIsDeletedAsync(imageId, null, refreshDelay, timeout, progress, cancellationToken); + } + #endregion + + #region IP Addresses + + /// + public Task> GetServerAddressAsync(Identifier serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetServerAddressAsync(serverId, key, cancellationToken); + } + + /// + public async Task>> ListServerAddressesAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListServerAddressesAsync(serverId, cancellationToken).ConfigureAwait(false); + } + + #endregion + + #region Server Volumes + /// + public Task GetServerVolumeAsync(Identifier serverId, Identifier volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetServerVolumeAsync(serverId, volumeId, cancellationToken); + } + + /// + public async Task> ListServerVolumesAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListServerVolumesAsync(serverId, cancellationToken).ConfigureAwait(false); + } + + /// + public Task AttachVolumeAsync(Identifier serverId, ServerVolumeDefinition volume, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.AttachVolumeAsync(serverId, volume, cancellationToken); + } + + /// + public Task DetachVolumeAsync(Identifier serverId, Identifier volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DetachVolumeAsync(serverId, volumeId, cancellationToken); + } + #endregion + + #region Keypairs + + /// + public virtual Task GetKeyPairAsync(string keypairName, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetKeyPairAsync(keypairName, cancellationToken); + } + + /// + /// Creates a new key pair. + /// + /// The key pair request. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// The response includes the generated private key. + public virtual Task CreateKeyPairAsync(KeyPairRequest request, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateKeyPairAsync(request, cancellationToken); + } + + /// + /// Imports a key pair. + /// + /// The keypair. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task ImportKeyPairAsync(KeyPairDefinition keypair, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateKeyPairAsync(keypair, cancellationToken); + } + + /// + public virtual async Task> ListKeyPairsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListKeyPairsAsync(cancellationToken).ConfigureAwait(false); + } + + /// + public virtual Task DeleteKeyPairAsync(string keypairName, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteKeyPairAsync(keypairName, cancellationToken); + } + #endregion + + #region Security Groups + + /// + public Task GetSecurityGroupAsync(Identifier securityGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetSecurityGroupAsync(securityGroupId, cancellationToken); + } + + /// + public Task CreateSecurityGroupAsync(SecurityGroupDefinition securityGroup, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateSecurityGroupAsync(securityGroup, cancellationToken); + } + + /// + public async Task> ListSecurityGroupsAsync(Identifier serverId = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListSecurityGroupsAsync(serverId, cancellationToken).ConfigureAwait(false); + } + + /// + public Task UpdateSecurityGroupAsync(Identifier securityGroupId, SecurityGroupDefinition securityGroup, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.UpdateSecurityGroupAsync(securityGroupId, securityGroup, cancellationToken); + } + + /// + public Task DeleteSecurityGroupAsync(Identifier securityGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteSecurityGroupAsync(securityGroupId, cancellationToken); + } + + #endregion + + #region Sever Groups + + /// + public Task GetServerGroupAsync(Identifier serverGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetServerGroupAsync(serverGroupId, cancellationToken); + } + + /// + public Task CreateServerGroupAsync(ServerGroupDefinition serverGroup, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateServerGroupAsync(serverGroup, cancellationToken); + } + + /// + public async Task> ListServerGroupsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListServerGroupsAsync(cancellationToken).ConfigureAwait(false); + } + + /// + public Task DeleteServerGroupAsync(Identifier serverGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteServerGroupAsync(serverGroupId, cancellationToken); + } + + #endregion + + #region Volumes + + /// + public Task GetVolumeAsync(Identifier volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetVolumeAsync(volumeId, cancellationToken); + } + + /// + public Task GetVolumeSnapshotAsync(Identifier snapshotId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetVolumeSnapshotAsync(snapshotId, cancellationToken); + } + + /// + public Task CreateVolumeAsync(VolumeDefinition volume, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateVolumeAsync(volume, cancellationToken); + } + + /// + public Task SnapshotVolumeAsync(VolumeSnapshotDefinition snapshot, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.SnapshotVolumeAsync(snapshot, cancellationToken); + } + + /// + public async Task> ListVolumesAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListVolumesAsync(cancellationToken).ConfigureAwait(false); + } + + /// + public async Task> ListVolumeSnapshotsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListVolumeSnapshotsAsync(cancellationToken).ConfigureAwait(false); + } + + /// + public Task DeleteVolumeAsync(Identifier volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteVolumeAsync(volumeId, cancellationToken); + } + + /// + public Task DeleteVolumeSnapshotAsync(Identifier snapshotId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.DeleteVolumeSnapshotAsync(snapshotId, cancellationToken); + } + + #endregion + + #region Compute Service + /// + public Task GetLimitsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetLimitsAsync(cancellationToken); + } + #endregion + } +} diff --git a/src/OpenStack/Compute/v2_1/ComputeServiceExtensions.cs b/src/OpenStack/Compute/v2_1/ComputeServiceExtensions.cs new file mode 100644 index 000000000..026c9a857 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ComputeServiceExtensions.cs @@ -0,0 +1,500 @@ +using System; +using System.Collections.Generic; +using OpenStack.Compute.v2_1; +using OpenStack.Images.v2; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ComputeServiceExtensions_v2_1 + { + #region Servers + /// + public static Server GetServer(this ComputeService service, Identifier serverId) + { + return service.GetServerAsync(serverId).ForceSynchronous(); + } + + /// + public static ServerMetadata GetServerMetadata(this ComputeService service, Identifier serverId) + { + return service.GetServerMetadataAsync(serverId).ForceSynchronous(); + } + + /// + public static string GetServerMetadataItem(this ComputeService service, Identifier serverId, string key) + { + return service.GetServerMetadataItemAsync(serverId, key).ForceSynchronous(); + } + + /// + public static Server CreateServer(this ComputeService service, ServerCreateDefinition server) + { + return service.CreateServerAsync(server).ForceSynchronous(); + } + + /// + public static void CreateServerMetadata(this ComputeService service, Identifier serverId, string key, string value) + { + service.CreateServerMetadataAsync(serverId, key, value).ForceSynchronous(); + } + + /// + public static Server WaitForServerStatus(this ComputeService service, Identifier serverId, ServerStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + return service.WaitForServerStatusAsync(serverId, status, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static Server WaitForServerStatus(this ComputeService service, Identifier serverId, IEnumerable statuses, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + return service.WaitForServerStatusAsync(serverId, statuses, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static IPage ListServerSummaries(this ComputeService service, ServerListOptions options = null) + { + return service.ListServerSummariesAsync(options).ForceSynchronous(); + } + + /// + public static IPage ListServers(this ComputeService service, ServerListOptions options = null) + { + return service.ListServersAsync(options).ForceSynchronous(); + } + + /// + public static Server UpdateServer(this ComputeService service, Identifier serverid, ServerUpdateDefinition server) + { + return service.UpdateServerAsync(serverid, server).ForceSynchronous(); + } + + /// + public static ServerMetadata UpdateServerMetadata(this ComputeService service, Identifier serverId, ServerMetadata metadata, bool overwrite = false) + { + return service.UpdateServerMetadataAsync(serverId, metadata, overwrite).ForceSynchronous(); + } + + /// + public static void DeleteServer(this ComputeService service, Identifier serverId) + { + service.DeleteServerAsync(serverId).ForceSynchronous(); + } + + /// + public static void DeleteServerMetadata(this ComputeService service, Identifier serverId, string key) + { + service.DeleteServerMetadataAsync(serverId, key).ForceSynchronous(); + } + + /// + public static void WaitUntilServerIsDeleted(this ComputeService service, Identifier serverId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + service.WaitUntilServerIsDeletedAsync(serverId, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static Image SnapshotServer(this ComputeService service, Identifier serverId, SnapshotServerRequest request) + { + return service.SnapshotServerAsync(serverId, request).ForceSynchronous(); + } + + /// + public static void StartServer(this ComputeService service, Identifier serverId) + { + service.StartServerAsync(serverId).ForceSynchronous(); + } + + /// + public static void StopServer(this ComputeService service, Identifier serverId) + { + service.StopServerAsync(serverId).ForceSynchronous(); + } + + /// + public static void RebootServer(this ComputeService service, Identifier serverId, RebootServerRequest request = null) + { + service.RebootServerAsync(serverId, request).ForceSynchronous(); + } + + /// + public static RemoteConsole GetVncConsole(this ComputeService service, Identifier serverId, RemoteConsoleType type) + { + return service.GetVncConsoleAync(serverId, type).ForceSynchronous(); + } + + /// + public static RemoteConsole GetSpiceConsole(this ComputeService service, Identifier serverId) + { + return service.GetSpiceConsoleAync(serverId).ForceSynchronous(); + } + + /// + public static RemoteConsole GetSerialConsole(this ComputeService service, Identifier serverId) + { + return service.GetSerialConsoleAync(serverId).ForceSynchronous(); + } + + /// + public static RemoteConsole GetRdpConsole(this ComputeService service, Identifier serverId) + { + return service.GetRdpConsoleAsync(serverId).ForceSynchronous(); + } + + /// + public static string GetConsoleOutput(this ComputeService service, Identifier serverId, int length = -1) + { + return service.GetConsoleOutputAsync(serverId, length).ForceSynchronous(); + } + + /// + public static string RescueServer(this ComputeService service, Identifier serverId, RescueServerRequest request = null) + { + return service.RescueServerAsync(serverId, request).ForceSynchronous(); + } + + /// + public static void UnrescueServer(this ComputeService service, Identifier serverId) + { + service.UnrescueServerAsync(serverId).ForceSynchronous(); + } + + /// + public static void ResizeServer(this ComputeService service, Identifier serverId, Identifier flavorId) + { + service.ResizeServerAsync(serverId, flavorId).ForceSynchronous(); + } + + /// + public static void ConfirmResizeServer(this ComputeService service, Identifier serverId) + { + service.ConfirmResizeServerAsync(serverId).ForceSynchronous(); + } + + /// + public static void CancelResizeServer(this ComputeService service, Identifier serverId) + { + service.CancelResizeServerAsync(serverId).ForceSynchronous(); + } + + /// + public static void AssociateFloatingIPAddressAsync(this ComputeService service, Identifier serverId, AssociateFloatingIPRequest request) + { + service.AssociateFloatingIPAddressAsync(serverId, request).ForceSynchronous(); + } + + /// + public static void DisassociateFloatingIPAsync(this ComputeService service, Identifier serverId, string floatingIPAddress) + { + service.DisassociateFloatingIPAsync(serverId, floatingIPAddress).ForceSynchronous(); + } + + /// + public static IEnumerable ListServerActions(this ComputeService service, Identifier serverId) + { + return service.ListServerActionSummariesAsync(serverId).ForceSynchronous(); + } + + /// + public static ServerAction GetServerAction(this ComputeService service, Identifier serverId, Identifier actionId) + { + return service.GetServerActionAsync(serverId, actionId).ForceSynchronous(); + } + #endregion + + #region Flavors + /// + public static Flavor GetFlavor(this ComputeService service, Identifier flavorId) + { + return service.GetFlavorAsync(flavorId).ForceSynchronous(); + } + + /// + public static IEnumerable ListFlavorSummaries(this ComputeService service) + { + return service.ListFlavorSummariesAsync().ForceSynchronous(); + } + + /// + public static IEnumerable ListFlavors(this ComputeService service) + { + return service.ListFlavorsAsync().ForceSynchronous(); + } + #endregion + + #region Images + /// + public static Image GetImage(this ComputeService service, Identifier imageId) + { + return service.GetImageAsync(imageId).ForceSynchronous(); + } + + /// + public static ImageMetadata GetImageMetadata(this ComputeService service, Identifier imageId) + { + return service.GetImageMetadataAsync(imageId).ForceSynchronous(); + } + + /// + public static string GetImageMetadataItem(this ComputeService service, Identifier imageId, string key) + { + return service.GetImageMetadataItemAsync(imageId, key).ForceSynchronous(); + } + + /// + public static void WaitForImageStatus(this ComputeService service, Identifier imageId, ImageStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + service.WaitForImageStatusAsync(imageId, status, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void CreateImageMetadata(this ComputeService service, Identifier imageId, string key, string value) + { + service.CreateImageMetadataAsync(imageId, key, value).ForceSynchronous(); + } + + /// + public static IPage ListImageSummaries(this ComputeService service, ImageListOptions options = null) + { + return service.ListImageSummariesAsync(options).ForceSynchronous(); + } + + /// + public static IPage ListImages(this ComputeService service, ImageListOptions options = null) + { + return service.ListImagesAsync(options).ForceSynchronous(); + } + + /// + public static ImageMetadata UpdateImageMetadata(this ComputeService service, Identifier imageId, ImageMetadata metadata, bool overwrite = false) + { + return service.UpdateImageMetadataAsync(imageId, metadata, overwrite).ForceSynchronous(); + } + + /// + public static void DeleteImage(this ComputeService service, Identifier imageId) + { + service.DeleteImageAsync(imageId).ForceSynchronous(); + } + + /// + public static void DeleteImageMetadata(this ComputeService service, Identifier imageId, string key) + { + service.DeleteImageMetadataAsync(imageId, key).ForceSynchronous(); + } + + /// + public static void WaitUntilImageIsDeleted(this ComputeService service, Identifier imageId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + service.WaitUntilImageIsDeletedAsync(imageId, refreshDelay, timeout, progress).ForceSynchronous(); + } + #endregion + + #region IP Addresses + + /// + public static IList GetServerAddress(this ComputeService service, Identifier serverId, string key) + { + return service.GetServerAddressAsync(serverId, key).ForceSynchronous(); + } + + /// + public static IDictionary> ListServerAddresses(this ComputeService service, Identifier serverId) + { + return service.ListServerAddressesAsync(serverId).ForceSynchronous(); + } + + #endregion + + #region Server Volumes + /// + public static ServerVolume GetServerVolume(this ComputeService service, Identifier serverId, Identifier volumeId) + { + return service.GetServerVolumeAsync(serverId, volumeId).ForceSynchronous(); + } + + /// + public static IEnumerable ListServerVolumes(this ComputeService service, Identifier serverId) + { + return service.ListServerVolumesAsync(serverId).ForceSynchronous(); + } + + /// + public static void AttachVolume(this ComputeService service, Identifier serverId, ServerVolumeDefinition volume) + { + service.AttachVolumeAsync(serverId, volume).ForceSynchronous(); + } + + /// + public static void DetachVolume(this ComputeService service, Identifier serverId, Identifier volumeId) + { + service.DetachVolumeAsync(serverId, volumeId).ForceSynchronous(); + } + #endregion + + #region KeyPairs + /// + public static KeyPair GetKeyPair(this ComputeService service, string keypairName) + { + return service.GetKeyPairAsync(keypairName).ForceSynchronous(); + } + + /// + public static KeyPairResponse CreateKeyPair(this ComputeService service, KeyPairRequest request) + { + return service.CreateKeyPairAsync(request).ForceSynchronous(); + } + + /// + public static KeyPairSummary ImportKeyPair(this ComputeService service, KeyPairDefinition keyPair) + { + return service.ImportKeyPairAsync(keyPair).ForceSynchronous(); + } + + /// + public static IEnumerable ListKeyPairs(this ComputeService service) + { + return service.ListKeyPairsAsync().ForceSynchronous(); + } + + /// + public static void DeleteKeyPair(this ComputeService service, string keypairName) + { + service.DeleteKeyPairAsync(keypairName).ForceSynchronous(); + } + + #endregion + + #region Security Groups + + /// + public static SecurityGroup GetSecurityGroup(this ComputeService service, Identifier securityGroupId) + { + return service.GetSecurityGroupAsync(securityGroupId).ForceSynchronous(); + } + + /// + public static SecurityGroup CreateSecurityGroup(this ComputeService service, SecurityGroupDefinition securityGroup) + { + return service.CreateSecurityGroupAsync(securityGroup).ForceSynchronous(); + } + + /// + public static IEnumerable ListSecurityGroups(this ComputeService service, Identifier serverId = null) + { + return service.ListSecurityGroupsAsync(serverId).ForceSynchronous(); + } + + /// + public static SecurityGroup UpdateSecurityGroup(this ComputeService service, Identifier securityGroupid, SecurityGroupDefinition securityGroup) + { + return service.UpdateSecurityGroupAsync(securityGroupid, securityGroup).ForceSynchronous(); + } + + /// + public static void DeleteSecurityGroup(this ComputeService service, Identifier securityGroupId) + { + service.DeleteSecurityGroupAsync(securityGroupId).ForceSynchronous(); + } + + #endregion + + #region Server Groups + + /// + public static ServerGroup GetServerGroup(this ComputeService service, Identifier severGroupId) + { + return service.GetServerGroupAsync(severGroupId).ForceSynchronous(); + } + + /// + public static ServerGroup CreateServerGroup(this ComputeService service, ServerGroupDefinition serverGroup) + { + return service.CreateServerGroupAsync(serverGroup).ForceSynchronous(); + } + + /// + public static IEnumerable ListServerGroups(this ComputeService service) + { + return service.ListServerGroupsAsync().ForceSynchronous(); + } + + /// + public static void DeleteServerGroup(this ComputeService service, Identifier serverGroupId) + { + service.DeleteServerGroupAsync(serverGroupId).ForceSynchronous(); + } + + #endregion + + #region Volumes + + /// + public static Volume GetVolume(this ComputeService service, Identifier volumeId) + { + return service.GetVolumeAsync(volumeId).ForceSynchronous(); + } + + /// + public static VolumeSnapshot GetVolumeSnapshot(this ComputeService service, Identifier snapshotId) + { + return service.GetVolumeSnapshotAsync(snapshotId).ForceSynchronous(); + } + + /// + public static Volume CreateVolume(this ComputeService service, VolumeDefinition volume) + { + return service.CreateVolumeAsync(volume).ForceSynchronous(); + } + + /// + public static VolumeSnapshot SnapshotVolume(this ComputeService service, VolumeSnapshotDefinition snapshot) + { + return service.SnapshotVolumeAsync(snapshot).ForceSynchronous(); + } + + /// + public static IEnumerable ListVolumes(this ComputeService service) + { + return service.ListVolumesAsync().ForceSynchronous(); + } + + ///// + //public static IEnumerable ListVolumeTypes(this ComputeService service) + //{ + // return service.ListVolumeTypesAsync().ForceSynchronous(); + //} + + /// + public static IEnumerable ListVolumeSnapshots(this ComputeService service) + { + return service.ListVolumeSnapshotsAsync().ForceSynchronous(); + } + + /// + public static void DeleteVolume(this ComputeService service, Identifier volumeId) + { + service.DeleteVolumeAsync(volumeId).ForceSynchronous(); + } + + /// + public static void DeleteVolumeSnapshot(this ComputeService service, Identifier snapshotId) + { + service.DeleteVolumeSnapshotAsync(snapshotId).ForceSynchronous(); + } + + #endregion + + #region Compute Service + /// + public static ServiceLimits GetLimits(this ComputeService service) + { + return service.GetLimitsAsync().ForceSynchronous(); + } + #endregion + } +} diff --git a/src/OpenStack/Compute/v2_1/DiskConfiguration.cs b/src/OpenStack/Compute/v2_1/DiskConfiguration.cs new file mode 100644 index 000000000..4885e5440 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/DiskConfiguration.cs @@ -0,0 +1,8 @@ +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + public class DiskConfiguration : DiskConfiguration + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Flavor.cs b/src/OpenStack/Compute/v2_1/Flavor.cs new file mode 100644 index 000000000..a44af3c12 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Flavor.cs @@ -0,0 +1,49 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Represents a resource configuration for a server. + /// Each flavor is a unique combination of disk space, memory capacity, vCPUs, and network bandwidth. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "flavor")] + public class Flavor : FlavorSummary + { + /// + /// The disk size. + /// + [JsonProperty("disk")] + public int DiskSize { get; set; } + + /// + /// The amount of RAM. + /// + [JsonProperty("ram")] + public int MemorySize { get; set; } + + /// + /// The amount of swap space. + /// + [JsonProperty("swap")] + public int? SwapSize { get; set; } + + /// + /// The number of virtual CPUs. + /// + [JsonProperty("vcpus")] + public int VirtualCPUs { get; set; } + + /// + /// The rxtx factor, which describes configured bandwidth cap values. + /// + [JsonProperty("rxtx_factor")] + public double? BandwidthCap { get; set; } + + /// + /// The number of ephemeral disks. + /// + [JsonProperty("OS-FLV-EXT-DATA:ephemeral")] + public int? EphemeralDiskSize { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/FlavorExtensions.cs b/src/OpenStack/Compute/v2_1/FlavorExtensions.cs new file mode 100644 index 000000000..928ff9513 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/FlavorExtensions.cs @@ -0,0 +1,18 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class FlavorExtensions_v2_1 + { + /// + public static Flavor GetFlavor(this FlavorReference flavor) + { + return flavor.GetFlavorAsync().ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/FlavorListOptions.cs b/src/OpenStack/Compute/v2_1/FlavorListOptions.cs new file mode 100644 index 000000000..35abe9f20 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/FlavorListOptions.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Optional filter and paging options when listing flavors. + /// + public class FlavorListOptions : PageOptions + { + /// + /// The minimum disk size provided by the flavor. + /// + public int? MininumDiskSize { get; set; } + + /// + /// The minimum amount of RAM provided by the flavor. + /// + public int? MininumMemorySize { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + var queryString = base.BuildQueryString(); + queryString["minDisk"] = MininumDiskSize; + queryString["minRam"] = MininumMemorySize; + + return queryString; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/FlavorReference.cs b/src/OpenStack/Compute/v2_1/FlavorReference.cs new file mode 100644 index 000000000..6fb56bef1 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/FlavorReference.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Reference to a flavor resource. + /// + public class FlavorReference : IHaveExtraData, IServiceResource + { + /// + /// The flavor identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task GetFlavorAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.GetFlavorAsync(Id, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/FlavorSummary.cs b/src/OpenStack/Compute/v2_1/FlavorSummary.cs new file mode 100644 index 000000000..ccec72d98 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/FlavorSummary.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Summary information for a flavor. + /// + public class FlavorSummary : FlavorReference + { + /// + /// The flavor name. + /// + [JsonProperty("name")] + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/IPProtocol.cs b/src/OpenStack/Compute/v2_1/IPProtocol.cs new file mode 100644 index 000000000..5455a39c7 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/IPProtocol.cs @@ -0,0 +1,8 @@ +namespace OpenStack.Compute.v2_1 +{ + /// + /// Internet Protocols. + /// + public class IPProtocol : Networking.v2.Serialization.IPProtocol + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Image.cs b/src/OpenStack/Compute/v2_1/Image.cs new file mode 100644 index 000000000..c0c2bcee6 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Image.cs @@ -0,0 +1,129 @@ +using System; +using System.Extensions; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Images.v2; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// A collection of files for a specific operating system (OS) that you use to create or rebuild a server. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "image")] + public class Image : ImageSummary + { + /// + /// Initializes a new instance of the class. + /// + public Image() + { + Metadata = new ImageMetadata(); + } + + /// + /// The date and time when the resource was created. + /// + [JsonProperty("created")] + public DateTimeOffset Created { get; set; } + + /// + /// The date and time when the resource was updated. + /// + [JsonProperty("updated")] + public DateTimeOffset Updated { get; set; } + + /// + /// The minimum disk size in GB that is required to boot the image. + /// + [JsonProperty("minDisk")] + public Int64 MinimumDiskSize { get; set; } + + /// + /// The minimum amount of RAM in MB that is required to boot the image. + /// + [JsonProperty("minRam")] + public Int64 MinimumMemorySize { get; set; } + + /// + /// The size of the image data, in bytes. + /// + [JsonProperty("OS-EXT-IMG-SIZE:size")] + public Int64? Size { get; set; } + + /// + /// The build completion progress, as a percentage. + /// + [JsonProperty("progress")] + public int Progress { get; set; } + + /// + /// The image status. + /// + [JsonProperty("status")] + public ImageStatus Status { get; set; } + + /// + /// The associated server. + /// + [JsonProperty("server")] + public ServerReference Server { get; set; } + + /// + /// Metadata key pairs containing information about the image. + /// + [JsonProperty("metadata")] + public ImageMetadata Metadata { get; set; } + + /// + /// Indicates whether the image is built-in (base) or custom (snapshot). + /// + [JsonIgnore] + public ImageType Type + { + get + { + string type; + if (Metadata != null && Metadata.TryGetValue("image_type", out type)) + return StringEnumeration.FromDisplayName(type); + + return ImageType.Base; + } + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task WaitForStatus(ImageStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + var result = await owner.WaitForImageStatusAsync(Id, status, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + /// Wait until the image is active. + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task WaitUntilActiveAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return WaitForStatus(ImageStatus.Active, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public override async Task WaitUntilDeletedAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + await base.WaitUntilDeletedAsync(refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + Status = ImageStatus.Deleted; + } + + [OnDeserialized] + private void OnDeserialized(StreamingContext context) + { + Metadata.SetParent(this); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/ImageExtensions.cs b/src/OpenStack/Compute/v2_1/ImageExtensions.cs new file mode 100644 index 000000000..77332b570 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ImageExtensions.cs @@ -0,0 +1,49 @@ +using System; +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ImageExtensions_v2_1 + { + /// + public static Image GetImage(this ImageReference image) + { + return image.GetImageAsync().ForceSynchronous(); + } + + /// + public static ImageMetadata GetMetadata(this ImageReference image) + { + return image.GetMetadataAsync().ForceSynchronous(); + } + + /// + public static string GetMetadataItem(this ImageReference image, string key) + { + return image.GetMetadataItemAsync(key).ForceSynchronous(); + } + + /// + public static void WaitUntilActive(this Image image, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + image.WaitUntilActiveAsync(refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void Delete(this ImageReference image) + { + image.DeleteAsync().ForceSynchronous(); + } + + /// + public static void WaitUntilDeleted(this ImageReference image, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + image.WaitUntilDeletedAsync(refreshDelay, timeout, progress).ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/ImageListOptions.cs b/src/OpenStack/Compute/v2_1/ImageListOptions.cs new file mode 100644 index 000000000..b1ff1bd31 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ImageListOptions.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Optional filter and paging options when listing images. + /// + public class ImageListOptions : PageOptions + { + /// + /// Filters the list of images to those that have changed since the specified date. + /// + public DateTimeOffset? UpdatedAfter { get; set; } + + /// + /// Filters the list of images by server. + /// + public Identifier ServerId { get; set; } + + /// + /// Filters the list of images by image name. + /// + public string Name { get; set; } + + /// + /// The minimum disk size required to create a server with the image. + /// + public int? MininumDiskSize { get; set; } + + /// + /// The minimum amount of RAM required to create a server with the image. + /// + public int? MininumMemorySize { get; set; } + + /// + /// Filters by base images or custom server images that you have created. + /// + public ImageType Type { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + var queryString = base.BuildQueryString(); + queryString["changes-since"] = UpdatedAfter?.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"); + queryString["server"] = ServerId; + queryString["name"] = Name; + queryString["minDisk"] = MininumDiskSize; + queryString["minRam"] = MininumMemorySize; + queryString["type"] = Type; + + return queryString; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ImageMetadata.cs b/src/OpenStack/Compute/v2_1/ImageMetadata.cs new file mode 100644 index 000000000..f8edf8951 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ImageMetadata.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Metadata key pairs containing information about the image. + /// + [JsonConverterWithConstructor(typeof (RootWrapperConverter), "metadata")] + public class ImageMetadata : Dictionary, IHaveExtraData, IChildResource + { + /// + /// The associated image. + /// + [JsonIgnore] + protected ImageReference Image { get; set; } + + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + protected internal void SetParent(ImageReference parent) + { + Image = parent; + } + + void IChildResource.SetParent(string parentId) + { + SetParent(new ImageReference { Id = parentId}); + } + + void IChildResource.SetParent(object parent) + { + SetParent((ImageReference)parent); + } + + /// + protected void AssertParentIsSet([CallerMemberName]string callerName = "") + { + if (Image != null) + return; + + throw new InvalidOperationException(string.Format($"{callerName} can only be used on instances which were constructed by the ComputeService. Use ComputeService.{callerName} instead.")); + } + + /// + public async Task CreateAsync(string key, string value, CancellationToken cancellationToken = default(CancellationToken)) + { + AssertParentIsSet(); + var compute = this.GetOwnerOrThrow(); + await compute.CreateImageMetadataAsync(Image.Id, key, value, cancellationToken).ConfigureAwait(false); + this[key] = value; + } + + /// + public async Task UpdateAsync(bool overwrite = false, CancellationToken cancellationToken = default(CancellationToken)) + { + AssertParentIsSet(); + var compute = this.GetOwnerOrThrow(); + var results = await compute.UpdateImageMetadataAsync(Image.Id, this, overwrite, cancellationToken).ConfigureAwait(false); + Clear(); + foreach (var result in results) + { + Add(result.Key, result.Value); + } + } + + /// + public async Task DeleteAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) + { + if (!ContainsKey(key)) + return; + + AssertParentIsSet(); + var compute = this.GetOwnerOrThrow(); + await compute.DeleteImageMetadataAsync(Image.Id, key, cancellationToken).ConfigureAwait(false); + Remove(key); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ImageMetadataExtensions.cs b/src/OpenStack/Compute/v2_1/ImageMetadataExtensions.cs new file mode 100644 index 000000000..b740c3654 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ImageMetadataExtensions.cs @@ -0,0 +1,30 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ImageMetadataExtensions_v2_1 + { + /// + public static void Create(this ImageMetadata metadata, string key, string value) + { + metadata.CreateAsync(key, value).ForceSynchronous(); + } + + /// + public static void Update(this ImageMetadata metadata, bool overwrite = false) + { + metadata.UpdateAsync(overwrite).ForceSynchronous(); + } + + /// + public static void Delete(this ImageMetadata metadata, string key) + { + metadata.DeleteAsync(key).ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/ImageReference.cs b/src/OpenStack/Compute/v2_1/ImageReference.cs new file mode 100644 index 000000000..78031046d --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ImageReference.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Images.v2; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Reference to an image. + /// + public class ImageReference : IHaveExtraData, IServiceResource + { + /// + /// The image identifier. + /// + [JsonProperty("id")] + public virtual Identifier Id { get; set; } + + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task GetImageAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.GetImageAsync(Id, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task GetMetadataAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.GetImageMetadataAsync(Id, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task GetMetadataItemAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.GetImageMetadataItemAsync(Id, key, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public virtual async Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + await owner.DeleteImageAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public virtual async Task WaitUntilDeletedAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + await owner.WaitUntilImageIsDeletedAsync(Id, null, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ImageSummary.cs b/src/OpenStack/Compute/v2_1/ImageSummary.cs new file mode 100644 index 000000000..f61fd09e4 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ImageSummary.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Summary information for an image. + /// + public class ImageSummary : ImageReference + { + /// + /// The image name. + /// + [JsonProperty("name")] + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ImageType.cs b/src/OpenStack/Compute/v2_1/ImageType.cs new file mode 100644 index 000000000..8ee76a3b3 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ImageType.cs @@ -0,0 +1,8 @@ +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + public class ImageType : ImageType + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/KeyPair.cs b/src/OpenStack/Compute/v2_1/KeyPair.cs new file mode 100644 index 000000000..5e8f82a27 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/KeyPair.cs @@ -0,0 +1,24 @@ +using System; +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Key kair resource. + /// Does not include the private key. + /// + public class KeyPair : KeyPairSummary + { + /// + /// The key pair identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The date and time when the resource was created. + /// + [JsonProperty("created_at")] + public DateTimeOffset Created { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/KeyPairDefinition.cs b/src/OpenStack/Compute/v2_1/KeyPairDefinition.cs new file mode 100644 index 000000000..b55f9f27a --- /dev/null +++ b/src/OpenStack/Compute/v2_1/KeyPairDefinition.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines an existing public key. + /// + [JsonConverter(typeof(KeyPairConverter))] + public class KeyPairDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// The key pair name. + /// The public ssh key to import. + public KeyPairDefinition(string name, string publicKey) + { + Name = name; + PublicKey = publicKey; + } + + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("public_key")] + public string PublicKey { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/KeyPairExtensions.cs b/src/OpenStack/Compute/v2_1/KeyPairExtensions.cs new file mode 100644 index 000000000..31b962afe --- /dev/null +++ b/src/OpenStack/Compute/v2_1/KeyPairExtensions.cs @@ -0,0 +1,18 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class KeypairExtensions_v2_1 + { + /// + public static void Delete(this KeyPairSummary keypair) + { + keypair.DeleteAsync().ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/KeyPairRequest.cs b/src/OpenStack/Compute/v2_1/KeyPairRequest.cs new file mode 100644 index 000000000..568dba5b4 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/KeyPairRequest.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// A request to generate a key pair. + /// + [JsonConverter(typeof(KeyPairConverter))] + public class KeyPairRequest + { + /// + /// Initializes a new instance of the class. + /// + /// The key pair name. + public KeyPairRequest(string name) + { + Name = name; + } + + /// + /// The key pair name. + /// + [JsonProperty("name")] + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/KeyPairResponse.cs b/src/OpenStack/Compute/v2_1/KeyPairResponse.cs new file mode 100644 index 000000000..765ec04c7 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/KeyPairResponse.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// The generated key pair. + /// Includes the generated private key, which is sensitive data. + /// + public class KeyPairResponse : KeyPairSummary + { + /// + /// The private ssh key. + /// + [JsonProperty("private_key")] + public string PrivateKey { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/KeyPairSummary.cs b/src/OpenStack/Compute/v2_1/KeyPairSummary.cs new file mode 100644 index 000000000..dc8313dfb --- /dev/null +++ b/src/OpenStack/Compute/v2_1/KeyPairSummary.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Key pair summary information. + /// + [JsonConverter(typeof(KeyPairConverter))] + public class KeyPairSummary : IHaveExtraData, IServiceResource + { + /// + /// The key pair name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The public ssh key. + /// + [JsonProperty("public_key")] + public string PublicKey { get; set; } + + /// + /// A short sequence of bytes used to authenticate, or look up, a longer public key. + /// + [JsonProperty("fingerprint")] + public string Fingerprint { get; set; } + + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + public Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return compute.DeleteKeyPairAsync(Name, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/NamespaceDoc.cs b/src/OpenStack/Compute/v2_1/NamespaceDoc.cs new file mode 100644 index 000000000..f333a2aca --- /dev/null +++ b/src/OpenStack/Compute/v2_1/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace OpenStack.Compute.v2_1 +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines provider-independent + /// interfaces and implementations for the OpenStack Compute v2.1 API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Compute/v2_1/Operator/ComputeServiceExtensions.cs b/src/OpenStack/Compute/v2_1/Operator/ComputeServiceExtensions.cs new file mode 100644 index 000000000..f42047b72 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Operator/ComputeServiceExtensions.cs @@ -0,0 +1,36 @@ +using System.Threading; +using System.Threading.Tasks; +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1.Operator +{ + /// + /// Provides operator extention methods for a instance. + /// + public static class ComputeServiceExtensions_v2_1 + { + #region Servers + + /// + public static Task EvacuateServerAsync(this ComputeService service, Identifier serverId, EvacuateServerRequest request, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._computeApi.EvacuateServerAsync(serverId, request, cancellationToken); + } + + #endregion + + #region Compute Service + /// + public static Task GetCurrentQuotasAsync(this ComputeService service, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._computeApi.GetCurrentQuotasAsync(cancellationToken); + } + + /// + public static Task GetDefaultQuotasAsync(this ComputeService service, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._computeApi.GetDefaultQuotasAsync(cancellationToken); + } + #endregion + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Operator/EvacuateServerRequest.cs b/src/OpenStack/Compute/v2_1/Operator/EvacuateServerRequest.cs new file mode 100644 index 000000000..4fea059a8 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Operator/EvacuateServerRequest.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Operator +{ + /// + /// Evacuates a server from a failed host to a new one. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "evacuate")] + public class EvacuateServerRequest + { + /// + /// Initializes a new instance of the class. + /// + /// if set to true [is server on shared storage]. + public EvacuateServerRequest(bool isServerOnSharedStorage) + { + IsServerOnSharedStorage = isServerOnSharedStorage; + } + + /// + /// The identifier of the host to which the server should be evacuated. + /// + [JsonProperty("host")] + public Identifier DestinationHostId { get; set; } + + /// + /// An administrative password to access the evacuated instance. + /// + [JsonProperty("adminPass")] // NOTE: The doc says admin_password but the API clearly wants adminPass, see https://bugs.launchpad.net/keystone/+bug/1526446 + public string AdminPassword { get; set; } + + /// + /// Specify if the server is on shared storage. + /// + [JsonProperty("onSharedStorage", DefaultValueHandling = DefaultValueHandling.Include)] // NOTE: The doc says on_shared_storage but the API clearly wants onSharedStorage, see https://bugs.launchpad.net/keystone/+bug/1526446 + public bool IsServerOnSharedStorage { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Operator/NamespaceDoc.cs b/src/OpenStack/Compute/v2_1/Operator/NamespaceDoc.cs new file mode 100644 index 000000000..62e7c6826 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Operator/NamespaceDoc.cs @@ -0,0 +1,12 @@ +using System.Runtime.CompilerServices; + +namespace OpenStack.Compute.v2_1.Operator +{ + /// + /// The namespace defines additional functionality that is restricted to cloud operators only. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Operator/ServerExtensions.cs b/src/OpenStack/Compute/v2_1/Operator/ServerExtensions.cs new file mode 100644 index 000000000..d49677234 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Operator/ServerExtensions.cs @@ -0,0 +1,23 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Operator +{ + /// + /// Provides operator extention methods for a instance. + /// + public static class ServerExtensions + { + /// + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public static async Task EvacuateAsync(this ServerReference server, EvacuateServerRequest request, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = server.GetOwnerOrThrow(); + await compute.EvacuateServerAsync(server.Id, request, cancellationToken).ConfigureAwait(false); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/Operator/ServiceQuotas.cs b/src/OpenStack/Compute/v2_1/Operator/ServiceQuotas.cs new file mode 100644 index 000000000..084fcfb00 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Operator/ServiceQuotas.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Operator +{ + /// + /// Compute service quotas. + /// + [JsonConverterWithConstructor(typeof (RootWrapperConverter), "quota_set")] + public class ServiceQuotas : IHaveExtraData + { + /// + /// Number of content bytes allowed per injected file. + /// + [JsonProperty("injected_file_content_bytes")] + public int InjectedFileContentSize { get; set; } + + /// + /// Number of metadata items allowed per instance. + /// + [JsonProperty("metadata_items")] + public int MetadataItems { get; set; } + + /// + /// Number of members per server group. + /// + [JsonProperty("server_group_members")] + public int ServerGroupMembers { get; set; } + + /// + /// Number of server groups per tenant. + /// + [JsonProperty("server_groups")] + public int ServerGroups { get; set; } + + /// + /// Megabytes of instance ram allowed per tenant. + /// + [JsonProperty("ram")] + public int MemorySize { get; set; } + + /// + /// Number of floating IP addresses allowed per tenant. + /// + [JsonProperty("floating_ips")] + public int FloatingIPs { get; set; } + + /// + /// Number of key pairs allowed per user. + /// + [JsonProperty("key_pairs")] + public int KeyPairs { get; set; } + + /// + /// The quota set identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// Number of instances allowed per tenant. + /// + [JsonProperty("instances")] + public int Instances { get; set; } + + /// + /// Number of rules per security group. + /// + [JsonProperty("security_group_rules")] + public int SecurityGroupRules { get; set; } + + /// + /// Number of injected files allowed per tenant. + /// + [JsonProperty("injected_files")] + public int InjectedFiles { get; set; } + + /// + /// Number of instance cores (VCPUs) allowed per tenant. + /// + [JsonProperty("cores")] + public int Cores { get; set; } + + /// + /// Number of fixed IP addresses allowed per tenant. This number must be equal to or greater than the number of allowed instances. + /// + [JsonProperty("fixed_ips")] + public int FixedIPs { get; set; } + + /// + /// Number of content bytes allowed per injected file. + /// + [JsonProperty("injected_file_path_bytes")] + public int InjectedFilePathSize { get; set; } + + /// + /// Number of security groups per tenant. + /// + [JsonProperty("security_groups")] + public int SecurityGroups { get; set; } + + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } +} diff --git a/src/OpenStack/Compute/v2_1/RemoteConsole.cs b/src/OpenStack/Compute/v2_1/RemoteConsole.cs new file mode 100644 index 000000000..ce0aa7535 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/RemoteConsole.cs @@ -0,0 +1,25 @@ +using System; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Specifies how to connect a console to a . + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "console")] + public class RemoteConsole + { + /// + /// The console type. + /// + [JsonProperty("type")] + public RemoteConsoleType Type { get; set; } + + /// + /// The console URL. + /// + [JsonProperty("url")] + public Uri Url { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/RemoteConsoleType.cs b/src/OpenStack/Compute/v2_1/RemoteConsoleType.cs new file mode 100644 index 000000000..7d2143d7b --- /dev/null +++ b/src/OpenStack/Compute/v2_1/RemoteConsoleType.cs @@ -0,0 +1,9 @@ +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + public class RemoteConsoleType : RemoteConsoleType + { + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/SchedulerHints.cs b/src/OpenStack/Compute/v2_1/SchedulerHints.cs new file mode 100644 index 000000000..9cfe765f6 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/SchedulerHints.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Hints passed to the compute scheduler when creating a server. + /// These may be used by the scheduler to determine how and where the server instance is created. + /// Custom hints can be set via the method. + /// + /// + public class SchedulerHints : IHaveExtraData + { + /// + public SchedulerHints() + { + DifferentHost = new List(); + SameHost = new List(); + } + + /// + /// Specifies a custom filter by passing a scheduler hint in JSON format. + /// + /// + [JsonProperty("query")] + public string Query { get; set; } + + /// + /// Schedules the instance based on host IP subnet range. Specifies the CIDR that corresponds to the subnet. + /// Must also specify . + /// + [JsonProperty("build_near_host_ip")] + public string BuildNearHostIP { get; set; } + + /// + /// Schedules the instance based on host IP subnet range. Specifies the first IP address in the subnet. + /// Must also specify . + /// + [JsonProperty("cidr")] + public string CIDR { get; set; } + + /// + /// Schedules the instance on a different host from a set of instances. + /// + [JsonProperty("different_host")] + public IList DifferentHost { get; set; } + + /// + /// Schedules the instance on the same host as another instance in a set of instances. + /// + [JsonProperty("same_host")] + public IList SameHost { get; set; } + + /// + /// Specifies additional custom hints to pass to the scheduler. + /// Use the method instead of accessing this property directly. + /// + [JsonExtensionData] + public IDictionary Data { get; set; } = new Dictionary(); + + /// + /// Adds a custom scheduling hint. + /// + /// The hint key. + /// The hint value. + public void Add(string hint, object value) + { + Data.Add(hint, JToken.FromObject(value)); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/SecurityGroup.cs b/src/OpenStack/Compute/v2_1/SecurityGroup.cs new file mode 100644 index 000000000..e7e2ccc98 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/SecurityGroup.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Extensions; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Security groups are sets of IP filter rules that are applied to an instance's networking. + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "security_group")] + public class SecurityGroup : SecurityGroupReference + { + /// + /// Initializes a new instance of the class. + /// + public SecurityGroup() + { + Rules = new List(); + } + + /// + /// The security group identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The security group description. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// The security group rules. + /// + [JsonProperty("rules")] + public IList Rules { get; set; } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task UpdateAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + var request = new SecurityGroupDefinition(Name, Description); + + var result = await compute.UpdateSecurityGroupAsync(Id, request, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task AddRuleAsync(SecurityGroupRuleDefinition rule, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + rule.GroupId = Id; + + var result = await compute.CreateSecurityGroupRuleAsync(rule, cancellationToken).ConfigureAwait(false); + Rules.Add(result); + return result; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/SecurityGroupDefinition.cs b/src/OpenStack/Compute/v2_1/SecurityGroupDefinition.cs new file mode 100644 index 000000000..943c41c07 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/SecurityGroupDefinition.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines a new security group. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "security_group")] + public class SecurityGroupDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// The security group name. + /// The security group description. + public SecurityGroupDefinition(string name, string description) + { + Name = name; + Description = description; + } + + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("description")] + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/SecurityGroupExtensions.cs b/src/OpenStack/Compute/v2_1/SecurityGroupExtensions.cs new file mode 100644 index 000000000..14e692dac --- /dev/null +++ b/src/OpenStack/Compute/v2_1/SecurityGroupExtensions.cs @@ -0,0 +1,42 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class SecurityGroupExtensions_v2_1 + { + /// + public static SecurityGroupRule AddRule(this SecurityGroup securityGroup, SecurityGroupRuleDefinition rule) + { + return securityGroup.AddRuleAsync(rule).ForceSynchronous(); + } + + /// + public static void Delete(this SecurityGroupReference securityGroup) + { + securityGroup.DeleteAsync().ForceSynchronous(); + } + + /// + public static void Delete(this SecurityGroupRule rule) + { + rule.DeleteAsync().ForceSynchronous(); + } + + /// + public static SecurityGroup GetSecurityGroup(this SecurityGroupReference securityGroup) + { + return securityGroup.GetSecurityGroupAsync().ForceSynchronous(); + } + + /// + public static void Update(this SecurityGroup securityGroup) + { + securityGroup.UpdateAsync().ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/SecurityGroupReference.cs b/src/OpenStack/Compute/v2_1/SecurityGroupReference.cs new file mode 100644 index 000000000..f45ad62da --- /dev/null +++ b/src/OpenStack/Compute/v2_1/SecurityGroupReference.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Reference to a security group. + /// + public class SecurityGroupReference : IHaveExtraData, IServiceResource + { + /// + /// The security group name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + private async Task LoadSecurityGroup(CancellationToken cancellationToken) + { + var securityGroup = this as SecurityGroup; + if (securityGroup != null) + return securityGroup; + + var owner = this.GetOwnerOrThrow(); + + // In some cases, such as when working with the groups on a server, we only have the name and not the id + var groups = await owner.ListSecurityGroupsAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + securityGroup = groups.FirstOrDefault(x => x.Name == Name); + if(securityGroup == null) + throw new Exception($"Unable to find the security group named: {Name}."); + + return securityGroup; + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task GetSecurityGroupAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return LoadSecurityGroup(cancellationToken); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + var securityGroup = await LoadSecurityGroup(cancellationToken).ConfigureAwait(false); + + await owner.DeleteSecurityGroupAsync(securityGroup.Id, cancellationToken).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/SecurityGroupRule.cs b/src/OpenStack/Compute/v2_1/SecurityGroupRule.cs new file mode 100644 index 000000000..2b0de65d6 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/SecurityGroupRule.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// A security group rule. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "security_group_rule")] + public class SecurityGroupRule : IHaveExtraData, IServiceResource + { + /// + /// The rule identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The IP protocol. + /// + [JsonProperty("ip_protocol")] + public IPProtocol Protocol { get; set; } + + /// + /// The port at start of range. + /// + [JsonProperty("from_port")] + public int FromPort { get; set; } + + /// + /// The port at end of range. + /// + [JsonProperty("to_port")] + public int ToPort { get; set; } + + /// + /// The CIDR for address range. + /// + [JsonIgnore] + public string CIDR + { + get { return _ipRange.CIDR; } + set { _ipRange.CIDR = value; } + } + + [JsonProperty("ip_range")] + private CIDRWrapper _ipRange = new CIDRWrapper(); + + /// + /// The associated security group identifier. + /// + [JsonProperty("parent_group_id")] + public Identifier GroupId { get; set; } + + /// + /// The associated source group identifier. + /// + [JsonProperty("group_id")] + public Identifier SourceGroupId { get; set; } + + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.DeleteSecurityGroupRuleAsync(Id, cancellationToken); + } + + private class CIDRWrapper + { + [JsonProperty("cidr")] + public string CIDR { get; set; } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/SecurityGroupRuleDefinition.cs b/src/OpenStack/Compute/v2_1/SecurityGroupRuleDefinition.cs new file mode 100644 index 000000000..83eaea8e9 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/SecurityGroupRuleDefinition.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines a new security group rule. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "security_group_rule")] + public class SecurityGroupRuleDefinition : IHaveExtraData + { + /// + /// Initializes a new instance of the class. + /// + /// The IP protocol. + /// The source port. + /// To destination port. + /// The CIDR. + public SecurityGroupRuleDefinition(IPProtocol protocol, int fromPort, int toPort, string cidr) + { + Protocol = protocol; + FromPort = fromPort; + ToPort = toPort; + CIDR = cidr; + } + + /// + [JsonProperty("ip_protocol")] + public IPProtocol Protocol { get; set; } + + /// + [JsonProperty("from_port")] + public int FromPort { get; set; } + + /// + [JsonProperty("to_port")] + public int ToPort { get; set; } + + /// + [JsonProperty("cidr")] + public string CIDR { get; set; } + + /// + [JsonProperty("parent_group_id")] + public Identifier GroupId { get; set; } + + /// + [JsonProperty("group_id")] + public Identifier SourceGroupId { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Serialization/AddressType.cs b/src/OpenStack/Compute/v2_1/Serialization/AddressType.cs new file mode 100644 index 000000000..ef2132281 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/AddressType.cs @@ -0,0 +1,22 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Server address types. + /// + /// + public class AddressType : StringEnumeration + where T : AddressType, new() + { + /// + /// Fixed IP address. + /// + public static readonly T Fixed = new T {DisplayName = "fixed"}; + + /// + /// Floating IP address. + /// + public static readonly T Floating = new T {DisplayName = "floating"}; + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ComputeApi.cs b/src/OpenStack/Compute/v2_1/Serialization/ComputeApi.cs new file mode 100644 index 000000000..03474cd1f --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ComputeApi.cs @@ -0,0 +1,2260 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Flurl; +using Flurl.Extensions; +using Flurl.Http; +using Newtonsoft.Json.Linq; +using OpenStack.Authentication; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Builds requests to the Compute API which can be further customized and then executed. + /// Intended for custom implementations. + /// + /// + /// OpenStack Compute API v2.1 Overview + public class ComputeApi + { + /// + /// The authentication service. + /// + protected readonly IAuthenticationProvider AuthenticationProvider; + + /// + /// The Nova microversion header key + /// + public const string MicroversionHeader = "X-OpenStack-Nova-API-Version"; + + /// + /// The Compute service endpoint. + /// + protected readonly ServiceEndpoint Endpoint; + + /// + /// Initializes a new instance of the class. + /// + /// The service type for the desired compute provider. + /// The authentication provider. + /// The region. + /// if set to true uses the internal URLs specified in the ServiceCatalog, otherwise the public URLs are used. + public ComputeApi(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl) + : this(serviceType, authenticationProvider, region, useInternalUrl, "2.1") + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The service type for the desired compute provider. + /// The authentication provider. + /// The region. + /// if set to true uses the internal URLs specified in the ServiceCatalog, otherwise the public URLs are used. + /// The requested API microversion. + /// + /// serviceType + /// or + /// authenticationProvider + /// + /// region cannot be null or empty;region + /// region cannot be null or empty + protected ComputeApi(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl, string microversion) + { + if (serviceType == null) + throw new ArgumentNullException("serviceType"); + if (authenticationProvider == null) + throw new ArgumentNullException("authenticationProvider"); + if (string.IsNullOrEmpty(region)) + throw new ArgumentException("region cannot be null or empty", "region"); + + AuthenticationProvider = authenticationProvider; + Endpoint = new ServiceEndpoint(serviceType, authenticationProvider, region, useInternalUrl, microversion, MicroversionHeader); + } + + #region Servers + + /// + /// Shows details for a server. + /// + /// The return type. + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetServerRequest(serverId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// is . + public virtual Task BuildGetServerRequest(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + if(serverId == null) + throw new ArgumentNullException("serverId"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}", cancellationToken); + } + + /// + /// Gets all metadata for a server. + /// + /// The return type. + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetServerMetadataAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IChildResource + { + return await BuildGetServerMetadataRequest(serverId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this) + .SetParent(serverId).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// is . + public virtual Task BuildGetServerMetadataRequest(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}/metadata", cancellationToken); + } + + /// + /// Shows details for a metadata item, by key, for a server. + /// + /// The server identifier. + /// The metadata key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetServerMetadataItemAsync(string serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + dynamic result = await BuildGetServerMetadataItemRequest(serverId, key, cancellationToken) + .SendAsync() + .ReceiveJson().ConfigureAwait(false); + + var meta = (IDictionary)result.meta; + return meta[key]?.ToString(); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetServerMetadataItemRequest(string serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + if (key == null) + throw new ArgumentNullException("key"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}/metadata/{key}", cancellationToken); + } + + /// + /// Builds the request. + /// + /// The server. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildCreateServerRequest(object server, CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareCreateResourceRequest("servers", server, cancellationToken); + } + + /// + /// Creates a server. + /// + /// The return type. + /// The server. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task CreateServerAsync(object server, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildCreateServerRequest(server, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Creates or replaces a metadata item, by key, for a server. + /// + /// The server identifier. + /// The metadata key. + /// The value. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task CreateServerMetadataAsync(string serverId, string key, string value, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildCreateServerMetadataRequest(serverId, key, value, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The key. + /// The value. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildCreateServerMetadataRequest(string serverId, string key, string value, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + if (key == null) + throw new ArgumentNullException("key"); + + var serverMetadata = new + { + meta = new Dictionary + { + [key] = value + } + }; + + PreparedRequest request = await Endpoint.PrepareRequest($"servers/{serverId}/metadata/{key}", cancellationToken).ConfigureAwait(false); + return request.PreparePutJson(serverMetadata, cancellationToken); + } + + /// + /// Waits for the server to reach the specified status. + /// + /// The server identifier. + /// The status to wait for. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitForServerStatusAsync(string serverId, TStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TServer : IServiceResource + where TStatus : ResourceStatus + { + Func> getServer = async () => await GetServerAsync(serverId, cancellationToken).ConfigureAwait(false); + return await Endpoint.WaitForStatusAsync(serverId, status, getServer, refreshDelay, timeout, progress, cancellationToken) + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Waits for the server to reach the specified status. + /// + /// The server identifier. + /// The status to wait for. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitForServerStatusAsync(string serverId, IEnumerable status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TServer : IServiceResource + where TStatus : ResourceStatus + { + Func> getServer = async () => await GetServerAsync(serverId, cancellationToken).ConfigureAwait(false); + return await Endpoint.WaitForStatusAsync(serverId, status, getServer, refreshDelay, timeout, progress, cancellationToken) + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Waits for the server to be deleted. + /// Treats a 404 NotFound exception as confirmation that it is deleted. + /// + /// The server identifier. + /// The deleted status to wait for. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public Task WaitUntilServerIsDeletedAsync(string serverId, TStatus deletedStatus = null, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TServer : IServiceResource + where TStatus : ResourceStatus + { + deletedStatus = deletedStatus ?? StringEnumeration.FromDisplayName("DELETED"); + Func> getServer = async () => await GetServerAsync(serverId, cancellationToken).ConfigureAwait(false); + return Endpoint.WaitUntilDeletedAsync(serverId, deletedStatus, getServer, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// Lists summary information for all servers. + /// + /// The return type. + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListServerSummariesAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where TPage : IPageBuilder, IEnumerable + { + Url initialRequestUrl = await BuildListServerSummariesUrl(queryString, cancellationToken).ConfigureAwait(false); + return await Endpoint.GetResourcePageAsync(initialRequestUrl, cancellationToken) + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the URL. + /// + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListServerSummariesUrl(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegment("servers") + .SetQueryParams(queryString?.Build()); + } + + /// + /// Lists all servers with details. + /// + /// The return type. + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListServersAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where TPage : IPageBuilder, IEnumerable + { + Url initialRequestUrl = await BuildListServersUrl(queryString, cancellationToken).ConfigureAwait(false); + return await Endpoint.GetResourcePageAsync(initialRequestUrl, cancellationToken) + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the list servers URL. + /// + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListServersUrl(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegment("servers/detail") + .SetQueryParams(queryString?.Build()); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The server. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildUpdateServerRequest(string serverId, object server, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + return Endpoint.PrepareUpdateResourceRequest($"servers/{serverId}", server, cancellationToken); + } + + /// + /// Updates the editable attributes of a server. + /// + /// The return type + /// The server identifier. + /// The server. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task UpdateServerAsync(string serverId, object server, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildUpdateServerRequest(serverId, server, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Creates or replaces one or more metadata items for a server. + /// Omitted keys are not removed unless is true. + /// + /// The return type + /// The server identifier. + /// The metadata. + /// if set to true overwrite all existing metadata keys. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task UpdateServerMetadataAsync(string serverId, object metadata, bool overwrite = false, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildUpdateServerMetadataRequest(serverId, metadata, overwrite, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The metadata. + /// if set to true overwrite all existing metadata keys. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildUpdateServerMetadataRequest(string serverId, object metadata, bool overwrite = false, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + PreparedRequest request = await Endpoint.PrepareRequest($"servers/{serverId}/metadata", cancellationToken).ConfigureAwait(false); + + if (overwrite) + return request.PreparePutJson(metadata, cancellationToken); + + return request.PreparePostJson(metadata, cancellationToken); + } + + /// + /// Deletes a server. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteServerRequest(serverId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteServerRequest(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + return Endpoint.PrepareDeleteResourceRequest($"servers/{serverId}", cancellationToken); + } + + /// + /// Deletes a metadata item, by key, from a server. + /// + /// The server identifier. + /// The metadata key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteServerMetadataAsync(string serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteServerMetadataRequest(serverId, key, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The metadata key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteServerMetadataRequest(string serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + if (key == null) + throw new ArgumentNullException("key"); + + return Endpoint.PrepareDeleteResourceRequest($"servers/{serverId}/metadata/{key}", cancellationToken); + } + + /// + /// Waits for an image to reach the specified state. + /// + /// The image identifier. + /// The image status. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitForImageStatusAsync(string imageId, TStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TImage : IServiceResource + where TStatus : ResourceStatus + { + Func> getImage = async () => await GetImageAsync(imageId, cancellationToken).ConfigureAwait(false); + return await Endpoint.WaitForStatusAsync(imageId, status, getImage, refreshDelay, timeout, progress, cancellationToken) + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Waits for the image to be deleted. + /// + /// The image identifier. + /// The deleted status to wait for. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public Task WaitUntilImageIsDeletedAsync(string imageId, TStatus deletedStatus, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TImage : IServiceResource + where TStatus : ResourceStatus + { + deletedStatus = deletedStatus ?? StringEnumeration.FromDisplayName("DELETED"); + Func> getImage = async () => await GetServerAsync(imageId, cancellationToken).ConfigureAwait(false); + return Endpoint.WaitUntilDeletedAsync(imageId, deletedStatus, getImage, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// Creates a snapshot image from a server. + /// + /// The return type. + /// The server identifier. + /// The request. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task SnapshotServerAsync(string serverId, object request, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + var response = await BuildServerActionRequest(serverId, request, cancellationToken).SendAsync().ConfigureAwait(false); + Identifier imageId = response.Headers.Location.Segments.Last(); // grab id off the end of the url, e.g. http://172.29.236.100:9292/images/baaab9b9-3635-429e-9969-2899a7cf2d97 + return await GetImageAsync(imageId, cancellationToken) + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Starts a stopped server and changes its status to ACTIVE. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task StartServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + var request = new Dictionary {["os-start"] = "" }; + return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync(); + } + + /// + /// Stops a running server and changes its status to SHUTOFF. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task StopServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + var request = new Dictionary {["os-stop"] = "" }; + return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync(); + } + + /// + /// Suspends a server and changes its status to SUSPENDED. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task SuspendServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + var request = new Dictionary {["suspend"] = "" }; + return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync(); + } + + /// + /// Resumes a suspended server and changes its status to ACTIVE. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task ResumeServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + var request = new Dictionary {["resume"] = "" }; + return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync(); + } + + /// + /// Reboots a server. + /// + /// The type of the request. + /// The server identifier. + /// The request. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task RebootServerAsync(string serverId, TRequest request = null, CancellationToken cancellationToken = default(CancellationToken)) + where TRequest : class, new() + { + request = request ?? new TRequest(); + return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync(); + } + + /// + /// Evacuates a server from a failed host to a new one. + /// + /// The server identifier. + /// The request. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task EvacuateServerAsync(string serverId, object request, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync(); + } + + /// + /// Gets a VNC console for a server. + /// + /// The return type. + /// The server identifier. + /// The remote console type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task GetVncConsoleAsync(string serverId, object type, CancellationToken cancellationToken = default(CancellationToken)) + { + if (type == null) + throw new ArgumentNullException("type"); + + var request = JObject.Parse($"{{ 'os-getVNCConsole': {{ 'type': '{type}' }} }}"); + return BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + /// Gets a SPICE console for a server. + /// + /// The return type. + /// The server identifier. + /// The remote console type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task GetSpiceConsoleAsync(string serverId, object type, CancellationToken cancellationToken = default(CancellationToken)) + { + if (type == null) + throw new ArgumentNullException("type"); + + var request = JObject.Parse($"{{ 'os-getSPICEConsole': {{ 'type': '{type}' }} }}"); + return BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + /// Gets a serial console for a server. + /// + /// The return type. + /// The server identifier. + /// The remote console type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task GetSerialConsoleAsync(string serverId, object type, CancellationToken cancellationToken = default(CancellationToken)) + { + if (type == null) + throw new ArgumentNullException("type"); + + var request = JObject.Parse($"{{ 'os-getSerialConsole': {{ 'type': '{type}' }} }}"); + return BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + /// Gets an RDP console for a server. + /// + /// The return type. + /// The server identifier. + /// The remote console type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task GetRdpConsoleAsync(string serverId, object type, CancellationToken cancellationToken = default(CancellationToken)) + { + if (type == null) + throw new ArgumentNullException("type"); + + var request = JObject.Parse($"{{ 'os-getRDPConsole': {{ 'type': '{type}' }} }}"); + return BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + /// Shows console output for a server instance. + /// + /// The server identifier. + /// The number of lines to fetch from the end of console log. -1 indicates unlimited. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetConsoleOutputAsync(string serverId, int length = -1, CancellationToken cancellationToken = default(CancellationToken)) + { + var request = JObject.Parse($"{{ 'os-getConsoleOutput': {{ 'length': '{length}' }} }}"); + dynamic result = await BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync() + .ReceiveJson().ConfigureAwait(false); + + return result.output; + } + + /// + /// Puts a server in rescue mode and changes its status to RESCUE. + /// + /// The server identifier. + /// The request. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task RescueServerAsync(string serverId, object request = null, CancellationToken cancellationToken = default(CancellationToken)) + { + request = request ?? new Dictionary {["rescue"] = null}; + dynamic result = await BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync() + .ReceiveJson().ConfigureAwait(false); + + return result.adminPass; + } + + /// + /// Unrescues a server. Changes status to ACTIVE. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task UnrescueServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + object request = new Dictionary {["unrescue"] = null}; + return BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync(); + } + + /// + /// Resizes a server. + /// Depending on the cloud configuration, may need to be called to complete the resize operation. + /// + /// The server identifier. + /// The flavor identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task ResizeServerAsync(string serverId, string flavorId, CancellationToken cancellationToken = default(CancellationToken)) + { + object request = new + { + resize = new + { + flavorRef = flavorId + } + }; + return BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync(); + } + + /// + /// Confirms a pending resize action for a server. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task ConfirmResizeServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + object request = new Dictionary {["confirmResize"] = null}; + return BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync(); + } + + /// + /// Cancels and reverts a pending resize action for a server. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task CancelResizeServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + object request = new Dictionary {["revertResize"] = null}; + return BuildServerActionRequest(serverId, request, cancellationToken) + .SendAsync(); + } + + /// + /// Associates a floating IP address to the server. + /// + /// The server identifier. + /// The request. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task AssociateFloatingIPAsync(string serverId, object request, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync(); + } + + /// + /// Disassociate a floating IP address from a server. + /// + /// The server identifier. + /// The floating IP address to remove. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task DisassociateFloatingIPAsync(string serverId, string floatingIPAddress, CancellationToken cancellationToken = default(CancellationToken)) + { + var request = new + { + removeFloatingIp = new + { + address = floatingIPAddress + } + }; + return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync(); + } + + /// + /// Builds a server action request, where the server operation is specified in the request body. + /// + /// The server identifier. + /// The request body. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildServerActionRequest(string serverId, object requestBody, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + var request = await Endpoint.PrepareRequest($"servers/{serverId}/action", cancellationToken).ConfigureAwait(false); + return request.PreparePostJson(requestBody, cancellationToken); + } + + /// + /// Lists the actions which have been applied to a sever. + /// + /// The return type. + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListServerActionSummariesAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListServerActionSummariesRequest(serverId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildListServerActionSummariesRequest(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + if(serverId == null) + throw new ArgumentNullException("serverId"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}/os-instance-actions", cancellationToken); + } + + /// + /// Shows details for a server action. + /// + /// The return type. + /// The server identifier. + /// The action identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetServerActionAsync(string serverId, string actionId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetServerActionRequest(serverId, actionId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The action identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetServerActionRequest(string serverId, string actionId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + if (serverId == null) + throw new ArgumentNullException("actionId"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}/os-instance-actions/{actionId}", cancellationToken); + } + + #endregion + + #region Flavors + + /// + /// Shows details for a flavor. + /// + /// The return type. + /// The flavor identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetFlavorAsync(string flavorId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetFlavorRequest(flavorId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The flavor identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetFlavorRequest(string flavorId, CancellationToken cancellationToken = default(CancellationToken)) + { + if(flavorId == null) + throw new ArgumentNullException("flavorId"); + + return Endpoint.PrepareGetResourceRequest($"flavors/{flavorId}", cancellationToken); + } + + /// + /// Lists summary information for available flavors. + /// + /// The return type. + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListFlavorSummariesAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where TPage : IPageBuilder, IEnumerable + { + Url initialRequestUrl = await BuildListFlavorSummariesURL(queryString, cancellationToken).ConfigureAwait(false); + return await Endpoint.GetResourcePageAsync(initialRequestUrl, cancellationToken) + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListFlavorSummariesURL(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegment("flavors") + .SetQueryParams(queryString?.Build()); + } + + /// + /// Lists available flavors. + /// + /// The return type. + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListFlavorsAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where TPage : IPageBuilder, IEnumerable + { + Url initialRequestUrl = await BuildListFlavorsURL(queryString, cancellationToken).ConfigureAwait(false); + return await Endpoint.GetResourcePageAsync(initialRequestUrl, cancellationToken) + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the URL. + /// + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListFlavorsURL(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegment("flavors/detail") + .SetQueryParams(queryString?.Build()); + } + + #endregion + + #region Images + + /// + /// Shows details for an image. + /// + /// The return type. + /// The image identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetImageAsync(string imageId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetImageRequest(imageId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The image identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetImageRequest(string imageId, CancellationToken cancellationToken = default(CancellationToken)) + { + if(imageId == null) + throw new ArgumentNullException("imageId"); + + return Endpoint.PrepareGetResourceRequest($"images/{imageId}", cancellationToken); + } + + /// + /// Shows metadata for an image. + /// + /// The return type. + /// The image identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetImageMetadataAsync(string imageId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IChildResource + { + return await BuildGetImageMetadataRequest(imageId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this) + .SetParent(imageId).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The image identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetImageMetadataRequest(string imageId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + + return Endpoint.PrepareGetResourceRequest($"images/{imageId}/metadata", cancellationToken); + } + + /// + /// Shows details for a metadata item, by key, for an image. + /// + /// The image identifier. + /// The metadata key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetImageMetadataItemAsync(string imageId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + dynamic result = await BuildGetImageMetadataItemRequest(imageId, key, cancellationToken) + .SendAsync() + .ReceiveJson().ConfigureAwait(false); + + var meta = (IDictionary)result.meta; + return meta[key]?.ToString(); + } + + /// + /// Builds the request. + /// + /// The image identifier. + /// The key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetImageMetadataItemRequest(string imageId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + + if (key == null) + throw new ArgumentNullException("key"); + + return Endpoint.PrepareGetResourceRequest($"images/{imageId}/metadata/{key}", cancellationToken); + } + + /// + /// Creates or replaces metadata for an image. + /// + /// The image identifier. + /// The metadata key. + /// The value. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task CreateImageMetadataAsync(string imageId, string key, string value, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildCreateImageMetadataRequest(imageId, key, value, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The image identifier. + /// The key. + /// The value. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildCreateImageMetadataRequest(string imageId, string key, string value, CancellationToken cancellationToken = default(CancellationToken)) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + + if (key == null) + throw new ArgumentNullException("key"); + + var imageMetadata = new + { + meta = new Dictionary + { + [key] = value + } + }; + + PreparedRequest request = await Endpoint.PrepareRequest($"images/{imageId}/metadata/{key}", cancellationToken).ConfigureAwait(false); + return request.PreparePutJson(imageMetadata, cancellationToken); + } + + /// + /// Lists summary information for available images. + /// + /// The return type. + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListImageSummariesAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where TPage : IPageBuilder, IEnumerable + { + Url initialRequestUrl = await BuildListImageSummariesRequest(queryString, cancellationToken).ConfigureAwait(false); + return await Endpoint.GetResourcePageAsync(initialRequestUrl, cancellationToken) + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListImageSummariesRequest(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegment("images") + .SetQueryParams(queryString?.Build()); + } + + /// + /// Lists available images. + /// + /// The return type. + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListImagesAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where TPage : IPageBuilder, IEnumerable + { + Url initialRequestUrl = await BuildListImagesRequest(queryString, cancellationToken).ConfigureAwait(false); + return await Endpoint.GetResourcePageAsync(initialRequestUrl, cancellationToken) + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// Options for paging and filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListImagesRequest(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegment("images/detail") + .SetQueryParams(queryString?.Build()); + } + + /// + /// Creates or replaces one or more metadata items for an image. + /// Omitted keys are not removed unless is true. + /// + /// The return type. + /// The image identifier. + /// The metadata. + /// if set to true overwrite all existing metadata keys. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task UpdateImageMetadataAsync(string imageId, object metadata, bool overwrite = false, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildUpdateImageMetadataRequest(imageId, metadata, overwrite, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The image identifier. + /// The metadata. + /// if set to true all existing metadata keys. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildUpdateImageMetadataRequest(string imageId, object metadata, bool overwrite = false, CancellationToken cancellationToken = default(CancellationToken)) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + + PreparedRequest request = await Endpoint.PrepareRequest($"images/{imageId}/metadata", cancellationToken).ConfigureAwait(false); + + if (overwrite) + return request.PreparePutJson(metadata, cancellationToken); + + return request.PreparePostJson(metadata, cancellationToken); + } + + /// + /// Deletes an image. + /// + /// The image identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteImageAsync(string imageId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteImageRequest(imageId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The image identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteImageRequest(string imageId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + + return Endpoint.PrepareDeleteResourceRequest($"images/{imageId}", cancellationToken); + } + + /// + /// Deletes a metadata item, by key, for an image. + /// + /// The image identifier. + /// The metadata key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteImageMetadataAsync(string imageId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteImageMetadataRequest(imageId, key, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The image identifier. + /// The key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteImageMetadataRequest(string imageId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + + if (key == null) + throw new ArgumentNullException("key"); + + return Endpoint.PrepareDeleteResourceRequest($"images/{imageId}/metadata/{key}", cancellationToken); + } + + #endregion + + #region IP Addresses + + /// + /// Shows IP addresses details for a network label of a server instance. + /// + /// The return type. + /// The server identifier. + /// The network key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task> GetServerAddressAsync(string serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + var result = await BuildGetServerAddressRequest(serverId, key, cancellationToken) + .SendAsync() + .ReceiveJson>>().ConfigureAwait(false); + + return result[key]; + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The key. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetServerAddressRequest(string serverId, string key, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + if (key == null) + throw new ArgumentNullException("key"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}/ips/{key}", cancellationToken); + } + + /// + /// Lists IP addresses that are assigned to a server. + /// + /// The return type. + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task ListServerAddressesAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildListServerAddressesRequest(serverId, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + /// Builds the request. + /// + /// The serverid. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildListServerAddressesRequest(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}/ips", cancellationToken); + } + + #endregion + + #region Server Volumes + + /// + /// Shows details for a volume attachment. + /// + /// The return type. + /// The server identifier. + /// The volume identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetServerVolumeAsync(string serverId, string volumeId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IChildResource + { + return await BuildGetServerVolumeRequest(serverId, volumeId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this) + .SetParent(serverId).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The volume identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetServerVolumeRequest(string serverId, string volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}/os-volume_attachments/{volumeId}", cancellationToken); + } + + /// + /// Lists the volume attachments for a server. + /// + /// The return type. + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListServerVolumesAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListServerVolumesRequest(serverId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this) + .SetParentOnChildren(serverId).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildListServerVolumesRequest(string serverId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + return Endpoint.PrepareGetResourceRequest($"servers/{serverId}/os-volume_attachments", cancellationToken); + } + + /// + /// Attaches a volume to a server. + /// + /// The return type. + /// The server identifier. + /// The request. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task AttachVolumeAsync(string serverId, object serverVolume, CancellationToken cancellationToken = default(CancellationToken)) + where T : IChildResource + { + return await BuildAttachVolumeRequest(serverId, serverVolume, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this) + .SetParent(serverId).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The server volume. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildAttachVolumeRequest(string serverId, object serverVolume, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + return Endpoint.PrepareCreateResourceRequest($"servers/{serverId}/os-volume_attachments", serverVolume, cancellationToken); + } + + /// + /// Detaches a volume from a server. + /// + /// The server identifier. + /// The volume identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DetachVolumeAsync(string serverId, string volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDetachVolumeRequest(serverId, volumeId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// The volume identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDetachVolumeRequest(string serverId, string volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + + return Endpoint.PrepareDeleteResourceRequest($"servers/{serverId}/os-volume_attachments/{volumeId}", cancellationToken); + } + + #endregion + + #region Keypairs + + /// + /// Shows details for a keypair that is associated with the account. + /// + /// The return type. + /// Name of the keypair. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetKeyPairAsync(string keypairName, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + + + return await BuildGetKeyPairRequest(keypairName, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// Name of the keypair. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetKeyPairRequest(string keypairName, CancellationToken cancellationToken = default(CancellationToken)) + { + if (keypairName == null) + throw new ArgumentNullException("keypairName"); + + return Endpoint.PrepareGetResourceRequest($"os-keypairs/{keypairName}", cancellationToken); + } + + /// + /// Generates or imports a keypair. + /// + /// The return type. + /// The keypair. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task CreateKeyPairAsync(object keypair, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildCreateKeyPairRequest(keypair, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The keypair. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// keypair + public virtual Task BuildCreateKeyPairRequest(object keypair, CancellationToken cancellationToken = default(CancellationToken)) + { + if (keypair == null) + throw new ArgumentNullException("keypair"); + + return Endpoint.PrepareCreateResourceRequest("os-keypairs", keypair, cancellationToken); + } + + /// + /// Lists keypairs that are associated with the account. + /// + /// The return type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListKeyPairsAsync(CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListKeyPairsRequest(cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildListKeyPairsRequest(CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareGetResourceRequest("os-keypairs", cancellationToken); + } + + /// + /// Deletes a keypair. + /// + /// Name of the keypair. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteKeyPairAsync(string keypairName, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteKeyPairRequest(keypairName, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// Name of the keypair. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteKeyPairRequest(string keypairName, CancellationToken cancellationToken = default(CancellationToken)) + { + if (keypairName == null) + throw new ArgumentNullException("keypairName"); + + return Endpoint.PrepareDeleteResourceRequest($"os-keypairs/{keypairName}", cancellationToken); + } + + #endregion + + #region Security Groups + + /// + /// Shows details for a security group. + /// + /// The return type. + /// The security group identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetSecurityGroupAsync(string securityGroupId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetSecurityGroupRequest(securityGroupId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The security group identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetSecurityGroupRequest(string securityGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (securityGroupId == null) + throw new ArgumentNullException("securityGroupId"); + + return Endpoint.PrepareGetResourceRequest($"os-security-groups/{securityGroupId}", cancellationToken); + } + + /// + /// Creates a security group. + /// + /// The return type. + /// The security group. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task CreateSecurityGroupAsync(object securityGroup, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildCreateSecurityGroupRequest(securityGroup, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The security group. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildCreateSecurityGroupRequest(object securityGroup, CancellationToken cancellationToken = default(CancellationToken)) + { + if (securityGroup == null) + throw new ArgumentNullException("securityGroup"); + + return Endpoint.PrepareCreateResourceRequest("os-security-groups", securityGroup, cancellationToken); + } + + /// + /// Creates a rule for a security group. + /// + /// The return type. + /// The rule. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task CreateSecurityGroupRuleAsync(object rule, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildCreateSecurityGroupRuleRequest(rule, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The rule. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildCreateSecurityGroupRuleRequest(object rule, CancellationToken cancellationToken = default(CancellationToken)) + { + if (rule == null) + throw new ArgumentNullException("rule"); + + return Endpoint.PrepareCreateResourceRequest("os-security-group-rules", rule, cancellationToken); + } + + /// + /// Lists security groups. + /// + /// The return type. + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListSecurityGroupsAsync(string serverId = null, CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListSecurityGroupsRequest(serverId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildListSecurityGroupsRequest(string serverId = null, CancellationToken cancellationToken = default(CancellationToken)) + { + string path = serverId == null ? "os-security-groups" : $"servers/{serverId}/os-security-groups"; + return Endpoint.PrepareGetResourceRequest(path, cancellationToken); + } + + /// + /// Updates a security group. + /// + /// The return type. + /// The security group identifier. + /// The security group. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task UpdateSecurityGroupAsync(string securityGroupId, object securityGroup, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildUpdateSecurityGroupRequest(securityGroupId, securityGroup, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The security group identifier. + /// The security group. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildUpdateSecurityGroupRequest(string securityGroupId, object securityGroup, CancellationToken cancellationToken = default(CancellationToken)) + { + if (securityGroupId == null) + throw new ArgumentNullException("securityGroupId"); + + return Endpoint.PrepareUpdateResourceRequest($"os-security-groups/{securityGroupId}", securityGroup, cancellationToken); + } + + /// + /// Deletes a security group. + /// + /// The security group identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteSecurityGroupAsync(string securityGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteSecurityGroupRequest(securityGroupId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The security group identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteSecurityGroupRequest(string securityGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (securityGroupId == null) + throw new ArgumentNullException("securityGroupId"); + + return Endpoint.PrepareDeleteResourceRequest($"os-security-groups/{securityGroupId}", cancellationToken); + } + + /// + /// Deletes a security group rule. + /// + /// The rule identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteSecurityGroupRuleAsync(string ruleId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteSecurityGroupRuleRequest(ruleId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The rule identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteSecurityGroupRuleRequest(string ruleId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (ruleId == null) + throw new ArgumentNullException("ruleId"); + + return Endpoint.PrepareDeleteResourceRequest($"os-security-group-rules/{ruleId}", cancellationToken); + } + + #endregion + + #region Server Groups + + /// + /// Shows details for a server group. + /// + /// The return type. + /// The server group identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetServerGroupAsync(string serverGroupId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetServerGroupRequest(serverGroupId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server group identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetServerGroupRequest(string serverGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverGroupId == null) + throw new ArgumentNullException("serverGroupId"); + + return Endpoint.PrepareGetResourceRequest($"os-server-groups/{serverGroupId}", cancellationToken); + } + + /// + /// Creates a server group. + /// + /// The return type. + /// The server group. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task CreateServerGroupAsync(object serverGroup, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildCreateServerGroupRequest(serverGroup, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The server group. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildCreateServerGroupRequest(object serverGroup, CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareCreateResourceRequest("os-server-groups", serverGroup, cancellationToken); + } + + /// + /// Lists all server groups for the account. + /// + /// The return type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListServerGroupsAsync(CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListServerGroupsRequest(cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildListServerGroupsRequest(CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareGetResourceRequest("os-server-groups", cancellationToken); + } + + /// + /// Deletes a server group. + /// + /// The server group identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteServerGroupAsync(string serverGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteServerGroupRequest(serverGroupId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The server group identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteServerGroupRequest(string serverGroupId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (serverGroupId == null) + throw new ArgumentNullException("serverGroupId"); + + return Endpoint.PrepareDeleteResourceRequest($"os-server-groups/{serverGroupId}", cancellationToken); + } + + #endregion + + #region Volumes + + /// + /// Shows details for a volume. + /// + /// The return type. + /// The volume identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetVolumeAsync(string volumeId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetVolumeRequest(volumeId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The volume identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetVolumeRequest(string volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + + return Endpoint.PrepareGetResourceRequest($"os-volumes/{volumeId}", cancellationToken); + } + + /// + /// Shows details for a volume snapshot. + /// + /// The return type. + /// The snapshot identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetVolumeSnapshotAsync(string snapshotId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetVolumeSnapshotRequest(snapshotId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The snapshot identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetVolumeSnapshotRequest(string snapshotId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (snapshotId == null) + throw new ArgumentNullException("snapshotId"); + + return Endpoint.PrepareGetResourceRequest($"os-snapshots/{snapshotId}", cancellationToken); + } + + /// + /// Creates a volume. + /// + /// The return type. + /// The volume. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task CreateVolumeAsync(object volume, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildCreateVolumeRequest(volume, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The volume. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildCreateVolumeRequest(object volume, CancellationToken cancellationToken = default(CancellationToken)) + { + if (volume == null) + throw new ArgumentNullException("volume"); + + return Endpoint.PrepareCreateResourceRequest("os-volumes", volume, cancellationToken); + } + + /// + /// Snapshots a volume. + /// + /// The return type. + /// The snapshot. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task SnapshotVolumeAsync(object snapshot, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildSnapshotVolumeRequest(snapshot, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The snapshot. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildSnapshotVolumeRequest(object snapshot, CancellationToken cancellationToken = default(CancellationToken)) + { + if (snapshot == null) + throw new ArgumentNullException("snapshot"); + + return await Endpoint.PrepareCreateResourceRequest("os-snapshots", snapshot, cancellationToken).ConfigureAwait(false); + } + + /// + /// Lists the volumes associated with the account. + /// + /// The return type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListVolumesAsync(CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListVolumesRequest(cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildListVolumesRequest(CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareGetResourceRequest("os-volumes", cancellationToken); + } + + /// + /// Lists volume snapshots. + /// + /// The return type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListVolumeSnapshotsAsync(CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListVolumeSnapshotsRequest(cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildListVolumeSnapshotsRequest(CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareGetResourceRequest("os-snapshots", cancellationToken); + } + + /// + /// Deletes a volume. + /// + /// The volume identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteVolumeAsync(string volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteVolumeRequest(volumeId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The volume identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteVolumeRequest(string volumeId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + + return Endpoint.PrepareDeleteResourceRequest($"os-volumes/{volumeId}", cancellationToken); + } + + /// + /// Deletes a volume snapshot. + /// + /// The snapshot identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteVolumeSnapshotAsync(string snapshotId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteVolumeSnapshotRequest(snapshotId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The snapshot identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// snapshotId + public virtual Task BuildDeleteVolumeSnapshotRequest(string snapshotId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (snapshotId == null) + throw new ArgumentNullException("snapshotId"); + + return Endpoint.PrepareDeleteResourceRequest($"os-snapshots/{snapshotId}", cancellationToken); + } + + /// + /// Waits for the volume to reach the specified status. + /// + /// The volume identifier. + /// The status to wait for. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitForVolumeStatusAsync(string volumeId, TStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TVolume : IServiceResource + where TStatus : ResourceStatus + { + Func> getVolume = async () => await GetVolumeAsync(volumeId, cancellationToken).ConfigureAwait(false); + return await Endpoint.WaitForStatusAsync(volumeId, status, getVolume, refreshDelay, timeout, progress, cancellationToken) + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Waits for the volume snapshot to reach the specified status. + /// + /// The snapshot identifier. + /// The status to wait for. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitForVolumeSnapshotStatusAsync(string snapshotId, TStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TSnapshot : IServiceResource + where TStatus : ResourceStatus + { + Func> getSnapshot = async () => await GetVolumeSnapshotAsync(snapshotId, cancellationToken).ConfigureAwait(false); + return await Endpoint.WaitForStatusAsync(snapshotId, status, getSnapshot, refreshDelay, timeout, progress, cancellationToken) + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Waits for the volume to reach the specified status. + /// + /// The volume identifier. + /// The status to wait for. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitForVolumeStatusAsync(string volumeId, IEnumerable status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TVolume : IServiceResource + where TStatus : ResourceStatus + { + Func> getVolume = async () => await GetVolumeAsync(volumeId, cancellationToken).ConfigureAwait(false); + return await Endpoint.WaitForStatusAsync(volumeId, status, getVolume, refreshDelay, timeout, progress, cancellationToken) + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Waits for the volume snapshot to reach the specified status. + /// + /// The snapshot identifier. + /// The status to wait for. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitForVolumeSnapshotStatusAsync(string snapshotId, IEnumerable status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TSnapshot : IServiceResource + where TStatus : ResourceStatus + { + Func> getSnapshot = async () => await GetVolumeSnapshotAsync(snapshotId, cancellationToken).ConfigureAwait(false); + return await Endpoint.WaitForStatusAsync(snapshotId, status, getSnapshot, refreshDelay, timeout, progress, cancellationToken) + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Waits for the volume to be deleted. + /// Treats a 404 NotFound exception as confirmation that it is deleted. + /// + /// The volume identifier. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public Task WaitUntilVolumeIsDeletedAsync(string volumeId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TVolume : IServiceResource + where TStatus : ResourceStatus + { + Func> getVolume = async () => await GetVolumeAsync(volumeId, cancellationToken).ConfigureAwait(false); + return Endpoint.WaitUntilDeletedAsync(volumeId, getVolume, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// Waits for the volume snapshot to be deleted. + /// Treats a 404 NotFound exception as confirmation that it is deleted. + /// + /// The snapshot identifier. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public Task WaitUntilVolumeSnapshotIsDeletedAsync(string snapshotId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + where TVolume : IServiceResource + where TStatus : ResourceStatus + { + Func> getSnapshot = async () => await GetVolumeSnapshotAsync(snapshotId, cancellationToken).ConfigureAwait(false); + return Endpoint.WaitUntilDeletedAsync(snapshotId, getSnapshot, refreshDelay, timeout, progress, cancellationToken); + } + + #endregion + + #region Compute Service + + /// + /// Shows rate and absolute limits for the account. + /// + /// The return type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task GetLimitsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildGetLimitsRequest(cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + /// Builds the request. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildGetLimitsRequest(CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareGetResourceRequest("limits", cancellationToken); + } + + /// + /// Get current quotas for an account. + /// + /// The return type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task GetCurrentQuotasAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildGetCurrentQuotasRequest(cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + /// Builds the request. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildGetCurrentQuotasRequest(CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareGetResourceRequest("os-quota-sets/detail", cancellationToken); + } + + /// + /// Gets the default quotas for an account. + /// + /// The return type. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task GetDefaultQuotasAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildGetDefaultQuotasRequest(cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + /// Builds the request. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task BuildGetDefaultQuotasRequest(CancellationToken cancellationToken = default(CancellationToken)) + { + return Endpoint.PrepareGetResourceRequest("os-quota-sets/defaults", cancellationToken); + } + + #endregion + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/DiskConfiguration.cs b/src/OpenStack/Compute/v2_1/Serialization/DiskConfiguration.cs new file mode 100644 index 000000000..c4b8f17fc --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/DiskConfiguration.cs @@ -0,0 +1,22 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Controls how the API partitions the disk when you create, rebuild, or resize servers. + /// + /// + public class DiskConfiguration : StringEnumeration + where T : DiskConfiguration, new() + { + /// + /// The API builds the server with a single partition the size of the target flavor disk. The API automatically adjusts the file system to fit the entire partition. + /// + public static readonly T Auto = new T {DisplayName = "AUTO"}; + + /// + /// The API builds the server by using whatever partition scheme and file system is in the source image. If the target flavor disk is larger, the API does not partition the remaining disk space. + /// + public static readonly T Manual = new T {DisplayName = "MANUAL"}; + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/FlavorCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/FlavorCollection.cs new file mode 100644 index 000000000..95235719a --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/FlavorCollection.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of flavor resources of the . + /// + /// + public class FlavorCollection : Page + where TPage : FlavorCollection + where TItem : IServiceResource + { + /// + [JsonProperty("flavors")] + protected IList Flavors => Items; + + /// + [JsonProperty("flavors_links")] + protected IList FlavorLinks => Links; + } + + /// + /// Represents a collection of flavor summary resources of the . + /// + /// + public class FlavorSummaryCollection : FlavorCollection + { } + + /// + /// + public class FlavorCollection : FlavorCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ImageCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/ImageCollection.cs new file mode 100644 index 000000000..d8d3866d3 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ImageCollection.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of image resources of the . + /// + /// + public class ImageCollection : Page + where TPage : ImageCollection + where TItem : IServiceResource + { + /// + [JsonProperty("images")] + protected IList Flavors => Items; + + /// + [JsonProperty("images_links")] + protected IList ServerLinks => Links; + } + + /// + /// Represents a collection of image summary resources of the . + /// + /// + public class ImageSummaryCollection : ImageCollection + { } + + /// + /// + public class ImageCollection : ImageCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ImageType.cs b/src/OpenStack/Compute/v2_1/Serialization/ImageType.cs new file mode 100644 index 000000000..3928356b7 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ImageType.cs @@ -0,0 +1,27 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Server image types. + /// + /// + public class ImageType : StringEnumeration + where T : ImageType, new() + { + /// + /// Base Image + /// + public static readonly T Base = new T{DisplayName = "base"}; + + /// + /// Server Backup + /// + public static readonly T Backup = new T{DisplayName = "backup"}; + + /// + /// Server Snapshot + /// + public static readonly T Snapshot = new T{DisplayName = "snapshot"}; + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/KeyPairCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/KeyPairCollection.cs new file mode 100644 index 000000000..5b98343f7 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/KeyPairCollection.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of keypair resources of the . + /// + /// + public class KeyPairCollection : ResourceCollection + where T : IServiceResource + { + /// + [JsonProperty("keypairs")] + protected IList KeyPairs => Items; + } + + /// + /// Represents a collection of key pair summary resources of the . + /// + /// + public class KeyPairSummaryCollection : KeyPairCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/KeyPairConverter.cs b/src/OpenStack/Compute/v2_1/Serialization/KeyPairConverter.cs new file mode 100644 index 000000000..5811d71ce --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/KeyPairConverter.cs @@ -0,0 +1,50 @@ +using System; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Handles serialization for Compute KeyPairs, which don't follow the usual convention of not wrapping the object when contained in a list. + /// + /// + public class KeyPairConverter : DefaultJsonConverter + { + private readonly string _name = "keypair"; + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + // Wrap + writer.WriteStartObject(); + writer.WritePropertyName(_name); + + // Default serialization + base.WriteJson(writer, value, serializer); + + writer.WriteEndObject(); + } + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + // Skip to the desired property + while (reader.Read()) + { + if (reader.TokenType != JsonToken.PropertyName || reader.Value.ToString() != _name) + continue; + + // Advance to the contained value + reader.Read(); + break; + } + + // Default Deserialization + object result = base.ReadJson(reader, objectType, existingValue, serializer); + + while (reader.Read() && reader.TokenType != JsonToken.EndObject) { } // Advance to end of object + + return result; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Serialization/RebootType.cs b/src/OpenStack/Compute/v2_1/Serialization/RebootType.cs new file mode 100644 index 000000000..379c88de6 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/RebootType.cs @@ -0,0 +1,22 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Server reboot type. + /// + /// + public class RebootType : StringEnumeration + where T : RebootType, new() + { + /// + /// A soft reboot is a graceful shutdown and restart of your server's operating system. + /// + public static readonly T Soft = new T {DisplayName = "SOFT"}; + + /// + /// A hard reboot power cycles your server, which performs an immediate shutdown and restart. + /// + public static readonly T Hard = new T {DisplayName = "HARD"}; + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/RemoteConsoleType.cs b/src/OpenStack/Compute/v2_1/Serialization/RemoteConsoleType.cs new file mode 100644 index 000000000..d7fd616fc --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/RemoteConsoleType.cs @@ -0,0 +1,37 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// The remote console type + /// + /// + public class RemoteConsoleType : StringEnumeration + where T : RemoteConsoleType, new() + { + /// + /// noVNC + /// + public static T NoVnc = new T {DisplayName = "novnc"}; + + /// + /// XVP VNC + /// + public static T XvpVnc = new T {DisplayName = "xvpvnc"}; + + /// + /// RDP + /// + public static T RdpHtml5 = new T {DisplayName = "rdp-html5"}; + + /// + /// Serial + /// + public static T Serial = new T {DisplayName = "serial"}; + + /// + /// Spice HTML5 + /// + public static T SpiceHtml5 = new T {DisplayName = "spice-html5"}; + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/SecurityGroupCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/SecurityGroupCollection.cs new file mode 100644 index 000000000..a37ff860f --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/SecurityGroupCollection.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of security group resources of the . + /// + /// + public class SecurityGroupCollection : ResourceCollection + where T : IServiceResource + { + /// + [JsonProperty("security_groups")] + protected IList SecurityGroups => Items; + } + + /// + /// + public class SecurityGroupCollection : SecurityGroupCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerActionCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerActionCollection.cs new file mode 100644 index 000000000..b88316465 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerActionCollection.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of server actions of the . + /// + /// + public class ServerActionCollection : ResourceCollection + where T : IServiceResource + { + /// + [JsonProperty("instanceActions")] + protected IList Events => Items; + } + + /// + /// Represents a collection of server action summary resources of the . + /// + /// + public class ServerActionSummaryCollection : ServerActionCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerAddressCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerAddressCollection.cs new file mode 100644 index 000000000..74dff1a38 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerAddressCollection.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of server IP address resources of the . + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "addresses")] + public class ServerAddressCollection : Dictionary> + {} + + /// + /// + public class ServerAddressCollection : ServerAddressCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerBlockDeviceType.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerBlockDeviceType.cs new file mode 100644 index 000000000..6a7187e6c --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerBlockDeviceType.cs @@ -0,0 +1,27 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Server block device types. + /// + /// + public class ServerBlockDeviceType : StringEnumeration + where T : ServerBlockDeviceType, new() + { + /// + public static readonly T Blank = new T{DisplayName = "blank"}; + + /// + public static readonly T Snapshot = new T{DisplayName = "snapshot"}; + + /// + public static readonly T Volume = new T{DisplayName = "volume"}; + + /// + public static readonly T Image = new T{DisplayName = "image"}; + + /// + public static readonly T Local = new T{DisplayName = "local"}; + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerCollection.cs new file mode 100644 index 000000000..efc2dff26 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerCollection.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of server resources of the . + /// + /// + public class ServerCollection : Page + where TPage : ServerCollection + where TItem : IServiceResource + { + /// + [JsonProperty("servers")] + protected IList Servers => Items; + + /// + [JsonProperty("servers_links")] + protected IList ServerLinks => Links; + } + + /// + /// Represents a collection of server summary resources of the . + /// + /// + public class ServerSummaryCollection : ServerCollection + { } + + /// + /// + public class ServerCollection : ServerCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerCreateDefinitionConverter.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerCreateDefinitionConverter.cs new file mode 100644 index 000000000..2dff15c54 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerCreateDefinitionConverter.cs @@ -0,0 +1,41 @@ +using System; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Serializes server create requests, which have an odd nesting structure. + /// + /// + public class ServerCreateDefinitionConverter : DefaultJsonConverter + { + /// + public override bool CanRead => false; + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteStartObject(); + // Serialize server + writer.WritePropertyName("server"); + base.WriteJson(writer, value, serializer); + + // Serialize scheduler hints + dynamic server = value; // Using dynamic so that other vendors can use this converter as well + if (server?.SchedulerHints != null) + { + writer.WritePropertyName("os:scheduler_hints"); + base.WriteJson(writer, (object)server.SchedulerHints, serializer); + } + + writer.WriteEndObject(); + } + + /// + public override bool CanConvert(Type objectType) + { + return typeof (ServerCreateDefinition).IsAssignableFrom(objectType); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerEventStatus.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerEventStatus.cs new file mode 100644 index 000000000..3c43fa07d --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerEventStatus.cs @@ -0,0 +1,18 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Server event statuses. + /// + /// + public class ServerEventStatus : ResourceStatus + where T : ServerEventStatus, new() + { + /// + public static readonly T Success = new T {DisplayName = "Success" }; + + /// + public static readonly T Error = new T {DisplayName = "Error", IsError = true}; + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerGroupCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerGroupCollection.cs new file mode 100644 index 000000000..24a5c1237 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerGroupCollection.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of server group resources of the . + /// + /// + public class ServerGroupCollection : ResourceCollection + where T : IServiceResource + { + /// + [JsonProperty("server_groups")] + protected IList ServerGroups => Items; + } + + /// + /// + public class ServerGroupCollection : ServerGroupCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerStatus.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerStatus.cs new file mode 100644 index 000000000..079787529 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerStatus.cs @@ -0,0 +1,103 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Server statuses. + /// + /// + public class ServerStatus : ResourceStatus + where T : ServerStatus, new() + { + /// + /// The server is active. + /// + public static readonly T Active = new T {DisplayName = "ACTIVE"}; + + /// + /// The server has not finished the original build process. + /// + public static readonly T Building = new T {DisplayName = "BUILDING"}; + + /// + /// The server is permanently deleted. + /// + public static readonly T Deleted = new T {DisplayName = "DELETED"}; + + /// + /// The server is in Error. + /// + public static readonly T Error = new T {DisplayName = "ERROR", IsError = true}; + + /// + /// The server is hard rebooting. This is equivalent to pulling the power plug on a physical server, plugging it back in, and rebooting it. + /// + public static readonly T HardReboot = new T {DisplayName = "HARD_REBOOT"}; + + /// + /// The server is being migrated to a new host. + /// + public static readonly T Migrating = new T {DisplayName = "MIGRATING"}; + + /// + /// The Password is being reset on the server. + /// + public static readonly T Password = new T {DisplayName = "PASSWORD"}; + + /// + /// In a Paused state, the state of the server is stored in RAM.A Paused server continues to run in frozen state. + /// + public static readonly T Paused = new T {DisplayName = "PAUSED"}; + + /// + /// The server is in a soft Reboot state. A Reboot command was passed to the operating system. + /// + public static readonly T Reboot = new T {DisplayName = "REBOOT"}; + + /// + /// The server is currently being rebuilt from an image. + /// + public static readonly T Rebuild = new T {DisplayName = "REBUILD"}; + + /// + /// The server is in rescue mode. A rescue image is running with the original server image attached. + /// + public static readonly T Rescue = new T {DisplayName = "RESCUE"}; + + /// + /// Server is performing the differential copy of data that changed during its initial copy. Server is down for this stage. + /// + public static readonly T Resizing = new T {DisplayName = "RESIZED"}; + + /// + /// The resize or migration of a server failed for some reason. The destination server is being cleaned up and the original source server is restarting. + /// + public static readonly T RevertResize = new T {DisplayName = "REVERT_RESIZE"}; + + /// + /// The server is marked as deleted but the disk images are still available to restore. + /// + public static readonly T SoftDeleted = new T {DisplayName = "SOFT_DELETED"}; + + /// + /// The server is powered off and the disk image still persists. + /// + public static readonly T Stopped = new T {DisplayName = "SHUTOFF"}; + + /// + /// The server is suspended, either by request or necessity. + /// + public static readonly T Suspended = new T {DisplayName = "SUSPENDED"}; + + /// + /// The state of the server is unknown.Contact your cloud provider. + /// + public static readonly T Unknown = new T {DisplayName = "UNKNOWN"}; + + /// + /// System is awaiting confirmation that the server is operational after a move or resize. + /// + public static readonly T VerifyResize = new T {DisplayName = "VERIFY_RESIZE"}; + + } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/ServerVolumeCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/ServerVolumeCollection.cs new file mode 100644 index 000000000..d485294a7 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/ServerVolumeCollection.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of server volume resources of the . + /// + /// + public class ServerVolumeCollection : ResourceCollection + where T : IServiceResource + { + /// + [JsonProperty("volumeAttachments")] + protected IList Volumes => Items; + } + + /// + /// Represents a collection of references to server volume resources of the . + /// + /// + public class ServerVolumeCollection : ServerVolumeCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/VolumeCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/VolumeCollection.cs new file mode 100644 index 000000000..5d105b9ff --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/VolumeCollection.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of volume resources of the . + /// + /// + public class VolumeCollection : ResourceCollection + where T : IServiceResource + { + /// + [JsonProperty("volumes")] + protected IList Volumes => Items; + } + + /// + /// Represents a collection of volume resources of the . + /// + /// + public class VolumeCollection : VolumeCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Serialization/VolumeSnapshotCollection.cs b/src/OpenStack/Compute/v2_1/Serialization/VolumeSnapshotCollection.cs new file mode 100644 index 000000000..6ed8e7507 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Serialization/VolumeSnapshotCollection.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1.Serialization +{ + /// + /// Represents a collection of volume snapshot resources of the . + /// + /// + public class VolumeSnapshotCollection : ResourceCollection + { + /// + [JsonProperty("snapshots")] + protected IList VolumeSnapshots => Items; + } + + /// + /// Represents a collection of volume snapshot resources of the . + /// + /// + public class VolumeSnapshotCollection : VolumeSnapshotCollection + { } +} diff --git a/src/OpenStack/Compute/v2_1/Server.cs b/src/OpenStack/Compute/v2_1/Server.cs new file mode 100644 index 000000000..c10b60b13 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Server.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections.Generic; +using System.Extensions; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// A virtual machine (VM) instance running on a host. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "server")] + public class Server : ServerSummary + { + /// + /// Initializes a new instance of the class. + /// + public Server() + { + Addresses = new Dictionary>(); + AttachedVolumes = new List(); + Metadata = new ServerMetadata(); + SecurityGroups = new List(); + } + + private string _adminPassword; + + /// + /// The IP addresses for the server. + /// + [JsonProperty("addresses")] + public IDictionary> Addresses { get; set; } + + /// + /// The flavor for the server instance. + /// + [JsonProperty("flavor")] + public FlavorReference Flavor { get; set; } + + /// + /// The date and time when the resource was created. + /// + [JsonProperty("created")] + public DateTimeOffset? Created { get; set; } + + /// + /// The image for the server instance. + /// + [JsonProperty("image")] + public ImageReference Image { get; set; } + + /// + /// The administrative password. + /// The password is only available immediately after creating the server, and otherwise is empty. + /// + [JsonProperty("adminPass")] + public string AdminPassword + { + get { return _adminPassword; } + set + { + // This is only set once, then never again. Capture it for safekeeping + _adminPassword = value ?? _adminPassword; + } + } + + /// + /// The name of associated key pair, if any. + /// + [JsonProperty("key_name")] + public string KeyPairName { get; set; } + + /// + /// The associated metadata key and value pairs. + /// + [JsonProperty("metadata")] + public ServerMetadata Metadata { get; set; } + + /// + /// The server v4 IP address. + /// + [JsonProperty("accessIPv4")] + public string IPv4Address { get; set; } + + /// + /// The server v6 IP address. + /// + [JsonProperty("accessIPv6")] + public string IPv6Address { get; set; } + + /// + /// The host identifier. + /// + [JsonProperty("hostId")] + public Identifier HostId { get; set; } + + /// + /// The server disk configuration. + /// + [JsonProperty("OS-DCF:diskConfig")] + public DiskConfiguration DiskConfig { get; set; } + + /// + /// The availability zone in which the server is located. + /// + [JsonProperty("OS-EXT-AZ:availability_zone")] + public string AvailabilityZone { get; set; } + + // TODO: These are operator only. If only we had extension properties... (https://github.com/dotnet/roslyn/issues/112) Need to figure out how to handle stuff like this. + //[JsonProperty("OS-EXT-SRV-ATTR:host")] + //public string HostName { get; set; } + //[JsonProperty("OS-EXT-SRV-ATTR:hypervisor_hostname")] + //public string HypervisorHostName { get; set; } + //[JsonProperty("OS-EXT-SRV-ATTR:instance_name")] + //public string InstanceName { get; set; } + + /// + /// The power state of the server. + /// + [JsonProperty("OS-EXT-STS:power_state")] + public string PowerState { get; set; } + + /// + /// The task state of the server. + /// + [JsonProperty("OS-EXT-STS:task_state")] + public string TaskState { get; set; } + + /// + /// The underlying VM state. + /// + [JsonProperty("OS-EXT-STS:vm_state")] + public string VMState { get; set; } + + /// + /// The date and time when the server was launched. + /// + [JsonProperty("OS-SRV-USG:launched_at")] + public DateTimeOffset? Launched { get; set; } + + /// + /// The date and time when the server was deleted. + /// + [JsonProperty("OS-SRV-USG:terminated_at")] + public DateTimeOffset? Deleted { get; set; } + + /// + /// A percentage value of the build progress. + /// + [JsonProperty("progress")] + public int Progress { get; set; } + + /// + /// The attached volumes, if any. + /// + [JsonProperty("os-extended-volumes:volumes_attached")] + public IList AttachedVolumes { get; set; } + + /// + /// Associated security groups. + /// + [JsonProperty("security_groups")] + public IList SecurityGroups { get; set; } + + /// + /// The server status. + /// + [JsonProperty("status")] + public ServerStatus Status { get; set; } + + /// + /// The date and time when the resource was updated. + /// + [JsonProperty("updated")] + public DateTimeOffset? LastModified { get; set; } + + /// + /// Waits the until the server is active. + /// + /// The refresh delay. + /// The timeout. + /// The progress. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task WaitUntilActiveAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return WaitForStatusAsync(ServerStatus.Active, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public override async Task WaitUntilDeletedAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + await base.WaitUntilDeletedAsync(refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + Status = ServerStatus.Deleted; + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task WaitForStatusAsync(ServerStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + var result = await owner.WaitForServerStatusAsync(Id, status, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task WaitForStatusAsync(IEnumerable status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + var result = await owner.WaitForServerStatusAsync(Id, status, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task UpdateAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + var request = new ServerUpdateDefinition(); + this.CopyProperties(request); + + var result = await compute.UpdateServerAsync(Id, request, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task AttachVolumeAsync(ServerVolumeDefinition volume, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + var result = await compute.AttachVolumeAsync(Id, volume, cancellationToken).ConfigureAwait(false); + AttachedVolumes.Add(result); + ((IChildResource)result).SetParent(this); + return result; + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public virtual async Task AssociateFloatingIPAsync(AssociateFloatingIPRequest request, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + await compute.AssociateFloatingIPAsync(Id, request, cancellationToken); + + Addresses = await compute.ListServerAddressesAsync(Id, cancellationToken); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public virtual async Task DisassociateFloatingIPAsync(string floatingIPAddress, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + await compute.DisassociateFloatingIPAsync(Id, floatingIPAddress, cancellationToken); + + // Remove the address from the current instance immediately + foreach (KeyValuePair> group in Addresses) + { + foreach (ServerAddress address in group.Value) + { + if (address.Type == AddressType.Floating && address.IP == floatingIPAddress) + { + Addresses[group.Key].Remove(address); + return; + } + } + } + } + + /// + [OnDeserialized] + private void OnDeserializedMethod(StreamingContext context) + { + Metadata.SetParent(this); + foreach (var volume in AttachedVolumes) + { + volume.SetParent(this); + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerAction.cs b/src/OpenStack/Compute/v2_1/ServerAction.cs new file mode 100644 index 000000000..2f704e8b2 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerAction.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// A record of an action applied to a server. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "instanceAction")] + public class ServerAction : ServerActionSummary + { + /// + /// Initializes a new instance of the class. + /// + public ServerAction() + { + Events = new List(); + } + + /// + [JsonProperty("events")] + public IList Events { get; set; } + } + + /// + /// A record of an event triggered during a server action. + /// + /// + public class ServerEvent : IHaveExtraData + { + /// + /// The event name. + /// + [JsonProperty("event")] + public string Name { get; set; } + + /// + /// The resulting event status. + /// + [JsonProperty("result")] + public ServerEventStatus Result { get; set; } + + /// + /// The event start time. + /// + [JsonProperty("start_time")] + public DateTimeOffset Started { get; set; } + + /// + /// The event completion time. + /// + [JsonProperty("finish_time")] + public DateTimeOffset? Finished { get; set; } + + /// + /// Additional error information, if any. + /// + [JsonProperty("traceback")] + public string StackTrace { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerActionExtensions.cs b/src/OpenStack/Compute/v2_1/ServerActionExtensions.cs new file mode 100644 index 000000000..52ab4831e --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerActionExtensions.cs @@ -0,0 +1,18 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ServerActionExtensions_v2_1 + { + /// + public static ServerAction GetAction(this ServerActionSummary action) + { + return action.GetActionAsync().ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/ServerActionSummary.cs b/src/OpenStack/Compute/v2_1/ServerActionSummary.cs new file mode 100644 index 000000000..fd5c98b84 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerActionSummary.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Summary informationm for a server action. + /// + public class ServerActionSummary : IHaveExtraData, IServiceResource + { + /// + /// The action identifier. + /// + [JsonProperty("request_id")] + public Identifier Id { get; set; } + + /// + /// The server identifier. + /// + [JsonProperty("instance_uuid")] + public Identifier ServerId { get; set; } + + /// + /// The action name. + /// + [JsonProperty("action")] + public string Name { get; set; } + + /// + /// The action output message. + /// + [JsonProperty("message")] + public string Message { get; set; } + + /// + /// The identifier of the user who performed the action. + /// + [JsonProperty("user_id")] + public Identifier UserId { get; set; } + + /// + /// The action start time. + /// + [JsonProperty("start_time")] + public DateTimeOffset Started { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task GetActionAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return compute.GetServerActionAsync(ServerId, Id, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerAddress.cs b/src/OpenStack/Compute/v2_1/ServerAddress.cs new file mode 100644 index 000000000..3c6d346ed --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerAddress.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Networking; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// An IP address associated with a server. + /// + public class ServerAddress : IHaveExtraData + { + /// + /// The IP address. + /// + [JsonProperty("addr")] + public string IP { get; set; } + + /// + /// The IP version, e.g. v4 or v6. + /// + [JsonProperty("version")] + public IPVersion Version { get; set; } + + /// + /// The MAC address. + /// + [JsonProperty("OS-EXT-IPS-MAC:mac_addr")] + public string MAC { get; set; } + + /// + /// The IP address type, e.g. fixed or floating. + /// + [JsonProperty("OS-EXT-IPS:type")] + public AddressType Type { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerBlockDeviceMapping.cs b/src/OpenStack/Compute/v2_1/ServerBlockDeviceMapping.cs new file mode 100644 index 000000000..f00add310 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerBlockDeviceMapping.cs @@ -0,0 +1,62 @@ +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines how to boot a server from a volume. + /// + /// + /// If you specify the volume status, you must set it to available. In the OpenStack Block Storage database, the volume attach_status must be detached. + /// + public class ServerBlockDeviceMapping + { + /// + /// Defines the order in which a hypervisor tries devices when it attempts to boot the guest from storage. + /// + [JsonProperty("boot_index", DefaultValueHandling = DefaultValueHandling.Include)] + public int BootIndex { get; set; } + + /// + /// A path to the device for the volume that you want to use to boot the server. + /// + [JsonProperty("device_name")] + public string DeviceName { get; set; } + + /// + /// The identifier of the source block device. + /// + [JsonProperty("uuid")] + public Identifier SourceId { get; set; } + + /// + /// The source type of the volume. + /// + [JsonProperty("source_type")] + public ServerBlockDeviceType SourceType { get; set; } + + /// + /// The source type of the volume. + /// + [JsonProperty("destination_type")] + public ServerBlockDeviceType DestinationType { get; set; } + + /// + /// The size of the destination volume, in GB. + /// + [JsonProperty("volume_size")] + public int? DestinationVolumeSize { get; set; } + + /// + /// Specifies if the volume should be deleted when the server is deleted. + /// + [JsonProperty("delete_on_termination")] + public bool DeleteWithServer { get; set; } + + /// + /// Specifies how/if to format the device prior to attaching, and should be only used with blank local images. + /// Denotes a swap disk if the value is swap. + /// + [JsonProperty("guest_format")] + public string GuestFormat { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerBlockDeviceType.cs b/src/OpenStack/Compute/v2_1/ServerBlockDeviceType.cs new file mode 100644 index 000000000..33eebc9bb --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerBlockDeviceType.cs @@ -0,0 +1,8 @@ +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + public class ServerBlockDeviceType : ServerBlockDeviceType + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerCreateDefinition.cs b/src/OpenStack/Compute/v2_1/ServerCreateDefinition.cs new file mode 100644 index 000000000..76365f967 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerCreateDefinition.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security; +using Newtonsoft.Json; +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines a new server instance. + /// + [JsonConverter(typeof(ServerCreateDefinitionConverter))] + public class ServerCreateDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// The server name. + /// The image identifier. + /// The flavor identifier. + public ServerCreateDefinition(string name, Identifier imageId, Identifier flavorId) + { + Name = name; + ImageId = imageId; + FlavorId = flavorId; + SecurityGroups = new List(); + Networks = new List(); + Metadata = new Dictionary(); + Personality = new List(); + BlockDeviceMapping = new List(); + } + + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("imageRef")] + public Identifier ImageId { get; set; } + + /// + [JsonProperty("flavorRef")] + public Identifier FlavorId { get; set; } + + /// + [JsonProperty("security_groups")] + public IList SecurityGroups { get; set; } + + /// + [JsonProperty("availability_zone")] + public string AvailabilityZone { get; set; } + + /// + /// Configuration information or scripts to use upon launch. Must be Base64 encoded. + /// + [JsonProperty("user_data")] + public string UserData { get; set; } + + /// + /// Specifies the networks to which the server should be attached. + /// + [JsonProperty("networks")] + public IList Networks { get; set; } + + /// + [JsonProperty("metadata")] + public IDictionary Metadata { get; set; } + + /// + /// The file path and contents, text only, to inject into the server at launch. + /// The maximum size of the file path data is 255 bytes. + /// The maximum limit is The number of allowed bytes in the decoded, rather than encoded, data. + /// + [JsonProperty("personality")] + public IList Personality { get; set; } + + /// + /// Enables you to boot a server from a volume. + /// + [JsonProperty("block_device_mapping_v2")] + public IList BlockDeviceMapping { get; set; } + + /// + /// Indicates whether a configuration drive enables metadata injection. + /// + [JsonProperty("config_drive")] + public bool ShouldUseConfigurationDrive { get; set; } + + /// + [JsonProperty("key_name")] + public string KeyPairName { get; set; } + + /// + /// Specifies hints for the compute scheduler. + /// + [JsonIgnore] // Serialized at the same level as "server" + public SchedulerHints SchedulerHints { get; set; } + + /// + [JsonProperty("OS-DCF:diskConfig")] + public DiskConfiguration DiskConfig { get; set; } + + /// + /// Load the UserData from the specified file path. + /// + /// The user data file path. + /// The specified path is invalid (for example, it is on an unmapped drive). + /// An I/O error occurred while opening the file. + /// This operation is not supported on the current platform.-or- specified a directory.-or- The caller does not have the required permission. + /// The file specified in was not found. + /// The caller does not have the required permission. + public void LoadUserDataFromFile(string path) + { + byte[] contents = File.ReadAllBytes(path); + UserData = Convert.ToBase64String(contents); + } + + /// + /// Configures the server to boot from an existing volume. + /// + /// The volume identifier. + /// if set to true [delete volume with server]. + public void ConfigureBootFromVolume(Identifier volumeId, bool deleteVolumeWithServer = false) + { + BlockDeviceMapping.Add(new ServerBlockDeviceMapping + { + SourceType = ServerBlockDeviceType.Volume, + SourceId = volumeId, + BootIndex = 0, + DeleteWithServer = deleteVolumeWithServer + }); + } + + /// + /// Configures the server to boot from a copy of an existing volume. + /// + /// The volume identifier. + /// Size of the volume. + /// if set to true [delete volume with server]. + public void ConfigureBootFromNewVolume(Identifier volumeId, int volumeSize, bool deleteVolumeWithServer = false) + { + BlockDeviceMapping.Add(new ServerBlockDeviceMapping + { + SourceType = ServerBlockDeviceType.Volume, + SourceId = volumeId, + BootIndex = 0, + DestinationType = ServerBlockDeviceType.Volume, + DestinationVolumeSize = volumeSize, + DeleteWithServer = deleteVolumeWithServer + }); + } + + /// + /// Configures the server to boot from a new volume, copied from the base server image. + /// + /// Size of the volume. + /// if set to true [delete volume with server]. + public void ConfigureBootFromNewVolume(int volumeSize, bool deleteVolumeWithServer = false) + { + BlockDeviceMapping.Add(new ServerBlockDeviceMapping + { + SourceType = ServerBlockDeviceType.Image, + SourceId = ImageId, + BootIndex = 0, + DestinationType = ServerBlockDeviceType.Volume, + DestinationVolumeSize = volumeSize, + DeleteWithServer = deleteVolumeWithServer + }); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerEventStatus.cs b/src/OpenStack/Compute/v2_1/ServerEventStatus.cs new file mode 100644 index 000000000..434dfb4da --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerEventStatus.cs @@ -0,0 +1,8 @@ +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + public class ServerEventStatus : ServerEventStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerExtensions.cs b/src/OpenStack/Compute/v2_1/ServerExtensions.cs new file mode 100644 index 000000000..c259a4409 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerExtensions.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ServerExtensions_v2_1 + { + /// + public static Server GetServer(this ServerReference server) + { + return server.GetServerAsync().ForceSynchronous(); + } + + /// + public static IList GetAddress(this ServerReference server, string key) + { + return server.GetAddressAsync(key).ForceSynchronous(); + } + + /// + public static ServerMetadata GetMetadata(this ServerReference server) + { + return server.GetMetadataAsync().ForceSynchronous(); + } + + /// + public static string GetMetadataItem(this ServerReference server, string key) + { + return server.GetMetadataItemAsync(key).ForceSynchronous(); + } + + /// + public static IDictionary> ListAddresses(this ServerReference server) + { + return server.ListAddressesAsync().ForceSynchronous(); + } + + /// + public static void WaitForStatus(this Server server, ServerStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + server.WaitForStatusAsync(status, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void WaitForStatus(this Server server, IEnumerable status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + server.WaitForStatusAsync(status, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void WaitUntilActive(this Server server, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + server.WaitUntilActiveAsync(refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void WaitUntilDeleted(this Server server, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + server.WaitUntilDeletedAsync(refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void Update(this Server server) + { + server.UpdateAsync().ForceSynchronous(); + } + + /// + public static void Delete(this Server server) + { + server.DeleteAsync().ForceSynchronous(); + } + + /// + public static Image Snapshot(this ServerReference server, SnapshotServerRequest request) + { + return server.SnapshotAsync(request).ForceSynchronous(); + } + + /// + public static void Start(this ServerReference server) + { + server.StartAsync().ForceSynchronous(); + } + + /// + public static void Stop(this ServerReference server) + { + server.StopAsync().ForceSynchronous(); + } + + /// + public static void Suspend(this ServerReference server) + { + server.SuspendAsync().ForceSynchronous(); + } + + /// + public static void Resume(this ServerReference server) + { + server.ResumeAsync().ForceSynchronous(); + } + + /// + public static void Reboot(this ServerReference server, RebootServerRequest request = null) + { + server.RebootAsync(request).ForceSynchronous(); + } + + /// + public static ServerVolume AttachVolume(this Server server, ServerVolumeDefinition volume) + { + return server.AttachVolumeAsync(volume).ForceSynchronous(); + } + + /// + public static IEnumerable ListVolumes(this ServerReference server) + { + return server.ListVolumesAsync().ForceSynchronous(); + } + + /// + public static RemoteConsole GetVncConsole(this ServerReference server, RemoteConsoleType type) + { + return server.GetVncConsoleAsync(type).ForceSynchronous(); + } + + /// + public static RemoteConsole GetSpiceConsole(this ServerReference server) + { + return server.GetSpiceConsoleAsync().ForceSynchronous(); + } + + /// + public static RemoteConsole GetSerialConsole(this ServerReference server) + { + return server.GetSerialConsoleAsync().ForceSynchronous(); + } + + /// + public static RemoteConsole GetRdpConsole(this ServerReference server) + { + return server.GetRdpConsoleAsync().ForceSynchronous(); + } + + /// + public static string GetConsoleOutput(this ServerReference server, int length = -1) + { + return server.GetConsoleOutputAsync(length).ForceSynchronous(); + } + + /// + public static string Rescue(this ServerReference server, RescueServerRequest request = null) + { + return server.RescueAsync(request).ForceSynchronous(); + } + + /// + public static void Unrescue(this ServerReference server) + { + server.UnrescueAsync().ForceSynchronous(); + } + + /// + public static void Resize(this ServerReference server, Identifier flavorId) + { + server.ResizeAsync(flavorId).ForceSynchronous(); + } + + /// + public static void ConfirmResize(this ServerReference server) + { + server.ConfirmResizeAsync().ForceSynchronous(); + } + + /// + public static void CancelResize(this ServerReference server) + { + server.CancelResizeAsync().ForceSynchronous(); + } + + /// + public static void AssociateFloatingIP(this Server server, AssociateFloatingIPRequest request) + { + server.AssociateFloatingIPAsync(request).ForceSynchronous(); + } + + /// + public static void DisassociateFloatingIP(this Server server, string floatingIPAddress) + { + server.DisassociateFloatingIPAsync(floatingIPAddress).ForceSynchronous(); + } + + /// + public static IEnumerable ListActionSummaries(this ServerReference server) + { + return server.ListActionSummariesAsync().ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/ServerGroup.cs b/src/OpenStack/Compute/v2_1/ServerGroup.cs new file mode 100644 index 000000000..b10eb90a7 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerGroup.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// A set of server instances used to apply common policies. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "server_group")] + public class ServerGroup : IHaveExtraData, IServiceResource + { + /// + /// Initializes a new instance of the class. + /// + public ServerGroup() + { + Policies = new List(); + } + + /// + /// The server group identitifer. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The server group name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// A list of one or more policy names to associate with the server group. + /// + [JsonProperty("policies")] + public IList Policies { get; set; } + + /// + /// The servers included in the group. + /// + [JsonProperty("members")] + public IList Members { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + public Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.DeleteServerGroupAsync(Id, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerGroupDefinition.cs b/src/OpenStack/Compute/v2_1/ServerGroupDefinition.cs new file mode 100644 index 000000000..4edec9930 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerGroupDefinition.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines a new server group. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "server_group")] + public class ServerGroupDefinition + { + /// + /// Initializes a new instance of the class. + /// + public ServerGroupDefinition(string name, params string[] policies) + { + Name = name; + Policies = new List(policies); + } + + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("policies")] + public IList Policies { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerGroupExtensions.cs b/src/OpenStack/Compute/v2_1/ServerGroupExtensions.cs new file mode 100644 index 000000000..614e6c436 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerGroupExtensions.cs @@ -0,0 +1,18 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ServerGroupExtensions_v2_1 + { + /// + public static void Delete(this ServerGroup group) + { + group.DeleteAsync().ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/ServerListOptions.cs b/src/OpenStack/Compute/v2_1/ServerListOptions.cs new file mode 100644 index 000000000..99db0ac06 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerListOptions.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Optional filter and paging options when listing servers. + /// + public class ServerListOptions : PageOptions + { + /// + /// Initializes a new instance of the class. + /// + public ServerListOptions() + { + Metadata = new Dictionary(); + } + + /// + /// Filter by a date and time stamp when the server last changed status. + /// + public DateTimeOffset? UpdatedAfter { get; set; } + + /// + /// Filter by an image. + /// + public Identifier ImageId { get; set; } + + /// + /// Filter by a flavor. + /// + public string FlavorId { get; set; } + + /// + /// Filter by a server name. + /// You can use regular expressions in the query. For example, the ?name=bob regular expression returns both bob and bobb. + /// + public string Name { get; set; } + + /// + /// Filter by a server status. + /// + public ServerStatus Status { get; set; } + + /// + /// Filter by associated server metadata. + /// + public IDictionary Metadata { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + var queryString = base.BuildQueryString(); + queryString["changes-since"] = UpdatedAfter?.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"); + queryString["image"] = ImageId; + queryString["flavor"] = FlavorId; + queryString["name"] = Name; + queryString["status"] = Status; + queryString["metadata"] = Metadata; + + return queryString; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerMetadata.cs b/src/OpenStack/Compute/v2_1/ServerMetadata.cs new file mode 100644 index 000000000..f6275a391 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerMetadata.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Key value pairs associated with a server instance. + /// + [JsonConverterWithConstructor(typeof (RootWrapperConverter), "metadata")] + public class ServerMetadata : Dictionary, IHaveExtraData, IChildResource + { + /// + /// The associated server. + /// + [JsonIgnore] + protected ServerReference Server { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + protected internal void SetParent(ServerReference parent) + { + Server = parent; + } + + void IChildResource.SetParent(string parentId) + { + SetParent(new ServerReference {Id = parentId}); + } + + void IChildResource.SetParent(object parent) + { + SetParent((ServerReference)parent); + } + + /// + protected void AssertParentIsSet([CallerMemberName]string callerName = "") + { + if (Server != null) + return; + + throw new InvalidOperationException(string.Format($"{callerName} can only be used on instances which were constructed by the ComputeService. Use ComputeService.{callerName} instead.")); + } + + /// + public async Task CreateAsync(string key, string value, CancellationToken cancellationToken = default(CancellationToken)) + { + AssertParentIsSet(); + var compute = this.GetOwnerOrThrow(); + await compute.CreateServerMetadataAsync(Server.Id, key, value, cancellationToken).ConfigureAwait(false); + this[key] = value; + } + + /// + public async Task UpdateAsync(bool overwrite = false, CancellationToken cancellationToken = default(CancellationToken)) + { + AssertParentIsSet(); + var compute = this.GetOwnerOrThrow(); + var results = await compute.UpdateServerMetadataAsync(Server.Id, this, overwrite, cancellationToken).ConfigureAwait(false); + Clear(); + foreach (var result in results) + { + Add(result.Key, result.Value); + } + } + + /// + public async Task DeleteAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) + { + if (!ContainsKey(key)) + return; + + AssertParentIsSet(); + var compute = this.GetOwnerOrThrow(); + await compute.DeleteServerMetadataAsync(Server.Id, key, cancellationToken).ConfigureAwait(false); + Remove(key); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerMetadataExtensions.cs b/src/OpenStack/Compute/v2_1/ServerMetadataExtensions.cs new file mode 100644 index 000000000..9f9b69f00 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerMetadataExtensions.cs @@ -0,0 +1,30 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ServerMetadataExtensions_v2_1 + { + /// + public static void Create(this ServerMetadata metadata, string key, string value) + { + metadata.CreateAsync(key, value).ForceSynchronous(); + } + + /// + public static void Update(this ServerMetadata metadata, bool overwrite = false) + { + metadata.UpdateAsync(overwrite).ForceSynchronous(); + } + + /// + public static void Delete(this ServerMetadata metadata, string key) + { + metadata.DeleteAsync(key).ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/ServerNetworkDefinition.cs b/src/OpenStack/Compute/v2_1/ServerNetworkDefinition.cs new file mode 100644 index 000000000..2ed8f316c --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerNetworkDefinition.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines additional networks to which a server should be attached. + /// + public class ServerNetworkDefinition + { + /// + /// Provisions a server with a NIC for the specified network. Required if you omit . + /// + [JsonProperty("uuid")] + public Identifier NetworkId { get; set; } + + /// + /// Provisions a server with a NIC for the specified port. Required if you omit . + /// + [JsonProperty("port")] + public Identifier PortId { get; set; } + + /// + /// A fixed IPv4 address for the NIC. + /// + [JsonProperty("fixed_ip")] + public string IPAddress { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerReference.cs b/src/OpenStack/Compute/v2_1/ServerReference.cs new file mode 100644 index 000000000..e52cd98b5 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerReference.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Reference to a server instance. + /// + public class ServerReference : IHaveExtraData, IServiceResource + { + /// + /// The server identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + public async Task GetServerAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.GetServerAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// + public async Task> GetAddressAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.GetServerAddressAsync(Id, key, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task GetMetadataAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.GetServerMetadataAsync(Id, cancellationToken); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task GetMetadataItemAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.GetServerMetadataItemAsync(Id, key, cancellationToken); + } + + /// + public async Task>> ListAddressesAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.ListServerAddressesAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.DeleteServerAsync(Id, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public virtual async Task WaitUntilDeletedAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + await owner.WaitUntilServerIsDeletedAsync(Id, null, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task SnapshotAsync(SnapshotServerRequest request, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.SnapshotServerAsync(Id, request, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task StartAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + await compute.StartServerAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + await compute.StopServerAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task SuspendAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + await compute.SuspendServerAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task ResumeAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + await compute.ResumeServerAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task RebootAsync(RebootServerRequest request = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + await compute.RebootServerAsync(Id, request, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task> ListVolumesAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.ListServerVolumesAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task GetVncConsoleAsync(RemoteConsoleType type, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.GetVncConsoleAsync(Id, type, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task GetSpiceConsoleAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.GetSpiceConsoleAsync(Id,RemoteConsoleType.SpiceHtml5, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task GetSerialConsoleAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.GetSerialConsoleAsync(Id, RemoteConsoleType.Serial, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task GetRdpConsoleAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.GetRdpConsoleAsync(Id, RemoteConsoleType.RdpHtml5, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task GetConsoleOutputAsync(int length = -1, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.GetConsoleOutputAsync(Id, length, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task RescueAsync(RescueServerRequest request = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.RescueServerAsync(Id, request, cancellationToken).ConfigureAwait(false); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task UnrescueAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return compute.UnrescueServerAsync(Id, cancellationToken); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task ResizeAsync(Identifier flavorId, CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return compute.ResizeServerAsync(Id, flavorId, cancellationToken); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task ConfirmResizeAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return compute.ConfirmResizeServerAsync(Id, cancellationToken); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task CancelResizeAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return compute.CancelResizeServerAsync(Id, cancellationToken); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task> ListActionSummariesAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var compute = this.GetOwnerOrThrow(); + return await compute.ListServerActionSummariesAsync(Id, cancellationToken).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerStatus.cs b/src/OpenStack/Compute/v2_1/ServerStatus.cs new file mode 100644 index 000000000..b037b24fd --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerStatus.cs @@ -0,0 +1,8 @@ +using OpenStack.Compute.v2_1.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + public class ServerStatus : ServerStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerSummary.cs b/src/OpenStack/Compute/v2_1/ServerSummary.cs new file mode 100644 index 000000000..1307094b9 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerSummary.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Summary information for a server instance. + /// + public class ServerSummary : ServerReference + { + /// + /// The server name. + /// + [JsonProperty("name")] + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerUpdateDefinition.cs b/src/OpenStack/Compute/v2_1/ServerUpdateDefinition.cs new file mode 100644 index 000000000..998bd2c96 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerUpdateDefinition.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines a set of fields to update on a server. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "server")] + public class ServerUpdateDefinition + { + private string _ipv4Address; + private string _ipv6Address; + + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("accessIPv4")] + public string IPv4Address + { + get { return _ipv4Address; } + set + { + // Nova returns "" when the value isn't set, which is causing us to serialize this propety during updates, when we really shouldn't + _ipv4Address = !string.IsNullOrEmpty(value) ? value : null; + } + } + + /// + [JsonProperty("accessIPv6")] + public string IPv6Address + { + get { return _ipv6Address; } + set + { + // Nova returns "" when the value isn't set, which is causing us to serialize this propety during updates, when we really shouldn't + _ipv6Address = !string.IsNullOrEmpty(value) ? value : null; + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerVolume.cs b/src/OpenStack/Compute/v2_1/ServerVolume.cs new file mode 100644 index 000000000..a37b66b9d --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerVolume.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Represents a volume attached to a server. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "volumeAttachment")] + public class ServerVolume : ServerVolumeReference + { + private Identifier _serverId; + + /// + /// A path to the device for the volume attached to the server. + /// + [JsonProperty("device")] + public string DeviceName { get; set; } + + /// + /// The server identifier. + /// + [JsonProperty("serverId")] + public Identifier ServerId + { + get { return _serverId; } + set + { + _serverId = value; + ((IChildResource)this).SetParent(_serverId); + } + } + + /// + /// The volume identifier. + /// + [JsonProperty("volumeId")] + public Identifier VolumeId { get; set; } + } +} diff --git a/src/OpenStack/Compute/v2_1/ServerVolumeDefinition.cs b/src/OpenStack/Compute/v2_1/ServerVolumeDefinition.cs new file mode 100644 index 000000000..bccd245b8 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerVolumeDefinition.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines how to attach a volume to a server. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "volumeAttachment")] + public class ServerVolumeDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// The volume identifier. + public ServerVolumeDefinition(Identifier volumeId) + { + VolumeId = volumeId; + } + + /// + [JsonProperty("device")] + public string DeviceName { get; set; } + + /// + [JsonProperty("volumeId")] + public Identifier VolumeId { get; set; } + } +} diff --git a/src/OpenStack/Compute/v2_1/ServerVolumeExtensions.cs b/src/OpenStack/Compute/v2_1/ServerVolumeExtensions.cs new file mode 100644 index 000000000..1de5ca724 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerVolumeExtensions.cs @@ -0,0 +1,23 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ServerVolumeExtensions + { + /// + public static ServerVolume GetServerVolume(this ServerVolumeReference volume) + { + return volume.GetServerVolumeAsync().ForceSynchronous(); + } + + /// + public static void Detach(this ServerVolumeReference volume) + { + volume.DetachAsync().ForceSynchronous(); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServerVolumeReference.cs b/src/OpenStack/Compute/v2_1/ServerVolumeReference.cs new file mode 100644 index 000000000..82cb1b075 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServerVolumeReference.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Reference to a volume attachment to a server. + /// + public class ServerVolumeReference : IHaveExtraData, IChildResource + { + /// + /// The associated server. + /// + [JsonIgnore] + protected ServerReference ServerRef { get; set; } + + /// + /// The attachment identifier. + /// + public Identifier Id { get; set; } + + object IServiceResource.Owner { get; set; } + + /// + protected internal void SetParent(ServerReference parent) + { + ServerRef = parent; + } + + void IChildResource.SetParent(object parent) + { + SetParent((ServerReference)parent); + } + + void IChildResource.SetParent(string parentId) + { + SetParent(new ServerReference {Id = parentId}); + } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + /// + protected void AssertParentIsSet([CallerMemberName]string callerName = "") + { + if (ServerRef != null) + return; + + throw new InvalidOperationException(string.Format($"{callerName} can only be used on instances which were constructed by the ComputeService. Use ComputeService.{callerName} instead.")); + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task GetServerVolumeAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + AssertParentIsSet(); + + var compute = this.GetOwnerOrThrow(); + var result = await compute.GetServerVolumeAsync(ServerRef.Id, Id, cancellationToken).ConfigureAwait(false); + result.ServerRef = ServerRef; + return result; + } + + /// + /// When this instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task DetachAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + AssertParentIsSet(); + + var compute = this.GetOwnerOrThrow(); + await compute.DetachVolumeAsync(ServerRef.Id, Id, cancellationToken).ConfigureAwait(false); + + var server = ServerRef as Server; + if (server != null) + { + var attachedVolume = server.AttachedVolumes.FirstOrDefault(v => v.Id == Id); + if (attachedVolume != null) + server.AttachedVolumes.Remove(attachedVolume); + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/ServiceLimits.cs b/src/OpenStack/Compute/v2_1/ServiceLimits.cs new file mode 100644 index 000000000..a6767c1d0 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/ServiceLimits.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Set of account limits for the compute service. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "limits")] + public class ServiceLimits : IHaveExtraData + { + /// + /// Initializes a new instance of the class. + /// + public ServiceLimits() + { + RateLimits = new List(); + } + + /// + /// Fixed resource limits. + /// + [JsonProperty("absolute")] + public ResourceLimits ResourceLimits { get; set; } + + /// + /// Threshold limits for the compute service that are reset after a certain amount of time passes. + /// + [JsonProperty("rate")] + public IList RateLimits { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } + + /// + /// Fixed resource limits for the compute service. + /// + public class ResourceLimits : IHaveExtraData + { + /// + /// Maximum number of metadata items associated with a server. + /// + [JsonProperty("maxServerMeta")] + public int? ServerMetadataMax { get; set; } + + /// + /// The maximum number of file path/content pairs that can be supplied on server build. + /// + [JsonProperty("maxPersonality")] + public int? PersonalityMax { get; set; } + + /// + /// Maximum number of metadata items associated with an image. + /// + [JsonProperty("maxImageMeta")] + public int? ImageMetadataMax { get; set; } + + /// + /// The maximum size, in bytes, for each personality file. + /// + [JsonProperty("maxPersonalitySize")] + public int? PersonalitySizeMax { get; set; } + + /// + /// The maximum number of key pairs per server. + /// + [JsonProperty("maxTotalKeypairs")] + public int? KeypairsMax { get; set; } + + /// + /// The maximum number of security group rules per security group. + /// + [JsonProperty("maxSecurityGroupRules")] + public int? SecurityGroupRulesMax { get; set; } + + /// + /// The number of security group rules used. + /// + [JsonProperty("totalServerGroupsUsed")] + public int? ServerGroupsUsed { get; set; } + + /// + /// The maximun number of server groups per server. + /// + [JsonProperty("maxServerGroups")] + public int? ServerGroupsMax { get; set; } + + /// + /// The number of cores used. + /// + [JsonProperty("totalCoresUsed")] + public int? CoresUsed { get; set; } + + /// + /// The maximum number of cores. + /// + [JsonProperty("maxTotalCores")] + public int? CoresMax { get; set; } + + /// + /// The amount of RAM (MB) used. + /// + [JsonProperty("totalRAMUsed")] + public int? MemoryUsed { get; set; } + + /// + /// Maximum total amount of RAM (MB) + /// + [JsonProperty("maxTotalRAMSize")] + public int? MemorySizeMax { get; set; } + + /// + /// The number of server instances used. + /// + [JsonProperty("totalInstancesUsed")] + public int? ServersUsed { get; set; } + + /// + /// The maximum number of servers at any one time. + /// + [JsonProperty("maxTotalInstances")] + public int? ServersMax { get; set; } + + /// + /// The number of security groups used. + /// + [JsonProperty("totalSecurityGroupsUsed")] + public int? SecurityGroupUsed { get; set; } + + /// + /// The maximum number of security groups per server. + /// + [JsonProperty("maxSecurityGroups")] + public int? SecurityGroupMax { get; set; } + + /// + /// The number of floating IP addresses used. + /// + [JsonProperty("totalFloatingIpsUsed")] + public int? FloatingIPUsed { get; set; } + + /// + /// The maximum number of floating IP addresses. + /// + [JsonProperty("maxTotalFloatingIps")] + public int? FloatingIPMax { get; set; } + + /// + /// The maximum number of server group members per server group. + /// + [JsonProperty("maxServerGroupMembers")] + public int? ServerGroupMemberMax { get; set; } + + /// + /// Contains additional limits that may be defined by the cloud provider. + /// + [JsonExtensionData] + public IDictionary Data { get; set; } = new Dictionary(); + } + + /// + /// Threshold limits for the compute service that are reset after a certain amount of time passes. + /// + public class RateLimits + { + /// + /// The service endpoint. + /// + [JsonProperty("uri")] + public string Name { get; set; } + + /// + /// The regular expression applied to the request URL. + /// + [JsonProperty("regex")] + public Regex Regex { get; set; } + + /// + /// The service endpoint rate limits. + /// + [JsonProperty("limit")] + public IList Limits { get; set; } + } + + /// + /// A rate limit for a service endpoint. + /// + public class RateLimit + { + /// + /// The request verb, e.g. GET, POST + /// + [JsonProperty("verb")] + public string HttpMethod { get; set; } + + /// + /// The maximum number of requests allowed in the current time frame. + /// + [JsonProperty("value")] + public int Maximum { get; set; } + + /// + /// The number of remaining requests allowed in the current time frame. + /// + [JsonProperty("remaining")] + public int Remaining { get; set; } + + /// + /// The time frame unit of measurement. + /// + [JsonProperty("unit")] + public string UnitOfMeasurement { get; set; } + + /// + /// Specifies when the current time frame expires and the rate limits are reset. + /// + [JsonProperty("next-available")] + public DateTimeOffset NextAvailable { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/Volume.cs b/src/OpenStack/Compute/v2_1/Volume.cs new file mode 100644 index 000000000..cc29af4d6 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/Volume.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Extensions; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.BlockStorage.v2; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Represents a volume which can be attached to a server. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "volume")] + public class Volume : IServiceResource, IHaveExtraData + { + /// + /// Initializes a new instance of the class. + /// + public Volume() + { + Attachments = new List(); + Metadata = new Dictionary(); + } + + /// + /// The volume identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The volume name. + /// + [JsonProperty("displayName")] + public string Name { get; set; } + + /// + /// The volume status. + /// + [JsonProperty("status")] + public VolumeStatus Status { get; set; } + + /// + /// The volume description. + /// + [JsonProperty("displayDescription")] + public string Description { get; set; } + + /// + /// The size of the volume, in gigabytes (GB). + /// + [JsonProperty("size")] + public int Size { get; set; } + + /// + /// The unique identifier for a volume type. + /// + [JsonProperty("volumeType")] + public Identifier VolumeTypeId { get; set; } + + /// + /// One or more metadata key and value pairs to associate with the volume. + /// + [JsonProperty("metadata")] + public IDictionary Metadata { get; set; } + + /// + /// The availability zone. + /// + [JsonProperty("availabilityZone")] + public string AvailabilityZone { get; set; } + + /// + /// The snapshot from which to create a volume. + /// + [JsonProperty("snapshotId")] + public Identifier SourceSnapshotId { get; set; } + + /// + /// A list of servers to which this volume is attached. + /// + [JsonProperty("attachments")] + public IList Attachments { get; set; } + + /// + /// The date and time when the resource was created. + /// + [JsonProperty("createdAt")] + public DateTime Created { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + /// Waits the until the volume is available. + /// + /// The refresh delay. + /// The timeout. + /// The progress. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task WaitUntilAvailableAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return WaitForStatusAsync(VolumeStatus.Available, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task WaitUntilDeletedAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.WaitUntilVolumeIsDeletedAsync(Id, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task WaitForStatusAsync(IEnumerable status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + var result = await owner.WaitForVolumeStatusAsync(Id, status, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task WaitForStatusAsync(VolumeStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + var result = await owner.WaitForVolumeStatusAsync(Id, status, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + public Task SnapshotAsync(VolumeSnapshotDefinition snapshot = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if(snapshot == null) + snapshot = new VolumeSnapshotDefinition(); + + snapshot.VolumeId = Id; + + var owner = this.GetOwnerOrThrow(); + return owner.SnapshotVolumeAsync(snapshot, cancellationToken); + } + + /// + public Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.DeleteVolumeAsync(Id, cancellationToken); + } + + [OnDeserialized] + private void OnDeserialize(StreamingContext context) + { + // Cleanup after an issue in Nova where an empty attachment is always returned. + var emptyAttachment = Attachments.FirstOrDefault(x => x.Id == null); + if (emptyAttachment != null) + { + Attachments.Remove(emptyAttachment); + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/VolumeDefinition.cs b/src/OpenStack/Compute/v2_1/VolumeDefinition.cs new file mode 100644 index 000000000..97b9b3451 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/VolumeDefinition.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines a new volume. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "volume")] + public class VolumeDefinition + { + /// + /// Initializes a new instance of the class. + /// + protected VolumeDefinition() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The size of the volume, in gigabytes (GB). + public VolumeDefinition(int size) + { + Size = size; + } + + /// + [JsonProperty("display_name")] + public string Name { get; set; } + + /// + [JsonProperty("display_description")] + public string Description { get; set; } + + /// + [JsonProperty("size")] + public int Size { get; set; } + + /// + [JsonProperty("volume_type")] + public Identifier VolumeTypeId { get; set; } + + /// + [JsonProperty("metadata")] + public IDictionary Metadata { get; set; } + + /// + [JsonProperty("availability_zone")] + public string AvailabilityZone { get; set; } + + /// + [JsonProperty("snapshot_id")] + public Identifier SourceSnapshotId { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/VolumeExtensions.cs b/src/OpenStack/Compute/v2_1/VolumeExtensions.cs new file mode 100644 index 000000000..1a7324624 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/VolumeExtensions.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using OpenStack.BlockStorage.v2; +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class VolumeExtensions_v2_1 + { + /// + public static VolumeSnapshot Snapshot(this Volume volume, VolumeSnapshotDefinition snapshot = null) + { + return volume.SnapshotAsync(snapshot).ForceSynchronous(); + } + + /// + public static void Delete(this Volume volume) + { + volume.DeleteAsync().ForceSynchronous(); + } + + /// + public static void WaitForStatus(this Volume volume, VolumeStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + volume.WaitForStatusAsync(status, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void WaitForStatus(this Volume volume, IEnumerable status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + volume.WaitForStatusAsync(status, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void WaitUntilAvailable(this Volume volume, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + volume.WaitUntilAvailableAsync(refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + public static void WaitUntilDeleted(this Volume volume, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + volume.WaitUntilDeletedAsync(refreshDelay, timeout, progress).ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_1/VolumeSnapshot.cs b/src/OpenStack/Compute/v2_1/VolumeSnapshot.cs new file mode 100644 index 000000000..69954e8e3 --- /dev/null +++ b/src/OpenStack/Compute/v2_1/VolumeSnapshot.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Extensions; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.BlockStorage.v2; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Represents a snapshot of a volume. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "snapshot")] + public class VolumeSnapshot : IServiceResource, IHaveExtraData + { + /// + /// The volume snapshot identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The volume identifier. + /// + [JsonProperty("volumeId")] + public Identifier VolumeId { get; set; } + + /// + /// The snapshot name. + /// + [JsonProperty("displayName")] + public string Name { get; set; } + + /// + /// The snapshot description. + /// + [JsonProperty("displayDescription")] + public string Description { get; set; } + + /// + /// The snapshot size, in GB. + /// + [JsonProperty("size")] + public int Size { get; set; } + + /// + /// The snapshot status. + /// + [JsonProperty("status")] + public SnapshotStatus Status { get; set; } + + /// + /// The date and time when the resource was created. + /// + [JsonProperty("createdAt")] + public DateTime Created { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + /// Waits the until the snapshot is available. + /// + /// The refresh delay. + /// The timeout. + /// The progress. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task WaitUntilAvailableAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return WaitForStatusAsync(SnapshotStatus.Available, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public Task WaitUntilDeletedAsync(TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.WaitUntilVolumeSnapshotIsDeletedAsync(Id, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task WaitForStatusAsync(IEnumerable status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + var result = await owner.WaitForVolumeSnapshotStatusAsync(Id, status, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + /// When the instance was not constructed by the , as it is missing the appropriate internal state to execute service calls. + public async Task WaitForStatusAsync(SnapshotStatus status, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + var result = await owner.WaitForVolumeSnapshotStatusAsync(Id, status, refreshDelay, timeout, progress, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + public Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var owner = this.GetOwnerOrThrow(); + return owner.DeleteVolumeSnapshotAsync(Id, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/VolumeSnapshotDefinition.cs b/src/OpenStack/Compute/v2_1/VolumeSnapshotDefinition.cs new file mode 100644 index 000000000..faa9eab3b --- /dev/null +++ b/src/OpenStack/Compute/v2_1/VolumeSnapshotDefinition.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Defines a new volume snapshot. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "snapshot")] + public class VolumeSnapshotDefinition + { + /// + /// Initializes a new instance of the class. + /// + public VolumeSnapshotDefinition() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The volume identifier. + public VolumeSnapshotDefinition(Identifier volumeId) + { + VolumeId = volumeId; + } + + /// + [JsonProperty("volume_id")] + public Identifier VolumeId { get; set; } + + /// + [JsonProperty("display_name")] + public string Name { get; set; } + + /// + [JsonProperty("display_description")] + public string Description { get; set; } + + /// + /// Specifies whether to snapshot a volume even if it's attached to an instance + /// + [JsonProperty("force")] + public bool? ShouldForce { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_1/VolumeSnapshotExtensions.cs b/src/OpenStack/Compute/v2_1/VolumeSnapshotExtensions.cs new file mode 100644 index 000000000..e15acb9cb --- /dev/null +++ b/src/OpenStack/Compute/v2_1/VolumeSnapshotExtensions.cs @@ -0,0 +1,18 @@ +using OpenStack.Compute.v2_1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class VolumeSnapshotExtensions_v2_1 + { + /// + public static void Delete(this VolumeSnapshot volume) + { + volume.DeleteAsync().ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_2/ComputeApi.cs b/src/OpenStack/Compute/v2_2/ComputeApi.cs new file mode 100644 index 000000000..153da7805 --- /dev/null +++ b/src/OpenStack/Compute/v2_2/ComputeApi.cs @@ -0,0 +1,19 @@ +using OpenStack.Authentication; + +namespace OpenStack.Compute.v2_2 +{ + /// + /// Compute Microversion 2.6 + public class ComputeApi : v2_1.Serialization.ComputeApi + { + /// + public ComputeApi(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl) + : this(serviceType, authenticationProvider, region, useInternalUrl, "2.2") + { } + + /// + protected ComputeApi(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl, string microversion) + : base(serviceType, authenticationProvider, region, useInternalUrl, microversion) + { } + } +} diff --git a/src/OpenStack/Compute/v2_2/ComputeService.cs b/src/OpenStack/Compute/v2_2/ComputeService.cs new file mode 100644 index 000000000..5b758c765 --- /dev/null +++ b/src/OpenStack/Compute/v2_2/ComputeService.cs @@ -0,0 +1,45 @@ +using System.Threading; +using System.Threading.Tasks; +using OpenStack.Authentication; +using OpenStack.Compute.v2_1; +using OpenStack.Compute.v2_2.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_2 +{ + /// + public class ComputeService + { + private readonly ComputeApi _computeApi; + + /// + public ComputeService(IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl) + { + _computeApi = new ComputeApi(ServiceType.Compute, authenticationProvider, region, useInternalUrl); + } + + #region Servers + /// + public virtual async Task> ListServerReferencesAsync(ServerListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListServerSummariesAsync(options, cancellationToken); + } + + /// + public virtual Task GetVncConsoleAync(Identifier serverId, RemoteConsoleType type, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetVncConsoleAsync(serverId, type, cancellationToken); + } + #endregion + + #region Keypairs + + /// + public virtual Task ImportKeyPairAsync(KeyPairDefinition keypair, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.CreateKeyPairAsync(keypair, cancellationToken); + } + + #endregion + } +} diff --git a/src/OpenStack/Compute/v2_2/ComputeServiceExtensions.cs b/src/OpenStack/Compute/v2_2/ComputeServiceExtensions.cs new file mode 100644 index 000000000..5e72f61df --- /dev/null +++ b/src/OpenStack/Compute/v2_2/ComputeServiceExtensions.cs @@ -0,0 +1,24 @@ +using OpenStack.Compute.v2_2; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ComputeServiceExtensions_v2_2 + { + /// + public static RemoteConsole GetVncConsole(this ComputeService service, Identifier serverId, RemoteConsoleType type) + { + return service.GetVncConsoleAync(serverId, type).ForceSynchronous(); + } + + /// + public static KeyPair ImportKeyPair(this ComputeService service, KeyPairDefinition keypair) + { + return service.ImportKeyPairAsync(keypair).ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_2/KeyPair.cs b/src/OpenStack/Compute/v2_2/KeyPair.cs new file mode 100644 index 000000000..c1f8bc5be --- /dev/null +++ b/src/OpenStack/Compute/v2_2/KeyPair.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_2 +{ + /// + public class KeyPair : v2_1.KeyPairSummary + { + /// + [JsonProperty("type")] + public KeyPairType Type { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/KeyPairDefinition.cs b/src/OpenStack/Compute/v2_2/KeyPairDefinition.cs new file mode 100644 index 000000000..0f5a9feef --- /dev/null +++ b/src/OpenStack/Compute/v2_2/KeyPairDefinition.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_2 +{ + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "keypair")] + public class KeyPairDefinition : v2_1.KeyPairDefinition + { + /// + public KeyPairDefinition(string name, string publicKey) + : base(name, publicKey) + { + } + + /// + [JsonProperty("type")] + public KeyPairType? Type { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/KeyPairType.cs b/src/OpenStack/Compute/v2_2/KeyPairType.cs new file mode 100644 index 000000000..470393690 --- /dev/null +++ b/src/OpenStack/Compute/v2_2/KeyPairType.cs @@ -0,0 +1,16 @@ +namespace OpenStack.Compute.v2_2 +{ + /// + public enum KeyPairType + { + /// + /// SSH + /// + SSH, + + /// + /// X509 + /// + x509 + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/RemoteConsole.cs b/src/OpenStack/Compute/v2_2/RemoteConsole.cs new file mode 100644 index 000000000..932e92be5 --- /dev/null +++ b/src/OpenStack/Compute/v2_2/RemoteConsole.cs @@ -0,0 +1,7 @@ +namespace OpenStack.Compute.v2_2 +{ + /// + public class RemoteConsole : v2_1.RemoteConsole + { + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/RemoteConsoleType.cs b/src/OpenStack/Compute/v2_2/RemoteConsoleType.cs new file mode 100644 index 000000000..65447349f --- /dev/null +++ b/src/OpenStack/Compute/v2_2/RemoteConsoleType.cs @@ -0,0 +1,9 @@ +namespace OpenStack.Compute.v2_2 +{ + /// + /// The remote console type + /// + public class RemoteConsoleType : v2_1.Serialization.RemoteConsoleType + { + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/Serialization/ServerCollection.cs b/src/OpenStack/Compute/v2_2/Serialization/ServerCollection.cs new file mode 100644 index 000000000..8685cfdcc --- /dev/null +++ b/src/OpenStack/Compute/v2_2/Serialization/ServerCollection.cs @@ -0,0 +1,16 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_2.Serialization +{ + /// + /// + public class ServerCollection : v2_1.Serialization.ServerCollection + where TPage : ServerCollection + where TItem : IServiceResource + { } + + /// + /// + public class ServerCollection : ServerCollection + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/Server.cs b/src/OpenStack/Compute/v2_2/Server.cs new file mode 100644 index 000000000..5104682fb --- /dev/null +++ b/src/OpenStack/Compute/v2_2/Server.cs @@ -0,0 +1,7 @@ +namespace OpenStack.Compute.v2_2 +{ + /// + public class Server : v2_1.Server + { + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/ServerListOptions.cs b/src/OpenStack/Compute/v2_2/ServerListOptions.cs new file mode 100644 index 000000000..b6d7e7d17 --- /dev/null +++ b/src/OpenStack/Compute/v2_2/ServerListOptions.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Compute.v2_2 +{ + /// + public class ServerListOptions : v2_1.ServerListOptions + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/ServerReference.cs b/src/OpenStack/Compute/v2_2/ServerReference.cs new file mode 100644 index 000000000..3ba31a236 --- /dev/null +++ b/src/OpenStack/Compute/v2_2/ServerReference.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Compute.v2_2 +{ + /// + public class ServerReference : v2_1.ServerReference + {} +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_2/ServerStatus.cs b/src/OpenStack/Compute/v2_2/ServerStatus.cs new file mode 100644 index 000000000..5d17be75f --- /dev/null +++ b/src/OpenStack/Compute/v2_2/ServerStatus.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Compute.v2_2 +{ + /// + public class ServerStatus : v2_1.Serialization.ServerStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/ComputeApi.cs b/src/OpenStack/Compute/v2_6/ComputeApi.cs new file mode 100644 index 000000000..6cda3d1cc --- /dev/null +++ b/src/OpenStack/Compute/v2_6/ComputeApi.cs @@ -0,0 +1,51 @@ +using System; +using System.ComponentModel; +using System.Threading; +using System.Threading.Tasks; +using Flurl.Extensions; +using Flurl.Http; +using OpenStack.Authentication; + +namespace OpenStack.Compute.v2_6 +{ + /// + /// Compute Microversion 2.6 + public class ComputeApi : v2_2.ComputeApi + { + /// + public ComputeApi(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl) + : this(serviceType, authenticationProvider, region, useInternalUrl, "2.6") + { } + + /// + protected ComputeApi(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl, string microversion) + : base(serviceType, authenticationProvider, region, useInternalUrl, microversion) + { } + +#pragma warning disable 809 + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("GetVncConsole was deprecated in v2.6. Use GetConsole instead.", true)] + public override Task GetVncConsoleAsync(string serverId, object type, CancellationToken cancellationToken = new CancellationToken()) + { + throw new NotSupportedException("GetVncConsole was deprecated in v2.6. Use GetConsole instead."); + } +#pragma warning restore 809 + + /// + public virtual Task GetConsoleAsync(string serverId, object protocol, object type, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildGetConsoleRequest(serverId, protocol, type, cancellationToken).SendAsync().ReceiveJson(); + } + + /// + public virtual async Task BuildGetConsoleRequest(string serverId, object protocol, object type, CancellationToken cancellationToken = default(CancellationToken)) + { + var body = new { remote_console = new { protocol, type } }; + + PreparedRequest request = await Endpoint.PrepareRequest($"servers/{serverId}/remote-consoles", cancellationToken); + return request.PreparePostJson(body, cancellationToken); + } + } +} diff --git a/src/OpenStack/Compute/v2_6/ComputeService.cs b/src/OpenStack/Compute/v2_6/ComputeService.cs new file mode 100644 index 000000000..793d8f052 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/ComputeService.cs @@ -0,0 +1,48 @@ +using System.Threading; +using System.Threading.Tasks; +using OpenStack.Authentication; +using OpenStack.Compute.v2_6.Serialization; + +namespace OpenStack.Compute.v2_6 +{ + /// + public class ComputeService + { + private readonly ComputeApi _computeApi; + + /// + public ComputeService(IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl = false) + { + _computeApi = new ComputeApi(ServiceType.Compute, authenticationProvider, region, useInternalUrl); + } + + #region Servers + + /// + public virtual async Task> ListServerReferencesAsync(ServerListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _computeApi.ListServerSummariesAsync(options, cancellationToken); + } + + /// + public virtual Task GetConsoleAsync(Identifier serverId, ConsoleProtocol protocol, RemoteConsoleType type, CancellationToken cancellationToken = default(CancellationToken)) + { + return _computeApi.GetConsoleAsync(serverId, protocol, type, cancellationToken); + } + #endregion + + #region Keypairs + + /// + public virtual Task CreateKeyPairAsync(string name, KeyPairType? type = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var keyPair = new KeyPairDefinition(name) + { + Type = type + }; + return _computeApi.CreateKeyPairAsync(keyPair, cancellationToken); + } + + #endregion + } +} diff --git a/src/OpenStack/Compute/v2_6/ComputeServiceExtensions.cs b/src/OpenStack/Compute/v2_6/ComputeServiceExtensions.cs new file mode 100644 index 000000000..adc0a8625 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/ComputeServiceExtensions.cs @@ -0,0 +1,18 @@ +using OpenStack.Compute.v2_6; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class ComputeServiceExtensions_v2_6 + { + /// + public static Console GetConsole(this ComputeService service, Identifier serverId, ConsoleProtocol protocol, RemoteConsoleType type) + { + return service.GetConsoleAsync(serverId, protocol, type).ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/Compute/v2_6/Console.cs b/src/OpenStack/Compute/v2_6/Console.cs new file mode 100644 index 000000000..a3b8f58c0 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/Console.cs @@ -0,0 +1,25 @@ +using System; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_6 +{ + /// + /// Specifies how to connect a console to a . + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "console")] + public class Console + { + /// + /// The console type. + /// + [JsonProperty("type")] + public RemoteConsoleType Type { get; set; } + + /// + /// The console URL. + /// + [JsonProperty("url")] + public Uri Url { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/ConsoleProtocol.cs b/src/OpenStack/Compute/v2_6/ConsoleProtocol.cs new file mode 100644 index 000000000..2d7e5b308 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/ConsoleProtocol.cs @@ -0,0 +1,39 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_6 +{ + /// + /// The remote console protocol + /// + public class ConsoleProtocol : StringEnumeration + { + /// + protected ConsoleProtocol() + { } + + /// + protected ConsoleProtocol(string displayName) + : base(displayName) + { } + + /// + /// VNC + /// + public static readonly ConsoleProtocol VNC = new ConsoleProtocol("vnc"); + + /// + /// RDP + /// + public static readonly ConsoleProtocol RDP = new ConsoleProtocol("rdp-html5"); + + /// + /// Serial + /// + public static readonly ConsoleProtocol Serial = new ConsoleProtocol("serial"); + + /// + /// Spice + /// + public static readonly ConsoleProtocol Spice = new ConsoleProtocol("spice-html5"); + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/KeyPair.cs b/src/OpenStack/Compute/v2_6/KeyPair.cs new file mode 100644 index 000000000..201cc7f17 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/KeyPair.cs @@ -0,0 +1,7 @@ +namespace OpenStack.Compute.v2_6 +{ + /// + public class KeyPair : v2_2.KeyPair + { + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/KeyPairDefinition.cs b/src/OpenStack/Compute/v2_6/KeyPairDefinition.cs new file mode 100644 index 000000000..53ba042b2 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/KeyPairDefinition.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_6 +{ + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "keypair")] + public class KeyPairDefinition + { + /// + public KeyPairDefinition(string name) + { + Name = name; + } + + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("public_key")] + public string PublicKey { get; set; } + + /// + [JsonProperty("type")] + public KeyPairType? Type { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/KeyPairType.cs b/src/OpenStack/Compute/v2_6/KeyPairType.cs new file mode 100644 index 000000000..187f56ca5 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/KeyPairType.cs @@ -0,0 +1,16 @@ +namespace OpenStack.Compute.v2_6 +{ + /// + public enum KeyPairType + { + /// + /// SSH + /// + SSH, + + /// + /// X509 + /// + x509 + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/RemoteConsoleType.cs b/src/OpenStack/Compute/v2_6/RemoteConsoleType.cs new file mode 100644 index 000000000..710a84b1b --- /dev/null +++ b/src/OpenStack/Compute/v2_6/RemoteConsoleType.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Compute.v2_6 +{ + /// + public class RemoteConsoleType : v2_1.Serialization.RemoteConsoleType + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/Serialization/ServerCollection.cs b/src/OpenStack/Compute/v2_6/Serialization/ServerCollection.cs new file mode 100644 index 000000000..e47f539a5 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/Serialization/ServerCollection.cs @@ -0,0 +1,16 @@ +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_6.Serialization +{ + /// + /// + public class ServerCollection : v2_2.Serialization.ServerCollection + where TPage : ServerCollection + where TItem : IServiceResource + { } + + /// + /// + public class ServerCollection : ServerCollection + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/Server.cs b/src/OpenStack/Compute/v2_6/Server.cs new file mode 100644 index 000000000..628f1893b --- /dev/null +++ b/src/OpenStack/Compute/v2_6/Server.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Compute.v2_6 +{ + /// + /// + /// + public class Server : IHaveExtraData + { + /// + /// Gets or sets the identifier. + /// + /// + /// The identifier. + /// + public Identifier Id { get; set; } + + /// + /// The xtended data + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/ServerListOptions.cs b/src/OpenStack/Compute/v2_6/ServerListOptions.cs new file mode 100644 index 000000000..e15f3febe --- /dev/null +++ b/src/OpenStack/Compute/v2_6/ServerListOptions.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Compute.v2_6 +{ + /// + public class ServerListOptions : v2_2.ServerListOptions + { } +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/ServerReference.cs b/src/OpenStack/Compute/v2_6/ServerReference.cs new file mode 100644 index 000000000..4cea6fd2a --- /dev/null +++ b/src/OpenStack/Compute/v2_6/ServerReference.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Compute.v2_6 +{ + /// + public class ServerReference : v2_2.ServerReference + {} +} \ No newline at end of file diff --git a/src/OpenStack/Compute/v2_6/ServerStatus.cs b/src/OpenStack/Compute/v2_6/ServerStatus.cs new file mode 100644 index 000000000..219362e30 --- /dev/null +++ b/src/OpenStack/Compute/v2_6/ServerStatus.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Compute.v2_6 +{ + /// + public class ServerStatus : v2_1.Serialization.ServerStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ContentDeliveryNetworkService.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ContentDeliveryNetworkService.cs new file mode 100644 index 000000000..657edd966 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ContentDeliveryNetworkService.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Flurl; +using Flurl.Extensions; +using Flurl.Http; +using Marvin.JsonPatch; +using OpenStack.Authentication; +using OpenStack.Serialization; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// The default provider for the OpenStack (Poppy) Content Delivery Network Service. + /// + /// + /// OpenStack (Poppy) Content Delivery Network Service API v1 Reference + public class ContentDeliveryNetworkService : IContentDeliveryNetworkService + { + private readonly IAuthenticationProvider _authenticationProvider; + private readonly ServiceEndpoint _endpoint; + + /// + /// Initializes a new instance of the class. + /// + /// The authentication provider. + /// The cloud region. + /// if set to true uses the internal URLs specified in the ServiceCatalog, otherwise the public URLs are used. + /// If the is . + /// If the is or empty. + public ContentDeliveryNetworkService(IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl = false) + { + if (authenticationProvider == null) + throw new ArgumentNullException("authenticationProvider"); + if (string.IsNullOrEmpty(region)) + throw new ArgumentException("region cannot be null or empty", "region"); + + _authenticationProvider = authenticationProvider; + _endpoint = new ServiceEndpoint(ServiceType.ContentDeliveryNetwork, authenticationProvider, region, useInternalUrl); + } + + /// + public async Task GetFlavorAsync(string flavorId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(flavorId)) + throw new ArgumentNullException("flavorId"); + + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return await endpoint + .AppendPathSegments("flavors", flavorId) + .Authenticate(_authenticationProvider) + .GetJsonAsync(cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task> ListFlavorsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return await endpoint + .AppendPathSegments("flavors") + .Authenticate(_authenticationProvider) + .GetJsonAsync(cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task PingAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + await endpoint + .AppendPathSegments("ping") + .Authenticate(_authenticationProvider) + .GetAsync(cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task> ListServicesAsync(string startServiceId = null, int? pageSize = null, CancellationToken cancellationToken = default(CancellationToken)) + { + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + string url = endpoint + .AppendPathSegments("services") + .SetQueryParams(new + { + marker = startServiceId, + limit = pageSize + }); + + return await ListServicesAsync(url, cancellationToken).ConfigureAwait(false); + } + + // TODO: move into a class that we can use via composition so that we aren't implementing this for everything that is paged? + private async Task ListServicesAsync(Url url, CancellationToken cancellationToken) + { + ServiceCollection result = await url + .Authenticate(_authenticationProvider) + .GetJsonAsync(cancellationToken) + .ConfigureAwait(false); + + ((IPageBuilder)result).SetNextPageHandler(ListServicesAsync); + + return result; + } + + /// + public async Task GetServiceAsync(string serviceId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(serviceId)) + throw new ArgumentNullException("serviceId"); + + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return await endpoint + .AppendPathSegments("services", serviceId) + .Authenticate(_authenticationProvider) + .GetJsonAsync(cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task CreateServiceAsync(ServiceDefinition service, CancellationToken cancellationToken = default(CancellationToken)) + { + if (service == null) + throw new ArgumentNullException("service"); + + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + var response = await endpoint + .AppendPathSegments("services") + .Authenticate(_authenticationProvider) + .PostJsonAsync(service, cancellationToken) + .ConfigureAwait(false); + + var location = response.Headers.Location; + return location.Segments.Last(); + } + + /// + public async Task DeleteServiceAsync(string serviceId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(serviceId)) + throw new ArgumentNullException("serviceId"); + + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + await endpoint + .AppendPathSegments("services", serviceId) + .Authenticate(_authenticationProvider) + .AllowHttpStatus(HttpStatusCode.NotFound) + .DeleteAsync(cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task UpdateServiceAsync(string serviceId, JsonPatchDocument patch, CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(serviceId)) + throw new ArgumentNullException("serviceId"); + if (patch == null) + throw new ArgumentNullException("patch"); + + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + await endpoint + .AppendPathSegments("services", serviceId) + .Authenticate(_authenticationProvider) + .PatchJsonAsync(patch, cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task PurgeCachedAssetAsync(string serviceId, string url, CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(serviceId)) + throw new ArgumentNullException("serviceId"); + if (string.IsNullOrEmpty(url)) + throw new ArgumentNullException("url"); + + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + await endpoint + .AppendPathSegments("services", serviceId, "assets") + .SetQueryParam("url", url) + .Authenticate(_authenticationProvider) + .AllowHttpStatus(HttpStatusCode.NotFound) + .DeleteAsync(cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task PurgeCachedAssetsAsync(string serviceId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(serviceId)) + throw new ArgumentNullException("serviceId"); + + string endpoint = await _endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + await endpoint + .AppendPathSegments("services", serviceId, "assets") + .SetQueryParam("all", true) + .Authenticate(_authenticationProvider) + .DeleteAsync(cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task WaitForServiceDeployedAsync(string serviceId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(serviceId)) + throw new ArgumentNullException("serviceId"); + + refreshDelay = refreshDelay ?? TimeSpan.FromSeconds(5); + timeout = timeout ?? TimeSpan.FromMinutes(5); + + using (var timeoutSource = new CancellationTokenSource(timeout.Value)) + using (var rootCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutSource.Token)) + { + while (true) + { + var service = await GetServiceAsync(serviceId, cancellationToken).ConfigureAwait(false); + if (service.Status == ServiceStatus.Failed) + throw new ServiceOperationFailedException(service.Errors); + + bool complete = service.Status == ServiceStatus.Deployed; + + if (progress != null) + progress.Report(complete); + + if (complete) + return service; + + try + { + await Task.Delay(refreshDelay.Value, rootCancellationToken.Token).ConfigureAwait(false); + } + catch (OperationCanceledException ex) + { + if (timeoutSource.IsCancellationRequested) + throw new TimeoutException(string.Format("The requested timeout of {0} seconds has been reached while waiting for the service ({1}) to be deployed.", timeout.Value.TotalSeconds, serviceId), ex); + + throw; + } + } + } + } + + /// + public async Task WaitForServiceDeletedAsync(string serviceId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (string.IsNullOrEmpty(serviceId)) + throw new ArgumentNullException("serviceId"); + + refreshDelay = refreshDelay ?? TimeSpan.FromSeconds(5); + timeout = timeout ?? TimeSpan.FromMinutes(5); + + using (var timeoutSource = new CancellationTokenSource(timeout.Value)) + using (var rootCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutSource.Token)) + { + while (true) + { + bool complete = false; + try + { + var service = await GetServiceAsync(serviceId, cancellationToken).ConfigureAwait(false); + if (service.Status == ServiceStatus.Failed) + throw new ServiceOperationFailedException(service.Errors); + } + catch (FlurlHttpException httpError) + { + if (httpError.Call.HttpStatus == HttpStatusCode.NotFound) + complete = true; + else + throw; + } + + if (progress != null) + progress.Report(complete); + + if (complete) + return; + + try + { + await Task.Delay(refreshDelay.Value, rootCancellationToken.Token).ConfigureAwait(false); + } + catch (OperationCanceledException ex) + { + if (timeoutSource.IsCancellationRequested) + throw new TimeoutException(string.Format("The requested timeout of {0} seconds has been reached while waiting for the service ({1}) to be deleted.", timeout.Value.TotalSeconds, serviceId), ex); + + throw; + } + } + } + } + } +} diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceExtensions.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceExtensions.cs new file mode 100644 index 000000000..ac9a9a407 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceExtensions.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Net; +using Flurl.Http; +using Marvin.JsonPatch; +using OpenStack.ContentDeliveryNetworks.v1; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for an instance. + /// + public static class ContentDeliveryNetworkServiceExtensions + { + /// + /// Gets the specified flavor. + /// + /// The service instance. + /// The flavor identifier. + /// If is or empty. + /// If the API call returns a bad . + /// The flavor associated with the specified identifer. + public static Flavor GetFlavor(this IContentDeliveryNetworkService cdnService, string flavorId) + { + return cdnService.GetFlavorAsync(flavorId).ForceSynchronous(); + } + + /// + /// Lists basic information for all available flavors. + /// + /// The service instance. + /// If the API call returns a bad . + /// A collection of objects describing the available flavors. + public static IEnumerable ListFlavors(this IContentDeliveryNetworkService cdnService) + { + return cdnService.ListFlavorsAsync().ForceSynchronous(); + } + + /// + /// Pings the service. + /// + /// If no exception is thrown, the service is considered up/healthy. + /// + /// + /// The service instance. + /// If the API call returns a bad . + public static void Ping(this IContentDeliveryNetworkService cdnService) + { + cdnService.PingAsync().ForceSynchronous(); + } + + /// + /// Lists all Content Delivery Network services associated with the account + /// + /// The service instance. + /// The id of the first service from which to start paging the results. + /// The numer of services to return per page. + /// If the service call returns a bad . + /// + /// A collection of associated wit the acccount./> + /// + public static IPage ListServices(this IContentDeliveryNetworkService cdnService, string startServiceId = null, int? pageSize = null) + { + return cdnService.ListServicesAsync(startServiceId, pageSize).ForceSynchronous(); + } + + /// + /// Gets the specified service. + /// + /// The service instance. + /// The service identifier. + /// If is . + /// If the API call returns a bad . + /// + /// The service associated with the specified identifer. + /// + public static Service GetService(this IContentDeliveryNetworkService cdnService, string serviceId) + { + return cdnService.GetServiceAsync(serviceId).ForceSynchronous(); + } + + /// + /// Creates a Content Delivery Network service. + /// + /// The service instance. + /// The service definition. + /// + /// The identifier of the newly created service. + /// + /// If is . + /// If the API call returns a bad . + public static string CreateService(this IContentDeliveryNetworkService cdnService, ServiceDefinition service) + { + return cdnService.CreateServiceAsync(service).ForceSynchronous(); + } + + /// + /// Deletes the specified Content Delivery Network service. + /// + /// The service instance. + /// The service identifier. + /// If is or empty. + public static void DeleteService(this IContentDeliveryNetworkService cdnService, string serviceId) + { + cdnService.DeleteServiceAsync(serviceId).ForceSynchronous(); + } + + /// + /// Updates the specified Content DeliveryNetwork service + /// + /// The service instance. + /// The service identifier. + /// The patch containing updated properties. + /// If or is . + public static void UpdateService(this IContentDeliveryNetworkService cdnService, string serviceId, JsonPatchDocument patch) + { + cdnService.UpdateServiceAsync(serviceId, patch).ForceSynchronous(); + } + + /// + /// Removes the current version of the specified asset that has been cached at the edge. + /// + /// The service instance. + /// The service identifier. + /// The asset URL. + /// If is . + /// If the API call returns a bad . + public static void PurgeCachedAsset(this IContentDeliveryNetworkService cdnService, string serviceId, string url) + { + cdnService.PurgeCachedAssetAsync(serviceId, url).ForceSynchronous(); + } + + /// + /// Removes the current version of all assets that has been cached at the edge. + /// + /// The service instance. + /// The service identifier. + /// If is . + /// If the API call returns a bad . + public static void PurgeCachedAssets(this IContentDeliveryNetworkService cdnService, string serviceId) + { + cdnService.PurgeCachedAssetsAsync(serviceId).ForceSynchronous(); + } + + /// + /// Waits for the service to be deployed. + /// + /// The service instance. + /// The service identifier. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// If the previous service operation failed. + /// If the value is reached. + /// If the API call returns a bad . + public static Service WaitForServiceDeployed(this IContentDeliveryNetworkService cdnService, string serviceId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + return cdnService.WaitForServiceDeployedAsync(serviceId, refreshDelay, timeout, progress).ForceSynchronous(); + } + + /// + /// Waits for the service to be deleted. + /// + /// The service instance. + /// The service identifier. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// If the service deletion failed. + /// If the value is reached. + /// If the API call returns a bad . + public static void WaitForServiceDeleted(this IContentDeliveryNetworkService cdnService, string serviceId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null) + { + cdnService.WaitForServiceDeletedAsync(serviceId, refreshDelay, timeout, progress).ForceSynchronous(); + } + } +} diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/Flavor.cs b/src/OpenStack/ContentDeliveryNetworks/v1/Flavor.cs new file mode 100644 index 000000000..ef5ad9dea --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/Flavor.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; +using net.openstack.Core.Domain; +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a flavor resource of the + /// + /// + public class Flavor + { + /// + /// The unique identifier for the flavor. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// Collection of links related to the current flavor. + /// + [JsonProperty("links")] + public IEnumerable Links { get; set; } + + /// + /// Collection of available providers for the current flavor. + /// + [JsonProperty("providers")] + public IEnumerable Providers { get; set; } + } +} diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/FlavorCollection.cs b/src/OpenStack/ContentDeliveryNetworks/v1/FlavorCollection.cs new file mode 100644 index 000000000..d9a7203bd --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/FlavorCollection.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a collection of flavor resources of the . + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "flavors")] + public class FlavorCollection : List + { + /// + /// Initializes a new instance of the class. + /// + public FlavorCollection() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The flavors. + public FlavorCollection(IEnumerable flavors) : base(flavors) + { + } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/IContentDeliveryNetworkService.cs b/src/OpenStack/ContentDeliveryNetworks/v1/IContentDeliveryNetworkService.cs new file mode 100644 index 000000000..b4f6f598c --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/IContentDeliveryNetworkService.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Flurl.Http; +using Marvin.JsonPatch; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a provider for the OpenStack (Poppy) Content Delivery Network Service. + /// + /// + /// OpenStack (Poppy) Content Delivery Network Service API v1 Reference + public interface IContentDeliveryNetworkService + { + /// + /// Gets the specified flavor. + /// + /// The flavor identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If is . + /// If the API call returns a bad . + /// + /// The flavor associated with the specified identifer. + /// + Task GetFlavorAsync(string flavorId, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Lists basic information for all available flavors. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the service call returns a bad . + /// + /// A collection of objects describing the available flavors. + /// + Task> ListFlavorsAsync(CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Pings the service. + /// + /// If no exception is thrown, the service is considered up/healthy. + /// + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the API call returns a bad . + Task PingAsync(CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Lists all Content Delivery Network services associated with the account. + /// + /// The id of the first service from which to start paging the results. + /// The numer of services to return per page. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the service call returns a bad . + /// + /// A collection of resources associated with the acccount./> + /// + Task> ListServicesAsync(string startServiceId = null, int? pageSize = null, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Gets the specified Content Delivery Network service. + /// + /// The service identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If is . + /// If the API call returns a bad . + /// + /// The service associated with the specified identifer. + /// + Task GetServiceAsync(string serviceId, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Creates a Content Delivery Network service. + /// + /// The service definition. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If is . + /// If the API call returns a bad . + /// + /// The identifier of the newly created service. + /// + Task CreateServiceAsync(ServiceDefinition service, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Deletes the specified Content Delivery Network service. + /// + /// The service identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If is . + /// If the API call returns a bad . + Task DeleteServiceAsync(string serviceId, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Updates the specified Content DeliveryNetwork service + /// + /// The service identifier. + /// The patch containing updated properties. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If or is . + /// If the API call returns a bad . + Task UpdateServiceAsync(string serviceId, JsonPatchDocument patch, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Removes the current version of the specified asset that has been cached at the edge. + /// + /// The service identifier. + /// The asset URL. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If is . + /// If the API call returns a bad . + Task PurgeCachedAssetAsync(string serviceId, string url, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Removes the current version of all assets that has been cached at the edge. + /// + /// The service identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If is . + /// If the API call returns a bad . + Task PurgeCachedAssetsAsync(string serviceId, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Waits for the service to be deployed. + /// + /// The service identifier. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the previous service operation failed. + /// If the value is reached. + /// If the API call returns a bad . + Task WaitForServiceDeployedAsync(string serviceId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Waits for the service to be deleted. + /// + /// The service identifier. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the service deletion failed. + /// If the value is reached. + /// If the API call returns a bad . + Task WaitForServiceDeletedAsync(string serviceId, TimeSpan? refreshDelay = null, TimeSpan? timeout = null, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/NamespaceDoc.cs b/src/OpenStack/ContentDeliveryNetworks/v1/NamespaceDoc.cs new file mode 100644 index 000000000..2558cdcb3 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines provider-independent + /// interfaces and implementations for the OpenStack Content Delivery Network API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/Provider.cs b/src/OpenStack/ContentDeliveryNetworks/v1/Provider.cs new file mode 100644 index 000000000..941956f1f --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/Provider.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using net.openstack.Core.Domain; +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a provider resource of the + /// + /// + public class Provider + { + /// + /// The provider name + /// + [JsonProperty("provider")] + public string Name { get; set; } + + /// + /// A collection of links related to the provider. + /// + [JsonProperty("links")] + public IEnumerable Links { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/Service.cs b/src/OpenStack/ContentDeliveryNetworks/v1/Service.cs new file mode 100644 index 000000000..d12fe1501 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/Service.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using net.openstack.Core.Domain; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a service resource of the + /// + /// + public class Service : IServiceResource + { + /// + /// The service identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The service name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The status of the service. + /// + [JsonProperty("status")] + public ServiceStatus Status { get; set; } + + /// + /// The identifier of the Content Delivery Network used by this service. + /// + [JsonProperty("flavor_id")] + public string FlavorId { get; set; } + + /// + /// Domains used by users to access the website. + /// + [JsonProperty("domains")] + public IEnumerable Domains { get; set; } + + /// + /// Domains or IP addresses where the canonical assets are stored. + /// + [JsonProperty("origins")] + public IEnumerable Origins { get; set; } + + /// + /// Caching rules for the assets under this service. + /// + [JsonProperty("caching")] + public IEnumerable Caches { get; set; } + + /// + /// Restrictions defining who can access assets. + /// + [JsonProperty("restrictions")] + public IEnumerable Restrictions { get; set; } + + /// + /// Any errors that occurred during the previous service operation. + /// + [JsonProperty("errors")] + public IEnumerable Errors { get; set; } + + /// + /// Links related to the service. + /// + [JsonProperty("links")] + public IEnumerable Links { get; set; } + + object IServiceResource.Owner { get; set; } + } +} diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCache.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCache.cs new file mode 100644 index 000000000..d5546d96e --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCache.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a cache resource of the . + /// + /// TTL caching rules for the assets under this service. Supports wildcard for fine grained control. + /// + /// + /// + public class ServiceCache + { + /// + /// Initializes a new instance of the class. + /// + /// The name of the cache. + /// The time to live (in seconds). + public ServiceCache(string name, TimeSpan timeToLive) + { + Name = name; + TimeToLive = timeToLive; + Rules = new List(); + } + + /// + /// The cache name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The time to live. + /// + [JsonProperty("ttl")] + [JsonConverter(typeof(TimeSpanInSecondsConverter))] + public TimeSpan TimeToLive { get; set; } + + /// + /// Rules defining if this ttl should be applied to an asset. + /// + [JsonProperty("rules")] + public IList Rules { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCacheRule.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCacheRule.cs new file mode 100644 index 000000000..044777b4c --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCacheRule.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a caching rule resource of the . + /// + /// + public class ServiceCacheRule + { + /// + /// Initializes a new instance of the class. + /// + /// The rule name. + /// The request rule. + public ServiceCacheRule(string name, string requestUrl) + { + Name = name; + RequestUrl = requestUrl; + } + + /// + /// The rule name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The request url this rule should match for this TTL to be used (regex is supported). + /// + [JsonProperty("request_url")] + public string RequestUrl { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCollection.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCollection.cs new file mode 100644 index 000000000..1b4797fda --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceCollection.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a collection of service resources of the . + /// + /// + public class ServiceCollection : Page + { + /// + /// The requested services. + /// + [JsonProperty("services")] + protected IList Services => Items; + + /// + /// The paging navigation links. + /// + [JsonProperty("links")] + protected IList ServiceLinks => Links; + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceDefinition.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceDefinition.cs new file mode 100644 index 000000000..a546412fa --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceDefinition.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents the definition of a service resource of the . + /// + /// + public class ServiceDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// The service name. + /// The flavor identifier. + /// The service domain. + /// The service asset origin. + public ServiceDefinition(string name, string flavorId, string domain, string origin) + : this(name, flavorId, new[] {new ServiceDomain(domain)}, new[] {new ServiceOrigin(origin)}) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The service name. + /// The flavor identifier. + /// The service domains. + /// The service asset origins. + public ServiceDefinition(string name, string flavorId, IEnumerable domains, IEnumerable origins) + { + Name = name; + FlavorId = flavorId; + Domains = domains.ToNonNullList(); + Origins = origins.ToNonNullList(); + Caches = new List(); + Restrictions = new List(); + } + + /// + /// The service name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The identifier of the Content Delivery Network to used by this service. + /// + [JsonProperty("flavor_id")] + public string FlavorId { get; set; } + + /// + /// Domains used by users to access the website. + /// + [JsonProperty("domains")] + public IList Domains { get; set; } + + /// + /// Domains or IP addresses where the canonical assets are stored. + /// + [JsonProperty("origins")] + public IList Origins { get; set; } + + /// + /// Caching rules for the assets under this service. + /// + [JsonProperty("caching")] + public IList Caches { get; set; } + + /// + /// Restrictions defining who can access assets. + /// + [JsonProperty("restrictions")] + public IList Restrictions { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceDomain.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceDomain.cs new file mode 100644 index 000000000..3569b9256 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceDomain.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a service domain resource of the . + /// + /// + public class ServiceDomain + { + /// + /// Initializes a new instance of the class. + /// + /// The domain name. + public ServiceDomain(string domain) + { + Domain = domain; + } + + /// + /// The domain used to access the assets on their website, which will have a CNAME entry pointed back to the CDN provider. + /// + [JsonProperty("domain")] + public string Domain { get; set; } + + /// + /// The protocol used to access the assets on this domain. + /// + [JsonProperty("protocol")] + public ServiceProtocol? Protocol { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceError.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceError.cs new file mode 100644 index 000000000..9cf0e06fa --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceError.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a service error generated by the . + /// + /// + public class ServiceError + { + /// + /// The error message. + /// + [JsonProperty("message")] + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOperationFailedException.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOperationFailedException.cs new file mode 100644 index 000000000..ba8f35596 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOperationFailedException.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// The exception that is thrown when a service operation (Create, Delete, Update) fails. + /// + /// + [Serializable] + public sealed class ServiceOperationFailedException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public ServiceOperationFailedException(IEnumerable errors) + { + Errors = errors; + } + + /// + /// Initializes a new instance of the class. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + private ServiceOperationFailedException(SerializationInfo info, StreamingContext context) : base(info, context) + { + Errors = OpenStackNet.Deserialize>(info.GetString("service_errors")); + } + + /// + /// Errors generated during the previous service operation. + /// + public IEnumerable Errors { get; private set; } + + + /// + /// When overridden in a derived class, sets the with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// + /// + /// + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + // ReSharper disable once ExceptionNotDocumented + info.AddValue("service_errors", OpenStackNet.Serialize(Errors)); + base.GetObjectData(info, context); + } + } +} diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOrigin.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOrigin.cs new file mode 100644 index 000000000..df1cc1743 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOrigin.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a service origin resource of the . + /// + /// + public class ServiceOrigin + { + /// + /// Initializes a new instance of the class. + /// + /// The URL or IP address. + public ServiceOrigin(string origin) + { + Origin = origin; + Rules = new List(); + } + + /// + /// URL or IP address from which to pull canonical content. + /// + [JsonProperty("origin")] + public string Origin { get; set; } + + /// + /// Port used to access the origin. + /// + [JsonProperty("port")] + public int? Port { get; set; } + + /// + /// Specifies if the origin should be accessed via SSL/HTTPS. + /// + [JsonProperty("ssl")] + public bool? SSL { get; set; } + + /// + /// Rules defining the conditions when this origin should be accessed + /// + /// + /// The rules. + /// + [JsonProperty("rules")] + public IList Rules { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOriginRule.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOriginRule.cs new file mode 100644 index 000000000..c0a070532 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceOriginRule.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a service origin rule resource of the . + /// + /// + public class ServiceOriginRule + { + /// + /// Initializes a new instance of the class. + /// + /// The rule name. + /// The request URL this rule should match for this origin to be used. + public ServiceOriginRule(string name, string requestUrl) + { + Name = name; + RequestUrl = requestUrl; + } + + /// + /// The rule name. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// The request URL this rule should match for this origin to be used. (regex is supported). + /// + [JsonProperty("request_url")] + public string RequestUrl { get; private set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceProtocol.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceProtocol.cs new file mode 100644 index 000000000..42a32152d --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceProtocol.cs @@ -0,0 +1,21 @@ +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Protocol used to access the assets on a domain. + /// + [JsonConverter(typeof(StringEnumConverter))] + public enum ServiceProtocol + { + /// + [EnumMember(Value = "http")] + HTTP, + + /// + [EnumMember(Value = "https")] + HTTPS + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceRestriction.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceRestriction.cs new file mode 100644 index 000000000..1e0af411d --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceRestriction.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a service restriction resource of the . + /// + /// + public class ServiceRestriction + { + /// + /// Initializes a new instance of the class. + /// + /// The restriction name. + /// The rules that define the restrictions to impose. + public ServiceRestriction(string name, IEnumerable rules) + { + Name = name; + Rules = rules.ToNonNullList(); + } + + /// + /// The restriction name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Rules that define the restrictions to impose. + /// + [JsonProperty("rules")] + public IList Rules { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceRestrictionRule.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceRestrictionRule.cs new file mode 100644 index 000000000..9afeb450b --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceRestrictionRule.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Represents a service restriction rule resource of the . + /// + /// + public class ServiceRestrictionRule + { + /// + /// Initializes a new instance of the class. + /// + /// The restriction name. + /// The http host from which requests must originate. + public ServiceRestrictionRule(string name, string referrer) + { + Name = name; + Referrer = referrer; + } + + /// + /// The restriction name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The http host from which requests must originate. + /// + [JsonProperty("referrer")] + public string Referrer { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/ContentDeliveryNetworks/v1/ServiceStatus.cs b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceStatus.cs new file mode 100644 index 000000000..717d0c209 --- /dev/null +++ b/src/OpenStack/ContentDeliveryNetworks/v1/ServiceStatus.cs @@ -0,0 +1,43 @@ +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + /// + /// Content Delivery Network (CDN) service status + /// + [JsonConverter(typeof(StringEnumConverter))] + public enum ServiceStatus + { + /// + /// The service is currently being created and deployed. + /// + [EnumMember(Value = "create_in_progress")] + CreateInProgress, + + /// + /// The service has been deployed and is ready to use. + /// + [EnumMember(Value = "deployed")] + Deployed, + + /// + /// The service is currently being updated. + /// + [EnumMember(Value = "update_in_progress")] + UpdateInProgress, + + /// + /// The service is currently being deleted. + /// + [EnumMember(Value = "delete_in_progress")] + DeleteInProgress, + + /// + /// The previous operation on the service failed. Looks for the details on + /// + [EnumMember(Value = "failed")] + Failed + } +} \ No newline at end of file diff --git a/src/OpenStack/Core/AsyncCompletionOption.cs b/src/OpenStack/Core/AsyncCompletionOption.cs new file mode 100644 index 000000000..f864dfa9e --- /dev/null +++ b/src/OpenStack/Core/AsyncCompletionOption.cs @@ -0,0 +1,24 @@ +namespace net.openstack.Core +{ + using System.Threading.Tasks; + + /// + /// Specifies when a representing an asynchronous server operation + /// should be considered complete. + /// + /// + public enum AsyncCompletionOption + { + /// + /// The representing the operation is considered complete after the + /// request has been submitted to the server. + /// + RequestSubmitted, + + /// + /// The representing the operation is considered complete after the + /// server has completed processing the request. + /// + RequestCompleted, + } +} diff --git a/src/OpenStack/Core/BackoffPolicy.cs b/src/OpenStack/Core/BackoffPolicy.cs new file mode 100644 index 000000000..56da6c791 --- /dev/null +++ b/src/OpenStack/Core/BackoffPolicy.cs @@ -0,0 +1,63 @@ +namespace net.openstack.Core +{ + using System; + using System.Collections.Generic; + + /// + /// This class provides a default implementation of . + /// The default implementation uses a progressive back-off policy with no expiration. + /// + /// + /// + public class BackoffPolicy : IBackoffPolicy + { + /// + /// This is the backing field for the property. + /// + private static readonly BackoffPolicy _default = new BackoffPolicy(); + + /// + /// Gets a default instance of . + /// + public static BackoffPolicy Default + { + get + { + return _default; + } + } + + /// + /// + /// The default implementation uses the following progressive back-off strategy. + /// + /// No delay before polling the first time. + /// Poll once per second, up to 10 times. + /// Poll once per 5 seconds, up to 10 times. + /// Poll once per 15 seconds, up to 10 times. + /// Poll once per 30 seconds indefinitely. + /// + /// + public virtual IEnumerable GetBackoffIntervals() + { + // no delay before the first polling + yield return TimeSpan.Zero; + + // 10x once a second + for (int i = 0; i < 10; i++) + yield return TimeSpan.FromSeconds(1); + + // 10x once every 5 seconds + for (int i = 0; i < 10; i++) + yield return TimeSpan.FromSeconds(5); + + // 10x once every 15 seconds + for (int i = 0; i < 10; i++) + yield return TimeSpan.FromSeconds(15); + + // once every 30 seconds after + while (true) + yield return TimeSpan.FromSeconds(30); + } + } +} diff --git a/src/OpenStack/Core/Caching/ICache`1.cs b/src/OpenStack/Core/Caching/ICache`1.cs new file mode 100644 index 000000000..74f73bc42 --- /dev/null +++ b/src/OpenStack/Core/Caching/ICache`1.cs @@ -0,0 +1,41 @@ +namespace net.openstack.Core.Caching +{ + using System; + + /// + /// Represents a thread-safe cache of objects identified by string keys. + /// + /// Type type of objects stored in the cache. + public interface ICache + { + /// + /// Gets a value cached for a particular key, updating the value if necessary. + /// + /// + /// This method returns a previously cached value when possible. If any of the following + /// conditions are met, the function will be called to + /// obtain a new value for which is then added to the cache, + /// replacing any previously cached value. + /// + /// + /// The cache does not contain any value associated with . + /// is . + /// The previously cached value for is no longer valid. The exact + /// algorithm for determining whether or not a value is valid in implementation-defined. + /// + /// + /// If any of the above conditions is met and is , + /// the previously cached value for , if any, is removed from the cache + /// and the default value for is returned. + /// + /// The key. + /// A function which returns a new value for the specified , or if no update function available (see remarks). + /// If , the value associated with will be always be refreshed by calling , even if a value is already cached. + /// + /// The cached value associated with the specified . If no cached value is + /// available (see remarks), the method returns the default value for . + /// + /// If is . + T Get(string key, Func refreshCallback, bool forceCacheRefresh = false); + } +} diff --git a/src/OpenStack/Core/Caching/NamespaceDoc.cs b/src/OpenStack/Core/Caching/NamespaceDoc.cs new file mode 100644 index 000000000..366144de1 --- /dev/null +++ b/src/OpenStack/Core/Caching/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Core.Caching +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines types + /// used for caching, for example, the results of calls to various REST APIs + /// that are frequently reused. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Caching/UserAccessCache.cs b/src/OpenStack/Core/Caching/UserAccessCache.cs new file mode 100644 index 000000000..329c53e5f --- /dev/null +++ b/src/OpenStack/Core/Caching/UserAccessCache.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using net.openstack.Core.Domain; +using net.openstack.Core.Providers; + +namespace net.openstack.Core.Caching +{ + /// + /// Provides a thread-safe cache of objects. A default shared + /// instance is available through . + /// + public class UserAccessCache : ICache + { + private static readonly Lazy _instance = new Lazy(CreateInstance, true); + + private readonly ConcurrentDictionary _tokenCache = new ConcurrentDictionary(); + + /// + /// Gets a cached for a particular key, updating the value if necessary. + /// + /// + /// This method returns a previously cached when possible. If any + /// of the following conditions are met, the function + /// will be called to obtain a new value for which is then added to + /// the cache, replacing any previously cached value. + /// + /// + /// The cache does not contain any value associated with . + /// is . + /// The previously cached for has expired + /// (see ). + /// + /// + /// If any of the above conditions is met and is , + /// the previously cached value for , if any, is removed from the cache + /// and the method returns . + /// + /// The key. + /// A function which returns a new value for the specified , + /// or if no update function available (see remarks). This function may perform a synchronous + /// authentication to an . + /// If , the value associated with will be always be refreshed by calling , even if a value is already cached. + /// + /// The cached associated with the specified . + /// If no cached value is available (see remarks), the method returns . + /// + /// If is . + public UserAccess Get(string key, Func refreshCallback, bool forceCacheRefresh = false) + { + UserAccess userAccess; + + if (forceCacheRefresh) + { + if (refreshCallback != null) + { + userAccess = _tokenCache.AddOrUpdate(key, k => refreshCallback(), (k, existing) => refreshCallback()); + } + else + { + UserAccess ignored; + _tokenCache.TryRemove(key, out ignored); + userAccess = null; + } + } + else + { + if (_tokenCache.TryGetValue(key, out userAccess)) + { + if (!IsValid(userAccess)) + { + bool remove = true; + if (refreshCallback != null) + { + /* Attempt to update the key. Call IsValid on existing in case another thread + * performed a concurrent update and the result is now valid. + */ + userAccess = _tokenCache.AddOrUpdate(key, k => refreshCallback(), (k, existing) => IsValid(existing) ? existing : refreshCallback()); + remove = userAccess == null; + } + + if (remove) + { + /* only remove the key if it was updated to null or no refresh callback was given, + * and make sure to check the value before actually removing the entry. + * see: http://blogs.msdn.com/b/pfxteam/archive/2011/04/02/10149222.aspx + */ + var pair = new KeyValuePair(key, userAccess); + ((ICollection>)_tokenCache).Remove(pair); + } + } + } + else + { + userAccess = _tokenCache.AddOrUpdate(key, k => refreshCallback(), (k, existing) => refreshCallback()); + } + } + + return userAccess; + } + + /// + /// Gets a default instance of . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public static UserAccessCache Instance + { + get + { + return _instance.Value; + } + } + + private static UserAccessCache CreateInstance() + { + return new UserAccessCache(); + } + + private static bool IsValid(UserAccess userAccess) + { + IdentityToken token = userAccess != null ? userAccess.Token : null; + return token != null && !token.IsExpired; + } + } +} diff --git a/src/OpenStack/Core/Collections/BasicReadOnlyCollectionPage`1.cs b/src/OpenStack/Core/Collections/BasicReadOnlyCollectionPage`1.cs new file mode 100644 index 000000000..9a166ceef --- /dev/null +++ b/src/OpenStack/Core/Collections/BasicReadOnlyCollectionPage`1.cs @@ -0,0 +1,55 @@ +namespace net.openstack.Core.Collections +{ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Provides a basic implementation of using + /// a function delegate as the implementation of . + /// + /// The type of elements in the collection. + /// + /// + public class BasicReadOnlyCollectionPage : ReadOnlyCollectionPage + { + /// + /// This is the backing field for both and . + /// + private readonly Func>> _getNextPageAsync; + + /// + /// Initializes a new instance of the class + /// that is a read-only wrapper around the specified list. + /// + /// The list to wrap. + /// A function that returns a representing the asynchronous operation to get the next page of items in the collection. If specified, this function implements . If the value is , then will return . + /// + /// If is . + /// + public BasicReadOnlyCollectionPage(IList list, Func>> getNextPageAsync) + : base(list) + { + _getNextPageAsync = getNextPageAsync; + } + + /// + public override bool CanHaveNextPage + { + get + { + return _getNextPageAsync != null; + } + } + + /// + public override Task> GetNextPageAsync(CancellationToken cancellationToken) + { + if (!CanHaveNextPage) + throw new InvalidOperationException("Cannot obtain the next page when CanHaveNextPage is false."); + + return _getNextPageAsync(cancellationToken); + } + } +} diff --git a/src/OpenStack/Core/Collections/NamespaceDoc.cs b/src/OpenStack/Core/Collections/NamespaceDoc.cs new file mode 100644 index 000000000..0f7adbb79 --- /dev/null +++ b/src/OpenStack/Core/Collections/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Core.Collections +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace contains interfaces and + /// classes that extend the collections support provided by the base class library. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Collections/ReadOnlyCollectionPage`1.cs b/src/OpenStack/Core/Collections/ReadOnlyCollectionPage`1.cs new file mode 100644 index 000000000..c1c04bc1b --- /dev/null +++ b/src/OpenStack/Core/Collections/ReadOnlyCollectionPage`1.cs @@ -0,0 +1,108 @@ +namespace net.openstack.Core.Collections +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Provides the base class for a generic read-only collection representing a + /// single page within a paginated collection. + /// + /// The type of elements in the collection. + /// + /// + public abstract class ReadOnlyCollectionPage : ReadOnlyCollection + { + /// + /// Initializes a new instance of the class + /// that is a read-only wrapper around the specified list. + /// + /// The list to wrap. + /// If is . + protected ReadOnlyCollectionPage(IList list) + : base(list) + { + } + + /// + /// Gets an empty page from a paginated collection. + /// + public static ReadOnlyCollectionPage Empty + { + get + { + return EmptyPage.Instance; + } + } + + /// + /// Gets a value indicating whether another page of results may follow the current page. + /// + /// if another page of results may follow the current page; otherwise, . + public abstract bool CanHaveNextPage + { + get; + } + + /// + /// Gets the next page in the paginated collection. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task + /// completes successfully, the property will contain + /// a collection containing the next page of results. + /// + /// If is . + /// If the REST request does not return successfully. + public abstract Task> GetNextPageAsync(CancellationToken cancellationToken); + + /// + /// Represents an empty page from a paginated collection. + /// + private sealed class EmptyPage : ReadOnlyCollectionPage + { + /// + /// This is the backing field for the property. + /// + private static readonly EmptyPage _instance = new EmptyPage(); + + /// + /// Initializes a new instance of the class. + /// + private EmptyPage() + : base(new T[0]) + { + } + + /// + /// Gets a singleton instance of an empty page from a paginated collection. + /// + public static EmptyPage Instance + { + get + { + return _instance; + } + } + + /// + public override bool CanHaveNextPage + { + get + { + return false; + } + } + + /// + public override Task> GetNextPageAsync(CancellationToken cancellationToken) + { + throw new InvalidOperationException("Cannot obtain the next page when CanHaveNextPage is false."); + } + } + } +} diff --git a/src/OpenStack/Core/Compat/Funcs.cs b/src/OpenStack/Core/Compat/Funcs.cs new file mode 100644 index 000000000..6d38079e5 --- /dev/null +++ b/src/OpenStack/Core/Compat/Funcs.cs @@ -0,0 +1,53 @@ +// +// System.Func.cs +// +// Authors: +// Alejandro Serrano "Serras" (trupill@yahoo.es) +// Marek Safar (marek.safar@gmail.com) +// + +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR TArg PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// + +using System.Runtime.CompilerServices; + +namespace net.openstack.Core { + +#if NET35 + /// + /// Encapsulates a method that has six parameters and returns a value of the type specified by the parameter. + /// + /// The type of the first parameter of the method that this delegate encapsulates. + /// The type of the second parameter of the method that this delegate encapsulates. + /// The type of the third parameter of the method that this delegate encapsulates. + /// The type of the fourth parameter of the method that this delegate encapsulates. + /// The type of the fifth parameter of the method that this delegate encapsulates. + /// The type of the sixth parameter of the method that this delegate encapsulates. + /// The type of the return value of the method that this delegate encapsulates. + /// The first parameter of the method that this delegate encapsulates. + /// The second parameter of the method that this delegate encapsulates. + /// The third parameter of the method that this delegate encapsulates. + /// The fourth parameter of the method that this delegate encapsulates. + /// The fifth parameter of the method that this delegate encapsulates. + /// The sixth parameter of the method that this delegate encapsulates. + /// The return value of the method that this delegate encapsulates. + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); +#endif + +} diff --git a/src/OpenStack/Core/Compat/ISafeSerializationData.cs b/src/OpenStack/Core/Compat/ISafeSerializationData.cs new file mode 100644 index 000000000..45e8c601d --- /dev/null +++ b/src/OpenStack/Core/Compat/ISafeSerializationData.cs @@ -0,0 +1,17 @@ +#if NET35 + +namespace System.Runtime.Serialization +{ + /// + /// For internal compatibility use only. + /// + internal interface ISafeSerializationData + { + /// + /// For internal compatibility use only. + /// + void CompleteDeserialization(object deserialized); + } +} + +#endif diff --git a/src/OpenStack/Core/Compat/IStructuralComparable.cs b/src/OpenStack/Core/Compat/IStructuralComparable.cs new file mode 100644 index 000000000..2101ecf41 --- /dev/null +++ b/src/OpenStack/Core/Compat/IStructuralComparable.cs @@ -0,0 +1,72 @@ +// +// IStructuralComparable.cs +// +// Authors: +// Zoltan Varga (vargaz@gmail.com) +// +// Copyright (C) 2009 Novell +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET35 + +using System; +using System.Collections; + +namespace net.openstack.Core +{ + /// + /// Supports the structural comparison of collection objects. + /// + public interface IStructuralComparable { + /// + /// Determines whether the current collection object precedes, occurs in the same position as, or follows another object in the sort order. + /// + /// The object to compare with the current instance. + /// An object that compares members of the current collection object with the corresponding members of . + /// + /// An integer that indicates the relationship of the current collection object to other, as shown in the following table. + /// + /// + /// + /// Return value + /// Description + /// + /// + /// -1 + /// The current instance precedes . + /// + /// + /// 0 + /// The current instance and are equal. + /// + /// + /// 1 + /// The current instance follows . + /// + /// + /// + /// This instance and are not the same type. + int CompareTo (object other, IComparer comparer); + } +} + +#endif diff --git a/src/OpenStack/Core/Compat/IStructuralEquatable.cs b/src/OpenStack/Core/Compat/IStructuralEquatable.cs new file mode 100644 index 000000000..ed2bb23de --- /dev/null +++ b/src/OpenStack/Core/Compat/IStructuralEquatable.cs @@ -0,0 +1,57 @@ +// +// IStructuralEquatable.cs +// +// Authors: +// Zoltan Varga (vargaz@gmail.com) +// +// Copyright (C) 2009 Novell +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET35 + +using System; +using System.Collections; + +namespace net.openstack.Core +{ + /// + /// Defines methods to support the comparison of objects for structural equality. + /// + public interface IStructuralEquatable { + /// + /// Determines whether an object is structurally equal to the current instance. + /// + /// The object to compare with the current instance. + /// An object that determines whether the current instance and are equal. + /// if the two objects are equal; otherwise, . + bool Equals (object other, IEqualityComparer comparer); + + /// + /// Returns a hash code for the current instance. + /// + /// An object that computes the hash code of the current object. + /// The hash code for the current instance. + int GetHashCode (IEqualityComparer comparer); + } +} + +#endif diff --git a/src/OpenStack/Core/Compat/Tuple.cs b/src/OpenStack/Core/Compat/Tuple.cs new file mode 100644 index 000000000..913cb5fe9 --- /dev/null +++ b/src/OpenStack/Core/Compat/Tuple.cs @@ -0,0 +1,222 @@ +// +// Tuple.cs +// +// Authors: +// Zoltan Varga (vargaz@gmail.com) +// +// Copyright (C) 2009 Novell +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET35 + +using System; + +namespace net.openstack.Core +{ + /// + /// Provides static methods for creating tuple objects. + /// + public static class Tuple + { + /// + /// Creates a new 8-tuple, or octuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + /// The type of the seventh component of the tuple. + /// The type of the eighth component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + /// The value of the seventh component of the tuple. + /// The value of the eighth component of the tuple. + /// An 8-tuple (octuple) whose value is (, , , , , , , ). + public static Tuple> Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6, + T7 item7, + T8 item8) { + return new Tuple> (item1, item2, item3, item4, item5, item6, item7, new Tuple (item8)); + } + + /// + /// Creates a new 7-tuple, or septuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + /// The type of the seventh component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + /// The value of the seventh component of the tuple. + /// A 7-tuple (septuple) whose value is (, , , , , , ). + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6, + T7 item7) { + return new Tuple (item1, item2, item3, item4, item5, item6, item7); + } + + /// + /// Creates a new 6-tuple, or sextuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + /// A 6-tuple (sextuple) whose value is (, , , , , ). + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6) { + return new Tuple (item1, item2, item3, item4, item5, item6); + } + + /// + /// Creates a new 5-tuple, or quintuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// A 5-tuple (quintuple) whose value is (, , , , ). + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5) { + return new Tuple (item1, item2, item3, item4, item5); + } + + /// + /// Creates a new 4-tuple, or quadruple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// A 4-tuple (quadruple) whose value is (, , , ). + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4) { + return new Tuple (item1, item2, item3, item4); + } + + /// + /// Creates a new 3-tuple, or triple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// A 3-tuple (triple) whose value is (, , ). + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3) { + return new Tuple (item1, item2, item3); + } + + /// + /// Creates a new 2-tuple, or pair. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// A 2-tuple (pair) whose value is (, ). + public static Tuple Create + ( + T1 item1, + T2 item2) { + return new Tuple (item1, item2); + } + + /// + /// Creates a new 1-tuple, or singleton. + /// + /// The type of the only component of the tuple. + /// The value of the only component of the tuple. + /// A 1-tuple (singleton) whose value is (). + public static Tuple Create + ( + T1 item1) { + return new Tuple (item1); + } + } +} + +#endif diff --git a/src/OpenStack/Core/Compat/Tuples.cs b/src/OpenStack/Core/Compat/Tuples.cs new file mode 100644 index 000000000..dc0592876 --- /dev/null +++ b/src/OpenStack/Core/Compat/Tuples.cs @@ -0,0 +1,1280 @@ +// +// Tuples.cs +// +// Authors: +// Zoltan Varga (vargaz@gmail.com) +// Marek Safar (marek.safar@gmail.com) +// +// Copyright (C) 2009 Novell +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET35 + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace net.openstack.Core +{ + public partial class Tuple + { + /// + /// Initializes a new instance of the class. + /// + /// The value of the tuple's first component. + /// The value of the tuple's second component. + /// The value of the tuple's third component. + /// The value of the tuple's fourth component. + /// The value of the tuple's fifth component. + /// The value of the tuple's sixth component. + /// The value of the tuple's seventh component. + /// Any generic Tuple object that contains the values of the tuple's remaining components. + /// is not a generic Tuple object. + public Tuple (T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + this.item7 = item7; + this.rest = rest; + + bool ok = true; + if (!typeof (TRest).IsGenericType) + ok = false; + if (ok) { + Type t = typeof (TRest).GetGenericTypeDefinition (); + if (!(t == typeof (Tuple<>) || t == typeof (Tuple<,>) || t == typeof (Tuple<,,>) || t == typeof (Tuple<,,,>) || t == typeof (Tuple<,,,,>) || t == typeof (Tuple <,,,,,>) || t == typeof (Tuple<,,,,,,>) || t == typeof (Tuple<,,,,,,,>))) + ok = false; + } + if (!ok) + throw new ArgumentException ("rest", "The last element of an eight element tuple must be a Tuple."); + } + } + + /* The rest is generated by the script at the bottom */ + + /// + /// Represents a 1-tuple, or singleton. + /// + /// The type of the tuple's only component. + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable + { + T1 item1; + + /// + /// Initializes a new instance of the class. + /// + /// The value of the tuple's only component. + public Tuple (T1 item1) + { + this.item1 = item1; + } + + /// + /// Gets the value of the current object's only component. + /// + public T1 Item1 { + get { return item1; } + } + + /// + int IComparable.CompareTo (object obj) + { + return ((IStructuralComparable) this).CompareTo (obj, Comparer.Default); + } + + /// + int IStructuralComparable.CompareTo (object other, IComparer comparer) + { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException ("other"); + } + + return comparer.Compare (item1, t.item1); + } + + /// + public override bool Equals (object obj) + { + return ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default); + } + + /// + bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer) + { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals (item1, t.item1); + } + + /// + public override int GetHashCode () + { + return ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default); + } + + /// + int IStructuralEquatable.GetHashCode (IEqualityComparer comparer) + { + return comparer.GetHashCode (item1); + } + + /// + public override string ToString () + { + return String.Format ("({0})", item1); + } + } + + /// + /// Represents a 2-tuple, or pair. + /// + /// The type of the tuple's first component. + /// The type of the tuple's second component. + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable + { + T1 item1; + T2 item2; + + /// + /// Initializes a new instance of the class. + /// + /// The value of the tuple's first component. + /// The value of the tuple's second component. + public Tuple (T1 item1, T2 item2) + { + this.item1 = item1; + this.item2 = item2; + } + + /// + /// Gets the value of the current object's first component. + /// + public T1 Item1 { + get { return item1; } + } + + /// + /// Gets the value of the current object's second component. + /// + public T2 Item2 { + get { return item2; } + } + + /// + int IComparable.CompareTo (object obj) + { + return ((IStructuralComparable) this).CompareTo (obj, Comparer.Default); + } + + /// + int IStructuralComparable.CompareTo (object other, IComparer comparer) + { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException ("other"); + } + + int res = comparer.Compare (item1, t.item1); + if (res != 0) return res; + return comparer.Compare (item2, t.item2); + } + + /// + public override bool Equals (object obj) + { + return ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default); + } + + /// + bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer) + { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals (item1, t.item1) && + comparer.Equals (item2, t.item2); + } + + /// + public override int GetHashCode () + { + return ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default); + } + + /// + int IStructuralEquatable.GetHashCode (IEqualityComparer comparer) + { + int h = comparer.GetHashCode (item1); + h = (h << 5) - h + comparer.GetHashCode (item2); + return h; + } + + /// + public override string ToString () + { + return String.Format ("({0}, {1})", item1, item2); + } + } + + /// + /// Represents a 3-tuple, or triple. + /// + /// The type of the tuple's first component. + /// The type of the tuple's second component. + /// The type of the tuple's third component. + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable + { + T1 item1; + T2 item2; + T3 item3; + + /// + /// Initializes a new instance of the class. + /// + /// The value of the tuple's first component. + /// The value of the tuple's second component. + /// The value of the tuple's third component. + public Tuple (T1 item1, T2 item2, T3 item3) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + } + + /// + /// Gets the value of the current object's first component. + /// + public T1 Item1 { + get { return item1; } + } + + /// + /// Gets the value of the current object's second component. + /// + public T2 Item2 { + get { return item2; } + } + + /// + /// Gets the value of the current object's third component. + /// + public T3 Item3 { + get { return item3; } + } + + /// + int IComparable.CompareTo (object obj) + { + return ((IStructuralComparable) this).CompareTo (obj, Comparer.Default); + } + + /// + int IStructuralComparable.CompareTo (object other, IComparer comparer) + { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException ("other"); + } + + int res = comparer.Compare (item1, t.item1); + if (res != 0) return res; + res = comparer.Compare (item2, t.item2); + if (res != 0) return res; + return comparer.Compare (item3, t.item3); + } + + /// + public override bool Equals (object obj) + { + return ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default); + } + + /// + bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer) + { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals (item1, t.item1) && + comparer.Equals (item2, t.item2) && + comparer.Equals (item3, t.item3); + } + + /// + public override int GetHashCode () + { + return ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default); + } + + /// + int IStructuralEquatable.GetHashCode (IEqualityComparer comparer) + { + int h = comparer.GetHashCode (item1); + h = (h << 5) - h + comparer.GetHashCode (item2); + h = (h << 5) - h + comparer.GetHashCode (item3); + return h; + } + + /// + public override string ToString () + { + return String.Format ("({0}, {1}, {2})", item1, item2, item3); + } + } + + /// + /// Represents a 4-tuple, or quadruple. + /// + /// The type of the tuple's first component. + /// The type of the tuple's second component. + /// The type of the tuple's third component. + /// The type of the tuple's fourth component. + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + + /// + /// Initializes a new instance of the class. + /// + /// The value of the tuple's first component. + /// The value of the tuple's second component. + /// The value of the tuple's third component. + /// The value of the tuple's fourth component. + public Tuple (T1 item1, T2 item2, T3 item3, T4 item4) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + } + + /// + /// Gets the value of the current object's first component. + /// + public T1 Item1 { + get { return item1; } + } + + /// + /// Gets the value of the current object's second component. + /// + public T2 Item2 { + get { return item2; } + } + + /// + /// Gets the value of the current object's third component. + /// + public T3 Item3 { + get { return item3; } + } + + /// + /// Gets the value of the current object's fourth component. + /// + public T4 Item4 { + get { return item4; } + } + + /// + int IComparable.CompareTo (object obj) + { + return ((IStructuralComparable) this).CompareTo (obj, Comparer.Default); + } + + /// + int IStructuralComparable.CompareTo (object other, IComparer comparer) + { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException ("other"); + } + + int res = comparer.Compare (item1, t.item1); + if (res != 0) return res; + res = comparer.Compare (item2, t.item2); + if (res != 0) return res; + res = comparer.Compare (item3, t.item3); + if (res != 0) return res; + return comparer.Compare (item4, t.item4); + } + + /// + public override bool Equals (object obj) + { + return ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default); + } + + /// + bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer) + { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals (item1, t.item1) && + comparer.Equals (item2, t.item2) && + comparer.Equals (item3, t.item3) && + comparer.Equals (item4, t.item4); + } + + /// + public override int GetHashCode () + { + return ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default); + } + + /// + int IStructuralEquatable.GetHashCode (IEqualityComparer comparer) + { + int h = comparer.GetHashCode (item1); + h = (h << 5) - h + comparer.GetHashCode (item2); + h = (h << 5) - h + comparer.GetHashCode (item3); + h = (h << 5) - h + comparer.GetHashCode (item4); + return h; + } + + /// + public override string ToString () + { + return String.Format ("({0}, {1}, {2}, {3})", item1, item2, item3, item4); + } + } + + /// + /// Represents a 5-tuple, or quintuple. + /// + /// The type of the tuple's first component. + /// The type of the tuple's second component. + /// The type of the tuple's third component. + /// The type of the tuple's fourth component. + /// The type of the tuple's fifth component. + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + + /// + /// Initializes a new instance of the class. + /// + /// The value of the tuple's first component. + /// The value of the tuple's second component. + /// The value of the tuple's third component. + /// The value of the tuple's fourth component. + /// The value of the tuple's fifth component. + public Tuple (T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + } + + /// + /// Gets the value of the current object's first component. + /// + public T1 Item1 { + get { return item1; } + } + + /// + /// Gets the value of the current object's second component. + /// + public T2 Item2 { + get { return item2; } + } + + /// + /// Gets the value of the current object's third component. + /// + public T3 Item3 { + get { return item3; } + } + + /// + /// Gets the value of the current object's fourth component. + /// + public T4 Item4 { + get { return item4; } + } + + /// + /// Gets the value of the current object's fifth component. + /// + public T5 Item5 { + get { return item5; } + } + + /// + int IComparable.CompareTo (object obj) + { + return ((IStructuralComparable) this).CompareTo (obj, Comparer.Default); + } + + /// + int IStructuralComparable.CompareTo (object other, IComparer comparer) + { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException ("other"); + } + + int res = comparer.Compare (item1, t.item1); + if (res != 0) return res; + res = comparer.Compare (item2, t.item2); + if (res != 0) return res; + res = comparer.Compare (item3, t.item3); + if (res != 0) return res; + res = comparer.Compare (item4, t.item4); + if (res != 0) return res; + return comparer.Compare (item5, t.item5); + } + + /// + public override bool Equals (object obj) + { + return ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default); + } + + /// + bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer) + { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals (item1, t.item1) && + comparer.Equals (item2, t.item2) && + comparer.Equals (item3, t.item3) && + comparer.Equals (item4, t.item4) && + comparer.Equals (item5, t.item5); + } + + /// + public override int GetHashCode () + { + return ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default); + } + + /// + int IStructuralEquatable.GetHashCode (IEqualityComparer comparer) + { + int h = comparer.GetHashCode (item1); + h = (h << 5) - h + comparer.GetHashCode (item2); + h = (h << 5) - h + comparer.GetHashCode (item3); + h = (h << 5) - h + comparer.GetHashCode (item4); + h = (h << 5) - h + comparer.GetHashCode (item5); + return h; + } + + /// + public override string ToString () + { + return String.Format ("({0}, {1}, {2}, {3}, {4})", item1, item2, item3, item4, item5); + } + } + + /// + /// Represents a 6-tuple, or sextuple. + /// + /// The type of the tuple's first component. + /// The type of the tuple's second component. + /// The type of the tuple's third component. + /// The type of the tuple's fourth component. + /// The type of the tuple's fifth component. + /// The type of the tuple's sixth component. + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + + /// + /// Initializes a new instance of the class. + /// + /// The value of the tuple's first component. + /// The value of the tuple's second component. + /// The value of the tuple's third component. + /// The value of the tuple's fourth component. + /// The value of the tuple's fifth component. + /// The value of the tuple's sixth component. + public Tuple (T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + } + + /// + /// Gets the value of the current object's first component. + /// + public T1 Item1 { + get { return item1; } + } + + /// + /// Gets the value of the current object's second component. + /// + public T2 Item2 { + get { return item2; } + } + + /// + /// Gets the value of the current object's third component. + /// + public T3 Item3 { + get { return item3; } + } + + /// + /// Gets the value of the current object's fourth component. + /// + public T4 Item4 { + get { return item4; } + } + + /// + /// Gets the value of the current object's fifth component. + /// + public T5 Item5 { + get { return item5; } + } + + /// + /// Gets the value of the current object's sixth component. + /// + public T6 Item6 { + get { return item6; } + } + + /// + int IComparable.CompareTo (object obj) + { + return ((IStructuralComparable) this).CompareTo (obj, Comparer.Default); + } + + /// + int IStructuralComparable.CompareTo (object other, IComparer comparer) + { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException ("other"); + } + + int res = comparer.Compare (item1, t.item1); + if (res != 0) return res; + res = comparer.Compare (item2, t.item2); + if (res != 0) return res; + res = comparer.Compare (item3, t.item3); + if (res != 0) return res; + res = comparer.Compare (item4, t.item4); + if (res != 0) return res; + res = comparer.Compare (item5, t.item5); + if (res != 0) return res; + return comparer.Compare (item6, t.item6); + } + + /// + public override bool Equals (object obj) + { + return ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default); + } + + /// + bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer) + { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals (item1, t.item1) && + comparer.Equals (item2, t.item2) && + comparer.Equals (item3, t.item3) && + comparer.Equals (item4, t.item4) && + comparer.Equals (item5, t.item5) && + comparer.Equals (item6, t.item6); + } + + /// + public override int GetHashCode () + { + return ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default); + } + + /// + int IStructuralEquatable.GetHashCode (IEqualityComparer comparer) + { + int h = comparer.GetHashCode (item1); + h = (h << 5) - h + comparer.GetHashCode (item2); + h = (h << 5) - h + comparer.GetHashCode (item3); + h = (h << 5) - h + comparer.GetHashCode (item4); + h = (h << 5) - h + comparer.GetHashCode (item5); + h = (h << 5) - h + comparer.GetHashCode (item6); + return h; + } + + /// + public override string ToString () + { + return String.Format ("({0}, {1}, {2}, {3}, {4}, {5})", item1, item2, item3, item4, item5, item6); + } + } + + /// + /// Represents a 7-tuple, or septuple. + /// + /// The type of the tuple's first component. + /// The type of the tuple's second component. + /// The type of the tuple's third component. + /// The type of the tuple's fourth component. + /// The type of the tuple's fifth component. + /// The type of the tuple's sixth component. + /// The type of the tuple's seventh component. + [Serializable] + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + T7 item7; + + /// + /// Initializes a new instance of the class. + /// + /// The value of the tuple's first component. + /// The value of the tuple's second component. + /// The value of the tuple's third component. + /// The value of the tuple's fourth component. + /// The value of the tuple's fifth component. + /// The value of the tuple's sixth component. + /// The value of the tuple's seventh component. + public Tuple (T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + this.item7 = item7; + } + + /// + /// Gets the value of the current object's first component. + /// + public T1 Item1 { + get { return item1; } + } + + /// + /// Gets the value of the current object's second component. + /// + public T2 Item2 { + get { return item2; } + } + + /// + /// Gets the value of the current object's third component. + /// + public T3 Item3 { + get { return item3; } + } + + /// + /// Gets the value of the current object's fourth component. + /// + public T4 Item4 { + get { return item4; } + } + + /// + /// Gets the value of the current object's fifth component. + /// + public T5 Item5 { + get { return item5; } + } + + /// + /// Gets the value of the current object's sixth component. + /// + public T6 Item6 { + get { return item6; } + } + + /// + /// Gets the value of the current object's seventh component. + /// + public T7 Item7 { + get { return item7; } + } + + /// + int IComparable.CompareTo (object obj) + { + return ((IStructuralComparable) this).CompareTo (obj, Comparer.Default); + } + + /// + int IStructuralComparable.CompareTo (object other, IComparer comparer) + { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException ("other"); + } + + int res = comparer.Compare (item1, t.item1); + if (res != 0) return res; + res = comparer.Compare (item2, t.item2); + if (res != 0) return res; + res = comparer.Compare (item3, t.item3); + if (res != 0) return res; + res = comparer.Compare (item4, t.item4); + if (res != 0) return res; + res = comparer.Compare (item5, t.item5); + if (res != 0) return res; + res = comparer.Compare (item6, t.item6); + if (res != 0) return res; + return comparer.Compare (item7, t.item7); + } + + /// + public override bool Equals (object obj) + { + return ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default); + } + + /// + bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer) + { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals (item1, t.item1) && + comparer.Equals (item2, t.item2) && + comparer.Equals (item3, t.item3) && + comparer.Equals (item4, t.item4) && + comparer.Equals (item5, t.item5) && + comparer.Equals (item6, t.item6) && + comparer.Equals (item7, t.item7); + } + + /// + public override int GetHashCode () + { + return ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default); + } + + /// + int IStructuralEquatable.GetHashCode (IEqualityComparer comparer) + { + int h = comparer.GetHashCode (item1); + h = (h << 5) - h + comparer.GetHashCode (item2); + h = (h << 5) - h + comparer.GetHashCode (item3); + h = (h << 5) - h + comparer.GetHashCode (item4); + h = (h << 5) - h + comparer.GetHashCode (item5); + h = (h << 5) - h + comparer.GetHashCode (item6); + h = (h << 5) - h + comparer.GetHashCode (item7); + return h; + } + + /// + public override string ToString () + { + return String.Format ("({0}, {1}, {2}, {3}, {4}, {5}, {6})", item1, item2, item3, item4, item5, item6, item7); + } + } + + /// + /// Represents an n-tuple, where n is 8 or greater. + /// + /// The type of the tuple's first component. + /// The type of the tuple's second component. + /// The type of the tuple's third component. + /// The type of the tuple's fourth component. + /// The type of the tuple's fifth component. + /// The type of the tuple's sixth component. + /// The type of the tuple's seventh component. + /// Any generic Tuple object that defines the types of the tuple's remaining components. + [Serializable] + public partial class Tuple : IStructuralEquatable, IStructuralComparable, IComparable + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + T7 item7; + TRest rest; + + /// + /// Gets the value of the current object's first component. + /// + public T1 Item1 { + get { return item1; } + } + + /// + /// Gets the value of the current object's second component. + /// + public T2 Item2 { + get { return item2; } + } + + /// + /// Gets the value of the current object's third component. + /// + public T3 Item3 { + get { return item3; } + } + + /// + /// Gets the value of the current object's fourth component. + /// + public T4 Item4 { + get { return item4; } + } + + /// + /// Gets the value of the current object's fifth component. + /// + public T5 Item5 { + get { return item5; } + } + + /// + /// Gets the value of the current object's sixth component. + /// + public T6 Item6 { + get { return item6; } + } + + /// + /// Gets the value of the current object's seventh component. + /// + public T7 Item7 { + get { return item7; } + } + + /// + /// Gets the current object's remaining components. + /// + public TRest Rest { + get { return rest; } + } + + /// + int IComparable.CompareTo (object obj) + { + return ((IStructuralComparable) this).CompareTo (obj, Comparer.Default); + } + + /// + int IStructuralComparable.CompareTo (object other, IComparer comparer) + { + var t = other as Tuple; + if (t == null) { + if (other == null) return 1; + throw new ArgumentException ("other"); + } + + int res = comparer.Compare (item1, t.item1); + if (res != 0) return res; + res = comparer.Compare (item2, t.item2); + if (res != 0) return res; + res = comparer.Compare (item3, t.item3); + if (res != 0) return res; + res = comparer.Compare (item4, t.item4); + if (res != 0) return res; + res = comparer.Compare (item5, t.item5); + if (res != 0) return res; + res = comparer.Compare (item6, t.item6); + if (res != 0) return res; + res = comparer.Compare (item7, t.item7); + if (res != 0) return res; + return comparer.Compare (rest, t.rest); + } + + /// + public override bool Equals (object obj) + { + return ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default); + } + + /// + bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer) + { + var t = other as Tuple; + if (t == null) + return false; + + return comparer.Equals (item1, t.item1) && + comparer.Equals (item2, t.item2) && + comparer.Equals (item3, t.item3) && + comparer.Equals (item4, t.item4) && + comparer.Equals (item5, t.item5) && + comparer.Equals (item6, t.item6) && + comparer.Equals (item7, t.item7) && + comparer.Equals (rest, t.rest); + } + + /// + public override int GetHashCode () + { + return ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default); + } + + /// + int IStructuralEquatable.GetHashCode (IEqualityComparer comparer) + { + int h = comparer.GetHashCode (item1); + h = (h << 5) - h + comparer.GetHashCode (item2); + h = (h << 5) - h + comparer.GetHashCode (item3); + h = (h << 5) - h + comparer.GetHashCode (item4); + h = (h << 5) - h + comparer.GetHashCode (item5); + h = (h << 5) - h + comparer.GetHashCode (item6); + h = (h << 5) - h + comparer.GetHashCode (item7); + h = (h << 5) - h + comparer.GetHashCode (rest); + return h; + } + + /// + public override string ToString () + { + return String.Format ("({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", item1, item2, item3, item4, item5, item6, item7, rest); + } + } + +} + +#endif + +#if FALSE + +// +// generator script +// + +using System; +using System.Text; + +public class TupleGen +{ + public static void Main () { + for (int arity = 1; arity < 9; ++arity) { + string type_name = GetTypeName (arity); + + Console.WriteLine ("\t[Serializable]"); + Console.Write ("\tpublic {0}class ", arity < 8 ? null : "partial "); + Console.Write (type_name); + Console.WriteLine (" : IStructuralEquatable, IStructuralComparable, IComparable"); + Console.WriteLine ("\t{"); + for (int i = 1; i <= arity; ++i) + Console.WriteLine ("\t\t{0} {1};", GetItemTypeName (i), GetItemName (i)); + + if (arity < 8) { + Console.WriteLine (); + Console.Write ("\t\tpublic Tuple ("); + for (int i = 1; i <= arity; ++i) { + Console.Write ("{0} {1}", GetItemTypeName (i), GetItemName (i)); + if (i < arity) + Console.Write (", "); + } + Console.WriteLine (")"); + Console.WriteLine ("\t\t{"); + for (int i = 1; i <= arity; ++i) + Console.WriteLine ("\t\t\t this.{0} = {0};", GetItemName (i)); + Console.WriteLine ("\t\t}"); + } + + for (int i = 1; i <= arity; ++i) { + Console.WriteLine (); + Console.WriteLine ("\t\tpublic {0} {1} {{", GetItemTypeName (i), + System.Globalization.CultureInfo.InvariantCulture.TextInfo.ToTitleCase (GetItemName (i))); + Console.Write ("\t\t\tget { "); + Console.WriteLine ("return {0}; }}", GetItemName (i)); + Console.WriteLine ("\t\t}"); + } + + Console.WriteLine (); + Console.WriteLine ("\t\tint IComparable.CompareTo (object obj)"); + Console.WriteLine ("\t\t{"); + Console.WriteLine ("\t\t\treturn ((IStructuralComparable) this).CompareTo (obj, Comparer.Default);"); + Console.WriteLine ("\t\t}"); + + Console.WriteLine (); + Console.WriteLine ("\t\tint IStructuralComparable.CompareTo (object other, IComparer comparer)"); + Console.WriteLine ("\t\t{"); + Console.WriteLine ("\t\t\tvar t = other as {0};", type_name); + Console.WriteLine ("\t\t\tif (t == null) {"); + Console.WriteLine ("\t\t\t\tif (other == null) return 1;"); + Console.WriteLine ("\t\t\t\tthrow new ArgumentException ("other");"); + Console.WriteLine ("\t\t\t}"); + Console.WriteLine (); + + for (int i = 1; i < arity; ++i) { + Console.Write ("\t\t\t"); + if (i == 1) + Console.Write ("int "); + + Console.WriteLine ("res = comparer.Compare ({0}, t.{0});", GetItemName (i)); + Console.WriteLine ("\t\t\tif (res != 0) return res;"); + } + Console.WriteLine ("\t\t\treturn comparer.Compare ({0}, t.{0});", GetItemName (arity)); + Console.WriteLine ("\t\t}"); + + Console.WriteLine (); + Console.WriteLine ("\t\tpublic override bool Equals (object obj)"); + Console.WriteLine ("\t\t{"); + Console.WriteLine ("\t\t\treturn ((IStructuralEquatable) this).Equals (obj, EqualityComparer.Default);"); + Console.WriteLine ("\t\t}"); + + Console.WriteLine (); + Console.WriteLine ("\t\tbool IStructuralEquatable.Equals (object other, IEqualityComparer comparer)"); + Console.WriteLine ("\t\t{"); + Console.WriteLine ("\t\t\tvar t = other as {0};", type_name); + Console.WriteLine ("\t\t\tif (t == null)"); + Console.WriteLine ("\t\t\t\treturn false;"); + Console.WriteLine (); + Console.Write ("\t\t\treturn"); + + for (int i = 1; i <= arity; ++i) { + if (i == 1) + Console.Write (" "); + else + Console.Write ("\t\t\t\t"); + + Console.Write ("comparer.Equals ({0}, t.{0})", GetItemName (i)); + if (i != arity) + Console.WriteLine (" &&"); + else + Console.WriteLine (";"); + } + Console.WriteLine ("\t\t}"); + + Console.WriteLine (); + Console.WriteLine ("\t\tpublic override int GetHashCode ()"); + Console.WriteLine ("\t\t{"); + Console.WriteLine ("\t\t\treturn ((IStructuralEquatable) this).GetHashCode (EqualityComparer.Default);"); + Console.WriteLine ("\t\t}"); + + Console.WriteLine (); + Console.WriteLine ("\t\tint IStructuralEquatable.GetHashCode (IEqualityComparer comparer)"); + Console.WriteLine ("\t\t{"); + if (arity == 1) { + Console.WriteLine ("\t\t\treturn comparer.GetHashCode ({0});", GetItemName (arity)); + } else { + Console.WriteLine ("\t\t\tint h = comparer.GetHashCode ({0});", GetItemName (1)); + for (int i = 2; i <= arity; ++i) + Console.WriteLine ("\t\t\th = (h << 5) - h + comparer.GetHashCode ({0});", GetItemName (i)); + Console.WriteLine ("\t\t\treturn h;"); + } + + Console.WriteLine ("\t\t}"); + + Console.WriteLine (); + Console.WriteLine ("\t\tpublic override string ToString ()"); + Console.WriteLine ("\t\t{"); + Console.Write ("\t\t\treturn String.Format (\"("); + for (int i = 1; i <= arity; ++i) { + Console.Write ("{" + (i - 1) + "}"); + if (i < arity) + Console.Write (", "); + } + Console.Write (")\", "); + for (int i = 1; i <= arity; ++i) { + Console.Write (GetItemName (i)); + if (i < arity) + Console.Write (", "); + } + Console.WriteLine (");"); + Console.WriteLine ("\t\t}"); + + Console.WriteLine ("\t}\n"); + } + } + + static string GetTypeName (int arity) + { + StringBuilder sb = new StringBuilder (); + sb.Append ("Tuple<"); + for (int i = 1; i <= arity; ++i) { + sb.Append (GetItemTypeName (i)); + if (i < arity) + sb.Append (", "); + } + sb.Append (">"); + + return sb.ToString (); + } + + static string GetItemName (int arity) + { + return arity < 8 ? "item" + arity.ToString () : "rest"; + } + + static string GetItemTypeName (int arity) + { + return arity < 8 ? "T" + arity.ToString () : "TRest"; + } +} + +#endif diff --git a/src/OpenStack/Core/CoreTaskExtensions.cs b/src/OpenStack/Core/CoreTaskExtensions.cs new file mode 100644 index 000000000..f02f1e498 --- /dev/null +++ b/src/OpenStack/Core/CoreTaskExtensions.cs @@ -0,0 +1,712 @@ +namespace net.openstack.Core +{ + using System; + using System.Threading.Tasks; + + /// + /// Provides extension methods for efficiently creating continuations, + /// with automatic handling of faulted and cancelled antecedent tasks. + /// + public static class CoreTaskExtensions + { + /// + /// Synchronously execute a continuation when a task completes successfully. + /// + /// + /// If the antecedent task is cancelled or faulted, the status of the antecedent is + /// directly applied to the task returned by this method; it is not wrapped in an additional + /// . + /// + /// + /// + /// Since the continuation is executed synchronously, this method should only be used for + /// lightweight continuation functions. For non-trivial continuation functions, use a + /// for the continuation operation and call + /// instead. + /// + /// + /// The type of the result produced by the continuation . + /// The antecedent task. + /// The continuation function to execute when completes successfully. + /// A representing the asynchronous operation. When the task completes successfully, + /// the property will contain the result returned from the . + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Select(this Task task, Func continuationFunction) + { + return task.Select(continuationFunction, false); + } + + /// + /// Synchronously execute a continuation when a task completes. The + /// parameter specifies whether the continuation is executed if the antecedent task is faulted. + /// + /// + /// If the antecedent task is cancelled, or faulted with + /// set to , the status of the antecedent is directly applied to the task + /// returned by this method; it is not wrapped in an additional . + /// + /// + /// + /// Since the continuation is executed synchronously, this method should only be used for + /// lightweight continuation functions. For non-trivial continuation functions, use a + /// for the continuation operation and call + /// instead. + /// + /// + /// The type of the result produced by the continuation . + /// The antecedent task. + /// The continuation function to execute when completes. + /// if the properly handles a faulted antecedent task; otherwise, . + /// A representing the asynchronous operation. When the task completes successfully, + /// the property will contain the result returned from the . + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Select(this Task task, Func continuationFunction, bool supportsErrors) + { + if (task == null) + throw new ArgumentNullException("task"); + if (continuationFunction == null) + throw new ArgumentNullException("continuationFunction"); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion; + task + .ContinueWith(continuationFunction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions) + .ContinueWith( + t => + { + if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted) + completionSource.SetFromTask(t); + }, TaskContinuationOptions.ExecuteSynchronously); + + TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion; + task + .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions); + + return completionSource.Task; + } + + /// + /// Synchronously execute a continuation when a task completes successfully. + /// + /// + /// If the antecedent task is cancelled or faulted, the status of the antecedent is + /// directly applied to the task returned by this method; it is not wrapped in an additional + /// . + /// + /// + /// + /// Since the continuation is executed synchronously, this method should only be used for + /// lightweight continuation functions. For non-trivial continuation functions, use + /// instead. + /// + /// + /// The type of the result produced by the antecedent . + /// The type of the result produced by the continuation . + /// The antecedent task. + /// The continuation function to execute when completes successfully. + /// A representing the asynchronous operation. When the task completes successfully, + /// the property will contain the result returned from the . + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Select(this Task task, Func, TResult> continuationFunction) + { + return task.Select(continuationFunction, false); + } + + /// + /// Synchronously execute a continuation when a task completes. The + /// parameter specifies whether the continuation is executed if the antecedent task is faulted. + /// + /// + /// If the antecedent task is cancelled, or faulted with + /// set to , the status of the antecedent is directly applied to the task + /// returned by this method; it is not wrapped in an additional . + /// + /// + /// + /// Since the continuation is executed synchronously, this method should only be used for + /// lightweight continuation functions. For non-trivial continuation functions, use + /// instead. + /// + /// + /// The type of the result produced by the antecedent . + /// The type of the result produced by the continuation . + /// The antecedent task. + /// The continuation function to execute when completes. + /// if the properly handles a faulted antecedent task; otherwise, . + /// A representing the asynchronous operation. When the task completes successfully, + /// the property will contain the result returned from the . + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Select(this Task task, Func, TResult> continuationFunction, bool supportsErrors) + { + if (task == null) + throw new ArgumentNullException("task"); + if (continuationFunction == null) + throw new ArgumentNullException("continuationFunction"); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion; + task + .ContinueWith(continuationFunction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions) + .ContinueWith( + t => + { + if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted) + completionSource.SetFromTask(t); + }, TaskContinuationOptions.ExecuteSynchronously); + + TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion; + task + .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions); + + return completionSource.Task; + } + + /// + /// Synchronously execute a continuation when a task completes successfully. + /// + /// + /// If the antecedent task is cancelled or faulted, the status of the antecedent is + /// directly applied to the task returned by this method; it is not wrapped in an additional + /// . + /// + /// + /// + /// Since the continuation is executed synchronously, this method should only be used for + /// lightweight continuation actions. For non-trivial continuation actions, use a + /// for the continuation operation and call + /// instead. + /// + /// + /// The antecedent task. + /// The continuation action to execute when completes successfully. + /// A representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Select(this Task task, Action continuationAction) + { + return task.Select(continuationAction, false); + } + + /// + /// Synchronously execute a continuation when a task completes. The + /// parameter specifies whether the continuation is executed if the antecedent task is faulted. + /// + /// + /// If the antecedent task is cancelled, or faulted with + /// set to , the status of the antecedent is directly applied to the task + /// returned by this method; it is not wrapped in an additional . + /// + /// + /// + /// Since the continuation is executed synchronously, this method should only be used for + /// lightweight continuation actions. For non-trivial continuation actions, use a + /// for the continuation operation and call + /// instead. + /// + /// + /// The antecedent task. + /// The continuation action to execute when completes. + /// if the properly handles a faulted antecedent task; otherwise, . + /// A representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Select(this Task task, Action continuationAction, bool supportsErrors) + { + if (task == null) + throw new ArgumentNullException("task"); + if (continuationAction == null) + throw new ArgumentNullException("continuationAction"); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion; + task + .ContinueWith(continuationAction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions) + .ContinueWith( + t => + { + if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted) + completionSource.SetFromTask(t); + }, TaskContinuationOptions.ExecuteSynchronously); + + TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion; + task + .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions); + + return completionSource.Task; + } + + /// + /// Synchronously execute a continuation when a task completes successfully. + /// + /// + /// If the antecedent task is cancelled or faulted, the status of the antecedent is + /// directly applied to the task returned by this method; it is not wrapped in an additional + /// . + /// + /// + /// + /// Since the continuation is executed synchronously, this method should only be used for + /// lightweight continuation actions. For non-trivial continuation actions, use + /// instead. + /// + /// + /// The type of the result produced by the antecedent . + /// The antecedent task. + /// The continuation action to execute when completes successfully. + /// A representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Select(this Task task, Action> continuationAction) + { + return task.Select(continuationAction, false); + } + + /// + /// Synchronously execute a continuation when a task completes. The + /// parameter specifies whether the continuation is executed if the antecedent task is faulted. + /// + /// + /// If the antecedent task is cancelled, or faulted with + /// set to , the status of the antecedent is directly applied to the task + /// returned by this method; it is not wrapped in an additional . + /// + /// + /// + /// Since the continuation is executed synchronously, this method should only be used for + /// lightweight continuation actions. For non-trivial continuation actions, use + /// instead. + /// + /// + /// The type of the result produced by the antecedent . + /// The antecedent task. + /// The continuation action to execute when completes. + /// if the properly handles a faulted antecedent task; otherwise, . + /// A representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Select(this Task task, Action> continuationAction, bool supportsErrors) + { + if (task == null) + throw new ArgumentNullException("task"); + if (continuationAction == null) + throw new ArgumentNullException("continuationAction"); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion; + task + .ContinueWith(continuationAction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions) + .ContinueWith( + t => + { + if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted) + completionSource.SetFromTask(t); + }, TaskContinuationOptions.ExecuteSynchronously); + + TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion; + task + .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions); + + return completionSource.Task; + } + + /// + /// Execute a continuation task when a task completes successfully. The continuation + /// task is synchronously created by a continuation function, and then unwrapped to + /// form the result of this method. + /// + /// + /// If the antecedent is cancelled or faulted, the status + /// of the antecedent is directly applied to the task returned by this method; it is + /// not wrapped in an additional . + /// + /// + /// + /// Since the is executed synchronously, this + /// method should only be used for lightweight continuation functions. This restriction + /// applies only to itself, not to the + /// returned by it. + /// + /// + /// The type of the result produced by the continuation . + /// The antecedent task. + /// The continuation function to execute when completes successfully. The continuation function returns a which provides the final result of the continuation. + /// A representing the asynchronous operation. When the task completes successfully, + /// the property will contain the result provided by the + /// property of the task returned from . + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Then(this Task task, Func> continuationFunction) + { + return task.Then(continuationFunction, false); + } + + /// + /// Execute a continuation task when a task completes. The continuation task is synchronously + /// created by a continuation function, and then unwrapped to form the result of this method. + /// The parameter specifies whether the continuation is + /// executed if the antecedent task is faulted. + /// + /// + /// If the antecedent is cancelled, or faulted with + /// set to , the status + /// of the antecedent is directly applied to the task returned by this method; it is + /// not wrapped in an additional . + /// + /// + /// + /// Since the is executed synchronously, this + /// method should only be used for lightweight continuation functions. This restriction + /// applies only to itself, not to the + /// returned by it. + /// + /// + /// The type of the result produced by the continuation . + /// The antecedent task. + /// The continuation function to execute when completes. The continuation function returns a which provides the final result of the continuation. + /// if the properly handles a faulted antecedent task; otherwise, . + /// A representing the asynchronous operation. When the task completes successfully, + /// the property will contain the result provided by the + /// property of the task returned from . + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Then(this Task task, Func> continuationFunction, bool supportsErrors) + { + if (task == null) + throw new ArgumentNullException("task"); + if (continuationFunction == null) + throw new ArgumentNullException("continuationFunction"); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion; + task + .ContinueWith(continuationFunction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions) + .Unwrap() + .ContinueWith( + t => + { + if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted) + completionSource.SetFromTask(t); + }, TaskContinuationOptions.ExecuteSynchronously); + + TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion; + task + .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions); + + return completionSource.Task; + } + + /// + /// Execute a continuation task when a task completes successfully. The continuation + /// task is synchronously created by a continuation function, and then unwrapped to + /// form the result of this method. + /// + /// + /// If the antecedent is cancelled or faulted, the status + /// of the antecedent is directly applied to the task returned by this method; it is + /// not wrapped in an additional . + /// + /// + /// + /// Since the is executed synchronously, this + /// method should only be used for lightweight continuation functions. This restriction + /// applies only to itself, not to the + /// returned by it. + /// + /// + /// The type of the result produced by the antecedent . + /// The type of the result produced by the continuation . + /// The antecedent task. + /// The continuation function to execute when completes successfully. The continuation function returns a which provides the final result of the continuation. + /// A representing the asynchronous operation. When the task completes successfully, + /// the property will contain the result provided by the + /// property of the task returned from . + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Then(this Task task, Func, Task> continuationFunction) + { + return task.Then(continuationFunction, false); + } + + /// + /// Execute a continuation task when a task completes. The continuation + /// task is synchronously created by a continuation function, and then unwrapped to + /// form the result of this method. The + /// parameter specifies whether the continuation is executed if the antecedent task is faulted. + /// + /// + /// If the antecedent is cancelled, or faulted with + /// set to , the status + /// of the antecedent is directly applied to the task returned by this method; it is + /// not wrapped in an additional . + /// + /// + /// + /// Since the is executed synchronously, this + /// method should only be used for lightweight continuation functions. This restriction + /// applies only to itself, not to the + /// returned by it. + /// + /// + /// The type of the result produced by the antecedent . + /// The type of the result produced by the continuation . + /// The antecedent task. + /// The continuation function to execute when completes. The continuation function returns a which provides the final result of the continuation. + /// if the properly handles a faulted antecedent task; otherwise, . + /// A representing the asynchronous operation. When the task completes successfully, + /// the property will contain the result provided by the + /// property of the task returned from . + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Then(this Task task, Func, Task> continuationFunction, bool supportsErrors) + { + if (task == null) + throw new ArgumentNullException("task"); + if (continuationFunction == null) + throw new ArgumentNullException("continuationFunction"); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion; + task + .ContinueWith(continuationFunction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions) + .Unwrap() + .ContinueWith( + t => + { + if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted) + completionSource.SetFromTask(t); + }, TaskContinuationOptions.ExecuteSynchronously); + + TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion; + task + .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions); + + return completionSource.Task; + } + + /// + /// Execute a continuation task when a task completes successfully. The continuation + /// task is synchronously created by a continuation function, and then unwrapped to + /// form the result of this method. + /// + /// + /// If the antecedent is cancelled or faulted, the status + /// of the antecedent is directly applied to the task returned by this method; it is + /// not wrapped in an additional . + /// + /// + /// + /// Since the is executed synchronously, this + /// method should only be used for lightweight continuation functions. This restriction + /// applies only to itself, not to the + /// returned by it. + /// + /// + /// The antecedent task. + /// The continuation function to execute when completes successfully. The continuation function returns a which provides the final result of the continuation. + /// A representing the unwrapped asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Then(this Task task, Func continuationFunction) + { + return task.Then(continuationFunction, false); + } + + /// + /// Execute a continuation task when a task completes. The continuation task is synchronously + /// created by a continuation function, and then unwrapped to form the result of this method. + /// The parameter specifies whether the continuation is + /// executed if the antecedent task is faulted. + /// + /// + /// If the antecedent is cancelled, or faulted with + /// set to , the status + /// of the antecedent is directly applied to the task returned by this method; it is + /// not wrapped in an additional . + /// + /// + /// + /// Since the is executed synchronously, this + /// method should only be used for lightweight continuation functions. This restriction + /// applies only to itself, not to the + /// returned by it. + /// + /// + /// The antecedent task. + /// The continuation function to execute when completes. The continuation function returns a which provides the final result of the continuation. + /// if the properly handles a faulted antecedent task; otherwise, . + /// A representing the unwrapped asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Then(this Task task, Func continuationFunction, bool supportsErrors) + { + if (task == null) + throw new ArgumentNullException("task"); + if (continuationFunction == null) + throw new ArgumentNullException("continuationFunction"); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion; + task + .ContinueWith(continuationFunction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions) + .Unwrap() + .ContinueWith( + t => + { + if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted) + completionSource.SetFromTask(t); + }, TaskContinuationOptions.ExecuteSynchronously); + + TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion; + task + .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions); + + return completionSource.Task; + } + + /// + /// Execute a continuation task when a task completes successfully. The continuation + /// task is synchronously created by a continuation function, and then unwrapped to + /// form the result of this method. + /// + /// + /// If the antecedent is cancelled or faulted, the status + /// of the antecedent is directly applied to the task returned by this method; it is + /// not wrapped in an additional . + /// + /// + /// + /// Since the is executed synchronously, this + /// method should only be used for lightweight continuation functions. This restriction + /// applies only to itself, not to the + /// returned by it. + /// + /// + /// The type of the result produced by the antecedent . + /// The antecedent task. + /// The continuation function to execute when completes successfully. The continuation function returns a which provides the final result of the continuation. + /// A representing the unwrapped asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Then(this Task task, Func, Task> continuationFunction) + { + return task.Then(continuationFunction, false); + } + + /// + /// Execute a continuation task when a task completes. The continuation + /// task is synchronously created by a continuation function, and then unwrapped to + /// form the result of this method. The + /// parameter specifies whether the continuation is executed if the antecedent task is faulted. + /// + /// + /// If the antecedent is cancelled, or faulted with + /// set to , the status + /// of the antecedent is directly applied to the task returned by this method; it is + /// not wrapped in an additional . + /// + /// + /// + /// Since the is executed synchronously, this + /// method should only be used for lightweight continuation functions. This restriction + /// applies only to itself, not to the + /// returned by it. + /// + /// + /// The type of the result produced by the antecedent . + /// The antecedent task. + /// The continuation function to execute when completes. The continuation function returns a which provides the final result of the continuation. + /// if the properly handles a faulted antecedent task; otherwise, . + /// A representing the unwrapped asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + public static Task Then(this Task task, Func, Task> continuationFunction, bool supportsErrors) + { + if (task == null) + throw new ArgumentNullException("task"); + if (continuationFunction == null) + throw new ArgumentNullException("continuationFunction"); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion; + task + .ContinueWith(continuationFunction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions) + .Unwrap() + .ContinueWith( + t => + { + if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted) + completionSource.SetFromTask(t); + }, TaskContinuationOptions.ExecuteSynchronously); + + TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion; + task + .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions); + + return completionSource.Task; + } + + private sealed class VoidResult + { + } + } +} diff --git a/src/OpenStack/Core/Domain/AuthenticationRequirement.cs b/src/OpenStack/Core/Domain/AuthenticationRequirement.cs new file mode 100644 index 000000000..e3a9d5ce3 --- /dev/null +++ b/src/OpenStack/Core/Domain/AuthenticationRequirement.cs @@ -0,0 +1,56 @@ +namespace net.openstack.Core.Domain +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This class models the authentication requirements resource hints + /// of the home document described by Home Documents for HTTP APIs. + /// + /// + /// Resource Hints: auth-req (Home Documents for HTTP APIs - draft-nottingham-json-home-03) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AuthenticationRequirement : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("scheme")] + private string _scheme; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("realms")] + private string[] _realms; +#pragma warning restore 649 + + /// + /// Gets the HTTP authentication scheme. + /// + public string Scheme + { + get + { + return _scheme; + } + } + + /// + /// Gets an optional collection of identity protection spaces the resource is a member of. + /// + public ReadOnlyCollection Realms + { + get + { + if (_realms == null) + return null; + + return new ReadOnlyCollection(_realms); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/AuthenticationType.cs b/src/OpenStack/Core/Domain/AuthenticationType.cs new file mode 100644 index 000000000..1932254c9 --- /dev/null +++ b/src/OpenStack/Core/Domain/AuthenticationType.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Concurrent; +using Newtonsoft.Json; + +namespace net.openstack.Core.Domain +{ + /// + /// Represents the way a user has authenticated. + /// + /// + /// This class functions as a strongly-typed enumeration of known authentication types, + /// with added support for unknown types returned by a server extension. + /// + /// + /// + [JsonConverter(typeof(AuthenticationType.Converter))] + public class AuthenticationType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + private static readonly AuthenticationType _password = FromName("PASSWORD"); + private static readonly AuthenticationType _rsa = FromName("RSAKEY"); + + private AuthenticationType(string name) : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static AuthenticationType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new AuthenticationType(i)); + } + + /// + /// Gets an representing that a user authenticated using a password. + /// + public static AuthenticationType Password + { + get + { + return _password; + } + } + + /// + /// Gets an representing that a user authenticated using an RSA key. + /// + public static AuthenticationType RSA + { + get + { + return _rsa; + } + } + + /// + /// Provides support for serializing and deserializing objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AuthenticationType FromName(string name) + { + return AuthenticationType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/CloudIdentity.cs b/src/OpenStack/Core/Domain/CloudIdentity.cs new file mode 100644 index 000000000..916a79383 --- /dev/null +++ b/src/OpenStack/Core/Domain/CloudIdentity.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Core.Domain +{ + /// + /// Represents a set of credentials used for accessing a cloud account. Individual providers + /// may impose restrictions on the values allowed for individual properties. + /// + /// + public class CloudIdentity + { + /// + /// Gets or sets the username for this identity. + /// + /// + /// The username for this identity. The value may be if the particular + /// provider supports authenticating without a username. + /// + public string Username { get; set; } + + /// + /// Gets or sets the password for this identity. + /// + /// + /// The class represents credentials (as opposed + /// to an account), so any changes made to this property value will not be + /// reflected in the account. + /// + /// + /// A password to use when authenticating this identity, or if authentication + /// should be performed by different method (e.g. with a ). + /// + public string Password { get; set; } + + /// + /// Gets or sets the API key for this identity. + /// + /// + /// The class represents credentials (as opposed + /// to an account), so any changes made to this property value will not be + /// reflected in the account. + /// + /// + /// An API key to use when authenticating this identity, or if authentication + /// should be performed by different method (e.g. with a ). + /// + public string APIKey { get; set; } + } +} diff --git a/src/OpenStack/Core/Domain/CloudIdentityWithProject.cs b/src/OpenStack/Core/Domain/CloudIdentityWithProject.cs new file mode 100644 index 000000000..f7b4562a2 --- /dev/null +++ b/src/OpenStack/Core/Domain/CloudIdentityWithProject.cs @@ -0,0 +1,38 @@ +namespace net.openstack.Core.Domain +{ + /// + /// This class extends with the addition of the + /// and properties, which + /// may be required for authentication with certain Identity Service providers. + /// + /// + /// + public class CloudIdentityWithProject : CloudIdentity + { + /// + /// Gets or sets the project ID for this identity. + /// + /// + /// The project ID for this identity. The value may be if the particular + /// provider supports authenticating without a project ID. + /// + public ProjectId ProjectId + { + get; + set; + } + + /// + /// Gets or sets the project name for this identity. + /// + /// + /// The project name for this identity. The value may be if the particular + /// provider supports authenticating without a project name. + /// + public string ProjectName + { + get; + set; + } + } +} diff --git a/src/OpenStack/Core/Domain/CloudNetwork.cs b/src/OpenStack/Core/Domain/CloudNetwork.cs new file mode 100644 index 000000000..5141eb900 --- /dev/null +++ b/src/OpenStack/Core/Domain/CloudNetwork.cs @@ -0,0 +1,39 @@ +namespace net.openstack.Core.Domain +{ + using Newtonsoft.Json; + + /// + /// Represents the detailed information for a labeled network in Rackspace Cloud Networks. + /// + /// Overview (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + public class CloudNetwork : ExtensibleJsonObject + { + /// + /// Gets the network ID. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the CIDR for the network. + /// + [JsonProperty("cidr")] + public string Cidr { get; private set; } + + /// + /// Gets the name of the network. + /// + /// + /// The Rackspace Cloud Networks product predefines two networks: + /// + /// PublicNet provides access to the Internet, Rackspace services such as Cloud Monitoring, Managed Cloud Support, RackConnect, Cloud Backup, and certain operating system updates. When you list networks through Cloud Networks, PublicNet is labeled public. + /// ServiceNet Provides access to Rackspace services such as Cloud Files, Cloud Databases, and Cloud Backup, and to certain packages and patches through an internal only, multi-tenant network connection within each Rackspace data center. When you list networks through Cloud Networks, ServiceNet is labeled as private. + /// + /// + /// Overview (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + [JsonProperty("label")] + public string Label { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/Container.cs b/src/OpenStack/Core/Domain/Container.cs new file mode 100644 index 000000000..bc09f7411 --- /dev/null +++ b/src/OpenStack/Core/Domain/Container.cs @@ -0,0 +1,49 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents the detailed information for a container stored in an Object Storage Provider. + /// + /// + /// Show account details and list containers (OpenStack Object Storage API v1 Reference) + /// Show Account Details and List Containers (Rackspace Cloud Files Developer Guide - API v1) + /// + [JsonObject(MemberSerialization.OptIn)] + public class Container : ExtensibleJsonObject + { + /// + /// Gets the name of the container. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + /// Show account details and list containers (OpenStack Object Storage API v1 Reference) + /// Show Account Details and List Containers (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the number of objects in the container. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + /// + /// This field is eventually consistent. + /// + /// Show account details and list containers (OpenStack Object Storage API v1 Reference) + /// Show Account Details and List Containers (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("count")] + public int Count { get; private set; } + + /// + /// Gets the total space utilized by the objects in this container. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + /// + /// This field is eventually consistent. + /// + /// Show account details and list containers (OpenStack Object Storage API v1 Reference) + /// Show Account Details and List Containers (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("bytes")] + public long Bytes { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/ContainerCDN.cs b/src/OpenStack/Core/Domain/ContainerCDN.cs new file mode 100644 index 000000000..b39fe944a --- /dev/null +++ b/src/OpenStack/Core/Domain/ContainerCDN.cs @@ -0,0 +1,111 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Provides the CDN properties for a container in an Object Storage provider. + /// + /// + /// + /// CDN-enabled containers are a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// CDN Container Services (Rackspace Cloud Files Developer Guide - API v1) + /// + [JsonObject(MemberSerialization.OptIn)] + public class ContainerCDN : ExtensibleJsonObject + { + /// + /// Gets the name of the container. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets a streaming URL suitable for use in links to content you want to stream, such as video. If streaming is not available, the value is . + /// + /// Streaming CDN-Enabled Containers (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("cdn_streaming_uri")] + public string CDNStreamingUri { get; private set; } + + /// + /// Gets a URL SSL URL for accessing the container on the CDN. If SSL is not available, the value is . + /// + /// CDN-Enabled Containers Served through SSL (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("cdn_ssl_uri")] + public string CDNSslUri { get; private set; } + + /// + /// Gets a value indicating whether or not the container is CDN-Enabled. + /// + /// + /// if the container is CDN-Enabled; otherwise, . + /// + /// + /// + /// CDN-Enable and CDN-Disable a Container (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("cdn_enabled")] + public bool CDNEnabled { get; private set; } + + /// + /// Gets the Time To Live (TTL) in seconds for a CDN-Enabled container. + /// + /// CDN-Enable and CDN-Disable a Container (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("ttl")] + public long Ttl { get; private set; } + + /// + /// Gets a value indicating whether or not log retention is enabled for a CDN-Enabled container. + /// + /// + /// This setting specifies whether the CDN access logs should be collected and stored in the Cloud Files storage system. + /// + /// + /// if log retention is enabled for the container; otherwise, . + /// + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("log_retention")] + public bool LogRetention { get; private set; } + + /// + /// Gets a publicly accessible URL for the container, which can be combined with any object name within the container to form the publicly accessible URL for that object for distribution over a CDN system. + /// + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("cdn_uri")] + public string CDNUri { get; private set; } + + /// + /// Gets a publicly accessible URL for the container for use in streaming content to iOS devices. If iOS streaming is not available for the container, the value is . + /// + /// + /// The may be combined with any object name within the container to form the publicly accessible URL for streaming that object to iOS devices. + /// + /// iOS Streaming (Rackspace Cloud Files Developer Guide - API v1) + [JsonProperty("cdn_ios_uri")] + public string CDNIosUri { get; private set; } + + /// + /// Initializes a new instance of the class with the specified properties. + /// + /// The name of the container (see ). + /// The URI of the container (see ). + /// A streaming URL (see ). + /// An SSL URL (see ). + /// The iOS URI of the container (see ). + /// Whether or not the container is CDN-enabled (see ). + /// The time-to-live (see ). + /// Whether or not log retention is enabled (see ). + public ContainerCDN(string name, string uri, string streamingUri, string sslUri, string iosUri, bool enabled, long ttl, bool logRetention) + { + Name = name; + CDNUri = uri; + CDNStreamingUri = streamingUri; + CDNSslUri = sslUri; + CDNIosUri = iosUri; + CDNEnabled = enabled; + Ttl = ttl; + LogRetention = logRetention; + } + } +} diff --git a/src/OpenStack/Core/Domain/ContainerObject.cs b/src/OpenStack/Core/Domain/ContainerObject.cs new file mode 100644 index 000000000..8a231cb64 --- /dev/null +++ b/src/OpenStack/Core/Domain/ContainerObject.cs @@ -0,0 +1,54 @@ +namespace net.openstack.Core.Domain +{ + using System; + using Newtonsoft.Json; + + /// + /// Provides the details of an object stored in an Object Storage provider. + /// + /// Show container details and list objects (OpenStack Object Storage API v1 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + public class ContainerObject : ExtensibleJsonObject + { + /// + /// Gets a "name" associated with the object. + /// The value of this property is not defined. Do not use. + /// + /// Show container details and list objects (OpenStack Object Storage API v1 Reference) + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the "hash" value associated with the object. + /// The value of this property is not defined. Do not use. + /// + /// Show container details and list objects (OpenStack Object Storage API v1 Reference) + [JsonProperty("hash")] + public string Hash { get; private set; } + + /// + /// Gets the "bytes" value associated with the object. + /// The value of this property is not defined. Do not use. + /// + /// Show container details and list objects (OpenStack Object Storage API v1 Reference) + [JsonProperty("bytes")] + public long Bytes { get; private set; } + + /// + /// Gets the "content type" value associated with the object. + /// The value of this property is not defined. Do not use. + /// + /// Show container details and list objects (OpenStack Object Storage API v1 Reference) + [JsonProperty("content_type")] + public string ContentType { get; private set; } + + /// + /// Gets the "last modified" value associated with the object. + /// The value of this property is not defined. Do not use. + /// + /// Show container details and list objects (OpenStack Object Storage API v1 Reference) + [JsonProperty("last_modified")] + public DateTimeOffset LastModified { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/Converters/IPAddressDetailsConverter.cs b/src/OpenStack/Core/Domain/Converters/IPAddressDetailsConverter.cs new file mode 100644 index 000000000..d12f48e81 --- /dev/null +++ b/src/OpenStack/Core/Domain/Converters/IPAddressDetailsConverter.cs @@ -0,0 +1,137 @@ +namespace net.openstack.Core.Domain.Converters +{ + using System; + using System.Globalization; + using System.Net; + using System.Net.Sockets; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// This implementation of allows for JSON serialization + /// and deserialization of objects in the "address details" + /// format used by operations such as + /// and . + /// + /// List Addresses (OpenStack Compute API v2 and Extensions Reference) + /// List Addresses by Network (OpenStack Compute API v2 and Extensions Reference) + /// + public class IPAddressDetailsConverter : JsonConverter + { + /// + /// Serialization is performed by creating an instance + /// equivalent to the given instance and serializing that as + /// a JSON object. + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + IPAddress address = value as IPAddress; + if (address == null) + throw new JsonSerializationException(string.Format(CultureInfo.InvariantCulture, "Unexpected value when converting IP address. Expected {0}, got {1}.", typeof(IPAddress), value.GetType())); + + AddressDetails details = new AddressDetails(address); + serializer.Serialize(writer, details); + } + + /// + /// Deserialization is performed by deserializing the JSON value as an + /// object, following by using to convert the value of + /// to an instance. + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (objectType != typeof(IPAddress)) + throw new JsonSerializationException(string.Format(CultureInfo.InvariantCulture, "Expected target type {0}, found {1}.", typeof(IPAddress), objectType)); + + AddressDetails details = serializer.Deserialize(reader); + if (details == null) + return null; + + return IPAddress.Parse(details.Address); + } + + /// if equals ; otherwise, . + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof(IPAddress); + } + + /// + /// Represents a network address in a format compatible with communication with the Compute Service APIs. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + protected class AddressDetails : ExtensibleJsonObject + { + /// + /// Gets the network address. This is an IPv4 address if is "4", + /// or an IPv6 address if is "6". + /// + [JsonProperty("addr")] + public string Address + { + get; + private set; + } + + /// + /// Gets the network address version. The value is either "4" or "6". + /// + [JsonProperty("version")] + public string Version + { + get; + private set; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// This constructor is used for JSON deserialization. + /// + [JsonConstructor] + protected AddressDetails() + { + } + + /// + /// Initializes a new instance of the class + /// using the given IP address. + /// + /// The IP address. + /// If is . + public AddressDetails(IPAddress address) + { + if (address == null) + throw new ArgumentNullException("address"); + + Address = address.ToString(); + switch (address.AddressFamily) + { + case AddressFamily.InterNetwork: + Version = "4"; + break; + + case AddressFamily.InterNetworkV6: + Version = "6"; + break; + + default: + throw new ArgumentException("The specified address family is not supported."); + } + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Converters/IPAddressNoneIsNullSimpleConverter.cs b/src/OpenStack/Core/Domain/Converters/IPAddressNoneIsNullSimpleConverter.cs new file mode 100644 index 000000000..c0d297568 --- /dev/null +++ b/src/OpenStack/Core/Domain/Converters/IPAddressNoneIsNullSimpleConverter.cs @@ -0,0 +1,32 @@ +namespace net.openstack.Core.Domain.Converters +{ + using System; + using System.Net; + using Newtonsoft.Json; + + /// + /// This implementation of extends the behavior of + /// by treating null values in the JSON representation as + /// instead of . + /// + /// + /// + public class IPAddressNoneIsNullSimpleConverter : IPAddressSimpleConverter + { + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + object result = base.ReadJson(reader, objectType, existingValue, serializer); + return result ?? IPAddress.None; + } + + /// + protected override string ConvertToString(IPAddress obj) + { + if (IPAddress.None.Equals(obj)) + return null; + + return base.ConvertToString(obj); + } + } +} diff --git a/src/OpenStack/Core/Domain/Converters/IPAddressSimpleConverter.cs b/src/OpenStack/Core/Domain/Converters/IPAddressSimpleConverter.cs new file mode 100644 index 000000000..20848e20b --- /dev/null +++ b/src/OpenStack/Core/Domain/Converters/IPAddressSimpleConverter.cs @@ -0,0 +1,30 @@ +namespace net.openstack.Core.Domain.Converters +{ + using System.Net; + using Newtonsoft.Json; + + /// + /// This implementation of allows for JSON serialization + /// and deserialization of objects using a simple string + /// representation. Serialization is performed using , + /// and deserialization is performed using . + /// + /// List Addresses (OpenStack Compute API v2 and Extensions Reference) + /// List Addresses by Network (OpenStack Compute API v2 and Extensions Reference) + /// + public class IPAddressSimpleConverter : SimpleStringJsonConverter + { + /// + /// If is an empty string, this method returns . + /// Otherwise, this method uses for deserialization. + /// + /// + protected override IPAddress ConvertToObject(string str) + { + if (string.IsNullOrEmpty(str)) + return null; + + return IPAddress.Parse(str); + } + } +} diff --git a/src/OpenStack/Core/Domain/Converters/NamespaceDoc.cs b/src/OpenStack/Core/Domain/Converters/NamespaceDoc.cs new file mode 100644 index 000000000..e395030eb --- /dev/null +++ b/src/OpenStack/Core/Domain/Converters/NamespaceDoc.cs @@ -0,0 +1,18 @@ +namespace net.openstack.Core.Domain.Converters +{ + using System.Net; + using System.Net.NetworkInformation; + using System.Runtime.CompilerServices; + + /// + /// The namespace defines specialized + /// JSON converters for calling the OpenStack REST APIs. These converters are useful for + /// standard .NET classes that have a one or more specific representations in the + /// OpenStack APIs (e.g. or ), and + /// for extensible enumerations (e.g. ). + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Domain/Converters/PhysicalAddressSimpleConverter.cs b/src/OpenStack/Core/Domain/Converters/PhysicalAddressSimpleConverter.cs new file mode 100644 index 000000000..54741db5e --- /dev/null +++ b/src/OpenStack/Core/Domain/Converters/PhysicalAddressSimpleConverter.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Core.Domain.Converters +{ + using System.Net.NetworkInformation; + using System.Text.RegularExpressions; + using Newtonsoft.Json; + + /// + /// This implementation of allows for JSON serialization + /// and deserialization of objects using a simple string + /// representation. Serialization produces an IEEE 802 representation of the form + /// 00:11:22:33:44:55, and deserialization supports representations + /// using hyphens or colons, along with bare strings containing 12 hexadecimal digits. + /// + /// + public class PhysicalAddressSimpleConverter : SimpleStringJsonConverter + { + private static readonly Regex Ieee802Expression = + new Regex(@"^[a-fA-F0-9]{2}(?:[\-\:][a-fA-F0-9]{2}){5}$", RegexOptions.Compiled); + + /// + /// If is an empty string, this method returns . + /// Otherwise, this method converts IEEE 802 addresses containing hyphens or colons + /// to a bare representation, and then uses for + /// deserialization. As a result, this converter can handle physical addresses in + /// any of the following forms: + /// + /// + /// 01-23-45-67-89-ab + /// 01:23:45:67:89:ab + /// 0123456789ab + /// + /// + /// + protected override PhysicalAddress ConvertToObject(string str) + { + if (string.IsNullOrEmpty(str)) + return null; + + str = str.Trim(); + if (str.Length > 12 && Ieee802Expression.IsMatch(str)) + str = str.Replace("-", string.Empty).Replace(":", string.Empty); + + return PhysicalAddress.Parse(str); + } + } +} diff --git a/src/OpenStack/Core/Domain/Converters/SimpleStringJsonConverter`1.cs b/src/OpenStack/Core/Domain/Converters/SimpleStringJsonConverter`1.cs new file mode 100644 index 000000000..9ee62015c --- /dev/null +++ b/src/OpenStack/Core/Domain/Converters/SimpleStringJsonConverter`1.cs @@ -0,0 +1,80 @@ +namespace net.openstack.Core.Domain.Converters +{ + using System; + using System.Globalization; + using Newtonsoft.Json; + + /// + /// Provides a base class for JSON converters that represent serialized objects + /// as a simple string. + /// + /// The deserialized object type. + /// + public abstract class SimpleStringJsonConverter : JsonConverter + { + /// + /// Serialization is performed by calling and writing + /// the result as a string value. + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + if (!(value is T)) + throw new JsonSerializationException(string.Format(CultureInfo.InvariantCulture, "Unexpected type when converting to JSON. Expected {0}, found {1}.", typeof(T), value.GetType())); + + T entity = (T)value; + serializer.Serialize(writer, ConvertToString(entity)); + } + + /// + /// Deserialization is performed by reading the raw value as a string and using + /// to convert it to an object of type + /// . + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (objectType != typeof(T)) + throw new JsonSerializationException(string.Format(CultureInfo.InvariantCulture, "Expected target type {0}, found {1}.", typeof(T), objectType)); + + string value = serializer.Deserialize(reader); + if (value == null) + return null; + + return ConvertToObject(value); + } + + /// if equals ; otherwise, . + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof(T); + } + + /// + /// Serializes an object of type to a string value. + /// + /// + /// The default implementation returns the result of calling . + /// + /// The object to serialize. + /// A string representation of the object. + protected virtual string ConvertToString(T obj) + { + return obj.ToString(); + } + + /// + /// Deserializes a string value to an object of type . + /// + /// The string to deserialize. + /// The deserialized object. + protected abstract T ConvertToObject(string str); + } +} diff --git a/src/OpenStack/Core/Domain/DiskConfiguration.cs b/src/OpenStack/Core/Domain/DiskConfiguration.cs new file mode 100644 index 000000000..528a437cb --- /dev/null +++ b/src/OpenStack/Core/Domain/DiskConfiguration.cs @@ -0,0 +1,101 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using Newtonsoft.Json; + + /// + /// This enumeration is part of the disk configuration extension, + /// which adds at attribute to images and servers to control how the disk is partitioned when + /// servers are created, rebuilt, or resized. + /// + /// + /// This class functions as a strongly-typed enumeration of known disk configurations, + /// with added support for unknown types returned by a server extension. + /// + /// Disk Configuration Extension (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonConverter(typeof(DiskConfiguration.Converter))] + public sealed class DiskConfiguration : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly DiskConfiguration _auto = FromName("AUTO"); + private static readonly DiskConfiguration _manual = FromName("MANUAL"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private DiskConfiguration(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static DiskConfiguration FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new DiskConfiguration(i)); + } + + /// + /// Gets a representing automatic configuration. + /// + /// + /// The server is built with a single partition the size of the target flavor disk. The + /// file system is automatically adjusted to fit the entire partition. This keeps things + /// simple and automated. is valid only for images and servers with a + /// single partition that use the EXT3 file system. This is the default setting for + /// applicable Rackspace base images. + /// + public static DiskConfiguration Auto + { + get + { + return _auto; + } + } + + /// + /// Gets a manual configuration. + /// + /// + /// The server is built using whatever partition scheme and file system is in the source + /// image. If the target flavor disk is larger, the remaining disk space is left + /// unpartitioned. This enables images to have non-EXT3 file systems, multiple partitions, + /// and so on, and enables you to manage the disk configuration. + /// + public static DiskConfiguration Manual + { + get + { + return _manual; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DiskConfiguration FromName(string name) + { + return DiskConfiguration.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Endpoint.cs b/src/OpenStack/Core/Domain/Endpoint.cs new file mode 100644 index 000000000..6c81a606c --- /dev/null +++ b/src/OpenStack/Core/Domain/Endpoint.cs @@ -0,0 +1,62 @@ +namespace net.openstack.Core.Domain +{ + using Newtonsoft.Json; + + /// + /// Represents an endpoint for a service provided in the . + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Endpoint : ExtensibleJsonObject + { + /// + /// Gets the public URL of the service. + /// + [JsonProperty("publicURL")] + public string PublicURL { get; private set; } + + /// + /// Gets the region where this service endpoint is located. If this is + /// or empty, the region is not specified. + /// + [JsonProperty("region")] + public string Region { get; private set; } + + /// + /// Gets the tenant (or account) ID which this endpoint operates on. + /// + [JsonProperty("tenantId")] + public string TenantId { get; private set; } + + /// + /// Gets the "versionId" property associated with the endpoint. + /// The value of this property is not defined. Do not use. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("versionId")] + public string VersionId { get; private set; } + + /// + /// Gets the "versionInfo" property associated with the endpoint. + /// The value of this property is not defined. Do not use. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("versionInfo")] + public string VersionInfo { get; private set; } + + /// + /// Gets the "versionList" property associated with the endpoint. + /// The value of this property is not defined. Do not use. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("versionList")] + public string VersionList { get; private set; } + + /// + /// Gets the internal URL of the service. If this is or empty, + /// the service should be accessed using the . + /// + [JsonProperty("internalURL")] + public string InternalURL { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/EndpointTemplate.cs b/src/OpenStack/Core/Domain/EndpointTemplate.cs new file mode 100644 index 000000000..b71c8d50c --- /dev/null +++ b/src/OpenStack/Core/Domain/EndpointTemplate.cs @@ -0,0 +1,64 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Diagnostics; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of an endpoint template resource in the OpenStack Identity Service V2. + /// + /// + /// This object is part of the OS-KSCATALOG extension to the OpenStack Identity Service V2. + /// + /// OS-KSCATALOG admin extension (Identity API v2.0 - OpenStack Complete API Reference) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + [DebuggerDisplay("{Id, nq}")] + public class EndpointTemplate : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private EndpointTemplateId _id; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected EndpointTemplate() + { + } + + /// + /// Initializes a new instance of the class with the specified endpoint template + /// identifier. + /// + /// The unique identifier of the endpoint template. + /// If is . + public EndpointTemplate(EndpointTemplateId id) + { + if (id == null) + throw new ArgumentNullException("id"); + + _id = id; + } + + /// + /// Gets the unique identifier for the endpoint template. + /// + /// + /// The unique identifier for the endpoint template. + /// NullIfNotIncluded + /// + public EndpointTemplateId Id + { + get + { + return _id; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/EndpointTemplateId.cs b/src/OpenStack/Core/Domain/EndpointTemplateId.cs new file mode 100644 index 000000000..805785177 --- /dev/null +++ b/src/OpenStack/Core/Domain/EndpointTemplateId.cs @@ -0,0 +1,45 @@ +namespace net.openstack.Core.Domain +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an . + /// + /// + /// This object is part of the OS-KSCATALOG extension to the OpenStack Identity Service V2. + /// + /// + /// + /// + [JsonConverter(typeof(EndpointTemplateId.Converter))] + public sealed class EndpointTemplateId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The identifier value. + /// If is . + /// If is empty. + public EndpointTemplateId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override EndpointTemplateId FromValue(string id) + { + return new EndpointTemplateId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ExtendedEndpoint.cs b/src/OpenStack/Core/Domain/ExtendedEndpoint.cs new file mode 100644 index 000000000..335f57f24 --- /dev/null +++ b/src/OpenStack/Core/Domain/ExtendedEndpoint.cs @@ -0,0 +1,37 @@ +using System.Diagnostics; +using Newtonsoft.Json; + +namespace net.openstack.Core.Domain +{ + /// + /// Represents an endpoint for a tenant that is returned outside of the . + /// + /// + /// List Token Endpoints (OpenStack Identity Service API v2.0 Reference) + [JsonObject(MemberSerialization.OptIn)] + [DebuggerDisplay("{Name,nq} ({Type,nq})")] + public class ExtendedEndpoint : Endpoint + { + /// + /// Gets the id of the endpoint, which may be a vendor-specific id. + /// + /// List Token Endpoints (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the display name of the service, which may be a vendor-specific + /// product name. + /// + /// List Token Endpoints (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the canonical name of the specification implemented by this service. + /// + /// List Token Endpoint (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("type")] + public string Type { get; private set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Core/Domain/ExtensibleJsonObject.cs b/src/OpenStack/Core/Domain/ExtensibleJsonObject.cs new file mode 100644 index 000000000..495e65f10 --- /dev/null +++ b/src/OpenStack/Core/Domain/ExtensibleJsonObject.cs @@ -0,0 +1,390 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using IEnumerable = System.Collections.IEnumerable; + using IEnumerator = System.Collections.IEnumerator; + + /// + /// This is the abstract base class for types modeling the JSON representation of a resource + /// which may be extended by specific providers or updated in future releases of a core + /// service. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class ExtensibleJsonObject + { + /// + /// An empty, and thus immutable, value which is the default return value + /// for when the backing field is . + /// + protected static readonly ReadOnlyDictionary EmptyExtensionData = + new ReadOnlyDictionary(new Dictionary()); + + /// + /// This is the backing field for the property. + /// + private Dictionary _extensionData; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ExtensibleJsonObject() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified extension data. + /// + /// The extension data. + /// If is . + protected ExtensibleJsonObject(IDictionary extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + if (extensionData.Count > 0) + _extensionData = new Dictionary(extensionData); + } + + /// + /// Initializes a new instance of the class + /// with the specified extension data. + /// + /// The extension data. + /// If is . + /// If contains any values. + protected ExtensibleJsonObject(IEnumerable extensionData) + : this(extensionData.ToArray()) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified extension data. + /// + /// The extension data. + /// If is . + /// If contains any values. + protected ExtensibleJsonObject(params JProperty[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + if (extensionData.Length > 0) + { + _extensionData = new Dictionary(); + foreach (JProperty property in extensionData) + { + if (property == null) + throw new ArgumentException("extensionData cannot contain any null values"); + + _extensionData[property.Name] = property.Value; + } + } + } + + /// + /// Gets a map of object properties which did not map to another field or property + /// during JSON deserialization. The keys of the map represent the property names, + /// and the values are instances containing the parsed JSON + /// values. + /// + /// + /// A collection of object properties which did not map to another field or property + /// during JSON deserialization. + /// -or- + /// An empty dictionary if the object did not contain any unmapped properties. + /// + public ReadOnlyDictionary ExtensionData + { + get + { + if (_extensionData == null) + return EmptyExtensionData; + + return new ReadOnlyDictionary(_extensionData); + } + } + + /// + /// This property exposes the field to Json.NET as a dictionary with + /// values instead of values, which works around a known bug in the + /// way Json.NET 5.x handled values in the extension data. + /// + [JsonExtensionData] + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ExtensionDataDictionary ExtensionDataWrapper + { + get + { + // This can never return null or Json.NET will attempt to set the value. + return new ExtensionDataDictionary(this); + } + + set + { + // This setter must exist or Json.NET will not recognize the extension data. It cannot be used because + // Json.NET will bypass the getter, resulting in a lost update. + throw new NotSupportedException("Attempted to set the extension data wrapper. See issue openstacknetsdk/openstack.net#419."); + } + } + + /// + /// Converts an object to a . + /// + /// + /// + /// Unlike , this method supports values. + /// + /// + /// The object. + /// + /// The result of calling on the input object. + /// -or- + /// if is . + /// + private static JToken ToJToken(object obj) + { + if (obj == null) + return null; + + return JToken.FromObject(obj); + } + + /// + /// This class works around a known bug in Json.NET's handling of JSON extension data. + /// + /// + /// Adding values to the underlying dictionary requires converting the value to a by + /// calling . Reading values does not require the inverse because the serializer + /// in Json.NET has no trouble handling values as input. + /// + /// + private sealed class ExtensionDataDictionary : IDictionary + { + private readonly ExtensibleJsonObject _underlying; + + [JsonConstructor] + private ExtensionDataDictionary() + { + // This constructor must exist or Json.NET will not be able to set the extension data. It cannot be used + // because Json.NET will not set the required _underlying field. + throw new NotSupportedException("Attempted to create the extension data wrapper with its underlying object. See issue openstacknetsdk/openstack.net#419."); + } + + public ExtensionDataDictionary(ExtensibleJsonObject extensibleJsonObject) + { + if (extensibleJsonObject == null) + throw new ArgumentNullException("extensibleJsonObject"); + + _underlying = extensibleJsonObject; + } + + public object this[string key] + { + get + { + return _underlying.ExtensionData[key]; + } + + set + { + GetOrCreateExtensionData()[key] = ToJToken(value); + } + } + + public int Count + { + get + { + return _underlying.ExtensionData.Count; + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public ICollection Keys + { + get + { + return _underlying.ExtensionData.Keys; + } + } + + public ICollection Values + { + get + { + return new ExtensionDataValues(_underlying.ExtensionData.Values); + } + } + + public void Add(KeyValuePair item) + { + IDictionary extensionData = GetOrCreateExtensionData(); + extensionData.Add(new KeyValuePair(item.Key, ToJToken(item.Value))); + } + + public void Add(string key, object value) + { + GetOrCreateExtensionData().Add(key, ToJToken(value)); + } + + public void Clear() + { + GetOrCreateExtensionData().Clear(); + } + + public bool Contains(KeyValuePair item) + { + return _underlying.ExtensionData.Contains(new KeyValuePair(item.Key, ToJToken(item.Value))); + } + + public bool ContainsKey(string key) + { + return _underlying.ExtensionData.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + IDictionary intermediate = new Dictionary(_underlying.ExtensionData.ToDictionary(i => i.Key, i => (object)i.Value)); + intermediate.CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return _underlying.ExtensionData.Select(i => new KeyValuePair(i.Key, i.Value)).GetEnumerator(); + } + + public bool Remove(KeyValuePair item) + { + IDictionary extensionData = _underlying._extensionData; + if (extensionData == null) + return false; + + return extensionData.Remove(new KeyValuePair(item.Key, ToJToken(item.Value))); + } + + public bool Remove(string key) + { + var extensionData = _underlying._extensionData; + if (extensionData == null) + return false; + + return extensionData.Remove(key); + } + + public bool TryGetValue(string key, out object value) + { + JToken intermediate; + bool result = _underlying.ExtensionData.TryGetValue(key, out intermediate); + value = intermediate; + return result; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + private Dictionary GetOrCreateExtensionData() + { + var result = _underlying._extensionData; + if (result == null) + { + result = new Dictionary(); + _underlying._extensionData = result; + } + + return result; + } + } + + /// + /// This class works around a known bug in Json.NET's handling of JSON extension data. + /// + /// + private class ExtensionDataValues : ICollection + { + private readonly ICollection _values; + + public ExtensionDataValues(ICollection values) + { + if (values == null) + throw new ArgumentNullException("values"); + + _values = values; + } + + public int Count + { + get + { + return _values.Count; + } + } + + public bool IsReadOnly + { + get + { + return _values.IsReadOnly; + } + } + + public void Add(object item) + { + _values.Add(ToJToken(item)); + } + + public void Clear() + { + _values.Clear(); + } + + public bool Contains(object item) + { + return _values.Contains(ToJToken(item)); + } + + public void CopyTo(object[] array, int arrayIndex) + { + ICollection intermediate = _values.ToArray(); + intermediate.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return _values.Cast().GetEnumerator(); + } + + public bool Remove(object item) + { + return _values.Remove(ToJToken(item)); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Flavor.cs b/src/OpenStack/Core/Domain/Flavor.cs new file mode 100644 index 000000000..f2a381e34 --- /dev/null +++ b/src/OpenStack/Core/Domain/Flavor.cs @@ -0,0 +1,35 @@ +namespace net.openstack.Core.Domain +{ + using Newtonsoft.Json; + + /// + /// Provides basic information about a flavor. A flavor is an available hardware configuration for a server. + /// + /// Flavors (OpenStack Compute API v2 and Extensions Reference - API v2) + /// Flavors (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + public class Flavor : ExtensibleJsonObject + { + /// + /// Gets the unique identifier for the flavor. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets a collection of links related to the current flavor. + /// + /// Links and References (OpenStack Compute API v2 and Extensions Reference - API v2) + [JsonProperty("links")] + public Link[] Links { get; private set; } + + /// + /// Gets the name of the flavor. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("name")] + public string Name { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/FlavorDetails.cs b/src/OpenStack/Core/Domain/FlavorDetails.cs new file mode 100644 index 000000000..7494c50e8 --- /dev/null +++ b/src/OpenStack/Core/Domain/FlavorDetails.cs @@ -0,0 +1,100 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Contains detailed information about a flavor. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class FlavorDetails : Flavor + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("rxtx_factor", DefaultValueHandling = DefaultValueHandling.Ignore)] + private double? _rxtxFactor; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("OS-FLV-EXT-DATA:ephemeral", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _dataDiskSize; +#pragma warning restore 649 + + /// + /// Gets the "OS-FLV-DISABLED:disabled" property associated with the flavor. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("OS-FLV-DISABLED:disabled")] + public bool Disabled { get; private set; } + + /// + /// Gets the size of the system disk for the flavor, in GB. + /// + [JsonProperty("disk")] + public int DiskSizeInGB { get; private set; } + + /// + /// Gets the amount of memory associated with the flavor, in MB. + /// + [JsonProperty("ram")] + public int RAMInMB { get; private set; } + + /// + /// Gets the number of virtual CPUs for the flavor. + /// + [JsonProperty("vcpus")] + public int VirtualCPUCount { get; private set; } + + /// + /// Gets the aggregate outbound bandwidth, in megabits per second, across all attached + /// network interfaces (PublicNet, ServiceNet, and Cloud Networks). + /// + /// + /// Outbound public Internet bandwidth can be up to 40% of the aggregate limit. Host + /// networking is redundant, and bandwidth is delivered over two separate bonded + /// interfaces, each able to carry 50% of the aggregate limit. We recommend using + /// multiple Layer 4 connections to maximize throughput. Inbound traffic is not limited. + /// + /// + /// This property is a Rackspace-specific extension to the OpenStack Compute Service. + /// + /// + /// List Flavors with the nova Client (Rackspace Next Generation Cloud Servers Getting Started - API v2) + /// + public double? RxtxFactor + { + get + { + return _rxtxFactor; + } + } + + /// + /// Gets the size of the data disks for the flavor, in GB. + /// + /// + /// + /// This property is a Rackspace-specific extension to the OpenStack Compute Service. + /// + /// + /// + /// The size of the data disks for the flavor, in GB. This property returns + /// if the JSON response from the server does not include the underlying property. + /// + /// List Flavors with the nova Client (Rackspace Next Generation Cloud Servers Getting Started - API v2) + /// + public int? DataDiskSize + { + get + { + return _dataDiskSize; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/FlavorId.cs b/src/OpenStack/Core/Domain/FlavorId.cs new file mode 100644 index 000000000..5c3dd3e07 --- /dev/null +++ b/src/OpenStack/Core/Domain/FlavorId.cs @@ -0,0 +1,41 @@ +namespace net.openstack.Core.Domain +{ + using System; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a flavor. + /// + /// + /// + /// + [JsonConverter(typeof(FlavorId.Converter))] + public sealed class FlavorId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The flavor identifier value. + /// If is . + /// If is empty. + public FlavorId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override FlavorId FromValue(string id) + { + return new FlavorId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/HomeDocument.cs b/src/OpenStack/Core/Domain/HomeDocument.cs new file mode 100644 index 000000000..80a253151 --- /dev/null +++ b/src/OpenStack/Core/Domain/HomeDocument.cs @@ -0,0 +1,36 @@ +namespace net.openstack.Core.Domain +{ + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the root object of the home document described by + /// Home Documents for HTTP APIs. + /// + /// JSON Home Documents (Home Documents for HTTP APIs - draft-nottingham-json-home-03) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class HomeDocument : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// The backing field for the property. + /// + [JsonProperty("resources")] + private Dictionary _resources; +#pragma warning restore 649 + + /// + /// Gets the resources. The keys of this dictionary are link relation types + /// (as defined by RFC5988). + /// + public Dictionary Resources + { + get + { + return _resources; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/IPAddressList.cs b/src/OpenStack/Core/Domain/IPAddressList.cs new file mode 100644 index 000000000..d2fc6275b --- /dev/null +++ b/src/OpenStack/Core/Domain/IPAddressList.cs @@ -0,0 +1,48 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Generic; + using System.Net; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + + /// + /// This implementation of is used to ensure the elements + /// are deserialized from a JSON string using the . + /// + /// + [JsonArray(ItemConverterType = typeof(IPAddressDetailsConverter))] + public class IPAddressList : List + { + /// + /// Initializes a new instance of the class. + /// that is empty and has the default initial capacity. + /// + public IPAddressList() + { + } + + /// + /// Initializes a new instance of the class + /// that is empty and has the specified initial capacity. + /// + /// The number of elements that the new list can initially store. + /// If is less than 0. + public IPAddressList(int capacity) + : base(capacity) + { + } + + /// + /// Initializes a new instance of the class that + /// contains elements copied from the specified + /// and has sufficient capacity to accommodate the number of elements copied. + /// + /// The collection whose elements are copied to the new list. + /// If is . + public IPAddressList(IEnumerable collection) + : base(collection) + { + } + } +} diff --git a/src/OpenStack/Core/Domain/IdentityToken.cs b/src/OpenStack/Core/Domain/IdentityToken.cs new file mode 100644 index 000000000..25fd52481 --- /dev/null +++ b/src/OpenStack/Core/Domain/IdentityToken.cs @@ -0,0 +1,64 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents the authentication token used for making authenticated calls to + /// multiple APIs. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class IdentityToken : ExtensibleJsonObject + { + /// + /// Gets the token expiration time in the format originally returned by the + /// authentication response. + /// + /// + [JsonProperty("expires")] + public string Expires { get; private set; } + + /// + /// Gets the token ID which can be used to make authenticated API calls. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets a object containing the name and ID of the + /// tenant (or account) for the authenticated credentials. + /// + [JsonProperty("tenant")] + public Tenant Tenant { get; private set; } + + /// + /// Gets whether or not the token has expired. This property simply checks + /// the property against the current system time. + /// If the value is missing or not in a recognized + /// format, the token is assumed to have expired. + /// + /// if the token has expired; otherwise, . + public bool IsExpired + { + get + { + DateTimeOffset expiration; + if (!DateTimeOffset.TryParse(Expires, out expiration)) + return true; + + return expiration <= DateTimeOffset.Now; + } + } + + /// + /// Gets a Collection of objects representing the ways the + /// user has authenticated. + /// + /// + [JsonProperty("RAX-AUTH:authenticatedBy", DefaultValueHandling = DefaultValueHandling.Ignore)] + public IEnumerable AuthenticationTypes { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/ImageId.cs b/src/OpenStack/Core/Domain/ImageId.cs new file mode 100644 index 000000000..b13b89d09 --- /dev/null +++ b/src/OpenStack/Core/Domain/ImageId.cs @@ -0,0 +1,41 @@ +namespace net.openstack.Core.Domain +{ + using System; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an image. + /// + /// + /// + /// + [JsonConverter(typeof(ImageId.Converter))] + public sealed class ImageId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The image identifier value. + /// If is . + /// If is empty. + public ImageId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ImageId FromValue(string id) + { + return new ImageId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ImageState.cs b/src/OpenStack/Core/Domain/ImageState.cs new file mode 100644 index 000000000..78e19cddb --- /dev/null +++ b/src/OpenStack/Core/Domain/ImageState.cs @@ -0,0 +1,129 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents the state of a compute image. + /// + /// + /// This class functions as a strongly-typed enumeration of known image states, + /// with added support for unknown states returned by an image extension. + /// + /// + [JsonConverter(typeof(ImageState.Converter))] + public sealed class ImageState : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly ImageState _active = FromName("ACTIVE"); + private static readonly ImageState _saving = FromName("SAVING"); + private static readonly ImageState _deleted = FromName("DELETED"); + private static readonly ImageState _error = FromName("ERROR"); + private static readonly ImageState _unknown = FromName("UNKNOWN"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private ImageState(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static ImageState FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new ImageState(i)); + } + + /// + /// Gets an representing an image which is active and ready to use. + /// + public static ImageState Active + { + get + { + return _active; + } + } + + /// + /// Gets an representing an image currently being saved. + /// + public static ImageState Saving + { + get + { + return _saving; + } + } + + /// + /// Gets an representing an image which has been deleted. + /// + /// + /// By default, the operation does not return + /// images which have been deleted. To list deleted images, call + /// specifying the changesSince + /// parameter. + /// + public static ImageState Deleted + { + get + { + return _deleted; + } + } + + /// + /// Gets an representing an image which failed to perform + /// an operation and is now in an error state. + /// + public static ImageState Error + { + get + { + return _error; + } + } + + /// + /// Gets an for an image that is currently in an unknown state. + /// + public static ImageState Unknown + { + get + { + return _unknown; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ImageState FromName(string name) + { + return ImageState.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ImageType.cs b/src/OpenStack/Core/Domain/ImageType.cs new file mode 100644 index 000000000..90be5ac74 --- /dev/null +++ b/src/OpenStack/Core/Domain/ImageType.cs @@ -0,0 +1,85 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using Newtonsoft.Json; + + /// + /// Represents an image type. + /// + /// + /// This class functions as a strongly-typed enumeration of known image types, + /// with added support for unknown types returned by a server extension. + /// + /// + [JsonConverter(typeof(ImageType.Converter))] + public sealed class ImageType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly ImageType _base = FromName("BASE"); + private static readonly ImageType _snapshot = FromName("SNAPSHOT"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private ImageType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static ImageType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new ImageType(i)); + } + + /// + /// Gets an representing a base image. + /// + public static ImageType Base + { + get + { + return _base; + } + } + + /// + /// Gets an representing an image created as a snapshot. + /// + public static ImageType Snapshot + { + get + { + return _snapshot; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ImageType FromName(string name) + { + return ImageType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Link.cs b/src/OpenStack/Core/Domain/Link.cs new file mode 100644 index 000000000..8a51e151c --- /dev/null +++ b/src/OpenStack/Core/Domain/Link.cs @@ -0,0 +1,48 @@ +namespace net.openstack.Core.Domain +{ + using System.Diagnostics; + using Newtonsoft.Json; + + /// + /// Represents a link associated with a resource. + /// + /// Links and References (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + [DebuggerDisplay("{Rel,nq}: {Href,nq}")] + public class Link : ExtensibleJsonObject + { + /// + /// Initializes a new instance of the class. + /// + /// The link type. + /// The link. + [JsonConstructor] + public Link(string rel, string href) + { + Rel = rel; + Href = href; + } + + /// + /// Gets the link target. + /// + /// Links and References (OpenStack Compute API v2 and Extensions Reference) + [JsonProperty("href")] + public string Href { get; private set; } + + /// + /// Gets the link relation. + /// + /// + /// + /// A self link contains a versioned link to the resource. Use these links when the link will be followed immediately. + /// A bookmark link provides a permanent link to a resource that is appropriate for long-term storage. + /// An alternate link can contain an alternative representation of the resource. For example, an OpenStack Compute image might have an alternate representation in the OpenStack Image service. + /// + /// + /// Links and References (OpenStack Compute API v2 and Extensions Reference) + [JsonProperty("rel")] + public string Rel { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/Mapping/IJsonObjectMapper`1.cs b/src/OpenStack/Core/Domain/Mapping/IJsonObjectMapper`1.cs new file mode 100644 index 000000000..09508ccca --- /dev/null +++ b/src/OpenStack/Core/Domain/Mapping/IJsonObjectMapper`1.cs @@ -0,0 +1,23 @@ +using System; +using Newtonsoft.Json.Linq; + +namespace net.openstack.Core.Domain.Mapping +{ + /// + /// Represents an object that can convert between generic instances + /// and instances of another specific type. + /// + /// The type which can be converted to and from . + public interface IJsonObjectMapper : IObjectMapper + { + /// + /// Converts a JSON string representation of to an instance + /// of . + /// + /// The JSON string representation. + /// An instance of represented by . + /// If is . + /// If the conversion cannot be performed. + T Map(string rawJson); + } +} diff --git a/src/OpenStack/Core/Domain/Mapping/IObjectMapper`2.cs b/src/OpenStack/Core/Domain/Mapping/IObjectMapper`2.cs new file mode 100644 index 000000000..bc6c9bed1 --- /dev/null +++ b/src/OpenStack/Core/Domain/Mapping/IObjectMapper`2.cs @@ -0,0 +1,41 @@ +namespace net.openstack.Core.Domain.Mapping +{ + using System; + using System.ComponentModel; + + /// + /// Represents an object that can convert between instances of two specific types. + /// + /// + /// This interface is similar to a which only supports + /// conversions between exactly two concrete types. + /// + /// The first type. + /// The second type. + public interface IObjectMapper + { + /// + /// Converts an instance of to an instance of . + /// + /// + /// This method provides behavior similar to a strongly-typed implementation + /// of . + /// + /// The instance to convert. + /// The converted instance. + /// The conversion cannot be performed. + TTo Map(TFrom from); + + /// + /// Converts an instance of to an instance of . + /// + /// + /// This method provides behavior similar to a strongly-typed implementation + /// of . + /// + /// The instance to convert. + /// The converted instance. + /// The conversion cannot be performed. + TFrom Map(TTo to); + } +} diff --git a/src/OpenStack/Core/Domain/Mapping/NamespaceDoc.cs b/src/OpenStack/Core/Domain/Mapping/NamespaceDoc.cs new file mode 100644 index 000000000..772237dcd --- /dev/null +++ b/src/OpenStack/Core/Domain/Mapping/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Core.Domain.Mapping +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines interfaces + /// and classes for mapping between various object types. Mappings are bidirectional + /// converters limited to operating on two specific types. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Domain/Metadata.cs b/src/OpenStack/Core/Domain/Metadata.cs new file mode 100644 index 000000000..3a821af80 --- /dev/null +++ b/src/OpenStack/Core/Domain/Metadata.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace net.openstack.Core.Domain +{ + /// + /// Represents metadata for servers and images in the Compute Service. + /// + /// + /// The metadata keys for the compute provider are case-sensitive. + /// + /// + [JsonDictionary] + [Serializable] + public class Metadata : Dictionary + { + } +} diff --git a/src/OpenStack/Core/Domain/NamespaceDoc.cs b/src/OpenStack/Core/Domain/NamespaceDoc.cs new file mode 100644 index 000000000..759d9f096 --- /dev/null +++ b/src/OpenStack/Core/Domain/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Core.Domain +{ + using System.Runtime.CompilerServices; + + /// + /// The namespaces define the provider-independent + /// object model for calling the OpenStack REST APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Domain/NetworkId.cs b/src/OpenStack/Core/Domain/NetworkId.cs new file mode 100644 index 000000000..bbd67ee46 --- /dev/null +++ b/src/OpenStack/Core/Domain/NetworkId.cs @@ -0,0 +1,41 @@ +namespace net.openstack.Core.Domain +{ + using System; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a network. + /// + /// + /// + /// + [JsonConverter(typeof(NetworkId.Converter))] + public sealed class NetworkId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The network identifier value. + /// If is . + /// If is empty. + public NetworkId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NetworkId FromValue(string id) + { + return new NetworkId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/NewServer.cs b/src/OpenStack/Core/Domain/NewServer.cs new file mode 100644 index 000000000..dc142380e --- /dev/null +++ b/src/OpenStack/Core/Domain/NewServer.cs @@ -0,0 +1,51 @@ +namespace net.openstack.Core.Domain +{ + using System; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Extends with information for a newly-created server. + /// + /// + /// Create Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewServer : ServerBase + { + /// + /// Gets the disk configuration used for creating the server. If the value was + /// not explicitly specified in the create request, the server inherits the value + /// from the image it was created from. + /// + /// + /// This property is defined by the Rackspace-specific Disk Configuration Extension to the OpenStack Compute API. + /// + /// Disk Configuration Extension (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + [JsonProperty("OS-DCF:diskConfig")] + public DiskConfiguration DiskConfig { get; private set; } + + /// + /// Gets the administrator password for the newly created server. + /// + [JsonProperty("adminPass")] + public string AdminPassword { get; private set; } + + /// + protected override void UpdateThis(ServerBase server) + { + if (server == null) + throw new ArgumentNullException("server"); + + base.UpdateThis(server); + + var details = server as NewServer; + + if (details == null) + return; + + DiskConfig = details.DiskConfig; + AdminPassword = details.AdminPassword; + } + } +} diff --git a/src/OpenStack/Core/Domain/NewUser.cs b/src/OpenStack/Core/Domain/NewUser.cs new file mode 100644 index 000000000..0871306a0 --- /dev/null +++ b/src/OpenStack/Core/Domain/NewUser.cs @@ -0,0 +1,78 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents the JSON result of an Add User operation. + /// + /// + /// Add User (OpenStack Identity Service API v2.0 Reference) + /// Add User (Rackspace Cloud Identity Client Developer Guide - API v2.0) + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewUser : ExtensibleJsonObject + { + /// + /// Gets the password for the new user. + /// + /// The generated password for the new user, or if the Add User request included a password. + [JsonProperty("OS-KSADM:password")] + public string Password { get; internal set; } + + /// + /// Gets the ID for the new user. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Include)] + public string Id { get; private set; } + + /// + /// Gets the username of the new user. + /// + /// The value of this property in the underlying JSON representation differs between + /// Rackspace and the OpenStack OS-KSADM extension. This property models the + /// Rackspace-specific representation of the resource. + /// + /// + [JsonProperty("username")] + public string Username { get; private set; } + + /// + /// Gets the email address of the new user. + /// + /// + /// The email address of the user. + /// -or- + /// if the response from the server did not include the underlying property. + /// + [JsonProperty("email")] + public string Email { get; private set; } + + /// + /// Gets a value indicating whether or not the user is enabled. + /// + /// + /// if the user is enabled; otherwise, . + /// + [JsonProperty("enabled")] + public bool Enabled { get; private set; } + + /// + /// Initializes a new instance of the class with the specified + /// username, email address, password, and value indicating whether or not the user + /// is initially enabled. + /// + /// The username of the new user (see ). + /// The email address of the new user (see ). + /// The password for the new user (see ). + /// if the user is initially enabled; otherwise, (see ). + public NewUser(string username, string email, string password = null, bool enabled = true) + { + Username = username; + Email = email; + Password = password; + Enabled = enabled; + } + } +} diff --git a/src/OpenStack/Core/Domain/ObjectStore.cs b/src/OpenStack/Core/Domain/ObjectStore.cs new file mode 100644 index 000000000..707007c82 --- /dev/null +++ b/src/OpenStack/Core/Domain/ObjectStore.cs @@ -0,0 +1,23 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + + /// + /// Represents the result of various Object Storage operations. + /// + /// + public enum ObjectStore + { + /// + /// The container was created. + /// + /// + ContainerCreated, + + /// + /// The container already exists. + /// + /// + ContainerExists, + } +} diff --git a/src/OpenStack/Core/Domain/Personality.cs b/src/OpenStack/Core/Domain/Personality.cs new file mode 100644 index 000000000..047dd4a67 --- /dev/null +++ b/src/OpenStack/Core/Domain/Personality.cs @@ -0,0 +1,133 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Text; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Describes a file to inject into the file system while creating or + /// rebuilding a server. + /// + /// + /// You can customize the personality of a server instance by injecting data into + /// its file system. For example, you might want to insert SSH keys, set configuration + /// files, or store data that you want to retrieve from inside the instance. This + /// feature provides a minimal amount of launch-time personalization. If you require + /// significant customization, create a custom image. + /// + /// Server Personality (OpenStack Compute API V2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + public sealed class Personality : ExtensibleJsonObject + { + /// + /// The path of the file to create on the target file system. + /// + /// + /// The behavior of the related methods is undefined + /// if the UTF-8 encoded value is longer than 255 bytes. + /// + [JsonProperty("path")] + public string Path { get; private set; } + + /// + /// The contents of the file to create on the target file system. + /// + /// + /// The maximum size of the file contents is determined by the compute provider + /// and may vary based on the image that is used to create the server. The provider + /// may provide a maxPersonalitySize absolute limit, which is a byte limit + /// that is guaranteed to apply to all images in the deployment. Providers can set + /// additional per-image personality limits. + /// + /// + /// The behavior of the related methods is undefined + /// if the value is not a UTF-8 encoded text file. + /// + /// + [JsonProperty("contents")] + public byte[] Content { get; private set; } + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + private Personality() + { + } + + /// + /// Initializes a new instance of the class with the specified + /// path and contents. + /// + /// The path of the file to create on the target file system. + /// The contents of the file to create on the target file system. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public Personality(string path, byte[] content) + { + if (path == null) + throw new ArgumentNullException("path"); + if (content == null) + throw new ArgumentNullException("content"); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("path cannot be empty"); + + Path = path; + Content = content; + } + + /// + /// Initializes a new instance of the class with the specified + /// path and text content, using for the content encoding. + /// + /// The path of the text file to create on the target file system. + /// The contents of the text file to create on the target file system. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public Personality(string path, string content) + : this(path, content, Encoding.UTF8) + { + } + + /// + /// Initializes a new instance of the class with the specified + /// path, text content, and context encoding. + /// + /// The path of the text file to create on the target file system. + /// The contents of the text file to create on the target file system. + /// The encoding to use for the text file. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public Personality(string path, string content, Encoding encoding) + { + if (path == null) + throw new ArgumentNullException("path"); + if (content == null) + throw new ArgumentNullException("content"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("path cannot be empty"); + + Path = path; + Content = encoding.GetBytes(content); + } + } +} diff --git a/src/OpenStack/Core/Domain/PowerState.cs b/src/OpenStack/Core/Domain/PowerState.cs new file mode 100644 index 000000000..844196b2f --- /dev/null +++ b/src/OpenStack/Core/Domain/PowerState.cs @@ -0,0 +1,106 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + + /// + /// Represents the power state of a server. + /// + /// + /// This class functions as a strongly-typed enumeration of known power states, + /// with added support for unknown states returned by a server extension. + /// + /// + /// This property is defined by the Rackspace-specific Extended Status Extension + /// to the OpenStack Compute API. The API does not regulate the status values, + /// so it is possible that values can be added, removed, or renamed. + /// + /// + /// + /// OS-EXT-STS:power_state (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonConverter(typeof(PowerState.Converter))] + public sealed class PowerState : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly PowerState _poweredDown = FromName("0"); + private static readonly PowerState _poweredUp = FromName("1"); + private static readonly PowerState _shutOff = FromName("4"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private PowerState(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static PowerState FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new PowerState(i)); + } + + /// + /// Gets a instance representing description. + /// + public static PowerState PoweredDown + { + get + { + return _poweredDown; + } + } + + /// + /// Gets a instance representing description. + /// + public static PowerState PoweredUp + { + get + { + return _poweredUp; + } + } + + /// + /// Gets a instance representing description. + /// + public static PowerState ShutOff + { + get + { + return _shutOff; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override PowerState FromName(string name) + { + return PowerState.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ProjectId.cs b/src/OpenStack/Core/Domain/ProjectId.cs new file mode 100644 index 000000000..549ef80aa --- /dev/null +++ b/src/OpenStack/Core/Domain/ProjectId.cs @@ -0,0 +1,40 @@ +namespace net.openstack.Core.Domain +{ + using System; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a project, , or account. + /// + /// + /// + [JsonConverter(typeof(ProjectId.Converter))] + public sealed class ProjectId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The project identifier value. + /// If is . + /// If is empty. + public ProjectId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ProjectId FromValue(string id) + { + return new ProjectId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ProviderStateBase`1.cs b/src/OpenStack/Core/Domain/ProviderStateBase`1.cs new file mode 100644 index 000000000..a22b6d4a6 --- /dev/null +++ b/src/OpenStack/Core/Domain/ProviderStateBase`1.cs @@ -0,0 +1,29 @@ +namespace net.openstack.Core.Domain +{ + /// + /// Provides a base class for domain objects which require access to the + /// provider which created them. + /// + /// The provider type. + /// + public abstract class ProviderStateBase : ExtensibleJsonObject + { + /// + /// Gets the provider which created the instance. + /// + protected internal T Provider { get; set; } + + /// + /// Gets the region where the current entity resides. + /// + protected internal string Region { get; set; } + + /// + /// Gets the identity the current entity belongs to, or if + /// the identity was not explicitly specified in the request that created + /// this object (i.e. the default identity of was + /// used). + /// + protected internal CloudIdentity Identity { get; set; } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/Claim.cs b/src/OpenStack/Core/Domain/Queues/Claim.cs new file mode 100644 index 000000000..230f61c27 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/Claim.cs @@ -0,0 +1,304 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Threading.Tasks; + using net.openstack.Core; + using net.openstack.Core.Providers; + using CancellationToken = System.Threading.CancellationToken; + + /// + /// Represents a claim of messages in a queue. + /// + /// + /// The claim is released when or + /// is called. At that time, any messages belonging to this claim which have not + /// been deleted will be eligible for claiming by another node in the system. + /// Messages belonging to this claim may be deleted by calling + /// or + /// . + /// + /// + /// + /// + public class Claim : IDisposable + { + /// + /// A private object used to ensure is only + /// initialized once in . + /// + private readonly object _lock = new object(); + + /// + /// The queueing service instance used for commands related to this claim. + /// + private readonly IQueueingService _service; + + /// + /// The name of the queue this claim belongs to. + /// + private readonly QueueName _queueName; + + /// + /// The backing field for the property. + /// + private readonly Uri _location; + + /// + /// The backing field for the property. + /// + private TimeSpan _age; + + /// + /// The backing field for the property. + /// + private TimeSpan _timeToLive; + + /// + /// The backing field for the property. + /// + private QueuedMessage[] _messages; + + /// + /// The object representing the asynchronous release of this claim. + /// Prior to calling or , the value of + /// this field is . + /// + private Task _releaseTask; + + /// + /// Initializes a new instance of the class using the provided values. + /// + /// The queueing service. + /// The name of the queue. + /// The absolute URI of the claim resource. If no claim was allocated by the server, this value is . + /// The time to live of the claim. + /// The age of the claim. + /// if the current instance owns the claim (and is responsible for releasing it); otherwise, . + /// A collection of messages belonging to the claim. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + public Claim(IQueueingService service, QueueName queueName, Uri location, TimeSpan timeToLive, TimeSpan age, bool owner, IEnumerable messages) + { + if (service == null) + throw new ArgumentNullException("service"); + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messages == null) + throw new ArgumentNullException("messages"); + + _service = service; + _queueName = queueName; + _location = location; + _timeToLive = timeToLive; + _age = age; + _messages = messages.ToArray(); + if (!owner) + { + // prevent this object from releasing the resource + _releaseTask = InternalTaskExtensions.CompletedTask(); + } + } + + /// + /// Gets the claim ID. + /// + /// + /// The claim ID is derived from the property according to the + /// URI template documented in the OpenStack Marconi API v1 Blueprint. + /// + /// + /// The ID of this claim. If the claim is empty (i.e. the queue did not have any unclaimed messages), this value is . + /// + public ClaimId Id + { + get + { + if (_location == null) + return null; + + string locationPath = _location.AbsolutePath; + return new ClaimId(locationPath.Substring(locationPath.LastIndexOf('/') + 1)); + } + } + + /// + /// Gets the absolute URI for this claim. + /// + /// + /// The absolute URI of this claim. If the claim is empty (i.e. the queue did not have any unclaimed messages), this value is . + /// + public Uri Location + { + get + { + return _location; + } + } + + /// + /// Gets the age of the claim as returned by the server. + /// + /// + /// This value does not automatically update. To obtain the age of a claim after a period of time elapses, + /// use . + /// + public TimeSpan Age + { + get + { + return _age; + } + } + + /// + /// Gets the Time To Live (TTL) of the claim. + /// + public TimeSpan TimeToLive + { + get + { + return _timeToLive; + } + + private set + { + _timeToLive = value; + } + } + + /// + /// Gets the messages which are included in this claim. + /// + public ReadOnlyCollection Messages + { + get + { + return new ReadOnlyCollection(_messages); + } + } + + /// + /// Refreshes the current claim. + /// + /// + /// This method calls to obtain updated + /// information about the current claim, and then synchronously invokes + /// to update the current instance to match the results. + /// + /// The that the task will observe. + /// A object representing the asynchronous operation. + public Task RefreshAsync(CancellationToken cancellationToken) + { + Action> applyChanges = task => RefreshImpl(task.Result); + return _service.QueryClaimAsync(_queueName, this, cancellationToken).Select(applyChanges); + } + + /// + /// Renews the claim by resetting the age and updating the TTL for the claim. + /// + /// + /// This method calls to renew the + /// current claim, and then synchronously updates the current instance to reflect + /// the new age and time-to-live values. + /// + /// + /// The new Time-To-Live value for the claim. This value may differ from the original TTL of the claim. + /// + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is negative or . + /// If the claim is empty (i.e. is empty). + public Task RenewAsync(TimeSpan timeToLive, CancellationToken cancellationToken) + { + if (timeToLive <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeToLive"); + if (_location == null) + throw new InvalidOperationException("Empty claims cannot be renewed."); + + Action applyChanges = + task => + { + _age = TimeSpan.Zero; + TimeToLive = timeToLive; + }; + return _service.UpdateClaimAsync(_queueName, this, timeToLive, cancellationToken).Select(applyChanges); + } + + /// + /// + /// This method calls to release messages + /// claimed by this claim. To prevent other subscribers from re-claiming the messages, make + /// sure to delete the messages before calling . + /// + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Asynchronously releases resources owned by this . + /// + /// + /// This method calls to release messages + /// claimed by this claim. To prevent other subscribers from re-claiming the messages, make + /// sure to delete the messages before calling . + /// + /// The that the task will observe. + /// A object representing the asynchronous operation. + public Task DisposeAsync(CancellationToken cancellationToken) + { + lock (_lock) + { + if (_releaseTask == null) + { + if (_messages.Length == 0) + _releaseTask = InternalTaskExtensions.CompletedTask(); + else + _releaseTask = _service.ReleaseClaimAsync(_queueName, this, cancellationToken); + } + } + + return _releaseTask; + } + + /// + /// Releases resources owned by this . + /// + /// if this method was called from ; otherwise, if this method was called from a finalizer. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + DisposeAsync(CancellationToken.None).Wait(); + } + } + + /// + /// Refresh the current claim to match the updated information in . + /// + /// A object containing updated claim information. + /// If is . + /// If the specified does not represent the same claim as the current instance. + protected virtual void RefreshImpl(Claim claim) + { + if (claim == null) + throw new ArgumentNullException("claim"); + if (Location != claim.Location) + throw new ArgumentException("The specified claim does not represent the same claim as the current instance.", "claim"); + + this._age = claim._age; + this._messages = claim._messages; + this._timeToLive = claim._timeToLive; + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/ClaimId.cs b/src/OpenStack/Core/Domain/Queues/ClaimId.cs new file mode 100644 index 000000000..6aef567d0 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/ClaimId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using Newtonsoft.Json; + using net.openstack.Core.Providers; + + /// + /// Represents the unique identifier of a claim in the . + /// + /// + /// + /// + [JsonConverter(typeof(ClaimId.Converter))] + public sealed class ClaimId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The claim identifier value. + /// If is . + /// If is empty. + public ClaimId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ClaimId FromValue(string id) + { + return new ClaimId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/CloudQueue.cs b/src/OpenStack/Core/Domain/Queues/CloudQueue.cs new file mode 100644 index 000000000..1d19af2b2 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/CloudQueue.cs @@ -0,0 +1,79 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + + /// + /// Represents a named queue in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CloudQueue : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// The backing field for the property. + /// + [JsonProperty("name")] + private QueueName _name; + + /// + /// The backing field for the property. + /// + [JsonProperty("href")] + private Uri _href; + + /// + /// The backing field for the property. + /// + [JsonProperty("metadata")] + private JObject _metadata; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected CloudQueue() + { + } + + /// + /// Gets the name of the queue. + /// + public QueueName Name + { + get + { + return _name; + } + } + + /// + /// Gets the URI of the queue resource. + /// + public Uri Href + { + get + { + return _href; + } + } + + /// + /// Gets a dynamic object containing the metadata associated with the queue. + /// + public JObject Metadata + { + get + { + return _metadata; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/Message.cs b/src/OpenStack/Core/Domain/Queues/Message.cs new file mode 100644 index 000000000..f5a21a213 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/Message.cs @@ -0,0 +1,36 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + + /// + /// Represents a queue message with a dynamic body. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Message : Message + { + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected Message() + { + } + + /// + /// Initializes a new instance of the class using + /// the specified time-to-live and message body. + /// + /// The time-to-live for the message. + /// The message data. + /// If is negative or . + public Message(TimeSpan timeToLive, JObject body) + : base(timeToLive, body) + { + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/MessageId.cs b/src/OpenStack/Core/Domain/Queues/MessageId.cs new file mode 100644 index 000000000..197c9380d --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/MessageId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using Newtonsoft.Json; + using net.openstack.Core.Providers; + + /// + /// Represents the unique identifier of a message in the . + /// + /// + /// + /// + [JsonConverter(typeof(MessageId.Converter))] + public sealed class MessageId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The message identifier value. + /// If is . + /// If is empty. + public MessageId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override MessageId FromValue(string id) + { + return new MessageId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/MessageStatistics.cs b/src/OpenStack/Core/Domain/Queues/MessageStatistics.cs new file mode 100644 index 000000000..34902cff7 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/MessageStatistics.cs @@ -0,0 +1,77 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON object used to represent statistics for a particular + /// message in a message queue. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MessageStatistics : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// The backing field for the property. + /// + [JsonProperty("href")] + private string _href; + + /// + /// The backing field for the property. + /// + [JsonProperty("age")] + private long _age; + + /// + /// The backing field for the property. + /// + [JsonProperty("created")] + private string _created; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected MessageStatistics() + { + } + + /// + /// Gets the absolute path of the URI to this message. + /// + public string Href + { + get + { + return _href; + } + } + + /// + /// Gets the age of the message in the queue. + /// + public TimeSpan Age + { + get + { + return TimeSpan.FromSeconds(_age); + } + } + + /// + /// Gets the timestamp when this message was first added to the queue. + /// + public DateTimeOffset Created + { + get + { + return JsonConvert.DeserializeObject(_created); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/Message`1.cs b/src/OpenStack/Core/Domain/Queues/Message`1.cs new file mode 100644 index 000000000..e5fffb5dc --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/Message`1.cs @@ -0,0 +1,75 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using Newtonsoft.Json; + + /// + /// Represents a queue message with a strongly-typed body. + /// + /// The type of the data stored in the message body. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Message : ExtensibleJsonObject + { + /// + /// The backing field for the property. + /// This value is stored in seconds. + /// + [JsonProperty("ttl")] + private long _timeToLive; + + /// + /// The backing field for the property. + /// + [JsonProperty("body")] + private T _body; + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected Message() + { + } + + /// + /// Initializes a new instance of the class using + /// the specified time-to-live and strongly-typed message body. + /// + /// The time-to-live for the message. + /// The message data. + /// If is negative or . + public Message(TimeSpan timeToLive, T body) + { + if (timeToLive <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeToLive"); + + _timeToLive = (long)timeToLive.TotalSeconds; + _body = body; + } + + /// + /// Gets the time-to-live for the message. + /// + public TimeSpan TimeToLive + { + get + { + return TimeSpan.FromSeconds(_timeToLive); + } + } + + /// + /// Gets the body of the message. + /// + public T Body + { + get + { + return _body; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/MessagesEnqueued.cs b/src/OpenStack/Core/Domain/Queues/MessagesEnqueued.cs new file mode 100644 index 000000000..511051dbc --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/MessagesEnqueued.cs @@ -0,0 +1,103 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using System.Collections.Generic; + using System.Linq; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents the response returned when posting messages to a queue in the . + /// + /// + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MessagesEnqueued : ExtensibleJsonObject + { + /// + /// A default instance of the class representing a successful + /// operation to post an empty collection of messages. + /// + /// + public static MessagesEnqueued Empty = new MessagesEnqueued(false, new Uri[0]); + +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("partial")] + private bool? _partial; + + /// + /// Contains a collection of message resource URIs. + /// + [JsonProperty("resources")] + private Uri[] _resources; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected MessagesEnqueued() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The value of the property. + /// A collection + /// If contains any values. + private MessagesEnqueued(bool? partial, IEnumerable resources) + { + _partial = partial; + + if (resources != null) + { + _resources = resources.ToArray(); + if (_resources.Contains(null)) + throw new ArgumentException("resources cannot contain any null values", "resources"); + } + } + + /// + /// Gets a value indicating whether the post operation was only partially successful. + /// + /// + /// if the Post Messages operation was fully successful. + /// -or- + /// if the Post Messages operation was partially successful. + /// -or- + /// if the JSON response from the server did not include the underlying property. + /// + public bool? Partial + { + get + { + return _partial; + } + } + + /// + /// Gets the posted message IDs. + /// + public IEnumerable Ids + { + get + { + if (_resources == null || _resources.Length == 0) + yield break; + + foreach (var resource in _resources) + { + yield return QueuedMessage.ParseMessageId(resource); + } + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Core/Domain/Queues/NamespaceDoc.cs b/src/OpenStack/Core/Domain/Queues/NamespaceDoc.cs new file mode 100644 index 000000000..5f62495cb --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines the provider-independent + /// object model for calling the OpenStack Queues API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Domain/Queues/QueueMessagesStatistics.cs b/src/OpenStack/Core/Domain/Queues/QueueMessagesStatistics.cs new file mode 100644 index 000000000..51358b7a2 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/QueueMessagesStatistics.cs @@ -0,0 +1,118 @@ +namespace net.openstack.Core.Domain.Queues +{ + using Newtonsoft.Json; + + /// + /// This models the JSON object used to represent statistics for messages + /// a particular message queue. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class QueueMessagesStatistics : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// The backing field for the property; + /// + [JsonProperty("free")] + private long _free; + + /// + /// The backing field for the property; + /// + [JsonProperty("claimed")] + private long _claimed; + + /// + /// The backing field for the property; + /// + [JsonProperty("total")] + private long _total; + + /// + /// The backing field for the property; + /// + [JsonProperty("oldest")] + private MessageStatistics _oldest; + + /// + /// The backing field for the property; + /// + [JsonProperty("newest")] + private MessageStatistics _newest; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected QueueMessagesStatistics() + { + } + + /// + /// Gets the number of unclaimed messages in the queue. + /// + public long Free + { + get + { + return _free; + } + } + + /// + /// Gets the number of claimed messages in the queue. + /// + public long Claimed + { + get + { + return _claimed; + } + } + + /// + /// Gets the total number of messages currently in the queue. + /// + public long Total + { + get + { + return _total; + } + } + + /// + /// Gets additional statistics for the oldest message in the queue. + /// + /// + /// A object containing statistics about the oldest message in the queue, + /// or if is 0. + /// + public MessageStatistics Oldest + { + get + { + return _oldest; + } + } + + /// + /// Gets additional statistics for the newest message in the queue. + /// + /// + /// A object containing statistics about the newest message in the queue, + /// or if is 0. + /// + public MessageStatistics Newest + { + get + { + return _newest; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/QueueName.cs b/src/OpenStack/Core/Domain/Queues/QueueName.cs new file mode 100644 index 000000000..1fc3de924 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/QueueName.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using Newtonsoft.Json; + using net.openstack.Core.Providers; + + /// + /// Represents the name of a queue in the . + /// + /// + /// + /// + [JsonConverter(typeof(QueueName.Converter))] + public sealed class QueueName : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The queue name. + /// If is . + /// If is empty. + public QueueName(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override QueueName FromValue(string id) + { + return new QueueName(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/QueueStatistics.cs b/src/OpenStack/Core/Domain/Queues/QueueStatistics.cs new file mode 100644 index 000000000..8a958bd21 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/QueueStatistics.cs @@ -0,0 +1,43 @@ +namespace net.openstack.Core.Domain.Queues +{ + using Newtonsoft.Json; + + /// + /// This models the JSON object used to represent statistics returned by the + /// Get Queue Statistics API call. + /// + /// Get Queue Statistics (Marconi API v1 Blueprint) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class QueueStatistics : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// The backing field for the property. + /// + [JsonProperty("messages")] + private QueueMessagesStatistics _messageStatistics; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected QueueStatistics() + { + } + + /// + /// Gets statistics about messages contained in the queue. + /// + public QueueMessagesStatistics MessageStatistics + { + get + { + return _messageStatistics; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/QueuedMessage.cs b/src/OpenStack/Core/Domain/Queues/QueuedMessage.cs new file mode 100644 index 000000000..09a809192 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/QueuedMessage.cs @@ -0,0 +1,129 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using System.Linq; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using net.openstack.Core.Providers; + + /// + /// Represents a message which is queued in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class QueuedMessage : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// The backing field for the property. + /// + [JsonProperty("href")] + private Uri _href; + + /// + /// The backing field for the property. + /// The value is stored in seconds. + /// + [JsonProperty("ttl")] + private long _ttl; + + /// + /// The backing field for the property. + /// The value is stored in seconds. + /// + [JsonProperty("age")] + private long _age; + + /// + /// The backing field for the property. + /// + [JsonProperty("body")] + private JObject _body; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected QueuedMessage() + { + } + + /// + /// Gets the ID of the message. + /// + public MessageId Id + { + get + { + if (Href == null) + return null; + + return ParseMessageId(Href); + } + } + + /// + /// Gets the URI of the message resource. + /// + public Uri Href + { + get + { + return _href; + } + } + + /// + /// Gets the time-to-live of the message. + /// + public TimeSpan TimeToLive + { + get + { + return TimeSpan.FromSeconds(_ttl); + } + } + + /// + /// Gets the age of the message. + /// + public TimeSpan Age + { + get + { + return TimeSpan.FromSeconds(_age); + } + } + + /// + /// Gets the JSON body of the message as a dynamic . + /// + public JObject Body + { + get + { + return _body; + } + } + + /// + /// Parses a URI to extract a . + /// + /// The resource URI. + /// The ID of the message. + public static MessageId ParseMessageId(Uri href) + { + // make sure we have an absolute URI, or Segments will throw an InvalidOperationException + if (!href.IsAbsoluteUri) + href = new Uri(new Uri("http://example.com"), href); + + if (href.Segments.Length == 0) + return null; + + return new MessageId(href.Segments.Last()); + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/QueuedMessageList.cs b/src/OpenStack/Core/Domain/Queues/QueuedMessageList.cs new file mode 100644 index 000000000..0392806ab --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/QueuedMessageList.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using net.openstack.Core.Collections; + using net.openstack.Core.Providers; + + /// + /// This class extends the class + /// to provide access to the opaque marker used for paginating messages + /// in the (via the + /// property. + /// + /// + /// + public class QueuedMessageList : BasicReadOnlyCollectionPage + { + /// + /// This is the backing field for the property. + /// + private QueuedMessageListId _nextPageId; + + /// + /// Initializes a new instance of the class + /// that is a read-only wrapper around the specified list. + /// + /// The list to wrap. + /// A function that returns a representing the asynchronous operation to get the next page of items in the collection. If specified, this function implements . If the value is , then will return . + /// The identifier of the next page in the message list. + /// + /// If is . + /// + public QueuedMessageList(IList list, Func>> getNextPageAsync, QueuedMessageListId nextPageId) + : base(list, getNextPageAsync) + { + _nextPageId = nextPageId; + } + + /// + /// Gets the identifier of the next page of the message list. + /// + public QueuedMessageListId NextPageId + { + get + { + return _nextPageId; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Queues/QueuedMessageListId.cs b/src/OpenStack/Core/Domain/Queues/QueuedMessageListId.cs new file mode 100644 index 000000000..f80219788 --- /dev/null +++ b/src/OpenStack/Core/Domain/Queues/QueuedMessageListId.cs @@ -0,0 +1,44 @@ +namespace net.openstack.Core.Domain.Queues +{ + using System; + using net.openstack.Core; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a message list page in the . + /// + /// + /// + /// + /// + [JsonConverter(typeof(QueuedMessageListId.Converter))] + public sealed class QueuedMessageListId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The identifier value. + /// If is null. + /// If is empty. + public QueuedMessageListId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override QueuedMessageListId FromValue(string id) + { + return new QueuedMessageListId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/RebootType.cs b/src/OpenStack/Core/Domain/RebootType.cs new file mode 100644 index 000000000..91d5acecd --- /dev/null +++ b/src/OpenStack/Core/Domain/RebootType.cs @@ -0,0 +1,86 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using Newtonsoft.Json; + + /// + /// Represents the type of a reboot operation. + /// + /// + /// This class functions as a strongly-typed enumeration of known reboot types, + /// with added support for unknown types returned by a server extension. + /// + /// + [JsonConverter(typeof(RebootType.Converter))] + public sealed class RebootType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly RebootType _hard = FromName("HARD"); + private static readonly RebootType _soft = FromName("SOFT"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private RebootType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static RebootType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new RebootType(i)); + } + + /// + /// Gets a representing the equivalent of cycling power to the server. + /// + public static RebootType Hard + { + get + { + return _hard; + } + } + + /// + /// Gets a representing a reboot performed by signaling the server's + /// operating system to restart, allowing for graceful shutdown of currently executing processes. + /// + public static RebootType Soft + { + get + { + return _soft; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override RebootType FromName(string name) + { + return RebootType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ResourceHints.cs b/src/OpenStack/Core/Domain/ResourceHints.cs new file mode 100644 index 000000000..0cb50edfa --- /dev/null +++ b/src/OpenStack/Core/Domain/ResourceHints.cs @@ -0,0 +1,298 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using JSIStudios.SimpleRESTServices.Client; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + using Newtonsoft.Json.Linq; + using ContentType = System.Net.Mime.ContentType; + + /// + /// This class models the Resource Hints of the home document described by + /// Home Documents for HTTP APIs. + /// + /// + /// Resource hints allow clients to find relevant information about + /// interacting with a resource beforehand, as a means of optimizing + /// communications, as well as advertising available behaviors (e.g., to + /// aid in laying out a user interface for consuming the API). + /// + /// Hints are just that - they are not a "contract", and are to only + /// be taken as advisory. The runtime behavior of the resource always + /// overrides hinted information. + /// + /// For example, a resource might hint that the PUT method is allowed + /// on all "widget" resources. This means that generally, the user has the + /// ability to PUT to a particular resource, but a specific resource + /// could reject a PUT based upon access control or other considerations. + /// More fine-grained information might be gathered by interacting with + /// the resource (e.g., via a GET), or by another resource "containing" + /// it (such as a "widgets" collection). + /// + /// The current specification defines a set of common hints, based + /// upon information that's discoverable by directly interacting with + /// resources. A future draft will explain how to define new hints. + /// + /// Resource Hints (Home Documents for HTTP APIs - draft-nottingham-json-home-03) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ResourceHints : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("allow", DefaultValueHandling = DefaultValueHandling.Ignore, ItemConverterType = typeof(StringEnumConverter))] + private HttpMethod[] _allow; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("formats", DefaultValueHandling = DefaultValueHandling.Ignore)] + private Dictionary _formats; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("accept-patch", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string[] _acceptPatch; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("accept-post", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string[] _acceptPost; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("accept-put", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string[] _acceptPut; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("accept-ranges", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string[] _acceptRanges; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("prefer", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string[] _prefer; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("docs", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _docs; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("precondition-req", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string[] _preconditionReq; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("auth-req", DefaultValueHandling = DefaultValueHandling.Ignore)] + private AuthenticationRequirement[] _authReq; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _status; +#pragma warning restore 649 + + /// + /// Gets the HTTP methods that the current client will be able to use to interact + /// with the resource; equivalent to the Allow HTTP response + /// header. + /// + public ReadOnlyCollection Allow + { + get + { + if (_allow == null) + return null; + + return new ReadOnlyCollection(_allow); + } + } + + /// + /// Gets the representation types that the resource produces and consumes, using the + /// GET and PUT methods respectively, subject to the hint. The + /// keys of this collections are media types, + /// and the values are objects which have not yet been defined. + /// + public Dictionary Formats + { + get + { + return _formats; + } + } + + /// + /// Gets the PATCH request formats accepted by the resource for this client; + /// equivalent to the Accept-Patch HTTP response header. + /// + /// RFC5789 (PATCH Method for HTTP) + public ReadOnlyCollection AcceptPatch + { + get + { + if (_acceptPatch == null) + return null; + + return new ReadOnlyCollection(_acceptPatch); + } + } + + /// + /// Gets the POST request formats accepted by the resource for this client. + /// + public ReadOnlyCollection AcceptPost + { + get + { + if (_acceptPost == null) + return null; + + return new ReadOnlyCollection(_acceptPost); + } + } + + /// + /// Gets the PUT request formats accepted by the resource for this client. + /// + /// + /// If this value is , a client may assume that any format indicated by + /// the hint is acceptable in a PUT. + /// + public ReadOnlyCollection AcceptPut + { + get + { + if (_acceptPut == null) + return null; + + return new ReadOnlyCollection(_acceptPut); + } + } + + /// + /// Gets the range-specifiers available to the client for this resource; + /// equivalent to the Accept-Ranges HTTP response header. + /// + /// + /// The values are HTTP range specifiers. + /// + /// Accept-Ranges (Hypertext Transfer Protocol (HTTP/1.1): Range Requests - draft-ietf-httpbis-p5-range-24) + public ReadOnlyCollection AcceptRanges + { + get + { + if (_acceptRanges == null) + return null; + + return new ReadOnlyCollection(_acceptRanges); + } + } + + /// + /// Gets the preferences supported by the resource. Note that, as per that + /// specification, a preference can be ignored by the server. + /// + /// Prefer Header for HTTP (draft-snell-http-prefer-12) + public ReadOnlyCollection Prefer + { + get + { + if (_prefer == null) + return null; + + return new ReadOnlyCollection(_prefer); + } + } + + /// + /// Gets the location for human-readable documentation for the relation type + /// of the resource. + /// + public Uri Docs + { + get + { + if (_docs == null) + return null; + + return new Uri(_docs); + } + } + + /// + /// Gets a collection of preconditions that the resource may require for + /// state-changing requests (e.g., PUT, PATCH) to include a precondition, + /// to avoid conflicts due to concurrent updates. + /// + /// + /// This collection may contain the values "etag" and + /// "last-modified" indicating the type of precondition + /// expected. + /// + /// Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests (draft-ietf-httpbis-p4-conditional-24) + public ReadOnlyCollection Preconditions + { + get + { + if (_preconditionReq == null) + return null; + + return new ReadOnlyCollection(_preconditionReq); + } + } + + /// + /// Gets a collection of requirements for authentication using the HTTP Authentication Framework. + /// + /// + /// Hypertext Transfer Protocol (HTTP/1.1): Authentication (draft-ietf-httpbis-p7-auth-24) + public ReadOnlyCollection AuthenticationRequirements + { + get + { + if (_authReq == null) + return null; + + return new ReadOnlyCollection(_authReq); + } + } + + /// + /// Gets the status of the resource. Possible values for the status are + /// "deprecated" and "gone". + /// + /// + /// Some possible values for this property are: + /// + /// + /// deprecated: indicates that use of the resource is not recommended, but it is still available. + /// gone: indicates that the resource is no longer available; i.e. it will return a 410 Gone HTTP status code if accessed. + /// + /// + public string Status + { + get + { + return _status; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ResourceObject.cs b/src/OpenStack/Core/Domain/ResourceObject.cs new file mode 100644 index 000000000..faac6e2e7 --- /dev/null +++ b/src/OpenStack/Core/Domain/ResourceObject.cs @@ -0,0 +1,112 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the Resource Object of the home document described by + /// Home Documents for HTTP APIs. + /// + /// Resource Objects (Home Documents for HTTP APIs - draft-nottingham-json-home-03) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ResourceObject : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("href", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _href; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("href-template", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _hrefTemplate; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("href-vars", DefaultValueHandling = DefaultValueHandling.Ignore)] + private Dictionary _hrefVars; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("hints")] + private ResourceHints _hints; +#pragma warning restore 649 + + /// + /// Gets the URI of the resource, if the resource is a direct link. The value + /// may be a relative URI whose base URI is that of the JSON Home Document itself. + /// + /// + /// The direct URI of the resource, or if this resource is + /// a templated link. + /// + /// RFC3986 (Uniform Resource Identifier (URI): Generic Syntax) + public Uri Href + { + get + { + if (_href == null) + return null; + + return new Uri(_href); + } + } + + /// + /// Gets the URI Template of the resource. The value may be a relative URI + /// whose base URI is that of the JSON Home Document itself. + /// + /// + /// The URI Template of the resource, or if this resource is + /// a direct link. + /// + /// RFC6570 (URI Template) + public string HrefTemplate + { + get + { + return _hrefTemplate; + } + } + + /// + /// Gets the template variables used to fill the template returned by + /// . + /// + /// + /// This is a mapping between variable names available to the template and + /// absolute URIs that are used as global identifiers for the semantics and + /// syntax of those variables. + /// + /// + /// The template variable mapping, or if this is a direct link. + /// + public IDictionary HrefVars + { + get + { + return _hrefVars; + } + } + + /// + /// Gets the additional Resource Hints describing the resource. + /// + /// + public ResourceHints Hints + { + get + { + return _hints; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Role.cs b/src/OpenStack/Core/Domain/Role.cs new file mode 100644 index 000000000..642a12fb5 --- /dev/null +++ b/src/OpenStack/Core/Domain/Role.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Core.Domain +{ + using System.Diagnostics; + using Newtonsoft.Json; + + /// + /// A personality that a user assumes when performing a specific set of operations. A role + /// includes a set of right and privileges. A user assuming that role inherits those rights + /// and privileges. + /// + /// + /// In OpenStack Identity Service, a token that is issued to a user includes the list of + /// roles that user can assume. Services that are being called by that user determine how + /// they interpret the set of roles a user has and to which operations or resources each + /// role grants access. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + [DebuggerDisplay("{Name,nq} ({Id, nq})")] + public class Role : ExtensibleJsonObject + { + /// + /// Gets the unique identifier for the role. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the name of the role. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets a description of the role, if one is provided. + /// + [JsonProperty("description")] + public string Description { get; private set; } + + /// + /// Initializes a new instance of the class with + /// the specified name and description. + /// + /// The name of the role. + /// The description of the role. + public Role(string name, string description) + { + Name = name; + Description = description; + } + } +} diff --git a/src/OpenStack/Core/Domain/Server.cs b/src/OpenStack/Core/Domain/Server.cs new file mode 100644 index 000000000..b3d4da6d6 --- /dev/null +++ b/src/OpenStack/Core/Domain/Server.cs @@ -0,0 +1,492 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using net.openstack.Core.Exceptions.Response; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Extends with detailed information about a server. + /// + /// + /// Get Server Details (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + public class Server : SimpleServer + { + private SimpleServerImage _image; + + /// + /// Gets the disk configuration used for creating, rebuilding, or resizing the server. + /// If the value was not explicitly specified in the create, rebuild, or resize request, + /// the server inherits the value from the image it was created from. + /// + /// + /// This property is defined by the Rackspace-specific Disk Configuration Extension to the OpenStack Compute API. + /// + /// Disk Configuration Extension (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + [JsonProperty("OS-DCF:diskConfig")] + public DiskConfiguration DiskConfig { get; private set; } + + /// + /// Gets the power state for the server. + /// + /// + /// This property is defined by the Rackspace-specific Extended Status Extension to the OpenStack Compute API. + /// + /// OS-EXT-STS:power_state (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + [JsonProperty("OS-EXT-STS:power_state")] + public PowerState PowerState { get; private set; } + + /// + /// Gets the task state for the server. + /// + /// + /// This property is defined by the Rackspace-specific Extended Status Extension to the OpenStack Compute API. + /// + /// OS-EXT-STS:task_state (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + [JsonProperty("OS-EXT-STS:task_state")] + public TaskState TaskState { get; private set; } + + /// + /// Gets the virtual machine (VM) state for the server. + /// + /// + /// This property is defined by the Rackspace-specific Extended Status Extension to the OpenStack Compute API. + /// + /// OS-EXT-STS:vm_state (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + [JsonProperty("OS-EXT-STS:vm_state")] + public VirtualMachineState VMState { get; private set; } + + /// + /// Gets the public IP version 4 access address. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("accessIPv4")] + public string AccessIPv4 { get; private set; } + + /// + /// Gets the public IP version 6 access address. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("accessIPv6")] + public string AccessIPv6 { get; private set; } + + /// + /// Gets the user ID for the server. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("user_id")] + public string UserId { get; private set; } + + /// + /// Gets basic information about the image the server was created from. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("image")] + public SimpleServerImage Image + { + get + { + // this is handled in the getter because the Provider/Region/Identity + // properties of the current instance might not be set at the point + // this property is set + if (_image != null) + { + _image.Provider = Provider; + _image.Region = Region; + _image.Identity = Identity; + } + + return _image; + } + + private set + { + _image = value; + } + } + + /// + /// Gets the server status. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("status")] + public ServerState Status + { + get; + private set; + } + + /// + /// Gets basic information about the flavor for the server. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("flavor")] + public Flavor Flavor { get; private set; } + + /// + /// Gets the public and private IP addresses for the server. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("addresses")] + public ServerAddresses Addresses { get; private set; } + + /// + /// Gets the time stamp for the creation date. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("created")] + public DateTimeOffset Created { get; private set; } + + /// + /// Gets the host ID for the server. + /// + /// + /// The compute provisioning algorithm has an anti-affinity property that attempts + /// to spread customer VMs across hosts. Under certain situations, VMs from the + /// same customer might be placed on the same host. The Host ID represents the host + /// your server runs on and can be used to determine this scenario if it is relevant + /// to your application. + /// + /// is unique per account and is not globally unique. + /// + [JsonProperty("hostId")] + public string HostId { get; private set; } + + /// + /// Gets the build completion progress, as a percentage. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + /// A percentage from 0 to 100 (inclusive) representing the build completion progress. + [JsonProperty("progress")] + public int Progress { get; private set; } + + /// + /// Gets the tenant ID of the server. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + /// + [JsonProperty("tenant_id")] + public string TenantId { get; private set; } + + /// + /// Gets the time stamp for the last update. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty("updated")] + public DateTimeOffset Updated { get; private set; } + + /// + protected override void UpdateThis(ServerBase server) + { + if (server == null) + throw new ArgumentNullException("server"); + + base.UpdateThis(server); + + var details = server as Server; + + if (details == null) + return; + + DiskConfig = details.DiskConfig; + PowerState = details.PowerState; + TaskState = details.TaskState; + VMState = details.VMState; + AccessIPv4 = details.AccessIPv4; + AccessIPv6 = details.AccessIPv6; + UserId = details.UserId; + Image = details.Image; + Status = details.Status; + Flavor = details.Flavor; + Addresses = details.Addresses; + Created = details.Created; + HostId = details.HostId; + Progress = details.Progress; + TenantId = details.TenantId; + Updated = details.Updated; + } + + /// + /// Lists the volume attachments for the server. + /// + /// A collection of objects describing the volumes attached to the server. + /// If the REST API request failed. + /// + /// List Volume Attachments (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + public IEnumerable GetVolumes() + { + return Provider.ListServerVolumes(Id, Region, Identity); + } + + /// + /// Gets the metadata associated with the server. + /// + /// A object containing the metadata associated with the server. + /// If the REST API request failed. + /// + /// List Metadata (OpenStack Compute API v2 and Extensions Reference) + public Metadata GetMetadata() + { + return Provider.ListServerMetadata(Id, Region, Identity); + } + + /// + /// Sets the metadata associated with the server, replacing any existing metadata. + /// + /// The metadata to associate with the server. + /// if the metadata for the server was successfully updated; otherwise, . + /// If is . + /// If contains any values with empty keys. + /// If the REST API request failed. + /// + /// Set Metadata (OpenStack Compute API v2 and Extensions Reference) + public bool SetMetadata(Metadata metadata) + { + return Provider.SetServerMetadata(Id, metadata, Region, Identity); + } + + /// + /// Updates the metadata for the server. + /// + /// + /// For each item in , if the key exists, the value is updated; otherwise, the item is added. + /// + /// The server metadata to update. + /// if the metadata for the server was successfully updated; otherwise, . + /// If is . + /// If contains any values with empty keys. + /// If the REST API request failed. + /// + /// Update Metadata (OpenStack Compute API v2 and Extensions Reference) + public bool AddMetadata(Metadata metadata) + { + return Provider.UpdateServerMetadata(Id, metadata, Region, Identity); + } + + /// + /// Adds or updates the value for the specified metadata item. + /// + /// The metadata key. + /// The new value for the metadata item. + /// if the metadata for the server was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// If the REST API request failed. + /// + /// Set Metadata Item (OpenStack Compute API v2 and Extensions Reference) + public bool AddMetadata(string key, string value) + { + return Provider.SetServerMetadataItem(Id, key, value, Region, Identity); + } + + /// + /// Updates the metadata for the server. + /// + /// + /// For each item in , if the key exists, the value is updated; otherwise, the item is added. + /// + /// The server metadata to update. + /// if the metadata for the server was successfully updated; otherwise, . + /// If is . + /// If contains any values with empty keys. + /// If the REST API request failed. + /// + /// Update Metadata (OpenStack Compute API v2 and Extensions Reference) + public bool UpdateMetadata(Metadata metadata) + { + return Provider.UpdateServerMetadata(Id, metadata, Region, Identity); + } + + /// + /// Deletes the specified metadata items from the server. + /// + /// + /// + /// This method ignores the values in . Metadata items are + /// removed whether or not their current values match those in . + /// + /// + /// A collection of metadata items to delete. + /// if all of the metadata item were removed; otherwise, . + /// If is . + /// If contains a null or empty key. + /// If the REST API request failed. + /// + /// Delete Metadata Item (OpenStack Compute API v2 and Extensions Reference) + public bool DeleteMetadata(Metadata metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + + bool success = true; + foreach (var item in metadata) + { + if (string.IsNullOrEmpty(item.Key)) + throw new ArgumentException("metadata cannot contain any empty keys"); + + success &= DeleteMetadataItem(item.Key); + } + + return success; + } + + /// + /// Deletes the specified metadata item from the server. + /// + /// The metadata key. + /// if the metadata item was removed; otherwise, . + /// If is . + /// If is empty. + /// If the REST API request failed. + /// + /// Delete Metadata Item (OpenStack Compute API v2 and Extensions Reference) + public bool DeleteMetadataItem(string key) + { + return Provider.DeleteServerMetadataItem(Id, key, Region, Identity); + } + + /// + /// Sets the value for the specified metadata item. If the key already exists, it is updated; otherwise, a new metadata item is added. + /// + /// The metadata key. + /// The new value for the metadata item. + /// if the metadata for the server was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// If the REST API request failed. + /// + /// Set Metadata Item (OpenStack Compute API v2 and Extensions Reference) + public bool UpdateMetadataItem(string key, string value) + { + return Provider.SetServerMetadataItem(Id, key, value, Region, Identity); + } + + /// + /// Lists all networks and server addresses associated with a server. + /// + /// A object containing the list of network addresses for the server. + /// If the REST API request failed. + /// + /// List Addresses (OpenStack Compute API v2 and Extensions Reference) + public ServerAddresses ListAddresses() + { + return Provider.ListAddresses(Id, Region, Identity); + } + + /// + /// Lists addresses for the server associated with the specified network. + /// + /// The network label. This is obtained from CloudNetwork.Label. + /// A collection of containing the network addresses associated with the server on the specified network. + /// If is . + /// If is empty. + /// If the REST API request failed. + /// + /// List Addresses by Network (OpenStack Compute API v2 and Extensions Reference) + public IEnumerable ListAddressesByNetwork(string networkLabel) + { + if (networkLabel == null) + throw new ArgumentNullException("networkLabel"); + if (string.IsNullOrEmpty(networkLabel)) + throw new ArgumentException("networkLabel cannot be empty"); + + return Provider.ListAddressesByNetwork(Id, networkLabel, Region, Identity); + } + + /// + /// Creates a new snapshot image for the server at its current state. + /// + /// + /// The server snapshot process is completed asynchronously. To wait for the image + /// to be completed, you may call on the + /// returned image. + /// + /// Name of the new image. + /// The metadata to associate to the new image. + /// A object containing the details of the new image if the image creation process was successfully started; otherwise, . + /// If is . + /// If is empty. + /// If the REST API request failed. + /// Create Image (OpenStack Compute API v2 and Extensions Reference) + public ServerImage Snapshot(string imageName, Metadata metadata = null) + { + if (!Provider.CreateImage(Id, imageName, metadata, Region, Identity)) + return null; + + return Provider.ListImagesWithDetails(Id, imageName, imageType: ImageType.Snapshot) + .OrderByDescending(i => i.Created) + .FirstOrDefault(); + } + + /// + /// Marks the server for asynchronous deletion. + /// + /// + /// The server deletion operation is completed asynchronously. The + /// method may be used to block execution until the server is finally deleted. + /// + /// if the server was successfully marked for deletion; otherwise, . + /// If the REST API request failed. + /// + /// Delete Server (OpenStack Compute API v2 and Extensions Reference) + public bool Delete() + { + return Provider.DeleteServer(Id, Region, Identity); + } + + /// + /// Lists the virtual interfaces for the server. + /// + /// A collection of objects describing the virtual interfaces for the server. + /// If the REST API request failed. + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + public IEnumerable ListVirtualInterfaces() + { + return Provider.ListVirtualInterfaces(Id, Region, Identity); + } + + /// + /// Creates a virtual interface for the specified network and attaches the network to the server. + /// + /// The network ID. This is obtained from CloudNetwork.Id. + /// A object containing the details of the newly-created virtual network. + /// If is . + /// If is empty. + /// If the REST API request failed. + /// + /// Create Virtual Interface (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + public VirtualInterface CreateVirtualInterface(string networkId) + { + return Provider.CreateVirtualInterface(Id, networkId, Region, Identity); + } + + /// + /// Deletes the specified virtual interface from the server. + /// + /// The virtual interface ID. This is obtained from VirtualInterface.Id. + /// if the virtual interface was successfully removed from the server; otherwise, . + /// If is . + /// If is empty. + /// If the REST API request failed. + /// + /// Delete Virtual Interface (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + public bool DeleteVirtualInterface(string virtualInterfaceId) + { + return Provider.DeleteVirtualInterface(Id, virtualInterfaceId, Region, Identity); + } + } +} diff --git a/src/OpenStack/Core/Domain/ServerAddresses.cs b/src/OpenStack/Core/Domain/ServerAddresses.cs new file mode 100644 index 000000000..195be5fdb --- /dev/null +++ b/src/OpenStack/Core/Domain/ServerAddresses.cs @@ -0,0 +1,50 @@ +namespace net.openstack.Core.Domain +{ + using System.Collections.Generic; + using System.Net; + using Newtonsoft.Json; + + /// + /// Represents a map of network labels to collections of IP addresses. + /// + /// + /// The keys of this collection are network labels (see ), + /// and the values are collections of IP addresses. + /// + /// + [JsonDictionary] + public class ServerAddresses : Dictionary + { + /// + /// Gets the server IP addresses associated with the private network. + /// + [JsonIgnore] + public IList Private + { + get + { + IPAddressList result; + if (!TryGetValue("private", out result)) + return null; + + return result; + } + } + + /// + /// Gets the server IP addresses associated with the public network. + /// + [JsonIgnore] + public IList Public + { + get + { + IPAddressList result; + if (!TryGetValue("public", out result)) + return null; + + return result; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ServerBase.cs b/src/OpenStack/Core/Domain/ServerBase.cs new file mode 100644 index 000000000..541c15fce --- /dev/null +++ b/src/OpenStack/Core/Domain/ServerBase.cs @@ -0,0 +1,487 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Providers; +using Newtonsoft.Json; + +namespace net.openstack.Core.Domain +{ + /// + /// Provides basic information about a server. + /// + /// Servers (OpenStack Compute API v2 and Extensions Reference - API v2) + /// Servers (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class ServerBase : ProviderStateBase + { + /// + /// Gets the unique identifier for the server. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty] + public string Id { get; private set; } + + /// + /// Gets a collection of links related to the current server. + /// + /// Links and References (OpenStack Compute API v2 and Extensions Reference - API v2) + [JsonProperty] + public Link[] Links { get; private set; } + + /// + /// Updates the current instance to match the information in . + /// + /// + /// + /// This method should be overridden in derived types to ensure all properties + /// for the current instance are updated. + /// + /// + /// The updated information for the current server. + /// If is . + protected virtual void UpdateThis(ServerBase server) + { + if (server == null) + throw new ArgumentNullException("server"); + + Id = server.Id; + Links = server.Links; + } + + /// + /// Waits for the server to enter the state. + /// + /// + /// When the method returns, the current instance is updated to reflect the state + /// of the server at the end of the operation. + /// + /// + /// This is a blocking operation and will not return until the server enters the state, an error state, or the retry count is exceeded. + /// + /// + /// Number of times to poll the server's status. + /// The time to wait between polling requests for the server status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// If the REST API request failed. + public void WaitForActive(int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null) + { + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + + var details = Provider.WaitForServerActive(Id, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, Region, Identity); + UpdateThis(details); + } + + /// + /// Waits for the server to enter the state. + /// + /// + /// + /// This is a blocking operation and will not return until the server enters the state, an error state, or the retry count is exceeded. + /// + /// + /// Number of times to poll the server's status. + /// The time to wait between polling requests for the server status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// If the REST API request failed. + public void WaitForDeleted(int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null) + { + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + + Provider.WaitForServerDeleted(Id, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, Region, Identity); + } + + /// + /// Waits for the server to enter a specified state. + /// + /// + /// When the method returns, the current instance is updated to reflect the state + /// of the server at the end of the operation. + /// + /// + /// This is a blocking operation and will not return until the server enters either an expected state, an error state, or the retry count is exceeded. + /// + /// + /// The expected state. + /// The error state(s) in which to throw an exception if the server enters. + /// Number of times to poll the server's status. + /// The time to wait between polling requests for the server status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// If the method returned due to the server entering one of the . + /// If the REST API request failed. + public void WaitForState(ServerState expectedState, ServerState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null) + { + if (expectedState == null) + throw new ArgumentNullException("expectedState"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + + var details = Provider.WaitForServerState(Id, expectedState, errorStates, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, Region, Identity); + UpdateThis(details); + } + + /// + /// Waits for the server to enter any one of a set of specified states. + /// + /// + /// When the method returns, the current instance is updated to reflect the state + /// of the server at the end of the operation. + /// + /// + /// This is a blocking operation and will not return until the server enters either an expected state, an error state, or the retry count is exceeded. + /// + /// + /// The expected state(s). + /// The error state(s) in which to throw an exception if the server enters. + /// Number of times to poll the server's status. + /// The time to wait between polling requests for the server status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// If the method returned due to the server entering one of the . + /// If the REST API request failed. + public void WaitForState(ServerState[] expectedStates, ServerState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null) + { + if (expectedStates == null) + throw new ArgumentNullException("expectedStates"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (expectedStates.Length == 0) + throw new ArgumentException("expectedStates cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + + var details = Provider.WaitForServerState(Id, expectedStates, errorStates, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, Region, Identity); + UpdateThis(details); + } + + /// + /// Initiates an asynchronous soft reboot operation on the specified server. + /// + /// if the reboot operation was successfully initiated; otherwise . + /// + /// If the provider does not support soft reboot operations. + /// + /// If the REST API request failed. + /// + public bool SoftReboot() + { + return Provider.RebootServer(Id, RebootType.Soft, Region, Identity); + } + + /// + /// Initiates an asynchronous hard reboot operation on the specified server. + /// + /// if the reboot operation was successfully initiated; otherwise . + /// + /// If the provider does not support hard reboot operations. + /// + /// If the REST API request failed. + /// + public bool HardReboot() + { + return Provider.RebootServer(Id, RebootType.Hard, Region, Identity); + } + + /// + /// Initiates an asynchronous rebuild of the server. + /// + /// + /// When the method returns, the current instance is updated to reflect the state + /// of the server at the end of the operation. + /// + /// The new name for the server. If the value is , the server name is not changed. + /// The image to rebuild the server from. This is specified as an image ID (see ) or a full URL. + /// The new flavor for server. This is obtained from . + /// The new admin password for the server. + /// The new IP v4 address for the server, or to remove the configured IP v4 address for the server. If the value is , the server's IP v4 address is not updated. + /// The new IP v6 address for the server, or to remove the configured IP v6 address for the server. If the value is , the server's IP v6 address is not updated. + /// The list of metadata to associate with the server. If the value is , the metadata associated with the server is not changed during the rebuild operation. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// The path and contents of a file to inject in the target file system during the rebuild operation. If the value is , no file is injected. + /// if the rebuild operation was successfully initiated; otherwise . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is not and the of is not . + /// -or- + /// If is not and the of is not . + /// + /// + /// If the provider does not support the given . + /// + /// If the REST API request failed. + public bool Rebuild(string name, string imageId, string flavor, string adminPassword, IPAddress accessIPv4 = null, IPAddress accessIPv6 = null, Metadata metadata = null, DiskConfiguration diskConfig = null, Personality personality = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (flavor == null) + throw new ArgumentNullException("flavor"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (string.IsNullOrEmpty(flavor)) + throw new ArgumentException("flavor cannot be empty"); + if (accessIPv4 != null && !IPAddress.None.Equals(accessIPv4) && accessIPv4.AddressFamily != AddressFamily.InterNetwork) + throw new ArgumentException("The specified value for accessIPv4 is not an IP v4 address.", "accessIPv4"); + if (accessIPv6 != null && !IPAddress.None.Equals(accessIPv6) && accessIPv6.AddressFamily != AddressFamily.InterNetworkV6) + throw new ArgumentException("The specified value for accessIPv6 is not an IP v6 address.", "accessIPv6"); + if (diskConfig != null && diskConfig != DiskConfiguration.Auto && diskConfig != DiskConfiguration.Manual) + throw new NotSupportedException("The specified disk configuration is not supported."); + + var details = Provider.RebuildServer(Id, name, imageId, flavor, adminPassword, accessIPv4, accessIPv6, metadata, diskConfig, personality, Region, Identity); + + if (details == null) + return false; + + UpdateThis(details); + + return true; + } + + /// + /// Initiates an asynchronous resize of the server. A server resize is performed by + /// specifying a new for the server. + /// + /// + /// Following a resize operation, the original server is not immediately removed. After testing + /// if the resulting server is operating successfully, a call should be made to + /// to keep the resized server, or to to revert to the original server. + /// If 24 hours pass and neither of these methods is called, the server will be automatically confirmed. + /// + /// The new name for the resized server. + /// The new flavor. This is obtained from Flavor.Id. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// if the resize operation is successfully started; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given . + /// + /// If the REST API request failed. + public bool Resize(string name, string flavor, DiskConfiguration diskConfig = null) + { + if (name == null) + throw new ArgumentNullException("name"); + if (flavor == null) + throw new ArgumentNullException("flavor"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (string.IsNullOrEmpty(flavor)) + throw new ArgumentException("flavor cannot be empty"); + if (diskConfig != null && diskConfig != DiskConfiguration.Auto && diskConfig != DiskConfiguration.Manual) + throw new NotSupportedException("The specified disk configuration is not supported."); + + return Provider.ResizeServer(Id, name, flavor, diskConfig, Region, Identity); + } + + /// + /// Confirms a completed asynchronous server resize action. + /// + /// + /// If a server resize operation is not manually confirmed or reverted within 24 hours, + /// the operation is automatically confirmed. + /// + /// if the resize operation was confirmed; otherwise, . + /// If the REST API request failed. + public bool ConfirmResize() + { + return Provider.ConfirmServerResize(Id, Region, Identity); + } + + /// + /// Cancels and reverts a server resize action. + /// + /// + /// If a server resize operation is not manually confirmed or reverted within 24 hours, + /// the operation is automatically confirmed. + /// + /// if the resize operation was reverted; otherwise, . + /// If the REST API request failed. + public bool RevertResize() + { + return Provider.RevertServerResize(Id, Region, Identity); + } + + /// + /// Places the server in rescue mode. + /// + /// + /// This operation is completed asynchronously. To wait for the server to enter rescue mode, + /// call with the state . + /// + /// + /// The provider may limit the duration of rescue mode, after which the rescue image is destroyed + /// and the server attempts to reboot. Rescue mode may be explicitly exited at any time by + /// calling . + /// + /// + /// The root password assigned for use during rescue mode. + /// If the REST API request failed. + public string Rescue() + { + return Provider.RescueServer(Id, Region, Identity); + } + + /// + /// Takes the server out of rescue mode. + /// + /// + /// This operation is completed asynchronously. To wait for the server to exit rescue mode, + /// call . + /// + /// + /// The provider may limit the duration of rescue mode, after which the rescue image is destroyed + /// and the server attempts to reboot. Rescue mode may be explicitly exited at any time by + /// calling . + /// + /// + /// if the server exited rescue mode; otherwise, . + /// If the REST API request failed. + public bool UnRescue() + { + return Provider.UnRescueServer(Id, Region, Identity); + } + + /// + /// Creates a new snapshot image for a specified server at its current state. + /// + /// + /// The server snapshot process is completed asynchronously. To wait for the image + /// to be completed, you may call . + /// + /// Name of the new image. + /// The metadata to associate to the new image. + /// if the image creation process was successfully started; otherwise, . + /// If is . + /// If is empty. + /// If the REST API request failed. + public bool CreateSnapshot(string imageName, Metadata metadata = null) + { + return Provider.CreateImage(Id, imageName, metadata, Region, Identity); + } + + /// + /// Gets the detailed information for the server. + /// + /// A object containing the details for the server. + /// If the REST API request failed. + public Server GetDetails() + { + return Provider.GetDetails(Id, Region, Identity); + } + + /// + /// Lists the volume attachments for the server. + /// + /// A collection of objects describing the volumes attached to the server. + /// If the REST API request failed. + public IEnumerable ListVolumes() + { + return Provider.ListServerVolumes(Id, Region, Identity); + } + + /// + /// Attaches a volume to the server. + /// + /// The volume ID. This is obtained from . + /// The name of the device, such as /dev/xvdb. If the value is , an automatically generated device name will be used. + /// A object containing the details about the volume. + /// If is . + /// If is empty. + /// If the REST API request failed. + public ServerVolume AttachVolume(string volumeId, string storageDevice) + { + return Provider.AttachServerVolume(Id, volumeId, storageDevice, Region, Identity); + } + + /// + /// Detaches the specified volume from the server. + /// + /// The volume attachment ID. This is obtained from ServerVolume.Id. + /// if the volume was successfully detached; otherwise, . + /// If is . + /// If is empty. + /// If the REST API request failed. + public bool DetachVolume(string volumeId) + { + return Provider.DetachServerVolume(Id, volumeId, Region, Identity); + } + + /// + /// Updates the current instance to match the values in the + /// instance returned from a call to . + /// + /// If the REST API request failed. + public void Refresh() + { + var details = this.GetDetails(); + + UpdateThis(details); + } + } +} diff --git a/src/OpenStack/Core/Domain/ServerId.cs b/src/OpenStack/Core/Domain/ServerId.cs new file mode 100644 index 000000000..55479bb9e --- /dev/null +++ b/src/OpenStack/Core/Domain/ServerId.cs @@ -0,0 +1,41 @@ +namespace net.openstack.Core.Domain +{ + using System; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a server. + /// + /// + /// + /// + [JsonConverter(typeof(ServerId.Converter))] + public sealed class ServerId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The server identifier value. + /// If is . + /// If is empty. + public ServerId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ServerId FromValue(string id) + { + return new ServerId(id); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ServerImage.cs b/src/OpenStack/Core/Domain/ServerImage.cs new file mode 100644 index 000000000..3c6afc163 --- /dev/null +++ b/src/OpenStack/Core/Domain/ServerImage.cs @@ -0,0 +1,312 @@ +namespace net.openstack.Core.Domain +{ + using System; + using net.openstack.Core.Exceptions.Response; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Extends with detailed information about an image. + /// + /// + /// + /// Get Image Details (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + public class ServerImage : SimpleServerImage + { + /// + /// This is the backing field for the property. + /// + private SimpleServer _server; + + /// + /// Gets the default disk configuration used when creating, rebuilding, or resizing servers + /// with the image. For images created from servers, the value is inherited from the server. + /// + /// + /// This property is defined by the Rackspace-specific Disk Configuration Extension to the OpenStack Compute API. + /// + /// Disk Configuration Extension (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + [JsonProperty("OS-DCF:diskConfig")] + public DiskConfiguration DiskConfig { get; private set; } + + /// + /// Gets the "status" property of the image. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("status")] + public ImageState Status + { + get; + private set; + } + + /// + /// Gets the "created" property of the image. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("created")] + public DateTimeOffset Created { get; private set; } + + /// + /// Gets the image completion progress, as a percentage. + /// The value of this property is not defined. Do not use. + /// + /// A percentage from 0 to 100 (inclusive) representing the image completion progress. + [JsonProperty("progress")] + public int Progress { get; private set; } + + /// + /// Gets the "updated" property of the image. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("updated")] + public DateTimeOffset Updated { get; private set; } + + /// + /// Gets the minimum disk requirements needed to create a server with the image. + /// The value of this property is not defined. Do not use. + /// + /// List Images (OpenStack Compute API v2 and Extensions Reference) + [JsonProperty("minDisk")] + public int MinDisk { get; private set; } + + /// + /// Gets the "server" property of the image. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("server")] + public SimpleServer Server + { + get + { + // this is handled in the getter because the Provider/Region/Identity + // properties of the current instance might not be set at the point + // this property is set + if (_server != null) + { + _server.Provider = Provider; + _server.Region = Region; + _server.Identity = Identity; + } + + return _server; + } + + private set + { + _server = value; + } + } + + /// + /// Gets the minimum RAM requirements needed to create a server with the image. + /// The value of this property is not defined. Do not use. + /// + /// List Images (OpenStack Compute API v2 and Extensions Reference) + [JsonProperty("minRam")] + public int MinRAM { get; private set; } + + /// + protected override void UpdateThis(SimpleServerImage serverImage) + { + if (serverImage == null) + throw new ArgumentNullException("serverImage"); + + base.UpdateThis(serverImage); + + var details = serverImage as ServerImage; + + if (details == null) + return; + + DiskConfig = details.DiskConfig; + Status = details.Status; + Created = details.Created; + Progress = details.Progress; + Updated = details.Updated; + MinDisk = details.MinDisk; + MinRAM = details.MinRAM; + } + + /// + /// Gets the metadata associated with the specified image. + /// + /// A object containing the metadata associated with the image. + /// If the REST API request failed. + /// + /// List Metadata (OpenStack Compute API v2 and Extensions Reference) + public Metadata GetMetadata() + { + return Provider.ListImageMetadata(Id, Region, Identity); + } + + /// + /// Sets the metadata associated with the specified image, replacing any existing metadata. + /// + /// The metadata to associate with the image. + /// if the metadata for the image was successfully updated; otherwise, . + /// If is . + /// If contains any values with empty keys. + /// If the REST API request failed. + /// + /// Set Metadata (OpenStack Compute API v2 and Extensions Reference) + public bool SetMetadata(Metadata metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + + return Provider.SetImageMetadata(Id, metadata, Region, Identity); + } + + /// + /// Updates the metadata for the specified image. + /// + /// + /// For each item in , if the key exists, the value is updated; otherwise, the item is added. + /// + /// The image metadata to update. + /// if the metadata for the image was successfully updated; otherwise, . + /// If is . + /// If contains any values with empty keys. + /// If the REST API request failed. + /// + /// Update Metadata (OpenStack Compute API v2 and Extensions Reference) + public bool AddMetadata(Metadata metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + + return Provider.UpdateImageMetadata(Id, metadata, Region, Identity); + } + + /// + /// Sets the value for the specified metadata item. If the key already exists, it is updated; otherwise, a new metadata item is added. + /// + /// The metadata key. + /// The new value for the metadata item. + /// if the metadata for the image was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// If the REST API request failed. + /// + /// Set Metadata Item (OpenStack Compute API v2 and Extensions Reference) + public bool AddMetadata(string key, string value) + { + if (key == null) + throw new ArgumentNullException("key"); + if (value == null) + throw new ArgumentNullException("value"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + + return Provider.SetImageMetadataItem(Id, key, value, Region, Identity); + } + + /// + /// Updates the metadata for the specified image. + /// + /// + /// For each item in , if the key exists, the value is updated; otherwise, the item is added. + /// + /// The image metadata to update. + /// if the metadata for the image was successfully updated; otherwise, . + /// If is . + /// If contains any values with empty keys. + /// If the REST API request failed. + /// + /// Update Metadata (OpenStack Compute API v2 and Extensions Reference) + public bool UpdateMetadata(Metadata metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + + return Provider.UpdateImageMetadata(Id, metadata, Region, Identity); + } + + /// + /// Deletes the specified metadata items from the image. + /// + /// + /// + /// This method ignores the values in . Metadata items are + /// removed whether or not their current values match those in . + /// + /// + /// A collection of metadata items to delete. + /// if all of the metadata item were removed; otherwise, . + /// If is . + /// If contains a null or empty key. + /// If the REST API request failed. + /// + /// Delete Metadata Item (OpenStack Compute API v2 and Extensions Reference) + public bool DeleteMetadata(Metadata metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + + bool success = true; + foreach (var item in metadata) + { + if (string.IsNullOrEmpty(item.Key)) + throw new ArgumentException("metadata cannot contain any empty keys"); + + success &= DeleteMetadataItem(item.Key); + } + + return success; + } + + /// + /// Deletes the specified metadata item from the image. + /// + /// The metadata key. + /// if the metadata item was removed; otherwise, . + /// If is . + /// If is empty. + /// If the REST API request failed. + /// + /// Delete Metadata Item (OpenStack Compute API v2 and Extensions Reference) + public bool DeleteMetadataItem(string key) + { + if (key == null) + throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + + return Provider.DeleteImageMetadataItem(Id, key, Region, Identity); + } + + /// + /// Sets the value for the specified metadata item. If the key already exists, it is updated; otherwise, a new metadata item is added. + /// + /// The metadata key. + /// The new value for the metadata item. + /// if the metadata for the image was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// If the REST API request failed. + /// + /// Set Metadata Item (OpenStack Compute API v2 and Extensions Reference) + public bool UpdateMetadataItem(string key, string value) + { + if (key == null) + throw new ArgumentNullException("key"); + if (value == null) + throw new ArgumentNullException("value"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + + return Provider.SetImageMetadataItem(Id, key, value, Region, Identity); + } + } +} diff --git a/src/OpenStack/Core/Domain/ServerState.cs b/src/OpenStack/Core/Domain/ServerState.cs new file mode 100644 index 000000000..bac655313 --- /dev/null +++ b/src/OpenStack/Core/Domain/ServerState.cs @@ -0,0 +1,309 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents the state of a compute server. + /// + /// + /// This class functions as a strongly-typed enumeration of known server states, + /// with added support for unknown states returned by a server extension. + /// + /// + [JsonConverter(typeof(ServerState.Converter))] + public sealed class ServerState : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly ServerState _active = FromName("ACTIVE"); + private static readonly ServerState _build = FromName("BUILD"); + private static readonly ServerState _deleted = FromName("DELETED"); + private static readonly ServerState _error = FromName("ERROR"); + private static readonly ServerState _hardReboot = FromName("HARD_REBOOT"); + private static readonly ServerState _migrating = FromName("MIGRATING"); + private static readonly ServerState _password = FromName("PASSWORD"); + private static readonly ServerState _reboot = FromName("REBOOT"); + private static readonly ServerState _rebuild = FromName("REBUILD"); + private static readonly ServerState _rescue = FromName("RESCUE"); + private static readonly ServerState _resize = FromName("RESIZE"); + private static readonly ServerState _revertResize = FromName("REVERT_RESIZE"); + private static readonly ServerState _suspended = FromName("SUSPENDED"); + private static readonly ServerState _unknown = FromName("UNKNOWN"); + private static readonly ServerState _verifyResize = FromName("VERIFY_RESIZE"); + private static readonly ServerState _prepRescue = FromName("PREP_RESCUE"); + private static readonly ServerState _prepUnrescue = FromName("PREP_UNRESCUE"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private ServerState(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static ServerState FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new ServerState(i)); + } + + /// + /// Gets a representing a server which is active and ready to use. + /// + public static ServerState Active + { + get + { + return _active; + } + } + + /// + /// Gets a representing a server which is currently being built. + /// + public static ServerState Build + { + get + { + return _build; + } + } + + /// + /// Gets a representing a server which has been deleted. + /// + /// + /// By default, the operation does not return + /// servers which have been deleted. To list deleted servers, call + /// specifying the changesSince + /// parameter. + /// + public static ServerState Deleted + { + get + { + return _deleted; + } + } + + /// + /// Gets a representing a server which failed to perform + /// an operation and is now in an error state. + /// + public static ServerState Error + { + get + { + return _error; + } + } + + /// + /// Gets a representing a server currently performing a hard + /// reboot. When the reboot operation completes, the server will be in the + /// state. + /// + /// + /// + public static ServerState HardReboot + { + get + { + return _hardReboot; + } + } + + /// + /// Gets a representing a server which is currently being moved + /// from one physical node to another. + /// + /// + /// Server migration is a Rackspace-specific extension. + /// + public static ServerState Migrating + { + get + { + return _migrating; + } + } + + /// + /// Gets a representing the password for the server is being changed. + /// + /// + public static ServerState Password + { + get + { + return _password; + } + } + + /// + /// Gets a representing a server currently performing a soft + /// reboot. When the reboot operation completes, the server will be in the + /// state. + /// + /// + /// + public static ServerState Reboot + { + get + { + return _reboot; + } + } + + /// + /// Gets a representing a server currently being rebuilt. + /// When the rebuild operation completes, the server will be in the + /// state if the rebuild was successful; otherwise, it will be in the state + /// if the rebuild operation failed. + /// + /// + /// + public static ServerState Rebuild + { + get + { + return _rebuild; + } + } + + /// + /// Gets a representing a server currently in rescue mode. + /// + /// + /// + public static ServerState Rescue + { + get + { + return _rescue; + } + } + + /// + /// Gets a representing a server currently executing a resize action. + /// When the resize operation completes, the server will be in the + /// state if the resize was successful; otherwise, it will be in the state + /// if the resize operation failed. + /// + /// + /// + public static ServerState Resize + { + get + { + return _resize; + } + } + + /// + /// Gets a representing a server currently executing a revert resize action. + /// + /// + /// + public static ServerState RevertResize + { + get + { + return _revertResize; + } + } + + /// + /// Gets a for a server that is currently inactive, either by request or necessity. + /// + public static ServerState Suspended + { + get + { + return _suspended; + } + } + + /// + /// Gets a for a server that is currently in an unknown state. + /// + public static ServerState Unknown + { + get + { + return _unknown; + } + } + + /// + /// Gets a representing a server which completed a resize operation + /// and is now waiting for the operation to be confirmed or reverted. + /// + /// + /// + /// + /// + public static ServerState VerifyResize + { + get + { + return _verifyResize; + } + } + + /// + /// Gets a representing a server currently executing a rescue action. + /// + /// + /// + public static ServerState PrepRescue + { + get + { + return _prepRescue; + } + } + + /// + /// Gets a representing a server currently executing an un-rescue action. + /// + /// + /// + public static ServerState PrepUnrescue + { + get + { + return _prepUnrescue; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ServerState FromName(string name) + { + return ServerState.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/ServerVolume.cs b/src/OpenStack/Core/Domain/ServerVolume.cs new file mode 100644 index 000000000..5eb9da3c3 --- /dev/null +++ b/src/OpenStack/Core/Domain/ServerVolume.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Core.Domain +{ + using Newtonsoft.Json; + + /// + /// This models the JSON description of a volume attachment. + /// + /// + /// Volume attachments are a Rackspace-specific extension to the OpenStack Compute Service. + /// + /// List Volume Attachments (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + public class ServerVolume : ExtensibleJsonObject + { + /// + /// Gets the "device" property associated with the volume attachment. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("device")] + public string Device { get; private set; } + + /// + /// Gets the "serverId" property associated with the volume attachment. + /// The value of this property is not defined. Do not use. + /// + /// + [JsonProperty("serverId")] + public string ServerId { get; private set; } + + /// + /// Gets the unique identifier for the volume attachment. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the "volumeId" property associated with the volume attachment. + /// The value of this property is not defined. Do not use. + /// + /// + [JsonProperty("volumeId")] + public string VolumeId { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/ServiceCatalog.cs b/src/OpenStack/Core/Domain/ServiceCatalog.cs new file mode 100644 index 000000000..38bb2ee64 --- /dev/null +++ b/src/OpenStack/Core/Domain/ServiceCatalog.cs @@ -0,0 +1,64 @@ +namespace net.openstack.Core.Domain +{ + using System.Diagnostics; + using Newtonsoft.Json; + + /// + /// Represents a single service provided to an authenticated user. Each service + /// has one or more providing access information for the + /// service. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + [DebuggerDisplay("{Name,nq} ({Type,nq})")] + public class ServiceCatalog : ExtensibleJsonObject + { + /// + /// Initializes a new instance of the class. + /// + /// + /// This constructor is used by the JSON deserializer. + /// + [JsonConstructor] + protected ServiceCatalog() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified name, username, and endpoints. + /// + /// The display name of the service. + /// The canonical name of the service. + /// A collection of objects describing the service endpoints. + public ServiceCatalog(string name, string type, Endpoint[] endpoints) + { + Name = name; + Type = type; + Endpoints = endpoints; + } + + /// + /// Gets the endpoints for the service. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("endpoints")] + public Endpoint[] Endpoints { get; private set; } + + /// + /// Gets the display name of the service, which may be a vendor-specific + /// product name. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the canonical name of the specification implemented by this service. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("type")] + public string Type { get; private set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Core/Domain/SimpleServer.cs b/src/OpenStack/Core/Domain/SimpleServer.cs new file mode 100644 index 000000000..d83538141 --- /dev/null +++ b/src/OpenStack/Core/Domain/SimpleServer.cs @@ -0,0 +1,38 @@ +namespace net.openstack.Core.Domain +{ + using System; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// This models the basic JSON description of a server. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class SimpleServer : ServerBase + { + /// + /// Gets the server name. + /// The value of this property is not defined by OpenStack, and may not be consistent across vendors. + /// + [JsonProperty] + public string Name { get; private set; } + + /// + protected override void UpdateThis(ServerBase server) + { + if (server == null) + throw new ArgumentNullException("server"); + + base.UpdateThis(server); + + var details = server as SimpleServer; + + if (details == null) + return; + + Name = details.Name; + } + } +} diff --git a/src/OpenStack/Core/Domain/SimpleServerImage.cs b/src/OpenStack/Core/Domain/SimpleServerImage.cs new file mode 100644 index 000000000..fba888d8d --- /dev/null +++ b/src/OpenStack/Core/Domain/SimpleServerImage.cs @@ -0,0 +1,225 @@ +namespace net.openstack.Core.Domain +{ + using System; + using net.openstack.Core.Exceptions; + using net.openstack.Core.Exceptions.Response; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Provides basic information about an image. + /// + /// Images (OpenStack Compute API v2 and Extensions Reference - API v2) + /// Images (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + public class SimpleServerImage : ProviderStateBase + { + /// + /// Gets the unique identifier for the image. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty] + public string Id { get; private set; } + + /// + /// Gets a collection of links related to the current image. + /// + /// Links and References (OpenStack Compute API v2 and Extensions Reference - API v2) + [JsonProperty] + public Link[] Links { get; private set; } + + /// + /// Gets the name of the image. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty] + public string Name { get; private set; } + + /// + /// Waits for the image to enter the state. + /// + /// + /// When the method returns, the current instance is updated to reflect the state + /// of the image at the end of the operation. + /// + /// + /// This is a blocking operation and will not return until the image enters either the + /// state, an error state, or the retry count is exceeded. + /// + /// + /// Number of times to poll the image's status. + /// The time to wait between polling requests for the image status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// If the REST API request failed. + /// + public void WaitForActive(int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null) + { + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + + var details = Provider.WaitForImageActive(Id, refreshCount, refreshDelay, progressUpdatedCallback, Region, Identity); + UpdateThis(details); + } + + /// + /// Waits for the image to enter the state or to be removed. + /// + /// + /// + /// This is a blocking operation and will not return until the image enters either the + /// state, an error state, is removed, or the retry count is exceeded. + /// + /// + /// Number of times to poll the image's status. + /// The time to wait between polling requests for the image status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// If the REST API request failed. + /// + public void WaitForDelete(int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null) + { + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + + Provider.WaitForImageDeleted(Id, refreshCount, refreshDelay, progressUpdatedCallback, Region, Identity); + } + + /// + /// Waits for the image to enter a specified state. + /// + /// + /// When the method returns, the current instance is updated to reflect the state + /// of the image at the end of the operation. + /// + /// + /// This is a blocking operation and will not return until the image enters either the expected state, an error state, or the retry count is exceeded. + /// + /// + /// The expected state. + /// The error state(s) in which to throw an exception if the image enters. + /// Number of times to poll the image's status. + /// The time to wait between polling requests for the image status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// If the method returned due to the image entering one of the . + /// If the REST API request failed. + /// + public void WaitForState(ImageState expectedState, ImageState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null) + { + if (expectedState == null) + throw new ArgumentNullException("expectedState"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + + var details = Provider.WaitForImageState(Id, expectedState, errorStates, refreshCount, refreshDelay, progressUpdatedCallback, Region, Identity); + UpdateThis(details); + } + + /// + /// Waits for the image to enter any one of a set of specified states. + /// + /// + /// When the method returns, the current instance is updated to reflect the state + /// of the image at the end of the operation. + /// + /// + /// This is a blocking operation and will not return until the image enters either an expected state, an error state, or the retry count is exceeded. + /// + /// + /// The expected state(s). + /// The error state(s) in which to throw an exception if the image enters. + /// Number of times to poll the image's status. + /// The time to wait between polling requests for the image status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// If the method returned due to the image entering one of the . + /// If the REST API request failed. + /// + public void WaitForState(ImageState[] expectedStates, ImageState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null) + { + if (expectedStates == null) + throw new ArgumentNullException("expectedStates"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (expectedStates.Length == 0) + throw new ArgumentException("expectedStates cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + + var details = Provider.WaitForImageState(Id, expectedStates, errorStates, refreshCount, refreshDelay, progressUpdatedCallback, Region, Identity); + UpdateThis(details); + } + + /// + /// Updates the current instance to match the information in . + /// + /// + /// + /// This method should be overridden in derived types to ensure all properties + /// for the current instance are updated. + /// + /// + /// The updated information for the current image. + /// If is . + protected virtual void UpdateThis(SimpleServerImage serverImage) + { + if (serverImage == null) + throw new ArgumentNullException("serverImage"); + + Id = serverImage.Id; + Links = serverImage.Links; + Name = serverImage.Name; + } + + /// + /// Deletes the specified image. + /// + /// if the image was successfully deleted; otherwise, . + /// If the REST API request failed. + /// + /// Delete Image (OpenStack Compute API v2 and Extensions Reference) + public bool Delete() + { + return Provider.DeleteImage(Id, Region, Identity); + } + } +} diff --git a/src/OpenStack/Core/Domain/Snapshot.cs b/src/OpenStack/Core/Domain/Snapshot.cs new file mode 100644 index 000000000..1bacf9db3 --- /dev/null +++ b/src/OpenStack/Core/Domain/Snapshot.cs @@ -0,0 +1,69 @@ +namespace net.openstack.Core.Domain +{ + using System; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// This models the basic JSON description of a snapshot. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Snapshot : ExtensibleJsonObject + { + /// + /// Gets the unique identifier for the snapshot. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the name of the snapshot. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("display_name")] + public string DisplayName { get; private set; } + + /// + /// Gets the description of the snapshot. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("display_description")] + public string DisplayDescription { get; private set; } + + /// + /// Gets the ID of the volume this snapshot was taken from. + /// The value of this property is not defined. Do not use. + /// + /// + [JsonProperty("volume_id")] + public string VolumeId { get; private set; } + + /// + /// Gets the status of the snapshot. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("status")] + public SnapshotState Status + { + get; + private set; + } + + /// + /// Gets the "size" property of the snapshot. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("size")] + public string Size { get; private set; } + + /// + /// Gets the "created_at" property of the snapshot. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("created_at")] + public DateTimeOffset CreatedAt { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/SnapshotState.cs b/src/OpenStack/Core/Domain/SnapshotState.cs new file mode 100644 index 000000000..e0ba9fd82 --- /dev/null +++ b/src/OpenStack/Core/Domain/SnapshotState.cs @@ -0,0 +1,121 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using Newtonsoft.Json; + + /// + /// Represents the state of a block storage snapshot. + /// + /// + /// This class functions as a strongly-typed enumeration of known snapshot states, + /// with added support for unknown states returned by a server extension. + /// + /// + [JsonConverter(typeof(SnapshotState.Converter))] + public sealed class SnapshotState : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly SnapshotState _creating = FromName("creating"); + private static readonly SnapshotState _available = FromName("available"); + private static readonly SnapshotState _deleting = FromName("deleting"); + private static readonly SnapshotState _error = FromName("error"); + private static readonly SnapshotState _errorDeleting = FromName("error_deleting"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private SnapshotState(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static SnapshotState FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new SnapshotState(i)); + } + + /// + /// Gets a indicating the snapshot is being created. + /// + public static SnapshotState Creating + { + get + { + return _creating; + } + } + + /// + /// Gets a indicating the snapshot is ready to be attached to an instance. + /// + public static SnapshotState Available + { + get + { + return _available; + } + } + + /// + /// Gets a indicating the snapshot is being deleted. + /// + public static SnapshotState Deleting + { + get + { + return _deleting; + } + } + + /// + /// Gets a indicating an error occurred during snapshot creation. + /// + public static SnapshotState Error + { + get + { + return _error; + } + } + + /// + /// Gets a indicating an error occurred during snapshot deletion. + /// + public static SnapshotState ErrorDeleting + { + get + { + return _errorDeleting; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override SnapshotState FromName(string name) + { + return SnapshotState.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Status.cs b/src/OpenStack/Core/Domain/Status.cs new file mode 100644 index 000000000..5b224448d --- /dev/null +++ b/src/OpenStack/Core/Domain/Status.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Core.Domain +{ + using System; + + /// + /// Represents the status of an operation with a status code and description + /// of the status. + /// + /// + [Serializable] + public class Status + { + /// + /// Gets the status code. + /// + public int Code { get; private set; } + + /// + /// Gets the description of the status. + /// + public string Description { get; private set; } + + /// + /// Initializes a new instance of the class with the specified + /// status code and description. + /// + /// The status code. + /// The description of the status. + /// If is . + /// If is empty. + public Status(int code, string description) + { + if (description == null) + throw new ArgumentNullException("description"); + if (string.IsNullOrEmpty(description)) + throw new ArgumentException("description cannot be empty"); + + Code = code; + Description = description; + } + } +} diff --git a/src/OpenStack/Core/Domain/TaskState.cs b/src/OpenStack/Core/Domain/TaskState.cs new file mode 100644 index 000000000..1af556e3f --- /dev/null +++ b/src/OpenStack/Core/Domain/TaskState.cs @@ -0,0 +1,461 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using Newtonsoft.Json; + + /// + /// Represents the task status of a server. + /// + /// + /// This class functions as a strongly-typed enumeration of known task states, + /// with added support for unknown states returned by a server extension. + /// + /// + /// This property is defined by the Rackspace-specific Extended Status Extension + /// to the OpenStack Compute API. The API does not regulate the status values, + /// so it is possible that values can be added, removed, or renamed. + /// + /// + /// + /// OS-EXT-STS:task_state (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonConverter(typeof(TaskState.Converter))] + public sealed class TaskState : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly TaskState _blockDeviceMapping = FromName("block_device_mapping"); + private static readonly TaskState _deleting = FromName("deleting"); + private static readonly TaskState _imageSnapshot = FromName("image_snapshot"); + private static readonly TaskState _imageBackup = FromName("image_backup"); + private static readonly TaskState _imagePendingUpload = FromName("image_pending_upload"); + private static readonly TaskState _imageUploading = FromName("image_uploading"); + private static readonly TaskState _migrating = FromName("migrating"); + private static readonly TaskState _networking = FromName("networking"); + private static readonly TaskState _pausing = FromName("pausing"); + private static readonly TaskState _poweringOff = FromName("powering_off"); + private static readonly TaskState _poweringOn = FromName("powering_on"); + private static readonly TaskState _rebooting = FromName("rebooting"); + private static readonly TaskState _rebootingHard = FromName("rebooting_hard"); + private static readonly TaskState _rebuilding = FromName("rebuilding"); + private static readonly TaskState _rebuildBlockDeviceMapping = FromName("rebuild_block_device_mapping"); + private static readonly TaskState _rebuildSpawning = FromName("rebuild_spawning"); + private static readonly TaskState _rescuing = FromName("rescuing"); + private static readonly TaskState _resizeConfirming = FromName("resize_confirming"); + private static readonly TaskState _resizeFinish = FromName("resize_finish"); + private static readonly TaskState _resizeMigrated = FromName("resize_migrated"); + private static readonly TaskState _resizeMigrating = FromName("resize_migrating"); + private static readonly TaskState _resizePrep = FromName("resize_prep"); + private static readonly TaskState _resizeReverting = FromName("resize_reverting"); + private static readonly TaskState _resuming = FromName("resuming"); + private static readonly TaskState _scheduling = FromName("scheduling"); + private static readonly TaskState _spawning = FromName("spawning"); + private static readonly TaskState _starting = FromName("starting"); + private static readonly TaskState _stopping = FromName("stopping"); + private static readonly TaskState _suspending = FromName("suspending"); + private static readonly TaskState _unpausing = FromName("unpausing"); + private static readonly TaskState _unrescuing = FromName("unrescuing"); + private static readonly TaskState _updatingPassword = FromName("updating_password"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private TaskState(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static TaskState FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new TaskState(i)); + } + + /// + /// Gets a instance representing description. + /// + public static TaskState BlockDeviceMapping + { + get + { + return _blockDeviceMapping; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Deleting + { + get + { + return _deleting; + } + } + + /// + /// Gets a instance indicating that a create image action has been + /// initiated and that the hypervisor is creating the snapshot. Any operations that would modify + /// data on the server's virtual hard disk should be avoided during this time. + /// + public static TaskState ImageSnapshot + { + get + { + return _imageSnapshot; + } + } + + /// + /// Gets a instance representing description. + /// + [Obsolete("This task state is no longer used.")] + public static TaskState ImageBackup + { + get + { + return _imageBackup; + } + } + + /// + /// Gets a instance indicating that the hypervisor has completed taking a + /// snapshot of the server. At this point, the hypervisor is packaging the snapshot and preparing + /// it for upload to the image store. + /// + /// + public static TaskState ImagePendingUpload + { + get + { + return _imagePendingUpload; + } + } + + /// + /// Gets a instance indicating that the hypervisor is currently uploading + /// a packaged snapshot of the server to the image store. + /// + /// + public static TaskState ImageUploading + { + get + { + return _imageUploading; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Migrating + { + get + { + return _migrating; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Networking + { + get + { + return _networking; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Pausing + { + get + { + return _pausing; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState PoweringOff + { + get + { + return _poweringOff; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState PoweringOn + { + get + { + return _poweringOn; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Rebooting + { + get + { + return _rebooting; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState RebootingHard + { + get + { + return _rebootingHard; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Rebuilding + { + get + { + return _rebuilding; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState RebuildBlockDeviceMapping + { + get + { + return _rebuildBlockDeviceMapping; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState RebuildSpawning + { + get + { + return _rebuildSpawning; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Rescuing + { + get + { + return _rescuing; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState ResizeConfirming + { + get + { + return _resizeConfirming; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState ResizeFinish + { + get + { + return _resizeFinish; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState ResizeMigrated + { + get + { + return _resizeMigrated; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState ResizeMigrating + { + get + { + return _resizeMigrating; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState ResizePrep + { + get + { + return _resizePrep; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState ResizeReverting + { + get + { + return _resizeReverting; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Resuming + { + get + { + return _resuming; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Scheduling + { + get + { + return _scheduling; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Spawning + { + get + { + return _spawning; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Starting + { + get + { + return _starting; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Stopping + { + get + { + return _stopping; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Suspending + { + get + { + return _suspending; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Unpausing + { + get + { + return _unpausing; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState Unrescuing + { + get + { + return _unrescuing; + } + } + + /// + /// Gets a instance representing description. + /// + public static TaskState UpdatingPassword + { + get + { + return _updatingPassword; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override TaskState FromName(string name) + { + return TaskState.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Tenant.cs b/src/OpenStack/Core/Domain/Tenant.cs new file mode 100644 index 000000000..9cfc81e0c --- /dev/null +++ b/src/OpenStack/Core/Domain/Tenant.cs @@ -0,0 +1,28 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// This models the basic JSON description of a tenant. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Tenant : ExtensibleJsonObject + { + /// + /// Gets the unique identifier for the tenant. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the "name" property for the tenant. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("name")] + public string Name { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/User.cs b/src/OpenStack/Core/Domain/User.cs new file mode 100644 index 000000000..5dceddb73 --- /dev/null +++ b/src/OpenStack/Core/Domain/User.cs @@ -0,0 +1,94 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents a user account. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class User : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("RAX-AUTH:domainId", DefaultValueHandling = DefaultValueHandling.Ignore)] + private ProjectId _domainId; +#pragma warning restore 649 + + /// + /// Gets or sets the default region of the user. + /// The value of this property is not defined. Do not use. + /// + /// + /// Changes to this property are not automatically saved on the server. To apply the + /// changes, call after setting this property. + /// + /// + /// This property is a Rackspace-specific extension to the OpenStack Identity Service. + /// + /// + [JsonProperty("RAX-AUTH:defaultRegion")] + public string DefaultRegion { get; set; } + + /// + /// Gets the domain ID of the user. + /// + /// + /// + /// This property is a Rackspace-specific extension to the OpenStack Identity Service. + /// + /// + /// + public ProjectId DomainId + { + get + { + return _domainId; + } + } + + /// + /// Gets the unique identifier for the user. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Include)] + public string Id { get; private set; } + + /// + /// Gets or sets the "username" property of the user. + /// The value of this property is not defined. Do not use. + /// + /// + /// Changes to this property are not automatically saved on the server. To apply the + /// changes, call after setting this property. + /// + [JsonProperty("username")] + public string Username { get; set; } + + /// + /// Gets or sets the "email" property of the user. + /// The value of this property is not defined. Do not use. + /// + /// + /// Changes to this property are not automatically saved on the server. To apply the + /// changes, call after setting this property. + /// + [JsonProperty("email")] + public string Email { get; set; } + + /// + /// Gets or sets the "enabled" property of the user. + /// The value of this property is not defined. Do not use. + /// + /// + /// Changes to this property are not automatically saved on the server. To apply the + /// changes, call after setting this property. + /// + [JsonProperty("enabled")] + public bool Enabled { get; set; } + } +} diff --git a/src/OpenStack/Core/Domain/UserAccess.cs b/src/OpenStack/Core/Domain/UserAccess.cs new file mode 100644 index 000000000..3bb0f0bf8 --- /dev/null +++ b/src/OpenStack/Core/Domain/UserAccess.cs @@ -0,0 +1,65 @@ +namespace net.openstack.Core.Domain +{ + using Newtonsoft.Json; + + /// + /// Represents the response to a user authentication. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + public class UserAccess : ExtensibleJsonObject + { + /// + /// Initializes a new instance of the class. + /// + /// + /// This constructor is used by the JSON deserializer. + /// + [JsonConstructor] + protected UserAccess() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified token, user, and service catalog. + /// + /// The . + /// The . + /// List of s. + public UserAccess(IdentityToken token, UserDetails user, ServiceCatalog[] serviceCatalog) + { + Token = token; + User = user; + ServiceCatalog = serviceCatalog; + } + + /// + /// Gets the which allows providers to make authenticated + /// calls to API methods. + /// + /// + /// The specific manner in which the token is used is provider-specific. Some implementations + /// pass the token's as an HTTP header when requesting a + /// resource. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("token")] + public IdentityToken Token { get; private set; } + + /// + /// Gets the details for the authenticated user, such as the username and roles. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("user")] + public UserDetails User { get; private set; } + + /// + /// Gets the services which may be accessed by this user. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + [JsonProperty("serviceCatalog")] + public ServiceCatalog[] ServiceCatalog { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/UserCredential.cs b/src/OpenStack/Core/Domain/UserCredential.cs new file mode 100644 index 000000000..112abe99f --- /dev/null +++ b/src/OpenStack/Core/Domain/UserCredential.cs @@ -0,0 +1,50 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents a set of credentials for a user. + /// + /// + /// List Credentials (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + public class UserCredential : ExtensibleJsonObject + { + /// + /// Gets the "name" property for the credentials. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the "username" property for the credentials. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("username")] + public string Username { get; private set; } + + /// + /// Gets the "apiKey" property for the credentials. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("apiKey")] + public string APIKey { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified name, username, and API key. + /// + /// The name. + /// The username. + /// The API key. + public UserCredential(string name, string username, string apiKey) + { + Name = name; + Username = username; + APIKey = apiKey; + } + } +} diff --git a/src/OpenStack/Core/Domain/UserDetails.cs b/src/OpenStack/Core/Domain/UserDetails.cs new file mode 100644 index 000000000..2d32a18b9 --- /dev/null +++ b/src/OpenStack/Core/Domain/UserDetails.cs @@ -0,0 +1,78 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Contains additional information about an authenticated user. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UserDetails : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("RAX-AUTH:domainId", DefaultValueHandling = DefaultValueHandling.Ignore)] + private ProjectId _domainId; +#pragma warning restore 649 + + /// + /// Gets the unique identifier for the user. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the "name" property for the user. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the "roles" property for the user. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("roles")] + public Role[] Roles { get; private set; } + + /// + /// Gets the default region for the user. + /// + /// + /// Users can be assigned a default region so that, when there is a choice between + /// multiple endpoints associated with a service in the user's catalog, the endpoint + /// for the user's default region will be selected if it is available. The default + /// region is only used when a region is not explicitly specified in the API call. + /// + /// + /// This property is a Rackspace-specific extension to the OpenStack Identity Service. + /// + /// + /// Sample Authentication Request and Response (Rackspace Cloud Identity Client Developer Guide - API v2.0) + [JsonProperty("RAX-AUTH:defaultRegion")] + public string DefaultRegion { get; private set; } + + /// + /// Gets the domain ID of the user. + /// + /// + /// + /// This property is a Rackspace-specific extension to the OpenStack Identity Service. + /// + /// + /// + public ProjectId DomainId + { + get + { + return _domainId; + } + } + } +} diff --git a/src/OpenStack/Core/Domain/VirtualInterface.cs b/src/OpenStack/Core/Domain/VirtualInterface.cs new file mode 100644 index 000000000..52beb7c02 --- /dev/null +++ b/src/OpenStack/Core/Domain/VirtualInterface.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Core.Domain +{ + using System.Net.NetworkInformation; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + + /// + /// Represents the detailed configuration of a virtual network interface. + /// + /// + /// + /// Virtual network interfaces are a Rackspace-specific extension to the OpenStack Networking Service. + /// + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + public class VirtualInterface : ExtensibleJsonObject + { + /// + /// Gets the virtual interface ID. + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the network addresses associated with the virtual interface. + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + [JsonProperty("ip_addresses")] + public VirtualInterfaceAddress[] Addresses { get; private set; } + + /// + /// Gets the Media Access Control (MAC) address for the virtual interface. + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + [JsonProperty("mac_address")] + [JsonConverter(typeof(PhysicalAddressSimpleConverter))] + public PhysicalAddress MACAddress + { + get; + private set; + } + } +} diff --git a/src/OpenStack/Core/Domain/VirtualInterfaceAddress.cs b/src/OpenStack/Core/Domain/VirtualInterfaceAddress.cs new file mode 100644 index 000000000..accd54ad6 --- /dev/null +++ b/src/OpenStack/Core/Domain/VirtualInterfaceAddress.cs @@ -0,0 +1,48 @@ +namespace net.openstack.Core.Domain +{ + using System.Net; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + + /// + /// Represents the IP address of a virtual interface on a specific network. + /// + /// + /// + /// Virtual network interfaces are a Rackspace-specific extension to the OpenStack Networking Service. + /// + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + public class VirtualInterfaceAddress : ExtensibleJsonObject + { + /// + /// Gets the IP address of the virtual interface. + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + [JsonProperty("address")] + [JsonConverter(typeof(IPAddressSimpleConverter))] + public IPAddress Address + { + get; + private set; + } + + /// + /// Gets the ID of the network this virtual interface is connected to. + /// + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + [JsonProperty("network_id")] + public string NetworkId { get; private set; } + + /// + /// Gets the label of the network this virtual interface is connected to. + /// + /// + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + [JsonProperty("network_label")] + public string NetworkLabel { get; private set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Core/Domain/VirtualMachineState.cs b/src/OpenStack/Core/Domain/VirtualMachineState.cs new file mode 100644 index 000000000..6098644e4 --- /dev/null +++ b/src/OpenStack/Core/Domain/VirtualMachineState.cs @@ -0,0 +1,189 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using Newtonsoft.Json; + + /// + /// Represents the virtual machine (VM) state of a server. + /// + /// + /// This class functions as a strongly-typed enumeration of known virtual machine states, + /// with added support for unknown states returned by a server extension. + /// + /// + /// This property is defined by the Rackspace-specific Extended Status Extension + /// to the OpenStack Compute API. The API does not regulate the status values, + /// so it is possible that values can be added, removed, or renamed. + /// + /// + /// + /// OS-EXT-STS:vm_state (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonConverter(typeof(VirtualMachineState.Converter))] + public sealed class VirtualMachineState : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly VirtualMachineState _active = FromName("ACTIVE"); + private static readonly VirtualMachineState _build = FromName("BUILD"); + private static readonly VirtualMachineState _deleted = FromName("DELETED"); + private static readonly VirtualMachineState _error = FromName("ERROR"); + private static readonly VirtualMachineState _paused = FromName("PAUSED"); + private static readonly VirtualMachineState _rescued = FromName("RESCUED"); + private static readonly VirtualMachineState _resized = FromName("RESIZED"); + private static readonly VirtualMachineState _softDeleted = FromName("SOFT_DELETED"); + private static readonly VirtualMachineState _stopped = FromName("STOPPED"); + private static readonly VirtualMachineState _suspended = FromName("SUSPENDED"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private VirtualMachineState(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static VirtualMachineState FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new VirtualMachineState(i)); + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Active + { + get + { + return _active; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Build + { + get + { + return _build; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Deleted + { + get + { + return _deleted; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Error + { + get + { + return _error; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Paused + { + get + { + return _paused; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Rescued + { + get + { + return _rescued; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Resized + { + get + { + return _resized; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState SoftDeleted + { + get + { + return _softDeleted; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Stopped + { + get + { + return _stopped; + } + } + + /// + /// Gets a instance representing description. + /// + public static VirtualMachineState Suspended + { + get + { + return _suspended; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override VirtualMachineState FromName(string name) + { + return VirtualMachineState.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/Volume.cs b/src/OpenStack/Core/Domain/Volume.cs new file mode 100644 index 000000000..336a63c25 --- /dev/null +++ b/src/OpenStack/Core/Domain/Volume.cs @@ -0,0 +1,101 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents a volume in a block storage provider. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Volume : ExtensibleJsonObject + { + /// + /// Gets the unique identifier for the volume. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the "display_name" property of this volume. + /// The value of this property is not defined. Do not use. + /// + /// + /// + /// This property is a Rackspace-specific extension to the OpenStack Block Storage Service. + /// + /// + [JsonProperty("display_name")] + public string DisplayName { get; private set; } + + /// + /// Gets the "display_description" property of this volume. + /// The value of this property is not defined. Do not use. + /// + /// + /// + /// This property is a Rackspace-specific extension to the OpenStack Block Storage Service. + /// + /// + [JsonProperty("display_description")] + public string DisplayDescription { get; private set; } + + /// + /// Gets the "size" property of this volume. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("size")] + public int Size { get; private set; } + + /// + /// Gets the "volume_type" property of this volume. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("volume_type")] + public string VolumeType { get; private set; } + + /// + /// Gets the "snapshot_id" property of this volume. + /// The value of this property is not defined. Do not use. + /// + /// + [JsonProperty("snapshot_id")] + public string SnapshotId { get; private set; } + + /// + /// Gets the "attachments" property of this volume. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("attachments")] + public Dictionary[] Attachments { get; private set; } + + /// + /// Gets the "status" property of this volume. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("status")] + public VolumeState Status + { + get; + private set; + } + + /// + /// Gets the "availability_zone" property of this volume. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("availability_zone")] + public string AvailabilityZone { get; private set; } + + /// + /// Gets the "created_at" property of this volume. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("created_at")] + public DateTimeOffset CreatedAt { get; private set; } + } +} diff --git a/src/OpenStack/Core/Domain/VolumeState.cs b/src/OpenStack/Core/Domain/VolumeState.cs new file mode 100644 index 000000000..c168fa918 --- /dev/null +++ b/src/OpenStack/Core/Domain/VolumeState.cs @@ -0,0 +1,181 @@ +namespace net.openstack.Core.Domain +{ + using System; + using System.Collections.Concurrent; + using Newtonsoft.Json; + + /// + /// Represents the state of a block storage volume. + /// + /// + /// This class functions as a strongly-typed enumeration of known volume states, + /// with added support for unknown states returned by a server extension. + /// + /// + [JsonConverter(typeof(VolumeState.Converter))] + public sealed class VolumeState : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly VolumeState _creating = FromName("creating"); + private static readonly VolumeState _available = FromName("available"); + private static readonly VolumeState _attaching = FromName("attaching"); + private static readonly VolumeState _inUse = FromName("in-use"); + private static readonly VolumeState _deleting = FromName("deleting"); + private static readonly VolumeState _error = FromName("error"); + private static readonly VolumeState _errorDeleting = FromName("error_deleting"); + private static readonly VolumeState _backingUp = FromName("backing-up"); + private static readonly VolumeState _restoringBackup = FromName("restoring-backup"); + private static readonly VolumeState _errorRestoring = FromName("error_restoring"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private VolumeState(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static VolumeState FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new VolumeState(i)); + } + + /// + /// Gets a indicating the volume is being created. + /// + public static VolumeState Creating + { + get + { + return _creating; + } + } + + /// + /// Gets a indicating the volume is ready to be attached to an instance. + /// + public static VolumeState Available + { + get + { + return _available; + } + } + + /// + /// Gets a indicating the volume is attaching to an instance. + /// + public static VolumeState Attaching + { + get + { + return _attaching; + } + } + + /// + /// Gets a indicating the volume is attached to an instance. + /// + public static VolumeState InUse + { + get + { + return _inUse; + } + } + + /// + /// Gets a indicating the volume is being deleted. + /// + public static VolumeState Deleting + { + get + { + return _deleting; + } + } + + /// + /// Gets a indicating an error occurred during volume creation. + /// + public static VolumeState Error + { + get + { + return _error; + } + } + + /// + /// Gets a indicating an error occurred during volume deletion. + /// + public static VolumeState ErrorDeleting + { + get + { + return _errorDeleting; + } + } + + /// + /// Gets a indicating the volume is being backed-up. + /// + public static VolumeState BackingUp + { + get + { + return _backingUp; + } + } + + /// + /// Gets a indicating a backup is being restored to the volume. + /// + public static VolumeState RestoringBackup + { + get + { + return _restoringBackup; + } + } + + /// + /// Gets a indicating an error occurred during backup restoration to a volume. + /// + public static VolumeState ErrorRestoring + { + get + { + return _errorRestoring; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override VolumeState FromName(string name) + { + return VolumeState.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Core/Domain/VolumeType.cs b/src/OpenStack/Core/Domain/VolumeType.cs new file mode 100644 index 000000000..a6c532951 --- /dev/null +++ b/src/OpenStack/Core/Domain/VolumeType.cs @@ -0,0 +1,29 @@ +namespace net.openstack.Core.Domain +{ + using net.openstack.Core.Providers; + using Newtonsoft.Json; + + /// + /// Represents the type of a volume in the Block Storage service. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class VolumeType : ExtensibleJsonObject + { + /// + /// Gets the unique identifier for this volume type. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("id")] + public string Id { get; private set; } + + /// + /// Gets the name of the volume type. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("name")] + public string Name { get; private set; } + } +} diff --git a/src/OpenStack/Core/Exceptions/CDNNotEnabledException.cs b/src/OpenStack/Core/Exceptions/CDNNotEnabledException.cs new file mode 100644 index 000000000..000dd3603 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/CDNNotEnabledException.cs @@ -0,0 +1,60 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Providers; + +namespace net.openstack.Core.Exceptions +{ + /// + /// The exception that is thrown when an attempt is made to modify CDN properties + /// of a container which is not CDN-enabled. + /// + /// + /// + [Serializable] + public class CDNNotEnabledException : InvalidOperationException + { + /// + /// Initializes a new instance of the class. + /// + public CDNNotEnabledException() + : base("The specified container is not CDN-enabled.") + { + } + + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public CDNNotEnabledException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. + /// If the parameter is not a null reference, the current + /// exception is raised in a catch block that handles the inner exception. + public CDNNotEnabledException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected CDNNotEnabledException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/CidrFormatException.cs b/src/OpenStack/Core/Exceptions/CidrFormatException.cs new file mode 100644 index 000000000..c022b01f5 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/CidrFormatException.cs @@ -0,0 +1,45 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Validators; + +namespace net.openstack.Core.Exceptions +{ + /// + /// Represents errors that occur while validating a CIDR. + /// + /// + /// + [Serializable] + public class CidrFormatException : FormatException + { + /// + /// Initializes a new instance of the class. + /// + public CidrFormatException() + : base("The specified CIDR is not in the correct format.") + { + } + + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public CidrFormatException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected CidrFormatException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/ContainerNameException.cs b/src/OpenStack/Core/Exceptions/ContainerNameException.cs new file mode 100644 index 000000000..ebc8973f8 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/ContainerNameException.cs @@ -0,0 +1,46 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Providers; +using net.openstack.Core.Validators; + +namespace net.openstack.Core.Exceptions +{ + /// + /// Represents errors that occur while validating a container name for an . + /// + /// + /// + [Serializable] + public class ContainerNameException : ArgumentException + { + /// + /// Initializes a new instance of the class. + /// + public ContainerNameException() + : base("The specified container name is not valid.") + { + } + + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public ContainerNameException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected ContainerNameException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/ContainerNotEmptyException.cs b/src/OpenStack/Core/Exceptions/ContainerNotEmptyException.cs new file mode 100644 index 000000000..b1c6b6ffe --- /dev/null +++ b/src/OpenStack/Core/Exceptions/ContainerNotEmptyException.cs @@ -0,0 +1,61 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Providers; + +namespace net.openstack.Core.Exceptions +{ + /// + /// Thrown when an Object Storage container operation fails because the specified container was not empty. + /// + /// + /// + [Serializable] + public class ContainerNotEmptyException : InvalidOperationException + { + /// + /// Initializes a new instance of the class. + /// + public ContainerNotEmptyException() + : base("The operation failed because the specified container is not empty.") + { + } + + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public ContainerNotEmptyException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified error message and a reference to the inner exception that is + /// the cause of this exception. + /// + /// The message that describes the error. + /// + /// The exception that is the cause of the current exception. If the + /// parameter is not , the current exception is raised in a catch block that handles the + /// inner exception. + /// + public ContainerNotEmptyException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected ContainerNotEmptyException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/ImageEnteredErrorStateException.cs b/src/OpenStack/Core/Exceptions/ImageEnteredErrorStateException.cs new file mode 100644 index 000000000..6048e001c --- /dev/null +++ b/src/OpenStack/Core/Exceptions/ImageEnteredErrorStateException.cs @@ -0,0 +1,63 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Domain; + +namespace net.openstack.Core.Exceptions +{ + /// + /// The exception that is thrown when the server enters an error state during a + /// call to . + /// + /// + [Serializable] + public class ImageEnteredErrorStateException : Exception + { + [NonSerialized] + private ExceptionData _state; + + /// + /// Gets the error state the image entered. + /// + /// + public ImageState Status + { + get + { + return ImageState.FromName(_state.Status); + } + } + + /// + /// Initializes a new instance of the class + /// with the specified error state. + /// + /// The error state entered by the image. + /// If is . + public ImageEnteredErrorStateException(ImageState status) + : base(string.Format("The image entered an error state: '{0}'", status)) + { + if (status == null) + throw new ArgumentNullException("status"); + + _state.Status = status.Name; +#if !NET35 + SerializeObjectState += (ex, args) => args.AddSerializedState(_state); +#endif + } + + [Serializable] + private struct ExceptionData : ISafeSerializationData + { + public string Status + { + get; + set; + } + + void ISafeSerializationData.CompleteDeserialization(object deserialized) + { + ((ImageEnteredErrorStateException)deserialized)._state = this; + } + } + } +} diff --git a/src/OpenStack/Core/Exceptions/InvalidCloudIdentityException.cs b/src/OpenStack/Core/Exceptions/InvalidCloudIdentityException.cs new file mode 100644 index 000000000..f7ae96ccf --- /dev/null +++ b/src/OpenStack/Core/Exceptions/InvalidCloudIdentityException.cs @@ -0,0 +1,37 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Domain; + +namespace net.openstack.Core.Exceptions +{ + /// + /// The exception thrown when the instance passed + /// to a provider method is not supported by that provider. + /// + /// + [Serializable] + internal class InvalidCloudIdentityException : NotSupportedException + { + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public InvalidCloudIdentityException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected InvalidCloudIdentityException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/NamespaceDoc.cs b/src/OpenStack/Core/Exceptions/NamespaceDoc.cs new file mode 100644 index 000000000..7709ba595 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Core.Exceptions +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines general + /// (not provider-specific) exception classes for errors which may occur while + /// working with OpenStack providers. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Exceptions/NoDefaultRegionSetException.cs b/src/OpenStack/Core/Exceptions/NoDefaultRegionSetException.cs new file mode 100644 index 000000000..e64a7a499 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/NoDefaultRegionSetException.cs @@ -0,0 +1,36 @@ +using System; +using System.Runtime.Serialization; + +namespace net.openstack.Core.Exceptions +{ + /// + /// The exception that is thrown when a service endpoint could not be obtained because + /// no region was specified and no default region is available for the provider. + /// + /// + [Serializable] + public class NoDefaultRegionSetException : InvalidOperationException + { + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public NoDefaultRegionSetException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected NoDefaultRegionSetException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/ObjectNameException.cs b/src/OpenStack/Core/Exceptions/ObjectNameException.cs new file mode 100644 index 000000000..cc710db34 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/ObjectNameException.cs @@ -0,0 +1,46 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Providers; +using net.openstack.Core.Validators; + +namespace net.openstack.Core.Exceptions +{ + /// + /// Represents errors that occur while validating an object name for an . + /// + /// + /// + [Serializable] + public class ObjectNameException : ArgumentException + { + /// + /// Initializes a new instance of the class. + /// + public ObjectNameException() + : base("The specified object name is not valid.") + { + } + + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public ObjectNameException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected ObjectNameException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/BadServiceRequestException.cs b/src/OpenStack/Core/Exceptions/Response/BadServiceRequestException.cs new file mode 100644 index 000000000..457e66b68 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/BadServiceRequestException.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Represents errors with status code resulting + /// from a call to a REST API. + /// + /// + [Serializable] + public class BadServiceRequestException : ResponseException + { + /// + /// Initializes a new instance of the class with the + /// specified REST response. + /// + /// The REST response. + public BadServiceRequestException(RestResponse response) + : base("Unable to process the service request. Please try again later.", response) + { + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public BadServiceRequestException(string message, RestResponse response) + : base(message, response) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/ItemNotFoundException.cs b/src/OpenStack/Core/Exceptions/Response/ItemNotFoundException.cs new file mode 100644 index 000000000..96f7ba75b --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/ItemNotFoundException.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Represents errors with status code resulting + /// from a call to a REST API. + /// + /// + [Serializable] + public class ItemNotFoundException : ResponseException + { + /// + /// Initializes a new instance of the class with the + /// specified REST response. + /// + /// The REST response. + public ItemNotFoundException(RestResponse response) + : base("The item was not found or does not exist.", response) + { + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public ItemNotFoundException(string message, RestResponse response) + : base(message, response) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/MethodNotImplementedException.cs b/src/OpenStack/Core/Exceptions/Response/MethodNotImplementedException.cs new file mode 100644 index 000000000..01c25abab --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/MethodNotImplementedException.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Represents errors with status code resulting + /// from a call to a REST API. + /// + /// + [Serializable] + public class MethodNotImplementedException : ResponseException + { + /// + /// Initializes a new instance of the class with the + /// specified REST response. + /// + /// The REST response. + public MethodNotImplementedException(RestResponse response) + : base("The requested method is not implemented at the service.", response) + { + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public MethodNotImplementedException(string message, RestResponse response) + : base(message, response) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/NamespaceDoc.cs b/src/OpenStack/Core/Exceptions/Response/NamespaceDoc.cs new file mode 100644 index 000000000..11c8582b2 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Core.Exceptions.Response +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace contains + /// exception classes that represent errors returned by a call to a REST API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/ResponseException.cs b/src/OpenStack/Core/Exceptions/Response/ResponseException.cs new file mode 100644 index 000000000..ff4d572ae --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/ResponseException.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Defines the base class for errors resulting from a call to a REST API. + /// + /// + [Serializable] + public class ResponseException : Exception + { + [NonSerialized] + private ExceptionData _state; + + /// + /// Gets the REST containing the details + /// about this error. + /// + public RestResponse Response + { + get + { + return _state.Response; + } + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public ResponseException(string message, RestResponse response) + : base(message) + { + _state.Response = response; +#if !NET35 + SerializeObjectState += (ex, args) => args.AddSerializedState(_state); +#endif + } + + /// + public override string Message + { + get + { + if (Response != null && Response.HasJsonBody()) + { + try + { + var response = JsonConvert.DeserializeObject>(Response.RawBody); + var pair = response.FirstOrDefault(); + if (pair.Value != null && !string.IsNullOrEmpty(pair.Value.Message)) + return pair.Value.Message; + } + catch (JsonSerializationException) + { + // will fall back to base.Message + } + } + + return base.Message; + } + } + + [JsonObject(MemberSerialization.OptIn)] + private sealed class ErrorDetails + { +#pragma warning disable 649 // Field '{fieldname}' is never assigned to, and will always have its default value {0 | null} + [JsonProperty("code")] + public int Code; + + [JsonProperty("message")] + public string Message; + + [JsonProperty("details")] + public string Details; +#pragma warning restore 649 + } + + [Serializable] + private struct ExceptionData : ISafeSerializationData + { + public RestResponse Response + { + get; + set; + } + + void ISafeSerializationData.CompleteDeserialization(object deserialized) + { + ((ResponseException)deserialized)._state = this; + } + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/ServiceConflictException.cs b/src/OpenStack/Core/Exceptions/Response/ServiceConflictException.cs new file mode 100644 index 000000000..8f5146759 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/ServiceConflictException.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Represents errors with status code resulting + /// from a call to a REST API. + /// + /// + [Serializable] + public class ServiceConflictException : ResponseException + { + /// + /// Initializes a new instance of the class with the + /// specified REST response. + /// + /// The REST response. + public ServiceConflictException(RestResponse response) + : base("There was a conflict with the service. Entity may already exist.", response) + { + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public ServiceConflictException(string message, RestResponse response) + : base(message, response) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/ServiceFaultException.cs b/src/OpenStack/Core/Exceptions/Response/ServiceFaultException.cs new file mode 100644 index 000000000..7bc9fe419 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/ServiceFaultException.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Represents errors with status code resulting + /// from a call to a REST API. + /// + /// + [Serializable] + public class ServiceFaultException : ResponseException + { + /// + /// Initializes a new instance of the class with the + /// specified REST response. + /// + /// The REST response. + public ServiceFaultException(RestResponse response) + : base("There was an unhandled error at the service endpoint. Please try again later.", response) + { + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public ServiceFaultException(string message, RestResponse response) + : base(message, response) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/ServiceLimitReachedException.cs b/src/OpenStack/Core/Exceptions/Response/ServiceLimitReachedException.cs new file mode 100644 index 000000000..f11b05ee7 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/ServiceLimitReachedException.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Represents errors with status code resulting + /// from a call to a REST API. + /// + /// + [Serializable] + public class ServiceLimitReachedException : ResponseException + { + /// + /// Initializes a new instance of the class with the + /// specified REST response. + /// + /// The REST response. + public ServiceLimitReachedException(RestResponse response) + : base("The service rate limit has been reached. Either request a service limit increase or wait until the limit resets.", response) + { + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public ServiceLimitReachedException(string message, RestResponse response) + : base(message, response) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/ServiceUnavailableException.cs b/src/OpenStack/Core/Exceptions/Response/ServiceUnavailableException.cs new file mode 100644 index 000000000..1a93a48ec --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/ServiceUnavailableException.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Represents errors with status code resulting + /// from a call to a REST API. + /// + /// + [Serializable] + public class ServiceUnavailableException : ResponseException + { + /// + /// Initializes a new instance of the class with the + /// specified REST response. + /// + /// The REST response. + public ServiceUnavailableException(RestResponse response) + : base("The service is currently unavailable. Please try again later.", response) + { + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public ServiceUnavailableException(string message, RestResponse response) + : base(message, response) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/Response/UserNotAuthorizedException.cs b/src/OpenStack/Core/Exceptions/Response/UserNotAuthorizedException.cs new file mode 100644 index 000000000..831399d07 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/Response/UserNotAuthorizedException.cs @@ -0,0 +1,38 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using RestResponse = JSIStudios.SimpleRESTServices.Client.Response; + +namespace net.openstack.Core.Exceptions.Response +{ + /// + /// Represents errors with status code , + /// , or + /// resulting from a call to a REST API. + /// + /// + [Serializable] + public class UserNotAuthorizedException : ResponseException + { + /// + /// Initializes a new instance of the class with the + /// specified REST response. + /// + /// The REST response. + public UserNotAuthorizedException(RestResponse response) + : base("Unable to authenticate user and retrieve authorized service endpoints", response) + { + } + + /// + /// Initializes a new instance of the class with the + /// specified error message and REST response. + /// + /// The message that describes the error. + /// The REST response. + public UserNotAuthorizedException(string message, RestResponse response) + : base(message, response) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/ServerEnteredErrorStateException.cs b/src/OpenStack/Core/Exceptions/ServerEnteredErrorStateException.cs new file mode 100644 index 000000000..50c4bc3f9 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/ServerEnteredErrorStateException.cs @@ -0,0 +1,63 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Domain; + +namespace net.openstack.Core.Exceptions +{ + /// + /// The exception that is thrown when the server enters an error state during a + /// call to . + /// + /// + [Serializable] + public class ServerEnteredErrorStateException : Exception + { + [NonSerialized] + private ExceptionData _state; + + /// + /// Gets the error state the server entered. + /// + /// + public ServerState Status + { + get + { + return ServerState.FromName(_state.Status); + } + } + + /// + /// Initializes a new instance of the class + /// with the specified error state. + /// + /// The error state entered by the server. + /// If is . + public ServerEnteredErrorStateException(ServerState status) + : base(string.Format("The server entered an error state: '{0}'", status)) + { + if (status == null) + throw new ArgumentNullException("status"); + + _state.Status = status.Name; +#if !NET35 + SerializeObjectState += (ex, args) => args.AddSerializedState(_state); +#endif + } + + [Serializable] + private struct ExceptionData : ISafeSerializationData + { + public string Status + { + get; + set; + } + + void ISafeSerializationData.CompleteDeserialization(object deserialized) + { + ((ServerEnteredErrorStateException)deserialized)._state = this; + } + } + } +} diff --git a/src/OpenStack/Core/Exceptions/SnapshotEnteredErrorStateException.cs b/src/OpenStack/Core/Exceptions/SnapshotEnteredErrorStateException.cs new file mode 100644 index 000000000..e5ab55834 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/SnapshotEnteredErrorStateException.cs @@ -0,0 +1,63 @@ +namespace net.openstack.Core.Exceptions +{ + using System; + using System.Runtime.Serialization; + using net.openstack.Core.Domain; + + /// + /// Represents errors that occur when a snapshot enters an error state while waiting + /// on it to enter a particular state. + /// + /// + [Serializable] + public class SnapshotEnteredErrorStateException : Exception + { + [NonSerialized] + private ExceptionData _state; + + /// + /// Gets the error state the snapshot entered. + /// + /// + public SnapshotState Status + { + get + { + return SnapshotState.FromName(_state.Status); + } + } + + /// + /// Initializes a new instance of the class with the + /// specified snapshot state. + /// + /// The erroneous snapshot state. + /// If is . + public SnapshotEnteredErrorStateException(SnapshotState status) + : base(string.Format("The snapshot entered an error state: '{0}'", status)) + { + if (status == null) + throw new ArgumentNullException("status"); + + _state.Status = status.Name; +#if !NET35 + SerializeObjectState += (ex, args) => args.AddSerializedState(_state); +#endif + } + + [Serializable] + private struct ExceptionData : ISafeSerializationData + { + public string Status + { + get; + set; + } + + void ISafeSerializationData.CompleteDeserialization(object deserialized) + { + ((SnapshotEnteredErrorStateException)deserialized)._state = this; + } + } + } +} diff --git a/src/OpenStack/Core/Exceptions/TTLLengthException.cs b/src/OpenStack/Core/Exceptions/TTLLengthException.cs new file mode 100644 index 000000000..38214fbcb --- /dev/null +++ b/src/OpenStack/Core/Exceptions/TTLLengthException.cs @@ -0,0 +1,44 @@ +using System; +using System.Runtime.Serialization; + +namespace net.openstack.Core.Exceptions +{ + /// + /// The exception that is thrown when the TTL argument to a method is outside + /// the range supported by the provider. + /// + /// + [Serializable] + public class TTLLengthException : ArgumentException + { + /// + /// Initializes a new instance of the class. + /// + public TTLLengthException() + : base("The specified TTL is outside the range supported by the provider.") + { + } + + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public TTLLengthException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected TTLLengthException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/UserAuthenticationException.cs b/src/OpenStack/Core/Exceptions/UserAuthenticationException.cs new file mode 100644 index 000000000..39a3187f2 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/UserAuthenticationException.cs @@ -0,0 +1,37 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Domain; + +namespace net.openstack.Core.Exceptions +{ + /// + /// The exception thrown when the user authentication process fails, or + /// the authentication process did not provide a value for the . + /// + /// + [Serializable] + public class UserAuthenticationException : Exception + { + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public UserAuthenticationException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected UserAuthenticationException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/UserAuthorizationException.cs b/src/OpenStack/Core/Exceptions/UserAuthorizationException.cs new file mode 100644 index 000000000..92650bf33 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/UserAuthorizationException.cs @@ -0,0 +1,40 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using net.openstack.Core.Domain; + +namespace net.openstack.Core.Exceptions +{ + /// + /// The exception that is thrown when a user does not have access to a REST API method + /// (status code ), or an endpoint could not be + /// obtained for a particular provider because it was not present in the user's + /// . + /// + /// + [Serializable] + public class UserAuthorizationException : InvalidOperationException + { + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + public UserAuthorizationException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected UserAuthorizationException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Core/Exceptions/VolumeEnteredErrorStateException.cs b/src/OpenStack/Core/Exceptions/VolumeEnteredErrorStateException.cs new file mode 100644 index 000000000..4db527f71 --- /dev/null +++ b/src/OpenStack/Core/Exceptions/VolumeEnteredErrorStateException.cs @@ -0,0 +1,63 @@ +namespace net.openstack.Core.Exceptions +{ + using System; + using System.Runtime.Serialization; + using net.openstack.Core.Domain; + + /// + /// Represents errors that occur when a volume enters an error state while waiting + /// on it to enter a particular state. + /// + /// + [Serializable] + public class VolumeEnteredErrorStateException : Exception + { + [NonSerialized] + private ExceptionData _state; + + /// + /// Gets the error state the volume entered. + /// + /// + public VolumeState Status + { + get + { + return VolumeState.FromName(_state.Status); + } + } + + /// + /// Initializes a new instance of the class with the + /// specified volume state. + /// + /// The erroneous volume state. + /// If is . + public VolumeEnteredErrorStateException(VolumeState status) + : base(string.Format("The volume entered an error state: '{0}'", status)) + { + if (status == null) + throw new ArgumentNullException("status"); + + _state.Status = status.Name; +#if !NET35 + SerializeObjectState += (ex, args) => args.AddSerializedState(_state); +#endif + } + + [Serializable] + private struct ExceptionData : ISafeSerializationData + { + public string Status + { + get; + set; + } + + void ISafeSerializationData.CompleteDeserialization(object deserialized) + { + ((VolumeEnteredErrorStateException)deserialized)._state = this; + } + } + } +} diff --git a/src/OpenStack/Core/ExtensibleEnum`1.cs b/src/OpenStack/Core/ExtensibleEnum`1.cs new file mode 100644 index 000000000..a240e6a1e --- /dev/null +++ b/src/OpenStack/Core/ExtensibleEnum`1.cs @@ -0,0 +1,97 @@ +namespace net.openstack.Core +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core.Domain.Converters; + + /// + /// Represents the base class for extensible enumeration types used + /// for strongly-typed values in JSON object models. + /// + /// The enumeration type. + /// + public abstract class ExtensibleEnum : IEquatable + where T : ExtensibleEnum + { + /// + /// This is the backing field for the property. + /// + private readonly string _name; + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// The name. + /// If is . + /// If is empty. + protected ExtensibleEnum(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + _name = name; + } + + /// + /// Gets the canonical name of this member. + /// + public string Name + { + get + { + return _name; + } + } + + /// + public bool Equals(T other) + { + return this == other; + } + + /// + public override string ToString() + { + return Name; + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + protected abstract class ConverterBase : SimpleStringJsonConverter + { + /// + /// This method uses for serialization. + /// + /// + protected override string ConvertToString(T obj) + { + return obj.Name; + } + + /// + /// If is an empty string, this method returns . + /// Otherwise, this method uses for deserialization. + /// + /// + protected override T ConvertToObject(string str) + { + if (string.IsNullOrEmpty(str)) + return null; + + return FromName(str); + } + + /// + /// Gets or creates the enumeration member with the given name. + /// + /// The name of the member. This value is never or empty. + /// The instance of corresponding to the specified . + protected abstract T FromName(string name); + } + } +} diff --git a/src/OpenStack/Core/HttpStatusCodeParser.cs b/src/OpenStack/Core/HttpStatusCodeParser.cs new file mode 100644 index 000000000..36fddc5d2 --- /dev/null +++ b/src/OpenStack/Core/HttpStatusCodeParser.cs @@ -0,0 +1,105 @@ +using System; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using net.openstack.Core.Domain; + +namespace net.openstack.Core +{ + /// + /// A status parser for HTTP status codes. + /// + /// + public class HttpStatusCodeParser : IStatusParser + { + /// + /// The default regular expression to use for matching HTTP status codes. + /// + protected static readonly string DefaultPattern = @"(?\d*)\s*(?\w*)"; + + /// + /// A singleton instance of the default . + /// + private static readonly HttpStatusCodeParser _default = new HttpStatusCodeParser(DefaultPattern); + + /// + /// The compiled regular expression to use for matching HTTP status codes. + /// + private readonly Regex _expression; + + /// + /// Initializes a new instance of the class for the default regular + /// expression. + /// + [Obsolete("Use HttpStatusCodeParser.Default instead.")] + public HttpStatusCodeParser() + : this(DefaultPattern) + { + } + + /// + /// Initializes a new instance of the class for the specified regular + /// expression. + /// + /// + /// The regular expression pattern to use. + /// + /// should contain the named capturing grounds StatusCode and status. + /// + /// is . + /// + /// does not contain a capturing group named StatusCode. + /// -or- + /// does not contain a capturing group named Status. + /// + protected HttpStatusCodeParser(string pattern) + { + if (pattern == null) + throw new ArgumentNullException("pattern"); + + _expression = new Regex(pattern, RegexOptions.Compiled); + + string[] groupNames = _expression.GetGroupNames(); + if (!groupNames.Contains("StatusCode", StringComparer.Ordinal)) + throw new ArgumentException("The pattern does not contain a StatusCode named capturing group.", "pattern"); + if (!groupNames.Contains("Status", StringComparer.Ordinal)) + throw new ArgumentException("The pattern does not contain a Status named capturing group.", "pattern"); + } + + /// + /// Gets a default . + /// + public static HttpStatusCodeParser Default + { + get + { + return _default; + } + } + + /// + public virtual bool TryParse(string value, out Status status) + { + if (value == null) + { + status = null; + return false; + } + + var match = _expression.Match(value); + if (!match.Success) + { + status = null; + return false; + } + + HttpStatusCode statusCode = (HttpStatusCode)int.Parse(match.Groups["StatusCode"].Value); + string description = match.Groups["Status"].Value; + if (string.IsNullOrEmpty(description)) + description = statusCode.ToString(); + + status = new Status((int)statusCode, description); + return true; + } + } +} diff --git a/src/OpenStack/Core/IBackoffPolicy.cs b/src/OpenStack/Core/IBackoffPolicy.cs new file mode 100644 index 000000000..3c844d469 --- /dev/null +++ b/src/OpenStack/Core/IBackoffPolicy.cs @@ -0,0 +1,28 @@ +namespace net.openstack.Core +{ + using System; + using System.Collections.Generic; + + /// + /// Represents a back-off policy. + /// + /// + public interface IBackoffPolicy + { + /// + /// Gets an enumeration of instances representing the + /// back-off policy intervals. + /// + /// + /// + /// This enumeration should always be lazily enumerated since implementations may + /// not bound the number of elements returned. + /// + /// + /// + /// An enumeration of instances representing the back-off + /// policy intervals. + /// + IEnumerable GetBackoffIntervals(); + } +} diff --git a/src/OpenStack/Core/IEncodeDecodeProvider.cs b/src/OpenStack/Core/IEncodeDecodeProvider.cs new file mode 100644 index 000000000..f81b09b35 --- /dev/null +++ b/src/OpenStack/Core/IEncodeDecodeProvider.cs @@ -0,0 +1,26 @@ +namespace net.openstack.Core +{ + /// + /// This interface provides methods for encoding and decoding strings which are + /// embedded in the query string section of a URL. + /// + public interface IEncodeDecodeProvider + { + /// + /// Encodes a string for inclusion in a URL. + /// + /// + /// The encoded string can be restored by calling . + /// + /// The string to encode. + /// The encoded string. If is , this method returns . + string UrlEncode(string stringToEncode); + + /// + /// Decodes a string which is embedded in a URL. + /// + /// The string to decode. + /// The decoded string. If is , this method returns . + string UrlDecode(string stringToDecode); + } +} diff --git a/src/OpenStack/Core/IObjectStorageMetadataProcessor.cs b/src/OpenStack/Core/IObjectStorageMetadataProcessor.cs new file mode 100644 index 000000000..6aab6709a --- /dev/null +++ b/src/OpenStack/Core/IObjectStorageMetadataProcessor.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using JSIStudios.SimpleRESTServices.Client; + +namespace net.openstack.Core +{ + /// + /// This interface represents an object that can extract metadata information from a + /// collection of HTTP headers returned from a REST request. + /// + public interface IObjectStorageMetadataProcessor + { + /// + /// Extracts metadata information from a collection of HTTP headers. The returned collection + /// may include multiple types of metadata information. The keys of the collection represent + /// the type of metadata, and the values are key-value collections of the corresponding + /// metadata. + /// + /// + /// + /// The resulting metadata dictionaries should use the + /// equality comparer to ensure lookups are not case sensitive. + /// + /// + /// The collection of HTTP headers. + /// The metadata. + /// If is . + /// + /// If contains any values. + /// -or- + /// If contains any values with a null or empty . + /// -or- + /// If contains two headers with equivalent values for when compared using . + /// + Dictionary> ProcessMetadata(IList httpHeaders); + } +} diff --git a/src/OpenStack/Core/IStatusParser.cs b/src/OpenStack/Core/IStatusParser.cs new file mode 100644 index 000000000..4e17f0b02 --- /dev/null +++ b/src/OpenStack/Core/IStatusParser.cs @@ -0,0 +1,23 @@ +using net.openstack.Core.Domain; + +namespace net.openstack.Core +{ + /// + /// Represents an object which can convert a string to a object + /// containing a status code and a textual representation of that status. + /// + public interface IStatusParser + { + /// + /// Converts a string to an equivalent object. A return value indicates whether the operation succeeded. + /// + /// A string containing a status to convert. + /// When this method returns, contains a instance + /// equivalent to , if the conversion succeeded, or if + /// the conversion failed. The conversion fails if the parameter is + /// or is not of the correct format. + /// + /// if was converted successfully; otherwise, . + bool TryParse(string value, out Status status); + } +} diff --git a/src/OpenStack/Core/InternalTaskExtensions.cs b/src/OpenStack/Core/InternalTaskExtensions.cs new file mode 100644 index 000000000..98468990e --- /dev/null +++ b/src/OpenStack/Core/InternalTaskExtensions.cs @@ -0,0 +1,57 @@ +namespace net.openstack.Core +{ + using System.Threading.Tasks; + + /// + /// Provides extension methods to and instances + /// for use within the openstack.net library. + /// + /// + /// + internal static class InternalTaskExtensions + { + /// + /// Gets a completed . + /// + /// A completed . + public static Task CompletedTask() + { + return CompletedTaskHolder.Default; + } + + /// + /// Gets a completed with the specified result. + /// + /// The task result type. + /// The result of the completed task. + /// A completed , whose property returns the specified . + public static Task CompletedTask(TResult result) + { + TaskCompletionSource completionSource = new TaskCompletionSource(); + completionSource.SetResult(result); + return completionSource.Task; + } + + private static class CompletedTaskHolder + { + public static readonly Task Default; + + static CompletedTaskHolder() + { + Default = CompletedTaskHolder.Default; + } + } + + private static class CompletedTaskHolder + { + public static readonly Task Default; + + static CompletedTaskHolder() + { + TaskCompletionSource completionSource = new TaskCompletionSource(); + completionSource.SetResult(default(T)); + Default = completionSource.Task; + } + } + } +} diff --git a/src/OpenStack/Core/LegacyAuthenticationProviderHelper.cs b/src/OpenStack/Core/LegacyAuthenticationProviderHelper.cs new file mode 100644 index 000000000..4b0aa932c --- /dev/null +++ b/src/OpenStack/Core/LegacyAuthenticationProviderHelper.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using net.openstack.Core.Domain; +using net.openstack.Core.Providers; +using OpenStack.Authentication; + +namespace OpenStack.Core +{ + /// + /// Provides methods to assist legacy implementations to implement the new interface which acts as a shim between the old provider model and the new service model. + /// + internal static class LegacyAuthenticationProviderHelper + { + /// + /// Gets the endpoint for the specified identity and region. + /// + /// The provider specific service type to look for in the service catalog + /// The user access instance. + /// The cloud identity. + /// The endpoint region. + /// if set to true [use internal URL]. + /// + /// + /// The user does not have access to the service or it does not exist. + /// or + /// The user does not have access to the service endpoint in the specified region. + /// + /// No region was specified and the service does not provide a region-independent endpoint. + public static string GetEndpoint(string serviceType, UserAccess userAccess, CloudIdentity defaultIdentity, string region, bool useInternalUrl) + { + ServiceCatalog service = userAccess.ServiceCatalog.FirstOrDefault(sc => string.Equals(sc.Type, serviceType, StringComparison.OrdinalIgnoreCase)); + if (service == null) + throw new UserAuthenticationException("The user does not have access to the {0} service or it does not exist.", serviceType); + + Endpoint endpoint = service.Endpoints + .Where(e => string.Equals(e.Region, region, StringComparison.OrdinalIgnoreCase)) + .OrderByDescending(e => e.Region) + .FirstOrDefault(); + + if (string.IsNullOrEmpty(region) && endpoint == null) + throw new RegionRequiredException("No region was specified and the {0} service does not provide a region-independent endpoint.", serviceType); + + if (endpoint == null) + throw new UserAuthenticationException("The user does not have access to the {0} endpoint in the {1} region.", serviceType, region); + + return useInternalUrl ? endpoint.InternalURL : endpoint.PublicURL; + } + } +} diff --git a/src/OpenStack/Core/NamespaceDoc.cs b/src/OpenStack/Core/NamespaceDoc.cs new file mode 100644 index 000000000..283ed6d18 --- /dev/null +++ b/src/OpenStack/Core/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Core +{ + using System.Runtime.CompilerServices; + + /// + /// The namespaces define provider-independent + /// interfaces and implementations of OpenStack APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/ParallelExtensionsExtras/TaskCompletionSourceExtensions.cs b/src/OpenStack/Core/ParallelExtensionsExtras/TaskCompletionSourceExtensions.cs new file mode 100644 index 000000000..bc9cc37d1 --- /dev/null +++ b/src/OpenStack/Core/ParallelExtensionsExtras/TaskCompletionSourceExtensions.cs @@ -0,0 +1,39 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TaskCompletionSourceExtensions.cs +// +//-------------------------------------------------------------------------- + +namespace System.Threading.Tasks +{ + /// Extension methods for TaskCompletionSource. + /// + internal static class TaskCompletionSourceExtensions + { + /// Transfers the result of a Task to the TaskCompletionSource. + /// Specifies the type of the result. + /// The TaskCompletionSource. + /// The task whose completion results should be transferred. + public static void SetFromTask(this TaskCompletionSource resultSetter, Task task) + { + switch (task.Status) + { + case TaskStatus.RanToCompletion: resultSetter.SetResult(task is Task ? ((Task)task).Result : default(TResult)); break; + case TaskStatus.Faulted: resultSetter.SetException(task.Exception.InnerExceptions); break; + case TaskStatus.Canceled: resultSetter.SetCanceled(); break; + default: throw new InvalidOperationException("The task was not completed."); + } + } + + /// Transfers the result of a Task to the TaskCompletionSource. + /// Specifies the type of the result. + /// The TaskCompletionSource. + /// The task whose completion results should be transferred. + public static void SetFromTask(this TaskCompletionSource resultSetter, Task task) + { + SetFromTask(resultSetter, (Task)task); + } + } +} diff --git a/src/OpenStack/Core/ParallelExtensionsExtras/TaskExtrasExtensions.cs b/src/OpenStack/Core/ParallelExtensionsExtras/TaskExtrasExtensions.cs new file mode 100644 index 000000000..496ccd600 --- /dev/null +++ b/src/OpenStack/Core/ParallelExtensionsExtras/TaskExtrasExtensions.cs @@ -0,0 +1,37 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TaskExtensions.cs +// +//-------------------------------------------------------------------------- + +using System.Linq; + +namespace System.Threading.Tasks +{ + /// Extensions methods for Task. + /// + internal static class TaskExtrasExtensions + { + #region Exception Handling + /// Propagates any exceptions that occurred on the specified task. + /// The Task whose exceptions are to be propagated. + public static void PropagateExceptions(this Task task) + { + if (!task.IsCompleted) throw new InvalidOperationException("The task has not completed."); + if (task.IsFaulted) task.Wait(); + } + + /// Propagates any exceptions that occurred on the specified tasks. + /// The Task instances whose exceptions are to be propagated. + public static void PropagateExceptions(this Task [] tasks) + { + if (tasks == null) throw new ArgumentNullException("tasks"); + if (tasks.Any(t => t == null)) throw new ArgumentException("tasks"); + if (tasks.Any(t => !t.IsCompleted)) throw new InvalidOperationException("A task has not completed."); + Task.WaitAll(tasks); + } + #endregion + } +} diff --git a/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_Common.cs b/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_Common.cs new file mode 100644 index 000000000..bc5ce8696 --- /dev/null +++ b/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_Common.cs @@ -0,0 +1,16 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TaskFactoryExtensions_Common.cs +// +//-------------------------------------------------------------------------- + +namespace System.Threading.Tasks +{ + /// Extensions for TaskFactory. + /// + internal static partial class TaskFactoryExtensions + { + } +} diff --git a/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_ContinueWhenAllAny.cs b/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_ContinueWhenAllAny.cs new file mode 100644 index 000000000..fafdf70b9 --- /dev/null +++ b/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_ContinueWhenAllAny.cs @@ -0,0 +1,26 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TaskFactoryExtensions_ContinueWhenAllAny.cs +// +//-------------------------------------------------------------------------- + +namespace System.Threading.Tasks +{ + partial class TaskFactoryExtensions + { + /// + /// Creates a continuation Task that will complete upon + /// the completion of a set of provided Tasks. + /// + /// The TaskFactory to use to create the continuation task. + /// The array of tasks from which to continue. + /// A task that, when completed, will return the array of completed tasks. + public static Task[]> WhenAll( + this TaskFactory factory, params Task[] tasks) + { + return factory.ContinueWhenAll(tasks, completedTasks => completedTasks); + } + } +} diff --git a/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_Delayed.cs b/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_Delayed.cs new file mode 100644 index 000000000..b5305b5fb --- /dev/null +++ b/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_Delayed.cs @@ -0,0 +1,63 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TaskFactoryExtensions_Delayed.cs +// +//-------------------------------------------------------------------------- + +namespace System.Threading.Tasks +{ + partial class TaskFactoryExtensions + { + #region TaskFactory No Action + /// Creates a Task that will complete after the specified delay. + /// The TaskFactory. + /// The delay after which the Task should transition to RanToCompletion. + /// The cancellation token that can be used to cancel the timed task. + /// A Task that will be completed after the specified duration and that's cancelable with the specified token. + public static Task StartNewDelayed(this TaskFactory factory, int millisecondsDelay, CancellationToken cancellationToken) + { + // Validate arguments + if (factory == null) throw new ArgumentNullException("factory"); + if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay"); + + // Check for a pre-canceled token + if (cancellationToken.IsCancellationRequested) + return factory.FromCancellation(cancellationToken); + + // Create the timed task + var tcs = new TaskCompletionSource(factory.CreationOptions); + var ctr = default(CancellationTokenRegistration); + + // Create the timer but don't start it yet. If we start it now, + // it might fire before ctr has been set to the right registration. + var timer = new Timer(self => + { + // Clean up both the cancellation token and the timer, and try to transition to completed + ctr.Dispose(); + ((Timer)self).Dispose(); + tcs.TrySetResult(null); + }); + + // Register with the cancellation token. + if (cancellationToken.CanBeCanceled) + { + // When cancellation occurs, cancel the timer and try to transition to canceled. + // There could be a race, but it's benign. + ctr = cancellationToken.Register(() => + { + timer.Dispose(); + tcs.TrySetCanceled(); + }); + } + + // Start the timer and hand back the task... + try { timer.Change(millisecondsDelay, Timeout.Infinite); } + catch(ObjectDisposedException) {} // in case there's a race with cancellation; this is benign + + return tcs.Task; + } + #endregion + } +} diff --git a/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_From.cs b/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_From.cs new file mode 100644 index 000000000..0929ea4d0 --- /dev/null +++ b/src/OpenStack/Core/ParallelExtensionsExtras/TaskFactoryExtensions_From.cs @@ -0,0 +1,25 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TaskFactoryExtensions_From.cs +// +//-------------------------------------------------------------------------- + +namespace System.Threading.Tasks +{ + partial class TaskFactoryExtensions + { + #region TaskFactory + /// Creates a Task that has completed in the Canceled state with the specified CancellationToken. + /// The target TaskFactory. + /// The CancellationToken with which the Task should complete. + /// The completed Task. + public static Task FromCancellation(this TaskFactory factory, CancellationToken cancellationToken) + { + if (!cancellationToken.IsCancellationRequested) throw new ArgumentOutOfRangeException("cancellationToken"); + return new Task(() => { }, cancellationToken); + } + #endregion + } +} diff --git a/src/OpenStack/Core/Providers/IBlockStorageProvider.cs b/src/OpenStack/Core/Providers/IBlockStorageProvider.cs new file mode 100644 index 000000000..0c9c543b6 --- /dev/null +++ b/src/OpenStack/Core/Providers/IBlockStorageProvider.cs @@ -0,0 +1,493 @@ +using System; +using System.Collections.Generic; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Providers.Rackspace.Exceptions; + +namespace net.openstack.Core.Providers +{ + /// + /// Represents a provider for the OpenStack Block Storage Service. + /// + /// OpenStack Block Storage Service API v2 Reference + public interface IBlockStorageProvider + { + #region Volume + + /// + /// Creates a new block storage volume. + /// + /// The size of the volume in GB. + /// A description of the volume. + /// The name of the volume. + /// The snapshot from which to create a volume. The value should be or obtained from Snapshot.Id. + /// The type of volume to create. If not defined, then the default is used. The value should be or obtained from VolumeType.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the request succeeded; otherwise, . + /// If is less than zero. + /// If is not valid for this provider. + /// + /// If the provider does not support the given type. + /// -or- + /// If the specified is not supported. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create Volume (OpenStack Block Storage Service API Reference) + Volume CreateVolume(int size, string displayDescription = null, string displayName = null, string snapshotId = null, string volumeType = null, string region = null, CloudIdentity identity = null); + + /// + /// Gets a list of volumes. + /// + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the volumes. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Volume Summaries (OpenStack Block Storage Service API Reference) + IEnumerable ListVolumes(string region = null, CloudIdentity identity = null); + + /// + /// View information about a single volume. + /// + /// The ID of the volume. The value should be obtained from Volume.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the volume details. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show Volume (OpenStack Block Storage Service API Reference) + Volume ShowVolume(string volumeId, string region = null, CloudIdentity identity = null); + + /// + /// Deletes a volume. + /// + /// + /// The deletion operation is performed asynchronously. After this call returns, + /// may be called to wait until the volume + /// is finally deleted. + /// + /// + /// It is not currently possible to delete a volume once you have created a snapshot from it. Any snapshots will need to be deleted prior to deleting the volume. + /// + /// + /// The ID of the volume to delete. The value should be obtained from Volume.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the volume was successfully deleted; otherwise . + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Volume (OpenStack Block Storage Service API Reference) + bool DeleteVolume(string volumeId, string region = null, CloudIdentity identity = null); + + /// + /// Get a list of volume types. + /// + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects containing the details of each volume type. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Volume Types (OpenStack Block Storage Service API Reference) + IEnumerable ListVolumeTypes(string region = null, CloudIdentity identity = null); + + /// + /// Get information about a volume type. + /// + /// The ID of the volume type. The value should be obtained from VolumeType.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the details of the volume type. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show Volume Type (OpenStack Block Storage Service API Reference) + VolumeType DescribeVolumeType(string volumeTypeId, string region = null, CloudIdentity identity = null); + + /// + /// Waits for a volume to be set to status. + /// + /// + /// This method can be used to ensure that a volume is correctly created prior to executing additional requests against it. + /// + /// The ID of the volume to poll. The value should be obtained from Volume.Id. + /// The number of times to poll for the volume to become available. + /// The refresh delay. If the value is , the default value is 2.4 seconds. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the details of the volume, including the final . + /// If is . + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + Volume WaitForVolumeAvailable(string volumeId, int refreshCount = 600, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for a volume to be deleted. + /// + /// + /// This method can be used to ensure that a volume is completely removed. + /// + /// The ID of the volume to poll. The value should be obtained from Volume.Id. + /// The number of times to poll for the volume to be deleted. + /// The refresh delay. If the value is , the default value is 10 seconds. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the volume was successfully deleted; otherwise, . + /// If is . + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + bool WaitForVolumeDeleted(string volumeId, int refreshCount = 360, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for a volume to be set to be set to a particular . + /// + /// + /// This method can be used to ensure that a volume is in an intended state prior to + /// executing additional requests against it. + /// + /// The ID of the volume to poll. The value should be obtained from Volume.Id. + /// The expected state for the volume. + /// The error state(s) in which to stop polling once reached. + /// The number of times to poll the volume. + /// The refresh delay. If the value is , the default value is 10 seconds. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the details of the volume, including the final . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the method returned due to the volume entering one of the . + /// If the REST API request failed. + /// Volume Status (Rackspace Cloud Block Storage Developer Guide - API V1.0) + Volume WaitForVolumeState(string volumeId, VolumeState expectedState, VolumeState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null); + + #endregion + + #region Snapshot + + /// + /// Creates a new snapshot. + /// + /// + /// The snapshot operation is performed asynchronously. After this call returns, + /// may be called to wait until the snapshot + /// process is complete and the snapshot is available. + /// + /// Creating a snapshot makes a point-in-time copy of the volume. + /// All writes to the volume should be flushed before creating the snapshot, either by un-mounting any file systems on the volume, or by detaching the volume before creating the snapshot. + /// Snapshots are incremental, so each time you create a new snapshot, you are appending the incremental changes for the new snapshot to the previous one. + /// The previous snapshot is still available. Note that you can create a new volume from the snapshot if desired. + /// + /// The ID of the volume to snapshot. The value should be obtained from Volume.Id. + /// If , the snapshot is created even if the volume is currently attached. + /// Name of the snapshot. + /// Description of snapshot. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the details about the snapshot. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create Snapshot (OpenStack Block Storage Service API Reference) + Snapshot CreateSnapshot(string volumeId, bool force = false, string displayName = "None", string displayDescription = null, string region = null, CloudIdentity identity = null); + + /// + /// Get a list of snapshots. + /// + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects containing the details of each snapshot. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Snapshot Summaries (OpenStack Block Storage Service API Reference) + IEnumerable ListSnapshots(string region = null, CloudIdentity identity = null); + + /// + /// View all information about a single snapshot. + /// + /// The ID of the snapshot. The value should be obtained from Snapshot.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the snapshot details. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show Snapshot (OpenStack Block Storage Service API Reference) + Snapshot ShowSnapshot(string snapshotId, string region = null, CloudIdentity identity = null); + + /// + /// Marks a snapshot for deletion. + /// + /// + /// The deletion operation is performed asynchronously. After this call returns, + /// may be called to wait until the snapshot + /// is finally deleted. + /// + /// The ID of the snapshot. The value should be obtained from Snapshot.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the snapshot was successfully marked for deletion; otherwise . + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Snapshot (OpenStack Block Storage Service API Reference) + bool DeleteSnapshot(string snapshotId, string region = null, CloudIdentity identity = null); + + /// + /// Waits for a snapshot to be set to status. + /// + /// + /// This method can be used to ensure that a snapshot is correctly created prior to executing additional requests against it. + /// + /// The ID of the snapshot to poll. The value should be obtained from Snapshot.Id. + /// The number of times to poll for the snapshot to become available. + /// The refresh delay. If the value is , the default value is 10 seconds. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the snapshot details, including the final . + /// If is . + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + Snapshot WaitForSnapshotAvailable(string snapshotId, int refreshCount = 360, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for a snapshot to be deleted. + /// + /// + /// This method can be used to ensure that a snapshot is completely removed. + /// + /// The ID of the snapshot to poll. The value should be obtained from Snapshot.Id. + /// The number of times to poll for the snapshot to be deleted. + /// The refresh delay. If the value is , the default value is 10 seconds. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the snapshot was successfully deleted; otherwise, . + /// If is . + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + bool WaitForSnapshotDeleted(string snapshotId, int refreshCount = 180, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for a snapshot to be set to be set to a particular status. + /// + /// + /// This method can be used to ensure that a snapshot is in an intended state prior to + /// executing additional requests against it. + /// + /// The ID of the snapshot to poll. The value should be obtained from Snapshot.Id. + /// The expected state for the snapshot. + /// The error state(s) in which to stop polling once reached. + /// The number of times to poll the snapshot. + /// The refresh delay. If the value is , the default value is 10 seconds. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the snapshot details, including the final . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the method returned due to the snapshot entering one of the . + /// If the REST API request failed. + Snapshot WaitForSnapshotState(string snapshotId, SnapshotState expectedState, SnapshotState[] errorStates, int refreshCount = 60, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null); + + #endregion + } +} diff --git a/src/OpenStack/Core/Providers/IComputeProvider.cs b/src/OpenStack/Core/Providers/IComputeProvider.cs new file mode 100644 index 000000000..9c1068e42 --- /dev/null +++ b/src/OpenStack/Core/Providers/IComputeProvider.cs @@ -0,0 +1,1765 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; + +namespace net.openstack.Core.Providers +{ + /// + /// DEPRECATED. Use or Rackspace.CloudServers.v2.CloudServerService (from the Rackspace NuGet package). + /// Represents a provider for the OpenStack Compute service. + /// + /// OpenStack Compute API v2 and Extensions Reference + [Obsolete("This will be removed in v2.0. Use OpenStack.Compute.v2_1.ComputeService or Rackspace.CloudServers.v2.CloudServerService (from the Rackspace NuGet package).")] + public interface IComputeProvider + { + /// + /// Returns a list of basic information for servers in the account. + /// + /// + /// If the parameter is specified, servers which have been + /// deleted since the specified time are returned by this method. Otherwise, deleted servers + /// are not included in the list of servers returned by this method. + /// + /// The image to filter the returned servers list. If + /// the value is , servers for all images are returned. This is + /// specified as an image ID (see ) or a full URL. + /// The flavor to filter the returned servers list. If + /// the value is , servers for all flavors are returned. This + /// is specified as a flavor ID (see ) or a full URL. + /// Filters the list to those with a name that matches. + /// If the value is , servers are not filtered by name. + /// Filters the list to those with a status that matches. + /// If the value is , servers are not filtered by status. See + /// for the allowed values. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// Filters the list to those that have changed since the given date. + /// If the value is , servers are not filtered by timestamp. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the requested servers. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Servers (OpenStack Compute API v2 and Extensions Reference) + IEnumerable ListServers(string imageId = null, string flavorId = null, string name = null, ServerState status = null, string markerId = null, int? limit = null, DateTimeOffset? changesSince = null, string region = null, CloudIdentity identity = null); + + /// + /// Returns a list of detailed information servers for servers in the account. + /// + /// + /// If the parameter is specified, servers which have been + /// deleted since the specified time are returned by this method. Otherwise, deleted servers + /// are not included in the list of servers returned by this method. + /// + /// The image to filter the returned servers list. If + /// the value is , servers for all images are returned. This is + /// specified as an image ID (see ) or a full URL. + /// The flavor to filter the returned servers list. If + /// the value is , servers for all flavors are returned. This + /// is specified as a flavor ID (see ) or a full URL. + /// Filters the list to those with a name that matches. + /// If the value is , servers are not filtered by name. + /// Filters the list to those with a status that matches. + /// If the value is , servers are not filtered by status. See + /// for the allowed values. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// Filters the list to those that have changed since the given date. + /// If the value is , servers are not filtered by timestamp. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the requested servers. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Servers (OpenStack Compute API v2 and Extensions Reference) + IEnumerable ListServersWithDetails(string imageId = null, string flavorId = null, string name = null, ServerState status = null, string markerId = null, int? limit = null, DateTimeOffset? changesSince = null, string region = null, CloudIdentity identity = null); + + /// + /// Creates a new server. + /// + /// + /// This operation asynchronously provisions a new server. The progress of this operation depends on + /// several factors including location of the requested image, network i/o, host load, and the selected + /// flavor. The progress of the request can be checked by calling and getting + /// the value of and . + /// + /// + /// This is the only time the server's admin password is returned. Make sure to retain the value. + /// + /// + /// + /// The parameter is ignored if the provider does not support the + /// disk configuration extension. + /// + /// + /// Name of the cloud server. + /// The image to use for the new server instance. This is + /// specified as an image ID (see ) or a full URL. + /// The flavor to use for the new server instance. This + /// is specified as a flavor ID (see ) or a full URL. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// The metadata to associate with the server. + /// A collection of objects describing the paths and contents of files to inject in the target file system during the creation process. If the value is , no files are injected. + /// if the private network will be attached to the newly created server; otherwise, . + /// if the public network will be attached to the newly created server; otherwise, . + /// A collection of IDs of networks to attach to the server. This is obtained from CloudNetwork.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A instance containing the details for the newly created server. + /// + /// is . + /// -or- + /// is . + /// -or- + /// is . + /// + /// + /// is empty. + /// -or- + /// is empty. + /// -or- + /// is empty. + /// -or- + /// contains a value with a null or empty key. + /// -or- + /// contains a null or empty value. + /// + /// + /// If the provider does not support the given . + /// -or- + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create Server (OpenStack Compute API v2 and Extensions Reference) + NewServer CreateServer(string cloudServerName, string imageName, string flavor, DiskConfiguration diskConfig = null, Metadata metadata = null, Personality[] personality = null, bool attachToServiceNetwork = false, bool attachToPublicNetwork = false, IEnumerable networks = null, string region = null, CloudIdentity identity = null); + + /// + /// Gets the detailed information for a specific server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the details for the given server. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Get Server Details (OpenStack Compute API v2 and Extensions Reference) + Server GetDetails(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Updates the editable attributes for the specified server. + /// + /// + /// Server names are not guaranteed to be unique. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The new name for the server. If the value is , the server name is not changed. + /// The new IP v4 address for the server, or to remove the configured IP v4 address for the server. If the value is , the server's IP v4 address is not updated. + /// The new IP v6 address for the server, or to remove the configured IP v6 address for the server. If the value is , the server's IP v6 address is not updated. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the server was successfully updated; otherwise . + /// If is . + /// + /// If is empty. + /// -or- + /// If is not and the of is not . + /// -or- + /// If is not and the of is not . + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Update Server (OpenStack Compute API v2 and Extensions Reference) + bool UpdateServer(string serverId, string name = null, IPAddress accessIPv4 = null, IPAddress accessIPv6 = null, string region = null, CloudIdentity identity = null); + + /// + /// Marks a server for asynchronous deletion. + /// + /// + /// The server deletion operation is completed asynchronously. The + /// method may be used to block execution until the server is finally deleted. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the server was successfully marked for deletion; otherwise, . + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Server (OpenStack Compute API v2 and Extensions Reference) + bool DeleteServer(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Lists all networks and server addresses associated with a specified server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the list of network addresses for the server. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Addresses (OpenStack Compute API v2 and Extensions Reference) + ServerAddresses ListAddresses(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Lists addresses associated with a specified server and network. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The network label. This is obtained from CloudNetwork.Label. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of containing the network addresses associated with the server on the specified network. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Addresses by Network (OpenStack Compute API v2 and Extensions Reference) + IEnumerable ListAddressesByNetwork(string serverId, string network, string region = null, CloudIdentity identity = null); + + /// + /// Changes the administrator password for a specified server. + /// + /// + /// The password change operation is performed asynchronously. If the password does not + /// meet the server's complexity requirements, the server may end up in an + /// state. In this case, the client may call again to + /// select a new password. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The new administrator password. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the administrator password change operation was successfully started; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Change Administrator Password (OpenStack Compute API v2 and Extensions Reference) + bool ChangeAdministratorPassword(string serverId, string password, string region = null, CloudIdentity identity = null); + + /// + /// Initiates an asynchronous reboot operation on the specified server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The type of reboot to perform. See for predefined values. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the reboot operation was successfully initiated; otherwise . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// + /// If the provider does not support the specified . + /// -or- + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Reboot Server (OpenStack Compute API v2 and Extensions Reference) + bool RebootServer(string serverId, RebootType rebootType, string region = null, CloudIdentity identity = null); + + /// + /// Initiates an asynchronous rebuild of the specified server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The new name for the server. If the value is , the server name is not changed. + /// The image to rebuild the server from. This is specified as an image ID (see ) or a full URL. + /// The new flavor for server. This is obtained from . + /// The new admin password for the server. + /// The new IP v4 address for the server, or to remove the configured IP v4 address for the server. If the value is , the server's IP v4 address is not updated. + /// The new IP v6 address for the server, or to remove the configured IP v6 address for the server. If the value is , the server's IP v6 address is not updated. + /// The list of metadata to associate with the server. If the value is , the metadata associated with the server is not changed during the rebuild operation. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// The path and contents of a file to inject in the target file system during the rebuild operation. If the value is , no file is injected. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the details for the given server. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is not and the of is not . + /// -or- + /// If is not and the of is not . + /// + /// + /// If the provider does not support the given . + /// -or- + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Rebuild Server (OpenStack Compute API v2 and Extensions Reference) + Server RebuildServer(string serverId, string serverName, string imageName, string flavor, string adminPassword, IPAddress accessIPv4 = null, IPAddress accessIPv6 = null, Metadata metadata = null, DiskConfiguration diskConfig = null, Personality personality = null, string region = null, CloudIdentity identity = null); + + /// + /// Initiates an asynchronous resize of the specified server. A server resize is performed by + /// specifying a new for the server. + /// + /// + /// Following a resize operation, the original server is not immediately removed. After testing + /// if the resulting server is operating successfully, a call should be made to + /// to keep the resized server, or to to revert to the original server. + /// If 24 hours pass and neither of these methods is called, the server will be automatically confirmed. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The new name for the resized server. + /// The new flavor. This is obtained from Flavor.Id. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the resize operation is successfully started; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given . + /// -or- + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Resize Server (OpenStack Compute API v2 and Extensions Reference) + bool ResizeServer(string serverId, string serverName, string flavor, DiskConfiguration diskConfig = null, string region = null, CloudIdentity identity = null); + + /// + /// Confirms a completed asynchronous server resize action. + /// + /// + /// If a server resize operation is not manually confirmed or reverted within 24 hours, + /// the operation is automatically confirmed. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the resize operation was confirmed; otherwise, . + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Confirm Resized Server (OpenStack Compute API v2 and Extensions Reference) + bool ConfirmServerResize(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Cancels and reverts a server resize action. + /// + /// + /// If a server resize operation is not manually confirmed or reverted within 24 hours, + /// the operation is automatically confirmed. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the resize operation was reverted; otherwise, . + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Revert Resized Server (OpenStack Compute API v2 and Extensions Reference) + bool RevertServerResize(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Places a server in rescue mode. + /// + /// + /// This operation is completed asynchronously. To wait for the server to enter rescue mode, + /// call with the state . + /// + /// + /// The provider may limit the duration of rescue mode, after which the rescue image is destroyed + /// and the server attempts to reboot. Rescue mode may be explicitly exited at any time by + /// calling . + /// + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The root password assigned for use during rescue mode. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Rescue Server (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + string RescueServer(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Takes a server out of rescue mode. + /// + /// + /// This operation is completed asynchronously. To wait for the server to exit rescue mode, + /// call . + /// + /// + /// The provider may limit the duration of rescue mode, after which the rescue image is destroyed + /// and the server attempts to reboot. Rescue mode may be explicitly exited at any time by + /// calling . + /// + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the server exited rescue mode; otherwise, . + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Unrescue Server (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + bool UnRescueServer(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Creates a new snapshot image for a specified server at its current state. + /// + /// + /// The server snapshot process is completed asynchronously. To wait for the image + /// to be completed, you may call . + /// + /// The server ID. This is obtained from ServerBase.Id. + /// Name of the new image. + /// The metadata to associate to the new image. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the image creation process was successfully started; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create Image (OpenStack Compute API v2 and Extensions Reference) + bool CreateImage(string serverId, string imageName, Metadata metadata = null, string region = null, CloudIdentity identity = null); + + /// + /// Attaches a volume to the specified server. + /// + /// The server ID. This is obtained from . + /// The volume ID. This is obtained from . + /// The name of the device, such as /dev/xvdb. If the value is , an automatically generated device name will be used. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the details about the volume. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Attach Volume to Server (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + ServerVolume AttachServerVolume(string serverId, string volumeId, string storageDevice = null, string region = null, CloudIdentity identity = null); + + /// + /// Lists the volume attachments for the specified server. + /// + /// The server ID. This is obtained from . + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the volumes attached to the server. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Volume Attachments (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + IEnumerable ListServerVolumes(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Gets detailed information about the specified server-attached volume. + /// + /// The server ID. This is obtained from . + /// The volume attachment ID. This is obtained from ServerVolume.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing details about the volume attachment. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Get Volume Attachment Details (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + ServerVolume GetServerVolumeDetails(string serverId, string volumeId, string region = null, CloudIdentity identity = null); + + /// + /// Detaches the specified volume from the specified server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The volume attachment ID. This is obtained from ServerVolume.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the volume was successfully detached; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Volume Attachment (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + bool DetachServerVolume(string serverId, string volumeId, string region = null, CloudIdentity identity = null); + + /// + /// Lists the virtual interfaces for the specified server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the virtual interfaces for the server. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + IEnumerable ListVirtualInterfaces(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Creates a virtual interface for the specified network and attaches the network to the specified server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The network ID. This is obtained from CloudNetwork.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the details of the newly-created virtual network. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create Virtual Interface (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + VirtualInterface CreateVirtualInterface(string serverId, string networkId, string region = null, CloudIdentity identity = null); + + /// + /// Deletes the specified virtual interface from the specified server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The virtual interface ID. This is obtained from VirtualInterface.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the virtual interface was successfully removed from the server; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Virtual Interface (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + bool DeleteVirtualInterface(string serverId, string virtualInterfaceId, string region = null, CloudIdentity identity = null); + + /// + /// Lists basic information for all available flavors. + /// + /// Filters the list of flavors to those with the specified minimum number of gigabytes of disk storage. If the value is , the results are not filtered by storage space. + /// Filters the list of flavors to those with the specified minimum amount of RAM in megabytes. If the value is , the results are not filtered by memory capacity. + /// The of the last item in the previous list. Used for pagination. + /// The maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the available flavors. + /// + /// If is less than 0. + /// -or- + /// If is less than 0. + /// -or- + /// If is less than 0. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// List Flavors (OpenStack Compute API v2 and Extensions Reference) + IEnumerable ListFlavors(int? minDiskInGB = null, int? minRamInMB = null, string markerId = null, int? limit = null, string region = null, CloudIdentity identity = null); + + /// + /// Lists full details for all available flavors. + /// + /// Filters the list of flavors to those with the specified minimum number of gigabytes of disk storage. If the value is , the results are not filtered by storage space. + /// Filters the list of flavors to those with the specified minimum amount of RAM in megabytes. If the value is , the results are not filtered by memory capacity. + /// The of the last item in the previous list. Used for pagination. + /// The maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects containing detailed information for the available flavors. + /// + /// If is less than 0. + /// -or- + /// If is less than 0. + /// -or- + /// If is less than 0. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// List Flavors (OpenStack Compute API v2 and Extensions Reference) + IEnumerable ListFlavorsWithDetails(int? minDiskInGB = null, int? minRamInMB = null, string markerId = null, int? limit = null, string region = null, CloudIdentity identity = null); + + /// + /// Gets details for the specified flavor. + /// + /// The flavor ID. This is obtained from Flavor.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing details of the flavor. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Get Flavor Details (OpenStack Compute API v2 and Extensions Reference) + FlavorDetails GetFlavor(string id, string region = null, CloudIdentity identity = null); + + // Images + + /// + /// Lists basic information for all available images. + /// + /// + /// If the parameter is not specified, deleted images are + /// not returned by this method. If the parameter is specified, + /// the result includes images which were deleted since the specified time. + /// + /// Filters the list of images by server. This is specified as a server ID (see ) or a full URL. If the value is , the results are not filtered by ID. + /// Filters the list of images by image name. If the value is , the results are not filtered by name. + /// Filters the list of images by status. If the value is , the results are not filtered by status. + /// Filters the list of images to those that have changed since the specified time. If the value is , the results are not filtered by timestamp. + /// The of the last item in the previous list. Used for pagination. If the value is , the results start at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// Filters base Rackspace images or any custom server images that you have created. If the value is , the results are not filtered by image type. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects containing basic information for the images. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// List Images (OpenStack Compute API v2 and Extensions Reference) + IEnumerable ListImages(string server = null, string imageName = null, ImageState imageStatus = null, DateTimeOffset? changesSince = null, string markerId = null, int? limit = null, ImageType imageType = null, string region = null, CloudIdentity identity = null); + + /// + /// Lists detailed information for all available images. + /// + /// + /// If the parameter is not specified, deleted images are + /// not returned by this method. If the parameter is specified, + /// the result includes images which were deleted since the specified time. + /// + /// Filters the list of images by server. This is specified as a server ID (see ) or a full URL. If the value is , the results are not filtered by ID. + /// Filters the list of images by image name. If the value is , the results are not filtered by name. + /// Filters the list of images by status. If the value is , the results are not filtered by status. + /// Filters the list of images to those that have changed since the specified time. If the value is , the results are not filtered by timestamp. + /// The of the last item in the previous list. Used for pagination. If the value is , the results start at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// Filters base Rackspace images or any custom server images that you have created. If the value is , the results are not filtered by image type. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects containing detailed information for the images. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// List Images (OpenStack Compute API v2 and Extensions Reference) + IEnumerable ListImagesWithDetails(string server = null, string imageName = null, ImageState imageStatus = null, DateTimeOffset? changesSince = null, string markerId = null, int? limit = null, ImageType imageType = null, string region = null, CloudIdentity identity = null); + + /// + /// Gets detailed information for the specified image. + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing detailed information about the specified image. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Get Image Details (OpenStack Compute API v2 and Extensions Reference) + ServerImage GetImage(string imageId, string region = null, CloudIdentity identity = null); + + /// + /// Deletes the specified image. + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the image was successfully deleted; otherwise, . + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Image (OpenStack Compute API v2 and Extensions Reference) + bool DeleteImage(string imageId, string region = null, CloudIdentity identity = null); + + /// + /// Gets the metadata associated with the specified server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the metadata associated with the server. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Metadata (OpenStack Compute API v2 and Extensions Reference) + Metadata ListServerMetadata(string serverId, string region = null, CloudIdentity identity = null); + + /// + /// Sets the metadata associated with the specified server, replacing any existing metadata. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The metadata to associate with the server. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the metadata for the server was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values with empty keys. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Set Metadata (OpenStack Compute API v2 and Extensions Reference) + bool SetServerMetadata(string serverId, Metadata metadata, string region = null, CloudIdentity identity = null); + + /// + /// Updates the metadata for the specified server. + /// + /// + /// For each item in , if the key exists, the value is updated; otherwise, the item is added. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The server metadata to update. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the metadata for the server was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values with empty keys. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Update Metadata (OpenStack Compute API v2 and Extensions Reference) + bool UpdateServerMetadata(string serverId, Metadata metadata, string region = null, CloudIdentity identity = null); + + /// + /// Gets the specified metadata item. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The metadata key. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The metadata value for the associated with the server for the specified key. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Get Metadata Item (OpenStack Compute API v2 and Extensions Reference) + string GetServerMetadataItem(string serverId, string key, string region = null, CloudIdentity identity = null); + + /// + /// Sets the value for the specified metadata item. If the key already exists, it is updated; otherwise, a new metadata item is added. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The metadata key. + /// The new value for the metadata item. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the metadata for the server was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Set Metadata Item (OpenStack Compute API v2 and Extensions Reference) + bool SetServerMetadataItem(string serverId, string key, string value, string region = null, CloudIdentity identity = null); + + /// + /// Deletes the specified metadata item from the server. + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The metadata key. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the metadata item was removed; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Metadata Item (OpenStack Compute API v2 and Extensions Reference) + bool DeleteServerMetadataItem(string serverId, string key, string region = null, CloudIdentity identity = null); + + /// + /// Gets the metadata associated with the specified image. + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the metadata associated with the image. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Metadata (OpenStack Compute API v2 and Extensions Reference) + Metadata ListImageMetadata(string imageId, string region = null, CloudIdentity identity = null); + + /// + /// Sets the metadata associated with the specified image, replacing any existing metadata. + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The metadata to associate with the image. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the metadata for the image was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values with empty keys. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Set Metadata (OpenStack Compute API v2 and Extensions Reference) + bool SetImageMetadata(string imageId, Metadata metadata, string region = null, CloudIdentity identity = null); + + /// + /// Updates the metadata for the specified image. + /// + /// + /// For each item in , if the key exists, the value is updated; otherwise, the item is added. + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The image metadata to update. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the metadata for the image was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values with empty keys. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Update Metadata (OpenStack Compute API v2 and Extensions Reference) + bool UpdateImageMetadata(string imageId, Metadata metadata, string region = null, CloudIdentity identity = null); + + /// + /// Gets the specified metadata item. + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The metadata key. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The metadata value for the associated with the image for the specified key. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Get Metadata Item (OpenStack Compute API v2 and Extensions Reference) + string GetImageMetadataItem(string imageId, string key, string region = null, CloudIdentity identity = null); + + /// + /// Sets the value for the specified metadata item. If the key already exists, it is updated; otherwise, a new metadata item is added. + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The metadata key. + /// The new value for the metadata item. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the metadata for the image was successfully updated; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Set Metadata Item (OpenStack Compute API v2 and Extensions Reference) + bool SetImageMetadataItem(string imageId, string key, string value, string region = null, CloudIdentity identity = null); + + /// + /// Deletes the specified metadata item from the image. + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The metadata key. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the metadata item was removed; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Metadata Item (OpenStack Compute API v2 and Extensions Reference) + bool DeleteImageMetadataItem(string imageId, string key, string region = null, CloudIdentity identity = null); + + /// + /// Waits for the server to enter a specified state. + /// + /// + /// + /// This is a blocking operation and will not return until the server enters either the expected state, an error state, or the retry count is exceeded. + /// + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The expected state. + /// The error state(s) in which to throw an exception if the server enters. + /// Number of times to poll the server's status. + /// The time to wait between polling requests for the server status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the server details, including the final . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the method returned due to the server entering one of the . + /// If the REST API request failed. + Server WaitForServerState(string serverId, ServerState expectedState, ServerState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for the server to enter any one of a set of specified states. + /// + /// + /// + /// This is a blocking operation and will not return until the server enters either an expected state, an error state, or the retry count is exceeded. + /// + /// + /// The server ID. This is obtained from ServerBase.Id. + /// The expected state(s). + /// The error state(s) in which to throw an exception if the server enters. + /// Number of times to poll the server's status. + /// The time to wait between polling requests for the server status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the server details, including the final . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the method returned due to the server entering one of the . + /// If the REST API request failed. + Server WaitForServerState(string serverId, ServerState[] expectedStates, ServerState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for the server to enter the state. + /// + /// + /// + /// This is a blocking operation and will not return until the server enters the state, an error state, or the retry count is exceeded. + /// + /// + /// The server ID. This is obtained from ServerBase.Id. + /// Number of times to poll the server's status. + /// The time to wait between polling requests for the server status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the server details, including the final . + /// + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + Server WaitForServerActive(string serverId, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for the server to enter the state or to be removed. + /// + /// + /// + /// This is a blocking operation and will not return until the server enters the state, an error state, or the retry count is exceeded. + /// + /// + /// The server ID. This is obtained from ServerBase.Id. + /// Number of times to poll the server's status. + /// The time to wait between polling requests for the server status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + void WaitForServerDeleted(string serverId, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for the image to enter a specified state. + /// + /// + /// + /// This is a blocking operation and will not return until the image enters either the expected state, an error state, or the retry count is exceeded. + /// + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The expected state. + /// The error state(s) in which to throw an exception if the image enters. + /// Number of times to poll the image's status. + /// The time to wait between polling requests for the image status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the image details, including the final . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the method returned due to the image entering one of the . + /// If the REST API request failed. + ServerImage WaitForImageState(string imageId, ImageState expectedState, ImageState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for the image to enter any one of a set of specified states. + /// + /// + /// + /// This is a blocking operation and will not return until the image enters either an expected state, an error state, or the retry count is exceeded. + /// + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// The expected state(s). + /// The error state(s) in which to throw an exception if the image enters. + /// Number of times to poll the image's status. + /// The time to wait between polling requests for the image status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the image details, including the final . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the method returned due to the image entering one of the . + /// If the REST API request failed. + ServerImage WaitForImageState(string imageId, ImageState[] expectedStates, ImageState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for the image to enter the state. + /// + /// + /// + /// This is a blocking operation and will not return until the image enters either the + /// state, an error state, or the retry count is exceeded. + /// + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// Number of times to poll the image's status. + /// The time to wait between polling requests for the image status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the image details, including the final . + /// + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + ServerImage WaitForImageActive(string imageId, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null); + + /// + /// Waits for the image to enter the state or to be removed. + /// + /// + /// + /// This is a blocking operation and will not return until the image enters either the + /// state, an error state, is removed, or the retry count is exceeded. + /// + /// + /// The image ID. This is obtained from SimpleServerImage.Id. + /// Number of times to poll the image's status. + /// The time to wait between polling requests for the image status. If this value is , the default is 2.4 seconds. + /// A callback delegate to execute each time the value increases. If this value is , progress updates are not reported. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// + /// + /// If is empty. + /// + /// + /// If is less than 0. + /// -or- + /// If is negative. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + void WaitForImageDeleted(string imageId, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null); + } +} diff --git a/src/OpenStack/Core/Providers/IIdentityProvider.cs b/src/OpenStack/Core/Providers/IIdentityProvider.cs new file mode 100644 index 000000000..6b543feca --- /dev/null +++ b/src/OpenStack/Core/Providers/IIdentityProvider.cs @@ -0,0 +1,330 @@ +using System; +using System.Collections.Generic; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Providers.Rackspace; +using OpenStack.Authentication; + +namespace net.openstack.Core.Providers +{ + /// + /// Represents a provider for the OpenStack Identity Service. + /// + /// OpenStack Identity Service API v2.0 Reference + public interface IIdentityProvider : IAuthenticationProvider + { + /// + /// Authenticates the user for the specified identity. + /// + /// + /// This method always authenticates to the server, even if an unexpired, cached + /// is available for the specified identity. + /// + /// The identity of the user to authenticate. If this value is , the authentication is performed with the . + /// A object containing the authentication token, service catalog and user data. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed. + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + UserAccess Authenticate(CloudIdentity identity = null); + + /// + /// Validates a given token. + /// + /// The token to be validated. + /// If specified, the validation ensures that the specified tenant is in scope. This is obtained from . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the authentication token and user data. The property of the result may be . + /// If is . + /// If is empty. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If is specified and the token is not valid within the specified tenant. + /// If the authentication request failed or the token does not exist. + /// Validate Token (OpenStack Identity Service API v2.0 Reference) + UserAccess ValidateToken(string token, string tenantId = null, CloudIdentity identity = null); + + /// + /// Gets the authentication token for the specified identity. If necessary, the identity is authenticated + /// on the server to obtain a token. + /// + /// + /// If is and a cached + /// is available for the specified , this method may return the cached + /// value without performing an authentication against the server. If + /// is , this method returns the equivalent of the following statement. + /// + /// provider.Authenticate(). + /// + /// The identity of the user to authenticate. If this value is , the authentication is performed with the . + /// If , the user is always authenticated against the server; otherwise a cached may be returned. + /// The user's authentication token. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed. + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + IdentityToken GetToken(CloudIdentity identity = null, bool forceCacheRefresh = false); + + /// + /// Lists global roles for a specified user. Excludes tenant roles. + /// + /// The user's ID. This is obtained from User.Id. + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// A collection of objects describing the roles for the specified user. + /// If is . + /// If is empty. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// List User Global Roles (OpenStack Identity Service API v2.0 Reference) + IEnumerable GetRolesByUser(string userId, CloudIdentity identity = null); + + /// + /// Lists all users for the account. + /// + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// A collection of objects describing the users for the account. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method using the + /// implementation of . For more information about creating the provider, see + /// . + /// + /// + /// + /// + /// + /// List Users (OpenStack Identity Service API v2.0 Reference) + IEnumerable ListUsers(CloudIdentity identity = null); + + /// + /// Gets the details for the user with the specified username. + /// + /// The username. + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// The details. + /// If is . + /// If is empty. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Get User Information by Name (OpenStack Identity Service API v2.0 Reference) + User GetUserByName(string name, CloudIdentity identity = null); + + /// + /// Gets the details for the user with the specified ID. + /// + /// The user ID. + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// The details. + /// If is . + /// If is empty. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Get User Information by ID (OpenStack Identity Service API v2.0 Reference) + User GetUser(string id, CloudIdentity identity = null); + + /// + /// Adds a user to the account. + /// + /// + /// The returned object will contain the password of the created user. + /// If no is specified in , the returned + /// password will be an automatically generated password from the server. + /// + /// After this call, there is no way to retrieve the password for a user. If the password was + /// auto-generated by the server, make sure to either store the returned value or provide the + /// information to the user for later use. + /// + /// + /// A object containing the details of the user to create. + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// A object containing the details of the created user. + /// If is . + /// If . is or empty. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// + /// If . is not (i.e. represents a user that already exists). + /// -or- + /// If is and no default identity is available for the provider. + /// + /// If a user with the specified already exists. + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method using the + /// implementation of . For more information about creating the provider, see + /// . + /// + /// + /// + /// + /// + /// Add User (OpenStack Identity Service API v2.0 Reference) + NewUser AddUser(NewUser user, CloudIdentity identity = null); + + /// + /// Updates the details for the specified user. + /// + /// + /// The ID of the user to update is specified in .. + /// The other fields of are either to keep the existing values + /// or non-null to specify an updated value. The returned instance contains + /// the complete details of the updated user. + /// + /// The details to update. + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// A object containing the details of the updated user. + /// If is . + /// If . is or empty. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method using the + /// implementation of . For more information about creating the provider, see + /// . + /// + /// + /// + /// + /// + /// Update User (OpenStack Identity Service API v2.0 Reference) + User UpdateUser(User user, CloudIdentity identity = null); + + /// + /// Deletes the specified user from the account. + /// + /// The user ID. This is obtained from or . + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// if the user was successfully deleted; otherwise, . + /// If is . + /// If is empty. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method using the + /// implementation of . For more information about creating the provider, see + /// . + /// + /// + /// + /// + /// + /// Delete User (OpenStack Identity Service API v2.0 Reference) + bool DeleteUser(string userId, CloudIdentity identity = null); + + /// + /// Lists the credentials for the specified user. + /// + /// The user ID. This is obtained from or . + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// List of objects describing the credentials of the specified user. + /// If is . + /// If is empty. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// List Credentials (OpenStack Identity Service API v2.0 Reference) + IEnumerable ListUserCredentials(string userId, CloudIdentity identity = null); + + /// + /// Lists the tenants for the currently authenticated user. + /// + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// List of objects describing the tenants of the currently authenticated user. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// List Tenants (OpenStack Identity Service API v2.0 Reference) + IEnumerable ListTenants(CloudIdentity identity = null); + + /// + /// Gets the user access details, authenticating with the server if necessary. + /// + /// + /// If is and a cached + /// is available for the specified , this method may return the cached + /// value without performing an authentication against the server. If + /// is , this method is equivalent to . + /// + /// The identity of the user to authenticate. If this value is , the authentication is performed with the . + /// If , the user is always authenticated against the server; otherwise a cached may be returned. + /// A object containing the authentication token, service catalog and user data. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + UserAccess GetUserAccess(CloudIdentity identity = null, bool forceCacheRefresh = false); + + /// + /// Gets the specified user credential. + /// + /// The user ID. This is obtained from or . + /// The credential key. + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// The details for the specified credentials type. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Get User Credentials (OpenStack Identity Service API v2.0 Reference) + UserCredential GetUserCredential(string userId, string credentialKey, CloudIdentity identity = null); + + /// + /// Lists the endpoints associated to a given authentication token. + /// + /// The authentication token Id. This is obtained from + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects containing endpoint details. + /// If is . + /// If is empty. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed or the token does not exist. + /// List Token Endpoints (OpenStack Identity Service API v2.0 Reference) + IEnumerable ListEndpoints(string token, CloudIdentity identity = null); + + /// + /// Gets the default to use for requests from this provider. + /// If no default identity is available, the value is . + /// + CloudIdentity DefaultIdentity { get; } + } +} diff --git a/src/OpenStack/Core/Providers/IIdentityService.cs b/src/OpenStack/Core/Providers/IIdentityService.cs new file mode 100644 index 000000000..531eed354 --- /dev/null +++ b/src/OpenStack/Core/Providers/IIdentityService.cs @@ -0,0 +1,68 @@ +namespace net.openstack.Core.Providers +{ + using System; + using System.Threading.Tasks; + using net.openstack.Core.Domain; + using net.openstack.Core.Exceptions.Response; + using CancellationToken = System.Threading.CancellationToken; + + /// + /// Represents a provider for asynchronous operations on the OpenStack Identity Service. + /// + /// OpenStack Identity Service API v2.0 Reference + /// + public interface IIdentityService + { + /// + /// Authenticates the user for the specified identity. + /// + /// + /// This method always authenticates to the server, even if an unexpired, cached + /// is available for the specified identity. + /// + /// The identity of the user to authenticate. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a object containing the authentication token, service catalog and user data. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed. + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + Task AuthenticateAsync(CloudIdentity identity, CancellationToken cancellationToken); + + /// + /// Gets the user access details, authenticating with the server if necessary. + /// + /// + /// If is and a cached + /// is available for the specified , this method may return the cached + /// value without performing an authentication against the server. If + /// is , this method is equivalent to . + /// + /// The identity of the user to authenticate. + /// If , the user is always authenticated against the server; otherwise a cached may be returned. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a object containing the authentication token, service catalog and user data. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + Task GetUserAccessAsync(CloudIdentity identity, bool forceCacheRefresh, CancellationToken cancellationToken); + + /// + /// Gets the authentication token for the specified identity. If necessary, the identity is authenticated + /// on the server to obtain a token. + /// + /// + /// If a cached is available for the specified , + /// this method may return the cached value without performing an authentication against the server. + /// + /// The identity of the user to authenticate. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain the user's authentication token. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed. + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + Task GetTokenAsync(CloudIdentity identity, CancellationToken cancellationToken); + } +} diff --git a/src/OpenStack/Core/Providers/INetworksProvider.cs b/src/OpenStack/Core/Providers/INetworksProvider.cs new file mode 100644 index 000000000..373ef04b5 --- /dev/null +++ b/src/OpenStack/Core/Providers/INetworksProvider.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; + +namespace net.openstack.Core.Providers +{ + /// + /// DEPRECATED. Use or Rackspace.CloudNetworks.v2.CloudNetworkService (from the Rackspace NuGet package). + /// Represents a provider for the OpenStack Networking service. + /// + /// OpenStack Networking API v2.0 Reference + [Obsolete("This will be removed in v2.0. Use OpenStack.Networking.v2.NetworkingService or Rackspace.CloudNetworks.v2.CloudNetworkService (from the Rackspace NuGet package).")] + public interface INetworksProvider + { + /// + /// List the networks configured for the account. + /// + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A list of objects describing the networks for the account. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List Networks (OpenStack Networking API v2.0 Reference) + IEnumerable ListNetworks(string region = null, CloudIdentity identity = null); + + /// + /// Create a network with the given IP block. + /// + /// The IP block from which to allocate the network. For example, 172.16.0.0/24 or 2001:DB8::/64. + /// The name of the new network. For example, my_new_network. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A instance containing details for the newly created network. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not in the correct format. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create Network (OpenStack Networking API v2.0 Reference) + CloudNetwork CreateNetwork(string cidr, string label, string region = null, CloudIdentity identity = null); + + /// + /// Retrieve details for the specified network. + /// + /// ID of the network to retrieve. This is obtained from . + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A instance containing the network details. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show Network (OpenStack Networking API v2.0 Reference) + CloudNetwork ShowNetwork(string networkId, string region = null, CloudIdentity identity = null); + + /// + /// Deletes the specified network. You cannot delete an isolated network unless the network is not attached to any server. + /// + /// ID of the network to delete. This is obtained from . + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the network was successfully deleted; otherwise, . + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Delete Network (OpenStack Networking API v2.0 Reference) + bool DeleteNetwork(string networkId, string region = null, CloudIdentity identity = null); + } +} diff --git a/src/OpenStack/Core/Providers/IObjectStorageProvider.cs b/src/OpenStack/Core/Providers/IObjectStorageProvider.cs new file mode 100644 index 000000000..b5201a913 --- /dev/null +++ b/src/OpenStack/Core/Providers/IObjectStorageProvider.cs @@ -0,0 +1,1639 @@ +using System; +using System.Collections.Generic; +using System.IO; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Providers.Rackspace; +using net.openstack.Providers.Rackspace.Exceptions; + +namespace net.openstack.Core.Providers +{ + /// + /// Represents a provider for the OpenStack Object Storage service. + /// + /// OpenStack Object Storage API v1 Reference + public interface IObjectStorageProvider + { + #region Container + + /// + /// Gets a list of containers stored in the account. + /// + /// The maximum number of containers to return. If the value is , a provider-specific default is used. + /// When specified, only containers with names greater than are returned. If the value is , the list starts at the beginning. + /// When specified, only containers with names less than are returned. If the value is , the list proceeds to the end, or until the is reached. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects containing the details of the specified containers. + /// If is less than or equal to 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show account details and list containers (OpenStack Object Storage API v1 Reference) + IEnumerable ListContainers(int? limit = null, string marker = null, string markerEnd = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Creates a container if it does not already exist. + /// + /// The container name. + /// A collection of custom HTTP headers to associate with the container (see ). + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// This method returns one of the following values. + /// + /// + /// - if the container was created. + /// - if the container was not created because it already exists. + /// + /// + /// If is . + /// + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create container (OpenStack Object Storage API v1 Reference) + ObjectStore CreateContainer(string container, Dictionary headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Deletes a container, and optionally all objects stored in the container. + /// + /// + /// Containers cannot be deleted unless they are empty. The parameter provides + /// a mechanism to combine the deletion of container objects with the deletion of the container itself. + /// + /// The container name. + /// When , all objects in the specified container are deleted before deleting the container. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the container could not be deleted because it was not empty and was . + /// If the specified container does not exist. + /// If the REST API request failed. + /// Delete container (OpenStack Object Storage API v1 Reference) + void DeleteContainer(string container, bool deleteObjects = false, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Gets the non-metadata headers associated with the container. + /// + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The container name. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of non-metadata HTTP headers returned with the container. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show container metadata (OpenStack Object Storage API v1 Reference) + Dictionary GetContainerHeader(string container, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Gets the container metadata. + /// + /// + /// The metadata associated with containers in the Object Storage Service are + /// case-insensitive. + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The container name. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of metadata associated with the container. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show container metadata (OpenStack Object Storage API v1 Reference) + Dictionary GetContainerMetaData(string container, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Gets the container CDN header. + /// + /// + /// + /// This method is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// The container name. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object describing the CDN properties of the container. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + ContainerCDN GetContainerCDNHeader(string container, string region = null, CloudIdentity identity = null); + + /// + /// Gets a list of CDN properties for a group of containers. + /// + /// + /// + /// This method is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// The maximum number of containers to return. If the value is , a provider-specific default is used. + /// When specified, only containers with names greater than are returned. If the value is , the list starts at the beginning. + /// When specified, only containers with names less than are returned. If the value is , the list proceeds to the end, or until the is reached. + /// If set to , the result is filtered to only include CDN-enabled containers. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the CDN properties of the specified containers. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// List CDN-Enabled Containers (Rackspace Cloud Files Developer Guide - API v1) + IEnumerable ListCDNContainers(int? limit = null, string markerId = null, string markerEnd = null, bool cdnEnabled = false, string region = null, CloudIdentity identity = null); + + /// + /// + /// When you CDN-enable a container, all the objects within it become available through the + /// Content Delivery Network (CDN). Similarly, once a container is CDN-enabled, any objects + /// added to it in the storage service become CDN-enabled. + /// + /// + /// + /// This feature is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// CDN-Enable and CDN-Disable a Container (Rackspace Cloud Files Developer Guide - API v1) + /// + /// + /// + /// Enables CDN on the container using the specified TTL and without log retention. + /// + /// + /// If the specified container is already CDN-enabled, this method updates the TTL + /// for the container based on the argument. + /// + /// + /// This method is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The container name. + /// The time (in seconds) to cache objects in the CDN. Each time the object is accessed after the TTL expires, the CDN re-fetches and caches the object for the TTL period. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of HTTP headers included in the response to the REST request. + /// If is . + /// If is empty. + /// If is less than 0. + /// If is not a valid container name. + /// If the provider does not support the specified . + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// CDN-Enable and CDN-Disable a Container (Rackspace Cloud Files Developer Guide - API v1) + Dictionary EnableCDNOnContainer(string container, long timeToLive, string region = null, CloudIdentity identity = null); + + /// + /// Enables CDN on the container using the specified log retention and a provider-specific + /// default TTL. + /// + /// + /// + /// This method is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The container name. + /// to enable log retention on the container; otherwise, . + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// A collection of HTTP headers included in the response to the REST request. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// CDN-Enable and CDN-Disable a Container (Rackspace Cloud Files Developer Guide - API v1) + Dictionary EnableCDNOnContainer(string container, bool logRetention, string region = null, CloudIdentity identity = null); + + /// + /// Enables CDN on the container using the specified TTL and log retention values. + /// + /// + /// + /// This method is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The container. + /// The time (in seconds) to cache objects in the CDN. Each time the object is accessed after the TTL expires, the CDN re-fetches and caches the object for the TTL period. + /// to enable log retention on the container; otherwise, . + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of HTTP headers included in the response to the REST request. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// If is less than 0. + /// If the provider does not support the specified . + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// CDN-Enable and CDN-Disable a Container (Rackspace Cloud Files Developer Guide - API v1) + Dictionary EnableCDNOnContainer(string container, long timeToLive, bool logRetention, string region = null, CloudIdentity identity = null); + + /// + /// Disables CDN on the container. + /// + /// + /// + /// This method is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The container name. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of HTTP headers included in the response to the REST request. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// CDN-Enable and CDN-Disable a Container (Rackspace Cloud Files Developer Guide - API v1) + Dictionary DisableCDNOnContainer(string container, string region = null, CloudIdentity identity = null); + + /// + /// Updates the metadata associated with the container. This method is used to add, update, and + /// remove metadata items associated with a storage container. + /// + /// + /// Each key/value pair in represents an updated metadata item. + /// If the value is or empty, then the metadata item represented by the key is + /// removed if it exists. If a metadata item already exists for the key, its value is updated. + /// Otherwise, a new metadata item is added for the key/value pair. + /// + /// The container name. + /// The account metadata to update. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// -or- + /// If contains a key or value with invalid characters. + /// -or- + /// If contains a key that is or empty. + /// + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// If contains a key or value with characters that are not supported by the implementation. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create, update, or delete container metadata (OpenStack Object Storage API v1 Reference) + void UpdateContainerMetadata(string container, Dictionary metadata, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Deletes multiple metadata items from the container. + /// + /// The container name. + /// The metadata items to delete. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any or empty values. + /// + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// If contains a key with characters that are not supported by the implementation. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create, update, or delete container metadata (OpenStack Object Storage API v1 Reference) + void DeleteContainerMetadata(string container, IEnumerable keys, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Deletes the specified metadata item from the container. + /// + /// The container name. + /// The metadata item to delete. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// If contains a character that is not supported by the implementation. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create, update, or delete container metadata (OpenStack Object Storage API v1 Reference) + void DeleteContainerMetadata(string container, string key, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Sets the CDN headers for the specified container, replacing any existing headers. + /// + /// + /// + /// This method replaces all existing CDN headers for the container with the + /// values found in . + /// + /// + /// + /// This method is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// The container name. + /// The complete set of CDN headers for the container. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the specified container does not exist. + /// If the REST API request failed. + /// Update CDN-Enabled Container Metadata (Rackspace Cloud Files Developer Guide - API v1) + void UpdateContainerCdnHeaders(string container, Dictionary headers, string region = null, CloudIdentity identity = null); + + /// + /// Enables anonymous web access to the static content of the specified container. + /// + /// The container name. + /// The index file to serve when users browse the container, such as index.html. This is the value for the header. + /// The suffix for the file to serve when an error occurs. If the value is error.html and a 404 (not found) error occurs, the file 400error.html will be served to the user. This is the value for the header. + /// The style sheet to use for file listings, such as lists.css. This is the value for the header. + /// to allow users to browse a list of files in the container when no index file is available; otherwise . This is the value for the header. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// + /// If is not a valid object name. + /// -or- + /// If is not a valid object name. + /// -or- + /// If is not a valid object name. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the provider requires containers be CDN-enabled before they can be accessed from the web, and the property is false. + /// If the REST API request failed. + /// Create static website (OpenStack Object Storage API v1 Reference) + void EnableStaticWebOnContainer(string container, string index, string error, string css, bool listing, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Enables anonymous web access to the static content of the specified container. + /// + /// The container name. + /// The index file to serve when users browse the container, such as index.html. This is the value for the header. + /// The suffix for the file to serve when an error occurs. If the value is error.html and a 404 (not found) error occurs, the file 400error.html will be served to the user. This is the value for the header. + /// to allow users to browse a list of files in the container when no index file is available; otherwise . This is the value for the header. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// + /// If is not a valid object name. + /// -or- + /// If is not a valid object name. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the provider requires containers be CDN-enabled before they can be accessed from the web, and the property is false. + /// If the REST API request failed. + /// Create static website (OpenStack Object Storage API v1 Reference) + void EnableStaticWebOnContainer(string container, string index, string error, bool listing, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Enables anonymous web access to the static content of the specified container. + /// + /// The container name. + /// The style sheet to use for file listings, such as lists.css. This is the value for the header. + /// to allow users to browse a list of files in the container when no index file is available; otherwise . This is the value for the header. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the provider requires containers be CDN-enabled before they can be accessed from the web, and the property is false. + /// If the REST API request failed. + /// Create static website (OpenStack Object Storage API v1 Reference) + void EnableStaticWebOnContainer(string container, string css, bool listing, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Enables anonymous web access to the static content of the specified container. + /// + /// The container name. + /// The index file to serve when users browse the container, such as index.html. This is the value for the header. + /// The suffix for the file to serve when an error occurs. If the value is error.html and a 404 (not found) error occurs, the file 400error.html will be served to the user. This is the value for the header. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// + /// If is not a valid object name. + /// -or- + /// If is not a valid object name. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the provider requires containers be CDN-enabled before they can be accessed from the web, and the property is false. + /// If the REST API request failed. + /// Create static website (OpenStack Object Storage API v1 Reference) + void EnableStaticWebOnContainer(string container, string index, string error, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Disables anonymous web access to the static content of the specified container. + /// + /// The container name. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the provider requires containers be CDN-enabled before they can be accessed from the web, and the property is false. + /// If the REST API request failed. + /// Create static website (OpenStack Object Storage API v1 Reference) + void DisableStaticWebOnContainer(string container, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + #endregion + + #region Container Objects + + /// + /// Gets the non-metadata headers for the specified object. + /// + /// + /// This call returns information for the first replicant of the object located in the distributed storage + /// system. If changes were made to the specified object that are not yet fully replicated through the + /// storage system, the results of this call may not match the most recent information uploaded to Object + /// Storage. + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The container name. + /// The object name. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of non-metadata headers associated with the specified object. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// Show object metadata (OpenStack Object Storage API v1 Reference) + Dictionary GetObjectHeaders(string container, string objectName, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Gets the object data. + /// + /// + /// The metadata associated with objects in the Object Storage Service are + /// case-insensitive. + /// + /// + /// This call returns information for the first replicant of the object located in the distributed storage + /// system. If changes were made to the specified object that are not yet fully replicated through the + /// storage system, the results of this call may not match the most recent information uploaded to Object + /// Storage. + /// + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The container name. + /// The object name. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of metadata associated with the object. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// Show object metadata (OpenStack Object Storage API v1 Reference) + Dictionary GetObjectMetaData(string container, string objectName, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Sets the object metadata, replacing any existing metadata values. + /// + /// + /// + /// This method replaces all existing metadata for the object with the values + /// found in . To add or change existing metadata values + /// without affecting all metadata for the object, first call , + /// modify the returned Dictionary<string, string>, + /// then call with the modified metadata dictionary. + /// + /// + /// The container name. + /// The object name. + /// The complete metadata to associate with the object. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create or update object metadata (OpenStack Object Storage API v1 Reference) + void UpdateObjectMetadata(string container, string objectName, Dictionary metadata, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Deletes multiple metadata items from the object. + /// + /// The container name. + /// The object name. + /// The metadata items to delete. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains any or empty values. + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create or update object metadata (OpenStack Object Storage API v1 Reference) + void DeleteObjectMetadata(string container, string objectName, IEnumerable keys, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Deletes the specified metadata item from the object. + /// + /// The container name. + /// The object name. + /// The metadata item to delete. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create or update object metadata (OpenStack Object Storage API v1 Reference) + void DeleteObjectMetadata(string container, string objectName, string key, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Lists the objects in a container. + /// + /// The container name. + /// The maximum number of objects to return. If the value is , a provider-specific default is used. + /// When specified, only objects with names greater than are returned. If the value is , the list starts at the beginning. + /// When specified, only objects with names less than are returned. If the value is , the list proceeds to the end, or until the is reached. + /// Prefix of object names to include + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects containing the details of the specified objects. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method to output the names of all objects in a container + /// using . In the example, the pagination details of this method are handled by the + /// helper method ListAllObjects. + /// + /// + /// + /// + /// + /// Show container details and list objects (OpenStack Object Storage API v1 Reference) + IEnumerable ListObjects(string container, int? limit = null, string marker = null, string markerEnd = null, string prefix = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Creates an object using data from a file. If the destination file already exists, the contents are overwritten. + /// + /// + /// + /// The content type for the object may be specified by providing the argument, + /// or by setting to True in the + /// argument. If neither of these is used, the resulting content type of the object + /// is unspecified. + /// + /// + /// Object metadata can be set at the time the object is created by including the custom metadata items in the + /// argument. Note that unlike the method, the + /// keys of all custom metadata items included as headers must be prefixed with + /// . + /// + /// + /// The container name. + /// The source file path. Example c:\folder1\folder2\image_name.jpeg + /// The destination object name. If , the filename portion of will be used. + /// The content type of the created object. If the value is or empty, the content type of the created object is unspecified. + /// The buffer size to use for copying streaming data. + /// A collection of custom HTTP headers to associate with the object (see ). + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// A callback for progress updates. If the value is , no progress updates are reported. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// If is less than 0. + /// If the file could not be found. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// The following code shows two ways to create an object with custom metadata. The first uses the + /// argument to this method, and the second shows an alternative method of calling after + /// the object is created. + /// + /// + /// + /// Create or replace object (OpenStack Object Storage API v1 Reference) + void CreateObjectFromFile(string container, string filePath, string objectName = null, string contentType = null, int chunkSize = 65536, Dictionary headers = null, string region = null, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Creates an object using data from a . If the destination file already exists, the contents are overwritten. + /// + /// + /// + /// The content type for the object may be specified by providing the argument, + /// or by setting to True in the + /// argument. If neither of these is used, the resulting content type of the object + /// is unspecified. + /// + /// + /// Object metadata can be set at the time the object is created by including the custom metadata items in the + /// argument. Note that unlike the method, the + /// keys of all custom metadata items included as headers must be prefixed with + /// . + /// + /// + /// The container name. + /// A providing the data for the file. + /// The destination object name. Example image_name.jpeg + /// The content type of the created object. If the value is or empty, the content type of the created object is unspecified. + /// The buffer size to use for copying streaming data. + /// A collection of custom HTTP headers to associate with the object (see ). + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// A callback for progress updates. If the value is , no progress updates are reported. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// The following code shows two ways to create an object with custom metadata. The first uses the + /// argument to this method, and the second shows an alternative method of calling after + /// the object is created. + /// + /// + /// + /// Create or replace object (OpenStack Object Storage API v1 Reference) + void CreateObject(string container, Stream stream, string objectName, string contentType = null, int chunkSize = 65536, Dictionary headers = null, string region = null, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Gets an object, writing the data to the specified . + /// + /// + /// This call returns information for the first replicant of the object located in the distributed storage + /// system. If changes were made to the specified object that are not yet fully replicated through the + /// storage system, the results of this call may not match the most recent information uploaded to Object + /// Storage. To force the system to locate the most recent replica instead, set to + /// "True" in the argument. + /// + /// The container name. + /// The source object name. Example image_name.jpeg + /// The output stream. + /// The buffer size to use for copying streaming data. + /// A collection of custom HTTP headers to include with the request. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// If and the object includes an ETag, the retrieved data will be verified before returning. + /// A callback for progress updates. If the value is , no progress updates are reported. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// is , the object is a static or dynamic large object, and the provider implementation does not support verifying ETags for large objects. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If is , the object includes an ETag header, and the downloaded data does not match the ETag header value. + /// If the REST API request failed. + /// + /// Get object content and metadata (OpenStack Object Storage API v1 Reference) + void GetObject(string container, string objectName, Stream outputStream, int chunkSize = 65536, Dictionary headers = null, string region = null, bool verifyEtag = false, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Gets an object, saving the data to the specified file. + /// + /// + /// This call returns information for the first replicant of the object located in the distributed storage + /// system. If changes were made to the specified object that are not yet fully replicated through the + /// storage system, the results of this call may not match the most recent information uploaded to Object + /// Storage. To force the system to locate the most recent replica instead, set to + /// "True" in the argument. + /// + /// The container name. + /// The destination directory name. Example c:\user\ + /// The source object name. Example image_name.jpeg + /// The destination file name. Example image_name1.jpeg + /// The buffer size to use for copying streaming data. + /// A collection of custom HTTP headers to include with the request. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// If and the object includes an ETag, the retrieved data will be verified before returning. + /// A callback for progress updates. If the value is , no progress updates are reported. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// If is less than 0. + /// If the directory could not be found. + /// If an error occurs while writing to the destination file. + /// + /// If the provider does not support the given type. + /// -or- + /// is , the object is a static or dynamic large object, and the provider implementation does not support verifying ETags for large objects. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If is , the object includes an ETag header, and the downloaded data does not match the ETag header value. + /// If the REST API request failed. + /// + /// Get object content and metadata (OpenStack Object Storage API v1 Reference) + void GetObjectSaveToFile(string container, string saveDirectory, string objectName, string fileName = null, int chunkSize = 65536, Dictionary headers = null, string region = null, bool verifyEtag = false, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Copies an object to a new location within the Object Storage provider. + /// + /// The source container name. + /// The source object name. Example image_name.jpeg + /// The destination container name. + /// The destination object name. Example image_name.jpeg + /// The content type of the destination object. If the value is or empty, the content type of the created object is unspecified. + /// A collection of custom HTTP headers to associate with the created object (see ). + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// + /// If is not a valid container name. + /// -or- + /// If is not a valid container name. + /// + /// + /// If is not a valid object name. + /// -or- + /// If is not a valid object name. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Copy object (OpenStack Object Storage API v1 Reference) + void CopyObject(string sourceContainer, string sourceObjectName, string destinationContainer, string destinationObjectName, string destinationContentType = null, Dictionary headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Moves an object to a new location within the Object Storage provider. + /// + /// + /// The original object is removed only if the move is completed successfully. + /// + /// + /// If your specific provider does not provide a "Move Object" API function, this + /// method may be implemented by performing a operation, + /// followed by a operation if the copy completed + /// successfully. + /// + /// + /// The source container name. + /// Name of the source object.Example image_name.jpeg + /// The destination container name. + /// Name of the destination object.Example image_name.jpeg + /// The content type of the destination object. If the value is or empty, the content type of the created object is unspecified. + /// A collection of custom HTTP headers to associate with the object (see ). + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// + /// If is not a valid container name. + /// -or- + /// If is not a valid container name. + /// + /// + /// If is not a valid object name. + /// -or- + /// If is not a valid object name. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Copy object (OpenStack Object Storage API v1 Reference) + /// Delete object (OpenStack Object Storage API v1 Reference) + void MoveObject(string sourceContainer, string sourceObjectName, string destinationContainer, string destinationObjectName, string destinationContentType = null, Dictionary headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Deletes an object from a container. + /// + /// + /// To support large files, the object storage services allows for a single logical file + /// to be split into multiple segments. The parameter + /// provides a way to delete a segmented file as though it were stored as a single object + /// by deleting both the logical file's metadata and the individual segments. The + /// parameter is ignored if the specified object is not + /// a segmented file. + /// + /// The container name. + /// The object name. Example image_name.jpeg + /// A collection of custom HTTP headers to include with the request. + /// Indicates whether the file's segments should be deleted if any exist. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Manifest objects (OpenStack Object Storage API v1 Reference) + /// Delete object (OpenStack Object Storage API v1 Reference) + void DeleteObject(string container, string objectName, Dictionary headers = null, bool deleteSegments = true, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Purges an object from the CDN, sending an email notification to the specified addresses when the object has been purged. + /// + /// The container name. + /// The object name. Example image_name.jpeg + /// The email addresses to notify once the object has been purged. If this value is , no email notifications are sent. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains a null or empty value. + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the specified is not CDN-enabled. + /// If the REST API request failed. + /// Delete CDN-Enabled Object (Rackspace Cloud Files Developer Guide - API v1) + void PurgeObjectFromCDN(string container, string objectName, IEnumerable emails = null, string region = null, CloudIdentity identity = null); + + #endregion + + #region Accounts + + /// + /// Gets the non-metadata headers associated with the specified account. + /// + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of non-metadata headers associated with the account. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show account metadata (OpenStack Object Storage API v1 Reference) + Dictionary GetAccountHeaders(string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Gets the account metadata. + /// + /// + /// The metadata associated with accounts in the Object Storage Service are + /// case-insensitive. + /// + /// + /// The resulting Dictionary<string, string> + /// should use the equality comparer to ensure + /// lookups are not case sensitive. + /// + /// + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of metadata associated with the account. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Show account metadata (OpenStack Object Storage API v1 Reference) + Dictionary GetAccountMetaData(string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + /// + /// Updates the metadata associated with the account. This method is used to add, update, and + /// remove metadata items associated with a storage account. + /// + /// + /// Each key/value pair in represents an updated metadata item. + /// If the value is or empty, then the metadata item represented by the key is + /// removed if it exists. If a metadata item already exists for the key, its value is updated. + /// Otherwise, a new metadata item is added for the key/value pair. + /// + /// The account metadata to update. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// If is . + /// + /// If contains two equivalent keys when compared using . + /// -or- + /// If contains a key or value with invalid characters. + /// -or- + /// If contains a key that is or empty. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// If contains a key or value with characters that are not supported by the implementation. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create, update, or delete account metadata (OpenStack Object Storage API v1 Reference) + void UpdateAccountMetadata(Dictionary metadata, string region = null, bool useInternalUrl = false, CloudIdentity identity = null); + + #endregion + } +} diff --git a/src/OpenStack/Core/Providers/IQueueingService.cs b/src/OpenStack/Core/Providers/IQueueingService.cs new file mode 100644 index 000000000..fe968c624 --- /dev/null +++ b/src/OpenStack/Core/Providers/IQueueingService.cs @@ -0,0 +1,555 @@ +namespace net.openstack.Core.Providers +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.ComponentModel; + using System.Threading.Tasks; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using net.openstack.Core.Domain.Queues; + using Newtonsoft.Json.Linq; + using CancellationToken = System.Threading.CancellationToken; + using CloudQueuesProvider = net.openstack.Providers.Rackspace.CloudQueuesProvider; + using JsonSerializationException = Newtonsoft.Json.JsonSerializationException; + using WebException = System.Net.WebException; + + /// + /// Represents a provider for asynchronous operations on the OpenStack Marconi (Cloud Queues) Service. + /// + /// OpenStack Marconi API v1 Blueprint + /// + public interface IQueueingService + { + #region Base endpoints + + /// + /// Gets the home document describing the operations supported by the service. + /// + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a object describing the operations supported by the service. + /// If the REST request does not return successfully. + /// + /// The following example demonstrates the use of this method using the + /// implementation of the . For more information about creating the provider, see + /// . + /// AsyncAwaitExample + /// + /// + /// + /// TplExample + /// + /// + /// + /// + /// + /// Get Home Document (OpenStack Marconi API v1 Blueprint) + Task GetHomeAsync(CancellationToken cancellationToken); + + /// + /// Checks the queueing service node status. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. If the service + /// is available, the task will complete successfully. If the service is unavailable due + /// to a storage driver failure or some other error, the task will fail and the + /// property will contain the reason for the failure. + /// + /// If the REST request does not return successfully. + /// + /// The following example demonstrates the use of this method using the + /// implementation of the . For more information about creating the provider, see + /// . + /// AsyncAwaitExample + /// + /// + /// + /// TplExample + /// + /// + /// + /// + /// + /// Check Node Health (OpenStack Marconi API v1 Blueprint) + Task GetNodeHealthAsync(CancellationToken cancellationToken); + + #endregion Base endpoints + + #region Queues + + /// + /// Creates a queue, if it does not already exist. + /// + /// The queue name. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain if the queue was created by the call, or if the queue already existed. + /// If is . + /// If the REST request does not return successfully. + /// + /// The following example demonstrates the use of this method using the + /// implementation of the . For more information about creating the provider, see + /// . + /// AsyncAwaitExample + /// + /// + /// + /// TplExample + /// + /// + /// + /// + /// + /// Create Queue (OpenStack Marconi API v1 Blueprint) + Task CreateQueueAsync(QueueName queueName, CancellationToken cancellationToken); + + /// + /// Gets a list of queues. + /// + /// The name of the last queue in the previous list. The resulting collection of queues will start with the first queue after this value, when sorted using . If this value is , the list starts at the beginning. + /// The maximum number of queues to return. If this value is , a provider-specific default value is used. + /// to return detailed information about each queue; otherwise, . + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain placeholder. + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// + /// The following example demonstrates the use of this method using the + /// implementation of the . For more information about creating the provider, see + /// . + /// AsyncAwaitExample + /// + /// + /// + /// TplExample + /// + /// + /// + /// + /// + /// List Queues (OpenStack Marconi API v1 Blueprint) + Task> ListQueuesAsync(QueueName marker, int? limit, bool detailed, CancellationToken cancellationToken); + + /// + /// Checks for the existence of a queue with a particular name. + /// + /// The queue name. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain if queue with the specified name exists; otherwise, . + /// If is . + /// If the REST request does not return successfully. + /// + /// The following example demonstrates the use of this method using the + /// implementation of the . For more information about creating the provider, see + /// . + /// AsyncAwaitExample + /// + /// + /// + /// TplExample + /// + /// + /// + /// + /// + /// Checking Queue Existence (OpenStack Marconi API v1 Blueprint) + Task QueueExistsAsync(QueueName queueName, CancellationToken cancellationToken); + + /// + /// Deletes a queue. + /// + /// + /// The queue will be deleted whether or not it is empty, even if one or more messages in the queue is currently claimed. + /// + /// The queue name. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// + /// The following example demonstrates the use of this method using the + /// implementation of the . For more information about creating the provider, see + /// . + /// AsyncAwaitExample + /// + /// + /// + /// TplExample + /// + /// + /// + /// + /// + /// Delete Queue (OpenStack Marconi API v1 Blueprint) + Task DeleteQueueAsync(QueueName queueName, CancellationToken cancellationToken); + + #endregion + + #region Queue metadata + + /// + /// Sets the metadata associated with a queue. + /// + /// The type of data to associate with the queue. + /// The queue name. + /// The metadata to associate with the queue. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Set Queue Metadata (OpenStack Marconi API v1 Blueprint) + Task SetQueueMetadataAsync(QueueName queueName, T metadata, CancellationToken cancellationToken) + where T : class; + + /// + /// Gets the metadata associated with a queue. + /// + /// The queue name. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a object containing the metadata associated with the queue. + /// If is . + /// If the REST request does not return successfully. + /// Get Queue Metadata (OpenStack Marconi API v1 Blueprint) + Task GetQueueMetadataAsync(QueueName queueName, CancellationToken cancellationToken); + + /// + /// Gets the metadata associated with a queue, as a strongly-typed object. + /// + /// The type of metadata associated with the queue. + /// The queue name. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a deserialized object of type representing the metadata associated with the queue. + /// If is . + /// If an error occurs while deserializing the metadata. + /// If the REST request does not return successfully. + /// Get Queue Metadata (OpenStack Marconi API v1 Blueprint) + Task GetQueueMetadataAsync(QueueName queueName, CancellationToken cancellationToken) + where T : class; + + /// + /// Gets statistics for a queue. + /// + /// The queue name. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a object containing statistics for the queue. + /// If is . + /// If the REST request does not return successfully. + /// Get Queue Stats (OpenStack Marconi API v1 Blueprint) + Task GetQueueStatisticsAsync(QueueName queueName, CancellationToken cancellationToken); + + #endregion Queue metadata + + #region Messages + + /// + /// Gets a list of messages currently in a queue. + /// + /// The queue name. + /// The identifier of the message list page to return. This is obtained from . If this value is , the list starts at the beginning. + /// The maximum number of messages to return. If this value is , a provider-specific default value is used. + /// to include messages created by the current client; otherwise, . + /// to include claimed messages; otherwise to return only unclaimed messages. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a collection of objects describing the messages in the queue. + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Messages (OpenStack Marconi API v1 Blueprint) + Task ListMessagesAsync(QueueName queueName, QueuedMessageListId marker, int? limit, bool echo, bool includeClaimed, CancellationToken cancellationToken); + + /// + /// Gets detailed information about a specific queued message. + /// + /// + /// This method will return information for the specified message regardless of the + /// Client-ID or claim associated with the message. + /// + /// The queue name. + /// The message ID. This is obtained from QueuedMessage.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a object containing detailed information about the specified message. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get a Specific Message (OpenStack Marconi API v1 Blueprint) + Task GetMessageAsync(QueueName queueName, MessageId messageId, CancellationToken cancellationToken); + + /// + /// Get messages from a queue. + /// + /// + /// This method will return information for the specified message regardless of the + /// Client-ID or claim associated with the message. + /// + /// The queue name. + /// The message IDs of messages to get. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a collection of objects containing detailed information about the specified messages. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Get a Set of Messages by ID (OpenStack Marconi API v1 Blueprint) + Task> GetMessagesAsync(QueueName queueName, IEnumerable messageIds, CancellationToken cancellationToken); + + /// + /// Posts messages to a queue. + /// + /// + /// If is empty, this call is equivalent to , + /// and the property of the returned task contains + /// . + /// + /// The queue name. + /// The messages to post. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes + /// successfully, the property will contain a + /// object representing the result of the operation. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + Task PostMessagesAsync(QueueName queueName, IEnumerable messages, CancellationToken cancellationToken); + + /// + /// Posts messages to a queue. + /// + /// + /// If is empty, this call is equivalent to , + /// and upon success the property of the returned task contains + /// . + /// + /// The queue name. + /// The that the task will observe. + /// The messages to post. + /// + /// A object representing the asynchronous operation. When the task completes + /// successfully, the property will contain a + /// object representing the result of the operation. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + Task PostMessagesAsync(QueueName queueName, CancellationToken cancellationToken, params Message[] messages); + + /// + /// Posts messages to a queue. + /// + /// + /// If is empty, this call is equivalent to , + /// and the property of the returned task contains + /// . + /// + /// The class modeling the JSON representation of the messages to post in the queue. + /// The queue name. + /// The messages to post. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes + /// successfully, the property will contain a + /// object representing the result of the operation. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + Task PostMessagesAsync(QueueName queueName, IEnumerable> messages, CancellationToken cancellationToken); + + /// + /// Posts messages to a queue. + /// + /// + /// If is empty, this call is equivalent to , + /// and upon success the property of the returned task contains + /// . + /// + /// The class modeling the JSON representation of the messages to post in the queue. + /// The queue name. + /// The that the task will observe. + /// The messages to post. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + Task PostMessagesAsync(QueueName queueName, CancellationToken cancellationToken, params Message[] messages); + + /// + /// Deletes a message from a queue. + /// + /// The queue name. + /// The ID of the message to delete. This is obtained from QueuedMessage.Id. + /// The claim for the message. If this value is , the delete operation will fail if the message is claimed. If this value is non-, the delete operation will fail if the message is not claimed by the specified claim. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete Message (OpenStack Marconi API v1 Blueprint) + Task DeleteMessageAsync(QueueName queueName, MessageId messageId, Claim claim, CancellationToken cancellationToken); + + /// + /// Deletes messages from a queue. + /// + /// + /// + /// This method deletes messages from a queue whether or not they are currently claimed. + /// + /// + /// The queue name. + /// The IDs of messages to delete. These are obtained from QueuedMessage.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Delete a Set of Messages by ID (OpenStack Marconi API v1 Blueprint) + Task DeleteMessagesAsync(QueueName queueName, IEnumerable messageIds, CancellationToken cancellationToken); + + #endregion Messages + + #region Claims + + /// + /// Claim messages from a queue. + /// + /// + /// When the claim is no longer required, the code should call + /// or to ensure the following actions are taken. + /// + /// Messages which are part of this claim which were not processed are made available to other nodes. + /// The claim resource is cleaned up without waiting for the time-to-live to expire. + /// + /// + /// Messages which are not deleted before the claim is released will be eligible for + /// reclaiming by another process. + /// + /// The queue name. + /// The maximum number of messages to claim. If this value is , a provider-specific default value is used. + /// The time to wait before the server automatically releases the claim. + /// The time to wait, after the time-to-live for the claim expires, before the server allows the claimed messages to be deleted due to the individual message's time-to-live expiring. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain object representing the claim. + /// If is . + /// + /// If is less than or equal to 0. + /// -or- + /// If is negative or . + /// -or- + /// If is negative. + /// + /// If the REST request does not return successfully. + /// Claim Messages (OpenStack Marconi API v1 Blueprint) + Task ClaimMessageAsync(QueueName queueName, int? limit, TimeSpan timeToLive, TimeSpan gracePeriod, CancellationToken cancellationToken); + + /// + /// Gets detailed information about the current state of a claim. + /// + /// + /// Use instead of calling this method directly. + /// + /// The queue name. + /// The claim to query. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will contain a object representing the claim. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Query Claim (OpenStack Marconi API v1 Blueprint) + [EditorBrowsable(EditorBrowsableState.Never)] + Task QueryClaimAsync(QueueName queueName, Claim claim, CancellationToken cancellationToken); + + /// + /// Renews a claim, by updating the time-to-live and resetting the age of the claim to zero. + /// + /// + /// Use instead of calling this method directly. + /// + /// The queue name. + /// The claim to renew. + /// The updated time-to-live for the claim. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is negative. + /// If the REST request does not return successfully. + /// Update Claim (OpenStack Marconi API v1 Blueprint) + [EditorBrowsable(EditorBrowsableState.Never)] + Task UpdateClaimAsync(QueueName queueName, Claim claim, TimeSpan timeToLive, CancellationToken cancellationToken); + + /// + /// Immediately release a claim, making any (remaining, non-deleted) messages associated + /// with the claim available to other workers. + /// + /// + /// Use instead of calling this method directly. + /// + /// The queue name. + /// The claim to release. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Release Claim (OpenStack Marconi API v1 Blueprint) + [EditorBrowsable(EditorBrowsableState.Never)] + Task ReleaseClaimAsync(QueueName queueName, Claim claim, CancellationToken cancellationToken); + + #endregion + } +} diff --git a/src/OpenStack/Core/Providers/NamespaceDoc.cs b/src/OpenStack/Core/Providers/NamespaceDoc.cs new file mode 100644 index 000000000..10b3a07bf --- /dev/null +++ b/src/OpenStack/Core/Providers/NamespaceDoc.cs @@ -0,0 +1,15 @@ +namespace net.openstack.Core.Providers +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines providers + /// interfaces for OpenStack services. These interfaces may expose optional + /// functionality and service extensions documented at OpenStack. Other + /// provider-specific extensions are included under the specific provider. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Providers/OpenStackIdentityProvider.cs b/src/OpenStack/Core/Providers/OpenStackIdentityProvider.cs new file mode 100644 index 000000000..ee08b700d --- /dev/null +++ b/src/OpenStack/Core/Providers/OpenStackIdentityProvider.cs @@ -0,0 +1,136 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack; +using OpenStack.Authentication; + +namespace net.openstack.Core.Providers +{ + using System; + using net.openstack.Core.Caching; + using net.openstack.Core.Domain; + using net.openstack.Providers.Rackspace; + using Newtonsoft.Json.Linq; + using HttpMethod = JSIStudios.SimpleRESTServices.Client.HttpMethod; + using IRestService = JSIStudios.SimpleRESTServices.Client.IRestService; + using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices; + + /// + /// This class extends the functionality of by + /// supporting identity objects. These + /// identities may include values for the tenantName and tenantId + /// properties, which may be required for authentication with certain + /// OpenStack-compatible service providers. + /// + /// + /// + public class OpenStackIdentityProvider : CloudIdentityProvider + { + /// + /// Initializes a new instance of the class + /// with no default identity, the specified base URL, and the default REST service + /// implementation and token cache. + /// + /// The base URL for the cloud instance. + /// If is . + public OpenStackIdentityProvider(Uri urlBase) + : this(urlBase, null, null, null) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified default identity and base URL, and the default REST service + /// implementation and token cache. + /// + /// The base URL for the cloud instance. + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// If is . + public OpenStackIdentityProvider(Uri urlBase, CloudIdentity defaultIdentity) + : this(urlBase, defaultIdentity, null, null) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, and the specified base URL, REST service + /// implementation, and token cache. + /// + /// The base URL for the cloud instance. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + /// If is . + public OpenStackIdentityProvider(Uri urlBase, IRestService restService, ICache tokenCache) + : this(urlBase, null, restService, tokenCache) + { + } + + /// + /// Initializes a new instance of the class + /// using the provided values. + /// + /// The base URL for the cloud instance. + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + /// If is . + public OpenStackIdentityProvider(Uri urlBase, CloudIdentity defaultIdentity, IRestService restService, ICache tokenCache) + : base(defaultIdentity, restService, tokenCache, urlBase) + { + if (urlBase == null) + throw new ArgumentNullException("urlBase"); + } + + /// + public override UserAccess GetUserAccess(CloudIdentity identity, bool forceCacheRefresh = false) + { + identity = identity ?? DefaultIdentity; + + CloudIdentityWithProject identityWithProject = identity as CloudIdentityWithProject; + if (identityWithProject == null) + return base.GetUserAccess(identityWithProject, forceCacheRefresh); + + if (string.IsNullOrEmpty(identityWithProject.Password)) + throw new NotSupportedException(string.Format("The {0} identity must specify a password.", typeof(CloudIdentityWithProject))); + if (!string.IsNullOrEmpty(identityWithProject.APIKey)) + throw new NotSupportedException(string.Format("The {0} identity does not support API key authentication.", typeof(CloudIdentityWithProject))); + + Func refreshCallback = + () => + { + var projectId = identityWithProject.ProjectId != null ? JToken.FromObject(identityWithProject.ProjectId) : string.Empty; + JObject requestBody = new JObject( + new JProperty("auth", new JObject( + new JProperty("passwordCredentials", new JObject( + new JProperty("username", JValue.CreateString(identityWithProject.Username)), + new JProperty("password", JValue.CreateString(identityWithProject.Password)))), + new JProperty("tenantName", JToken.FromObject(identityWithProject.ProjectName)), + new JProperty("tenantId", projectId)))); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "/v2.0/tokens"), HttpMethod.POST, requestBody, isTokenRequest: true); + if (response == null || response.Data == null) + return null; + + // The defalut json serialization is helpfully formatting the expires date string. Use our custom serializer for this part to prevent chaos of timezone proportions. + var rawJson = response.Data["access"]?.ToString(Formatting.None); + if (rawJson == null) + return null; + + UserAccess access = OpenStackNet.Deserialize(rawJson); + if (access == null || access.Token == null) + return null; + + return access; + }; + string key = string.Format("{0}:{1}/{2}", UrlBase, identityWithProject.ProjectId, identityWithProject.Username); + var userAccess = TokenCache.Get(key, refreshCallback, forceCacheRefresh); + + return userAccess; + } + + /// + protected override string LookupServiceTypeKey(IServiceType serviceType) + { + return serviceType.Type; + } + } +} diff --git a/src/OpenStack/Core/ReadOnlyCollectionPageExtensions.cs b/src/OpenStack/Core/ReadOnlyCollectionPageExtensions.cs new file mode 100644 index 000000000..1aa3640b5 --- /dev/null +++ b/src/OpenStack/Core/ReadOnlyCollectionPageExtensions.cs @@ -0,0 +1,104 @@ +namespace net.openstack.Core +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Threading; + using System.Threading.Tasks; + using net.openstack.Core.Collections; + + /// + /// This class provides extension methods for the class. + /// + /// + /// + public static class ReadOnlyCollectionPageExtensions + { + /// + /// Get all pages in a paginated collection. + /// + /// + /// If is non-, the first call to + /// will specify the + /// argument. After each task to obtain to the next page of results completes, + /// the method will be called again with the + /// new page of results. + /// + /// This method determines that the end of the collection is reached when either of + /// the following conditions is true. + /// + /// + /// The property returns . + /// An empty page is reached. + /// + /// + /// The type of elements in the collection. + /// The first page in the collection. + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// read-only collection containing the complete set of results from the paginated collection. + /// + /// If is . + public static Task> GetAllPagesAsync(this ReadOnlyCollectionPage page, CancellationToken cancellationToken, IProgress> progress) + { + if (page == null) + throw new ArgumentNullException("page"); + + if (progress != null) + progress.Report(page); + + if (!page.CanHaveNextPage || page.Count == 0) + { + return InternalTaskExtensions.CompletedTask>(page); + } + + TaskCompletionSource> taskCompletionSource = new TaskCompletionSource>(); + + List result = new List(page); + ReadOnlyCollectionPage currentPage = page; + Func>> getNextPage = () => currentPage.GetNextPageAsync(cancellationToken); + Task> currentTask = getNextPage(); + Action>> continuation = null; + continuation = + previousTask => + { + if (previousTask.Status != TaskStatus.RanToCompletion) + { + taskCompletionSource.SetFromTask(previousTask); + return; + } + + currentPage = previousTask.Result; + if (currentPage == null) + { + // TODO: should we throw an exception instead? + taskCompletionSource.SetResult(result.AsReadOnly()); + return; + } + + if (progress != null) + progress.Report(currentPage); + + result.AddRange(currentPage); + if (!currentPage.CanHaveNextPage || currentPage.Count == 0) + { + taskCompletionSource.SetResult(result.AsReadOnly()); + return; + } + + // continue with the next page + currentTask = getNextPage(); + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + }; + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + + + return taskCompletionSource.Task; + } + } +} diff --git a/src/OpenStack/Core/ResourceIdentifier`1.cs b/src/OpenStack/Core/ResourceIdentifier`1.cs new file mode 100644 index 000000000..0afc09715 --- /dev/null +++ b/src/OpenStack/Core/ResourceIdentifier`1.cs @@ -0,0 +1,155 @@ +namespace net.openstack.Core +{ + using System; + using net.openstack.Core.Domain.Converters; + + /// + /// Represents a unique identifier within the context of a cloud services provider. + /// + /// The resource identifier type. + /// + /// + public abstract class ResourceIdentifier : IEquatable + where T : ResourceIdentifier + { + /// + /// This is the backing field for the property. + /// + private readonly string _id; + + /// + /// Initializes a new instance of the class + /// with the specified identifier. + /// + /// The resource identifier value. + /// If is . + /// If is empty. + protected ResourceIdentifier(string id) + { + if (id == null) + throw new ArgumentNullException("id"); + if (string.IsNullOrEmpty(id)) + throw new ArgumentException("id cannot be empty"); + + _id = id; + } + + /// + /// Determines whether two specified resource identifiers have the same value. + /// + /// The first resource identifier to compare, or . + /// The second resource identifier to compare, or . + /// if the value of is the same as the value of ; otherwise, . + public static bool operator ==(ResourceIdentifier left, ResourceIdentifier right) + { + if (object.ReferenceEquals(left, null)) + return object.ReferenceEquals(right, null); + else if (object.ReferenceEquals(right, null)) + return false; + + return left.Equals(right); + } + + /// + /// Determines whether two specified resource identifiers have different values. + /// + /// The first resource identifier to compare, or . + /// The second resource identifier to compare, or . + /// if the value of is different from the value of ; otherwise, . + public static bool operator !=(ResourceIdentifier left, ResourceIdentifier right) + { + return !(left == right); + } + + /// + /// Gets the value of this resource identifier. + /// + public string Value + { + get + { + return _id; + } + } + + /// + /// + /// The default implementation uses to compare + /// the property of two identifiers. + /// + /// + /// This method may be overridden to change the way unique identifiers are compared. + /// + /// + public virtual bool Equals(T other) + { + if (object.ReferenceEquals(other, null)) + return false; + + return StringComparer.Ordinal.Equals(_id, other._id); + } + + /// + public override bool Equals(object obj) + { + return this.Equals(obj as T); + } + + /// + /// + /// The default implementation uses to calculate + /// and return a hash code from the property. + /// + /// + /// This method may be overridden to change the way unique identifiers are compared. + /// + /// + public override int GetHashCode() + { + return StringComparer.Ordinal.GetHashCode(_id); + } + + /// + public override string ToString() + { + return _id; + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + protected abstract class ConverterBase : SimpleStringJsonConverter + { + /// + /// This method uses for serialization. + /// + /// + protected override string ConvertToString(T obj) + { + return obj.Value; + } + + /// + /// If is or an empty string, this method returns . + /// Otherwise, this method uses for deserialization. + /// + /// + protected override T ConvertToObject(string str) + { + if (string.IsNullOrEmpty(str)) + return null; + + return FromValue(str); + } + + /// + /// Creates a resource identifier with the given value. + /// + /// The resource identifier value. This value is never or empty. + /// An instance of corresponding representing the specified . + protected abstract T FromValue(string id); + } + } +} diff --git a/src/OpenStack/Core/ResponseExtensions.cs b/src/OpenStack/Core/ResponseExtensions.cs new file mode 100644 index 000000000..6c191e88e --- /dev/null +++ b/src/OpenStack/Core/ResponseExtensions.cs @@ -0,0 +1,85 @@ +namespace net.openstack.Core +{ + using System; + using System.Linq; + using System.Net; + using JSIStudios.SimpleRESTServices.Client; + using JSIStudios.SimpleRESTServices.Client.Json; + + /// + /// Contains extension methods to the class. + /// + /// + internal static class ResponseExtensions + { + /// + /// The content type used for standard JSON requests and responses. + /// + private static readonly string JsonContentType = new JsonRequestSettings().ContentType; + + /// + /// Retrieves a standard HTTP response header from a REST response, if available. + /// + /// The REST response. + /// The header to retrieve. + /// Returns the value for . + /// if the specified header is contained in , otherwise . + /// is . + public static bool TryGetHeader(this Response response, HttpResponseHeader header, out string value) + { + if (response == null) + throw new ArgumentNullException("response"); + + if (response.Headers == null) + { + value = null; + return false; + } + + WebHeaderCollection collection = new RestWebHeaderCollection(response.Headers); + value = collection[header]; + return value != null; + } + + /// + /// Retrieves a custom HTTP response header from a REST response, if available. + /// + /// The REST response. + /// The header to retrieve. + /// Returns the value for . + /// if the specified header is contained in , otherwise . + /// is . + public static bool TryGetHeader(this Response response, string header, out string value) + { + HttpHeader httpHeader = response.Headers.FirstOrDefault(i => string.Equals(i.Key, header, StringComparison.OrdinalIgnoreCase)); + value = httpHeader != null ? httpHeader.Value : null; + return value != null; + } + + /// + /// This method checks if a REST contains a JSON-formatted body. + /// The response is assumed to be JSON if the content type is reported as application/json + /// and the body is not empty. + /// + /// The REST response. + /// if contains a JSON response body, otherwise . + public static bool HasJsonBody(this Response response) + { + if (response == null) + throw new ArgumentNullException("response"); + + string contentTypeHeader; + if (response.TryGetHeader(HttpResponseHeader.ContentType, out contentTypeHeader)) + { + // ignore optional parameters when checking the content type + string contentType = contentTypeHeader.Split(';')[0].Trim(); + if (string.Equals(contentType, JsonContentType, StringComparison.OrdinalIgnoreCase)) + { + return !string.IsNullOrEmpty(response.RawBody); + } + } + + return false; + } + } +} diff --git a/src/OpenStack/Core/RestWebHeaderCollection.cs b/src/OpenStack/Core/RestWebHeaderCollection.cs new file mode 100644 index 000000000..797526e31 --- /dev/null +++ b/src/OpenStack/Core/RestWebHeaderCollection.cs @@ -0,0 +1,83 @@ +namespace net.openstack.Core +{ + using System; + using System.Collections.Generic; + using System.Net; + using System.Runtime.Serialization; + using JSIStudios.SimpleRESTServices.Client; + + /// + /// Contains protocol headers associated with a REST request or response. + /// + /// + /// This collection does restrict headers which are exposed through properties, + /// allowing users to explicitly construct a complete set of headers. + /// + /// + [Serializable] + public class RestWebHeaderCollection : WebHeaderCollection + { + /// + /// Initializes a new instance of the class. + /// + public RestWebHeaderCollection() + { + } + + /// + /// Initializes a new instance of the class from + /// the specified headers. + /// + /// The headers to initially add to this collection. + /// + /// A header name is , , or contains invalid characters. + /// -or- + /// A header value contains invalid characters. + /// + /// A header contains a value longer than 65535 characters. + public RestWebHeaderCollection(IEnumerable headers) + { + foreach (HttpHeader header in headers) + Add(header.Key, header.Value); + } + + /// + /// Initializes a new instance of the class from the specified + /// instances of the and classes. + /// + /// A containing the information required to serialize the . + /// A containing the source of the serialized stream associated with the new . + /// + /// This constructor implements the interface for the class. + /// + /// If a serialized header name contains invalid characters. + /// If a serialized header name is a null reference or . + protected RestWebHeaderCollection(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Inserts a header with the specified name and value into the collection. + /// + /// + /// If the header specified in does not exist, the method + /// inserts a new header into the list of header name/value pairs. + /// + /// If the header specified in is already present, + /// is added to the existing comma-separated list of values associated with . + /// + /// The header to add to the collection. + /// The content of the header. + /// + /// A is , , or contains invalid characters. + /// -or- + /// A contains invalid characters. + /// + /// The length of is greater than 65535. + public override void Add(string name, string value) + { + AddWithoutValidate(name, value); + } + } +} diff --git a/src/OpenStack/Core/Synchronous/AutoScaleServiceExtensions.cs b/src/OpenStack/Core/Synchronous/AutoScaleServiceExtensions.cs new file mode 100644 index 000000000..6c64062f4 --- /dev/null +++ b/src/OpenStack/Core/Synchronous/AutoScaleServiceExtensions.cs @@ -0,0 +1,816 @@ +namespace net.openstack.Core.Synchronous +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using System.Threading; + using net.openstack.Core.Collections; + using net.openstack.Providers.Rackspace; + using net.openstack.Providers.Rackspace.Objects.AutoScale; + + /// + /// Provides extension methods to allow synchronous calls to the methods in . + /// + /// + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static class AutoScaleServiceExtensions + { + #region Groups + + /// + /// Gets a collection of scaling groups. + /// + /// The Auto Scale service instance. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// A collection of objects describing the current scaling groups. + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List scaling groups (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListScalingGroups(this IAutoScaleService service, ScalingGroupId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListScalingGroupsAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Create a new scaling group. + /// + /// The Auto Scale service instance. + /// A object describing the scaling group configuration. + /// A object describing the newly created scaling group. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create group (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ScalingGroup CreateGroup(this IAutoScaleService service, ScalingGroupConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateGroupAsync(configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get detailed information about a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// A object describing the scaling group. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Show scaling group details (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ScalingGroup GetGroup(this IAutoScaleService service, ScalingGroupId groupId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetGroupAsync(groupId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// to delete the scaling group even if it has active or pending entities; otherwise, to only delete the group if it does not contain any entities. If the value is , a provider-specific default value is used. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Delete scaling group (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void DeleteGroup(this IAutoScaleService service, ScalingGroupId groupId, bool? force) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.DeleteGroupAsync(groupId, force, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get information about the current state of a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// A object describing the current state of the scaling group. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get scaling group state (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static GroupState GetGroupState(this IAutoScaleService service, ScalingGroupId groupId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetGroupStateAsync(groupId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Suspend the execution of scaling policies for a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Pause group policy execution (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void PauseGroup(this IAutoScaleService service, ScalingGroupId groupId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.PauseGroupAsync(groupId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Resume the execution of scaling policies for a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Resume group policy execution (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void ResumeGroup(this IAutoScaleService service, ScalingGroupId groupId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.ResumeGroupAsync(groupId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Groups + + #region Configurations + + /// + /// Get the group configuration for a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// A object describing the group configuration of the scaling group. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Show scaling group configuration (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static GroupConfiguration GetGroupConfiguration(this IAutoScaleService service, ScalingGroupId groupId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetGroupConfigurationAsync(groupId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Set the group configuration for a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The new group configuration for the scaling group. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update scaling group configuration (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetGroupConfiguration(this IAutoScaleService service, ScalingGroupId groupId, GroupConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetGroupConfigurationAsync(groupId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get the launch configuration for a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// A object describing the launch configuration of the scaling group. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Show launch configuration (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static LaunchConfiguration GetLaunchConfiguration(this IAutoScaleService service, ScalingGroupId groupId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetLaunchConfigurationAsync(groupId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Set the launch configuration for a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The new launch configuration for the scaling group. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update launch configuration (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetLaunchConfiguration(this IAutoScaleService service, ScalingGroupId groupId, LaunchConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetLaunchConfigurationAsync(groupId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Configurations + + #region Policies + + /// + /// Gets a collection of scaling policies for a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// A collection of objects describing the scaling policies for the scaling group. + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List policies (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListPolicies(this IAutoScaleService service, ScalingGroupId groupId, PolicyId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListPoliciesAsync(groupId, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Create a new scaling policy for a scaling group. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// A object describing the scaling policy configuration. + /// A object describing the newly created scaling policy. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create policy (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Policy CreatePolicy(this IAutoScaleService service, ScalingGroupId groupId, PolicyConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreatePolicyAsync(groupId, configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get detailed information about a scaling policy. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// A object describing the scaling policy. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Show policy details (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Policy GetPolicy(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetPolicyAsync(groupId, policyId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Replace the configuration for a scaling policy. + /// + /// + /// This method can be used to replace the behavior associated with webhooks which + /// have already in use by applications. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// A object describing the new scaling policy configuration. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Replace policy (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetPolicy(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId, PolicyConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetPolicyAsync(groupId, policyId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a scaling policy. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete policy (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void DeletePolicy(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.DeletePolicyAsync(groupId, policyId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Execute a scaling policy. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Execute policy (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void ExecutePolicy(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.ExecutePolicyAsync(groupId, policyId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Policies + + #region Webhooks + + /// + /// Gets a collection of webhooks which trigger the execution of a particular + /// scaling policy. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// A collection of objects describing the webhooks for the scaling policy. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List webhooks for the policy (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListWebhooks(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId, WebhookId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListWebhooksAsync(groupId, policyId, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Create a webhook capable of anonymously executing a scaling policy. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// A object describing the webhook configuration. + /// A object describing the newly created webhook. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create a webhook (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Webhook CreateWebhook(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId, NewWebhookConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateWebhookAsync(groupId, policyId, configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Create a collection of webhooks capable of anonymously executing a scaling policy. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// A collection of objects describing the webhook configurations. + /// A collection of objects describing the newly created webhooks. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If contains any values. + /// If the REST request does not return successfully. + /// Create a webhook (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection CreateWebhookRange(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId, IEnumerable configurations) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateWebhookRangeAsync(groupId, policyId, configurations, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get detailed information about a webhook associated with a scaling policy. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The ID of the webhook. This is obtained from Webhook.Id. + /// A object describing the webhook. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Show webhook details (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Webhook GetWebhook(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetWebhookAsync(groupId, policyId, webhookId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Update the configuration for a webhook. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The ID of the webhook. This is obtained from Webhook.Id. + /// An object containing the updated configuration for the webhook. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update webhook (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateWebhook(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId, UpdateWebhookConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateWebhookAsync(groupId, policyId, webhookId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a webhook associated with a scaling policy. + /// + /// The Auto Scale service instance. + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The ID of the webhook. This is obtained from Webhook.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete webhook (Rackspace Auto Scale Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void DeleteWebhook(this IAutoScaleService service, ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.DeleteWebhookAsync(groupId, policyId, webhookId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Webhooks + } +} diff --git a/src/OpenStack/Core/Synchronous/ClaimExtensions.cs b/src/OpenStack/Core/Synchronous/ClaimExtensions.cs new file mode 100644 index 000000000..ab11ea884 --- /dev/null +++ b/src/OpenStack/Core/Synchronous/ClaimExtensions.cs @@ -0,0 +1,86 @@ +namespace net.openstack.Core.Synchronous +{ + using System; + using System.Collections.ObjectModel; + using net.openstack.Core.Domain; + using net.openstack.Core.Domain.Queues; + using CancellationToken = System.Threading.CancellationToken; + using IQueueingService = net.openstack.Core.Providers.IQueueingService; + using WebException = System.Net.WebException; + + /// + /// Provides extension methods to allow synchronous calls to the methods in . + /// + /// + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static class ClaimExtensions + { + /// + /// Refreshes the current claim. + /// + /// + /// This method calls to obtain updated + /// information about the current claim, and then synchronously invokes + /// to update the current instance to match the results. + /// + /// The claim. + /// If is . + /// If the REST request does not return successfully. + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void Refresh(this Claim claim) + { + if (claim == null) + throw new ArgumentNullException("claim"); + + try + { + claim.RefreshAsync(CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Renews the claim by resetting the age and updating the TTL for the claim. + /// + /// + /// This method calls to renew the + /// current claim, and then synchronously updates the current instance to reflect + /// the new age and time-to-live values. + /// + /// The claim. + /// + /// The new Time-To-Live value for the claim. This value may differ from the original TTL of the claim. + /// + /// If is . + /// If is negative or . + /// If the claim is empty (i.e. is empty). + /// If the REST request does not return successfully. + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void Renew(this Claim claim, TimeSpan timeToLive) + { + if (claim == null) + throw new ArgumentNullException("claim"); + + try + { + claim.RenewAsync(timeToLive, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + } +} diff --git a/src/OpenStack/Core/Synchronous/DatabaseServiceExtensions.cs b/src/OpenStack/Core/Synchronous/DatabaseServiceExtensions.cs new file mode 100644 index 000000000..a554d9af4 --- /dev/null +++ b/src/OpenStack/Core/Synchronous/DatabaseServiceExtensions.cs @@ -0,0 +1,1006 @@ +namespace net.openstack.Core.Synchronous +{ + using System; + using System.Collections.ObjectModel; + using net.openstack.Core.Collections; + using net.openstack.Providers.Rackspace; + using net.openstack.Providers.Rackspace.Objects.Databases; + using CancellationToken = System.Threading.CancellationToken; + using WebException = System.Net.WebException; + + /// + /// Provides extension methods to allow synchronous calls to the methods in . + /// + /// + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static class DatabaseServiceExtensions + { + #region Database instances + + /// + /// Create a new database instance. + /// + /// The database service instance. + /// A object describing the configuration of the new database instance. + /// + /// A object describing the new database instance. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create Database Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DatabaseInstance CreateDatabaseInstance(this IDatabaseService service, DatabaseInstanceConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateDatabaseInstanceAsync(configuration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of all database instances. + /// + /// + /// + /// This is a paginated collection. + /// + /// + /// The database service instance. + /// The database instance ID of the last in the previous page of results. This parameter is used for pagination. If the value is , the list starts at the beginning. + /// The maximum number of objects to return in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A collection of objects describing the database instances. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List All Database Instances (Rackspace Cloud Databases Developer Guide - API v1.0) + /// Pagination (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListDatabaseInstances(this IDatabaseService service, DatabaseInstanceId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListDatabaseInstancesAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a database instance by ID. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// + /// A object describing the database instance. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Database Instance Status and Details (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DatabaseInstance GetDatabaseInstance(this IDatabaseService service, DatabaseInstanceId instanceId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetDatabaseInstanceAsync(instanceId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes and deletes a database instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Delete Database Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveDatabaseInstance(this IDatabaseService service, DatabaseInstanceId instanceId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveDatabaseInstanceAsync(instanceId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Enables login from any host for the root user, and returns the root username and generated password. + /// + /// + /// + /// Changes you make as a root user may cause detrimental effects to the database instance and unpredictable + /// behavior for API operations. When you enable the root user, you accept the possibility that the provider + /// will not be able to support your database instance. While enabling root does not prevent the provider + /// from a "best effort" approach to helping you if something goes wrong with your instance, the provider + /// cannot ensure that they will be able to assist you if you change core MySQL settings. These changes can + /// be (but are not limited to) turning off binlogs, removing users that the provider uses to access your + /// instance, and so forth. + /// + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// + /// A object containing the username and password of the root database user. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Enable Root User (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static RootUser EnableRootUser(this IDatabaseService service, DatabaseInstanceId instanceId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.EnableRootUserAsync(instanceId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Checks whether or not root access has been enabled for a database instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// + /// if root access is enabled for the database instance; otherwise, . + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Root-Enabled Status (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static bool? CheckRootEnabledStatus(this IDatabaseService service, DatabaseInstanceId instanceId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CheckRootEnabledStatusAsync(instanceId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Database instance actions + + /// + /// Restarts the database service on the instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Restart Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RestartDatabaseInstance(this IDatabaseService service, DatabaseInstanceId instanceId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RestartDatabaseInstanceAsync(instanceId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Resize the memory of the database instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The new flavor to use for the database instance. This is obtained from DatabaseFlavor.Href. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Resize the Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void ResizeDatabaseInstance(this IDatabaseService service, DatabaseInstanceId instanceId, FlavorRef flavorRef) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.ResizeDatabaseInstanceAsync(instanceId, flavorRef, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Resize the volume attached to the database instance. + /// + /// + /// The provider may limit database volume resize operations to increasing the volume size. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The new volume size for the database instance. + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// Resize the Instance Volume (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void ResizeDatabaseInstanceVolume(this IDatabaseService service, DatabaseInstanceId instanceId, int volumeSize) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.ResizeDatabaseInstanceVolumeAsync(instanceId, volumeSize, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Databases + + /// + /// Create a new database within a database instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object describing the configuration of the new database. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create Database (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void CreateDatabase(this IDatabaseService service, DatabaseInstanceId instanceId, DatabaseConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.CreateDatabaseAsync(instanceId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of all databases within a database instance. + /// + /// + /// + /// This is a paginated collection. + /// + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The of the last in the previous page of results. This parameter is used for pagination. If the value is , the list starts at the beginning. + /// The maximum number of objects to return in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A collection of objects describing the databases. + /// + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Databases for Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + /// Pagination (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListDatabases(this IDatabaseService service, DatabaseInstanceId instanceId, DatabaseName marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListDatabasesAsync(instanceId, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes and deletes a database from a database instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The database name. This is obtained from Database.Name. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete Database (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveDatabase(this IDatabaseService service, DatabaseInstanceId instanceId, DatabaseName databaseName) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveDatabaseAsync(instanceId, databaseName, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Users + + /// + /// Create a new user in a database instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object describing the configuration of the new user. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create User (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void CreateUser(this IDatabaseService service, DatabaseInstanceId instanceId, UserConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.CreateUserAsync(instanceId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of all users within a database instance. + /// + /// + /// + /// This is a paginated collection. + /// + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The of the last user in the previous page of results. This parameter is used for pagination. If the value is , the list starts at the beginning. + /// The maximum number of objects to return in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A collection of objects describing the database instance users. + /// + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Users in Database Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + /// Pagination (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListDatabaseUsers(this IDatabaseService service, DatabaseInstanceId instanceId, UserName marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListDatabaseUsersAsync(instanceId, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Set the password for a database user. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// The new password for the user. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// If the REST request does not return successfully. + /// Change User(s) Password (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetUserPassword(this IDatabaseService service, DatabaseInstanceId instanceId, UserName userName, string password) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetUserPasswordAsync(instanceId, userName, password, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Update properties of a database user. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// An object describing the updates to apply to the user. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Modify User Attributes (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateUser(this IDatabaseService service, DatabaseInstanceId instanceId, UserName userName, UpdateUserConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateUserAsync(instanceId, userName, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get a database user by ID. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// + /// A object describing the user. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List User (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DatabaseUser GetUser(this IDatabaseService service, DatabaseInstanceId instanceId, UserName userName) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetUserAsync(instanceId, userName, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a user from a database instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete User (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveUser(this IDatabaseService service, DatabaseInstanceId instanceId, UserName userName) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveUserAsync(instanceId, userName, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a list of all databases a user has permission to access. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// + /// A collection of objects identifying the databases the user can access. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List User Access (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListUserAccess(this IDatabaseService service, DatabaseInstanceId instanceId, UserName userName) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListUserAccessAsync(instanceId, userName, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Grant access to a database for a particular user. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The database name. This is obtained from Database.Name. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Grant User Access (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void GrantUserAccess(this IDatabaseService service, DatabaseInstanceId instanceId, DatabaseName databaseName, UserName userName) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.GrantUserAccessAsync(instanceId, databaseName, userName, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Revoke access to a database for a particular user. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The database name. This is obtained from Database.Name. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Revoke User Access (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RevokeUserAccess(this IDatabaseService service, DatabaseInstanceId instanceId, DatabaseName databaseName, UserName userName) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RevokeUserAccessAsync(instanceId, databaseName, userName, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Flavors + + /// + /// Get a collection of all database instance flavors available with the provider. + /// + /// The database service instance. + /// + /// A collection of objects describing the database instance flavors. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Flavors (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListFlavors(this IDatabaseService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListFlavorsAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get a database instance flavor by ID. + /// + /// The database service instance. + /// The flavor ID. This is obtained from DatabaseFlavor.Id + /// + /// A object describing the flavor. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Flavor By ID (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DatabaseFlavor GetFlavor(this IDatabaseService service, FlavorId flavorId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetFlavorAsync(flavorId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Backups + + /// + /// Create a backup of a database instance. + /// + /// The database service instance. + /// A object containing the backup parameters. + /// + /// A object describing the backup. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create Backup (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Backup CreateBackup(this IDatabaseService service, BackupConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateBackupAsync(configuration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get a collection of all backups for database instances in an account. + /// + /// The database service instance. + /// + /// A collection of objects describing the database instance backups. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Backups (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListBackups(this IDatabaseService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListBackupsAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get information about a database instance backup by ID. + /// + /// The database service instance. + /// The backup ID. This is obtained from Backup.Id + /// + /// A object describing the backup. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Backup by ID (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Backup GetBackup(this IDatabaseService service, BackupId backupId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetBackupAsync(backupId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a database instance backup. + /// + /// The database service instance. + /// The backup ID. This is obtained from Backup.Id + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Delete Backup (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveBackup(this IDatabaseService service, BackupId backupId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveBackupAsync(backupId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get a collection of all backups for a particular database instance. + /// + /// The database service instance. + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// + /// A collection of objects describing the backups for the database instance + /// identified by . + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Backups (Rackspace Cloud Databases Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListBackupsForInstance(this IDatabaseService service, DatabaseInstanceId instanceId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListBackupsForInstanceAsync(instanceId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + } +} diff --git a/src/OpenStack/Core/Synchronous/DnsServiceExtensions.cs b/src/OpenStack/Core/Synchronous/DnsServiceExtensions.cs new file mode 100644 index 000000000..cdae8a1dc --- /dev/null +++ b/src/OpenStack/Core/Synchronous/DnsServiceExtensions.cs @@ -0,0 +1,964 @@ +namespace net.openstack.Core.Synchronous +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using net.openstack.Core.Collections; + using net.openstack.Providers.Rackspace; + using net.openstack.Providers.Rackspace.Objects.Dns; + using Newtonsoft.Json; + using CancellationToken = System.Threading.CancellationToken; + using ServiceCatalog = net.openstack.Core.Domain.ServiceCatalog; + + /// + /// Provides extension methods to allow synchronous calls to the methods in . + /// + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static class DnsServiceExtensions + { + #region Limits + + /// + /// Get information about the provider-specific limits of this service. + /// + /// The DNS service instance. + /// A object containing detailed information about the limits for the service provider. + /// If is . + /// If the REST request does not return successfully. + /// List All Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsServiceLimits ListLimits(this IDnsService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListLimitsAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get information about the types of provider-specific limits in place for this service. + /// + /// The DNS service instance. + /// A collection of objects containing the limit types supported by the service. + /// If is . + /// If the REST request does not return successfully. + /// List Limit Types (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListLimitTypes(this IDnsService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListLimitTypesAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get information about the provider-specific limits of this service for a particular . + /// + /// The DNS service instance. + /// The limit type. + /// A object containing detailed information about the limits of the specified for the service provider. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Specific Limit (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsServiceLimits ListLimits(this IDnsService service, LimitType type) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListLimitsAsync(type, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Limits + + #region Jobs + + /// + /// Gets information about an asynchronous task being executed by the DNS service. + /// + /// The DNS service instance. + /// The to query. + /// to include detailed information about the job; otherwise, . + /// A object containing the updated job information. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Synchronous and Asynchronous Responses (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob GetJobStatus(this IDnsService service, DnsJob job, bool showDetails) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetJobStatusAsync(job, showDetails, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets information about an asynchronous task with a strongly-typed result being executed by the DNS service. + /// + /// The class modeling the JSON result of the asynchronous operation. + /// The DNS service instance. + /// The to query. + /// to include detailed information about the job; otherwise, . + /// A object containing the updated job information. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If an error occurs while deserializing the response object. + /// If the REST request does not return successfully. + /// Synchronous and Asynchronous Responses (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob GetJobStatus(this IDnsService service, DnsJob job, bool showDetails) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetJobStatusAsync(job, showDetails, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Jobs + + #region Domains + + /// + /// Gets information about domains currently listed in the DNS service. + /// + /// The DNS service instance. + /// If specified, the list will be filtered to only include the specified domain and its subdomains (if any exist). + /// The index of the last item in the previous page of results. If not specified, the list starts at the beginning. + /// The maximum number of domains to return in a single page. + /// + /// A tuple of the resulting collection of objects and the total number of domains in + /// the list. If the total number of domains in the list is not available, the second element of the tuple will + /// be . + /// + /// If is . + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List Domains (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Search Domains with Filtering (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Tuple, int?> ListDomains(this IDnsService service, string domainName, int? offset, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListDomainsAsync(domainName, offset, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets detailed information about a specific domain. + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// to populate the property of the result; otherwise, . + /// to populate the property of the result; otherwise, . + /// A object containing the DNS information for the requested domain. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Domain Details (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsDomain ListDomainDetails(this IDnsService service, DomainId domainId, bool showRecords, bool showSubdomains) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListDomainDetailsAsync(domainId, showRecords, showSubdomains, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets information about all changes made to a domain since a specified time. + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// The timestamp of the earliest changes to consider. If this is , a provider-specific default value is used. + /// A object describing the changes made to a domain registered in the DNS service. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Domain Changes (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsDomainChanges ListDomainChanges(this IDnsService service, DomainId domainId, DateTimeOffset? since) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListDomainChangesAsync(domainId, since, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Exports a domain registered in the DNS service. + /// + /// + /// The exported domain represents a single domain, and does not include subdomains. + /// + /// + /// The format does not support comments, so any + /// comments associated with a domain or its records will not be included in the exported + /// result. + /// + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// A object describing the asynchronous server operation. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Export Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob ExportDomain(this IDnsService service, DomainId domainId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ExportDomainAsync(domainId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Registers one or more new domains in the DNS service. + /// + /// The DNS service instance. + /// A object describing the domains to register in the DNS service. + /// A object describing the asynchronous server operation. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob CreateDomains(this IDnsService service, DnsConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateDomainsAsync(configuration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates one or more domains in the DNS service. + /// + /// The DNS service instance. + /// A object describing updates to apply to the domains. + /// A object describing the asynchronous server operation. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Modify Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob UpdateDomains(this IDnsService service, DnsUpdateConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.UpdateDomainsAsync(configuration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Clones a domain registered in the DNS service, optionally cloning its subdomains as well. + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// The name of the new (cloned) domain. + /// to recursively clone subdomains; otherwise, to only clone the top-level domain and its records. Cloned subdomain configurations are modified the same way that cloned top-level domain configurations are modified. If this is , a provider-specific default value is used. + /// to replace occurrences of the reference domain name with the new domain name in comments on the cloned (new) domain. If this is , a provider-specific default value is used. + /// to replace occurrences of the reference domain name with the new domain name in email addresses on the cloned (new) domain. If this is , a provider-specific default value is used. + /// true to replace occurrences of the reference domain name with the new domain name in data fields (of records) on the cloned (new) domain. Does not affect NS records. If this is , a provider-specific default value is used. + /// A object describing the asynchronous server operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + /// If the REST request does not return successfully. + /// Clone Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob CloneDomain(this IDnsService service, DomainId domainId, string cloneName, bool? cloneSubdomains, bool? modifyRecordData, bool? modifyEmailAddress, bool? modifyComment) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CloneDomainAsync(domainId, cloneName, cloneSubdomains, modifyRecordData, modifyEmailAddress, modifyComment, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Imports domains into the DNS service. + /// + /// The DNS service instance. + /// A collection of objects containing the serialized domain information to import. + /// A object describing the asynchronous server operation. + /// If is . + /// If is . + /// If is contains any values. + /// If the REST request does not return successfully. + /// Import Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob ImportDomain(this IDnsService service, IEnumerable serializedDomains) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ImportDomainAsync(serializedDomains, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes one or more domains from the DNS service. + /// + /// The DNS service instance. + /// A collection of IDs for the domains to remove. These are obtained from DnsDomain.Id. + /// to delete any subdomains associated with the specified domains; otherwise, to promote any subdomains to top-level domains. + /// A object describing the asynchronous server operation. + /// If is . + /// If is . + /// If contains any values. + /// If the REST request does not return successfully. + /// Remove Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob RemoveDomains(this IDnsService service, IEnumerable domainIds, bool deleteSubdomains) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.RemoveDomainsAsync(domainIds, deleteSubdomains, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Subdomains + + /// + /// Gets information about subdomains currently associated with a domain in the DNS service. + /// + /// The DNS service instance. + /// The top-level domain ID. This is obtained from DnsDomain.Id. + /// The index of the last item in the previous page of results. If not specified, the list starts at the beginning. + /// The maximum number of subdomains to return in a single page. + /// + /// A tuple of the resulting collection of objects and the total number + /// of domains in the list. If the total number of subdomains in the list is not available, the second + /// element of the tuple will be . + /// + /// If is . + /// If is . + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List Subdomains (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Tuple, int?> ListSubdomains(this IDnsService service, DomainId domainId, int? offset, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListSubdomainsAsync(domainId, offset, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Records + + /// + /// Gets information about records currently associated with a domain in the DNS service, optionally filtering the results + /// to include only records of a specific type, name, and/or data. + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// The specific record type to consider, or to consider all record types. + /// The record name, which is matched to the property, or to consider all records. + /// The record data, which is matched to the property, or to consider all records. + /// The index of the last item in the previous page of results. If not specified, the list starts at the beginning. + /// The maximum number of records to return in a single page. + /// + /// A tuple of the resulting collection of objects and the total number of records + /// in the list. If the total number of records in the list is not available, the second element of the + /// tuple will be . + /// + /// If is . + /// If is . + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List Records (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Search Records (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Tuple, int?> ListRecords(this IDnsService service, DomainId domainId, DnsRecordType recordType, string recordName, string recordData, int? offset, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListRecordsAsync(domainId, recordType, recordName, recordData, offset, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets detailed information about a specific DNS record. + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// The record ID. This is obtained from DnsRecord.Id. + /// A object containing the details of the specified DNS record. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Record Details (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsRecord ListRecordDetails(this IDnsService service, DomainId domainId, RecordId recordId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListRecordDetailsAsync(domainId, recordId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Adds records to a domain in the DNS service. + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// A collection of objects describing the records to add. + /// A object describing the asynchronous server operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Add Records (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob AddRecords(this IDnsService service, DomainId domainId, IEnumerable recordConfigurations) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.AddRecordsAsync(domainId, recordConfigurations, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates domain records in the DNS service. + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// A collection of objects describing the updates to apply to domain records. + /// A object describing the asynchronous server operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Modify Records (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob UpdateRecords(this IDnsService service, DomainId domainId, IEnumerable recordConfigurations) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.UpdateRecordsAsync(domainId, recordConfigurations, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes one or more domain records from the DNS service. + /// + /// The DNS service instance. + /// The domain ID. This is obtained from DnsDomain.Id. + /// A collection of IDs for the records to remove. These are obtained from DnsRecord.Id. + /// A object describing the asynchronous server operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Records (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob RemoveRecords(this IDnsService service, DomainId domainId, IEnumerable recordId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.RemoveRecordsAsync(domainId, recordId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Reverse DNS + + /// + /// Gets information about reverse DNS records currently associated with a cloud resource in the DNS service. + /// + /// The DNS service instance. + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// The index of the last item in the previous page of results. If not specified, the list starts at the beginning. + /// The maximum number of records to return in a single page. + /// + /// A tuple of the resulting collection of objects and the total number of domains + /// in the list. If the total number of subdomains in the list is not available, the second element of the + /// tuple will be . + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List PTR Records (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Tuple, int?> ListPtrRecords(this IDnsService service, string serviceName, Uri deviceResourceUri, int? offset, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListPtrRecordsAsync(serviceName, deviceResourceUri, offset, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets detailed information about a reverse DNS record currently associated with a cloud resource in the DNS service. + /// + /// The DNS service instance. + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// The record ID. This is obtained from DnsRecord.Id. + /// A object containing the details of the specified reverse DNS record. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If the REST request does not return successfully. + /// List PTR Record Details (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsRecord ListPtrRecordDetails(this IDnsService service, string serviceName, Uri deviceResourceUri, RecordId recordId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListPtrRecordDetailsAsync(serviceName, deviceResourceUri, recordId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Adds reverse DNS records to a cloud resource in the DNS service. + /// + /// The DNS service instance. + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// A collection of objects describing the records to add. + /// A object describing the asynchronous server operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Add PTR Records (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob AddPtrRecords(this IDnsService service, string serviceName, Uri deviceResourceUri, IEnumerable recordConfigurations) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.AddPtrRecordsAsync(serviceName, deviceResourceUri, recordConfigurations, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Update reverse DNS records for a cloud resource in the DNS service. + /// + /// The DNS service instance. + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// A collection of objects describing the updates to apply to domain records. + /// A object describing the asynchronous server operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Modify PTR Records (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob UpdatePtrRecords(this IDnsService service, string serviceName, Uri deviceResourceUri, IEnumerable recordConfigurations) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.UpdatePtrRecordsAsync(serviceName, deviceResourceUri, recordConfigurations, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes one or more reverse DNS records from the DNS service. + /// + /// The DNS service instance. + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// The specific record to remove. If this is , all reverse DNS records associated with the specified device are removed. + /// A object describing the asynchronous server operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + /// If the REST request does not return successfully. + /// Remove PTR Records (Rackspace Cloud DNS Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static DnsJob RemovePtrRecords(this IDnsService service, string serviceName, Uri deviceResourceUri, IPAddress ipAddress) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.RemovePtrRecordsAsync(serviceName, deviceResourceUri, ipAddress, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + } +} diff --git a/src/OpenStack/Core/Synchronous/LoadBalancerServiceExtensions.cs b/src/OpenStack/Core/Synchronous/LoadBalancerServiceExtensions.cs new file mode 100644 index 000000000..b61e86f65 --- /dev/null +++ b/src/OpenStack/Core/Synchronous/LoadBalancerServiceExtensions.cs @@ -0,0 +1,2238 @@ +namespace net.openstack.Core.Synchronous +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using System.Net.Sockets; + using net.openstack.Core.Collections; + using net.openstack.Providers.Rackspace; + using net.openstack.Providers.Rackspace.Objects.LoadBalancers; + using CancellationToken = System.Threading.CancellationToken; + + /// + /// Provides extension methods to allow synchronous calls to the methods in . + /// + /// + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static class LoadBalancerServiceExtensions + { + #region Load Balancers + + /// + /// Gets a collection of current load balancers. + /// + /// The load balancer service instance. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// + /// A collection of objects describing the current load balancers. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Load Balancers (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListLoadBalancers(this ILoadBalancerService service, LoadBalancerId markerId, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListLoadBalancersAsync(markerId, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets detailed information about a specific load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A object containing detailed information about the specified load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Load Balancer Details (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static LoadBalancer GetLoadBalancer(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetLoadBalancerAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Creates a new load balancer. + /// + /// The load balancer service instance. + /// The configuration for the new load balancer. + /// + /// A object describing the new load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Load Balancer Details (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static LoadBalancer CreateLoadBalancer(this ILoadBalancerService service, LoadBalancerConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateLoadBalancerAsync(configuration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates attributes for an existing load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The updated configuration for the load balancer. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Load Balancer Attributes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateLoadBalancer(this ILoadBalancerService service, LoadBalancerId loadBalancerId, LoadBalancerUpdate configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateLoadBalancerAsync(loadBalancerId, configuration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Remove Load Balancer (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveLoadBalancer(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveLoadBalancerAsync(loadBalancerId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes one or more load balancers. + /// + /// The load balancer service instance. + /// The IDs of load balancers to remove. These is obtained from LoadBalancer.Id. + /// If is . + /// If is . + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Load Balancer (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveLoadBalancerRange(this ILoadBalancerService service, IEnumerable loadBalancerIds) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveLoadBalancerRangeAsync(loadBalancerIds, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Load Balancers + + #region Error Page + + /// + /// Gets the HTML content of the page which is shown to an end user who is attempting to access a load balancer node that is offline or unavailable. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// The HTML content of the error page which is shown to an end user who is attempting to access a load balancer + /// node that is offline or unavailable. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Error Page Operations (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static string GetErrorPage(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetErrorPageAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Sets the HTML content of the custom error page which is shown to an end user who is attempting to access a load balancer node that is offline or unavailable. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The HTML content of the error page which is shown to an end user who is attempting to access a load balancer node that is offline or unavailable. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + /// If the REST request does not return successfully. + /// Error Page Operations (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetErrorPage(this ILoadBalancerService service, LoadBalancerId loadBalancerId, string content) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetErrorPageAsync(loadBalancerId, content, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes the custom error page which is shown to an end user who is attempting to access a load balancer node that is offline or unavailable. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Error Page Operations (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveErrorPage(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveErrorPageAsync(loadBalancerId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Error Page + + #region Load Balancer Statistics + + /// + /// Get detailed statistics for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A object containing the detailed statistics for the + /// load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Load Balancer Stats (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static LoadBalancerStatistics GetStatistics(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetStatisticsAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Load Balancer Statistics + + #region Nodes + + /// + /// List the load balancer nodes associated with a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A collection of objects describing the load balancer nodes associated with the specified + /// load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListNodes(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListNodesAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get detailed information about a load balancer node. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// + /// A object describing the specified load balancer node. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Node GetNode(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeId nodeId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetNodeAsync(loadBalancerId, nodeId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Add a node to a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A object describing the load balancer node to add. + /// + /// A object describing the new load balancer node. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Add Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Node AddNode(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeConfiguration nodeConfiguration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.AddNodeAsync(loadBalancerId, nodeConfiguration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Add one or more nodes to a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A collection of objects describing the load balancer nodes to add. + /// + /// A collection of objects describing the new load balancer nodes. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Add Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection AddNodeRange(this ILoadBalancerService service, LoadBalancerId loadBalancerId, IEnumerable nodeConfigurations) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.AddNodeRangeAsync(loadBalancerId, nodeConfigurations, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Update the configuration of a load balancer node. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node IDs. This is obtained from Node.Id. + /// The updated configuration for the load balancer node. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Modify Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateNode(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeId nodeId, NodeUpdate configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateNodeAsync(loadBalancerId, nodeId, configuration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove a nodes from a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node IDs. This is obtained from Node.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Remove Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveNode(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeId nodeId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveNodeAsync(loadBalancerId, nodeId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove one or more nodes from a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node IDs of nodes to remove. These are obtained from Node.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveNodeRange(this ILoadBalancerService service, LoadBalancerId loadBalancerId, IEnumerable nodeIds) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveNodeRangeAsync(loadBalancerId, nodeIds, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// List the service events for a load balancer node. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// + /// A collection of objects describing the service events for the load balancer node. + /// + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// View Node Service Events (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListNodeServiceEvents(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeServiceEventId markerId, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListNodeServiceEventsAsync(loadBalancerId, markerId, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Nodes + + #region Virtual IPs + + /// + /// Get a list of all virtual addresses associated with a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A collection of objects describing the virtual addresses + /// associated with the load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Virtual IPs (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListVirtualAddresses(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListVirtualAddressesAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Add a virtual address to a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The virtual address type. + /// The family of address to add. This should be or . + /// + /// A object describing the added virtual address. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If the specified is not supported by this provider. + /// + /// If the REST request does not return successfully. + /// Add Virtual IP Version 6 (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static LoadBalancerVirtualAddress AddVirtualAddress(this ILoadBalancerService service, LoadBalancerId loadBalancerId, LoadBalancerVirtualAddressType type, AddressFamily addressFamily) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.AddVirtualAddressAsync(loadBalancerId, type, addressFamily, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove a virtual address associated with a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The virtual address ID. This is obtained from LoadBalancerVirtualAddress.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Remove Virtual IP (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveVirtualAddress(this ILoadBalancerService service, LoadBalancerId loadBalancerId, VirtualAddressId virtualAddressId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveVirtualAddressAsync(loadBalancerId, virtualAddressId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove a collection of virtual addresses associated with a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The virtual address IDs. These are obtained from LoadBalancerVirtualAddress.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Virtual IP (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveVirtualAddressRange(this ILoadBalancerService service, LoadBalancerId loadBalancerId, IEnumerable virtualAddressIds) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveVirtualAddressRangeAsync(loadBalancerId, virtualAddressIds, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Virtual IPs + + #region Allowed Domains + + /// + /// Gets the domain name restrictions in place for adding load balancer nodes. + /// + /// The load balancer service instance. + /// + /// A collection of strings containing the allowed domain names used for adding load balancer nodes. + /// + /// If is . + /// If the REST request does not return successfully. + /// View Node Service Events (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListAllowedDomains(this ILoadBalancerService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAllowedDomainsAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Allowed Domains + + #region Usage Reports + + /// + /// List billable load balancers for a given date range. + /// + /// The load balancer service instance. + /// The start date to consider. The time component, if any, is ignored. If the value is , the result includes all usage prior to the specified . + /// The end date to consider. The time component, if any, is ignored. If the value is , the result includes all usage following the specified . + /// The index of the last item in the previous page of results. If the value is , the list starts at the beginning. + /// Gets the maximum number of load balancers to return in a single page of results. If the value is , a provider-specific default value is used. + /// + /// A collection of objects describing the load balancers active in the specified + /// date range. + /// + /// If is . + /// If occurs before . + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListBillableLoadBalancers(this ILoadBalancerService service, DateTimeOffset? startTime, DateTimeOffset? endTime, int? offset, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListBillableLoadBalancersAsync(startTime, endTime, offset, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// List all usage for an account during a specified date range. + /// + /// The load balancer service instance. + /// The start date to consider. The time component, if any, is ignored. If the value is , the result includes all usage prior to the specified . + /// The end date to consider. The time component, if any, is ignored. If the value is , the result includes all usage following the specified . + /// + /// A collection of objects describing the load balancer usage for an account + /// in the specified date range. + /// + /// If is . + /// If occurs before . + /// If the REST request does not return successfully. + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListAccountLevelUsage(this ILoadBalancerService service, DateTimeOffset? startTime, DateTimeOffset? endTime) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAccountLevelUsageAsync(startTime, endTime, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// List all usage for a specific load balancer during a specified date range. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The start date to consider. The time component, if any, is ignored. If the value is , the result includes all usage prior to the specified . + /// The end date to consider. The time component, if any, is ignored. If the value is , the result includes all usage following the specified . + /// + /// A collection of objects describing the usage for the load balancer in + /// the specified date range. + /// + /// If is . + /// If is . + /// + /// If occurs before . + /// + /// If the REST request does not return successfully. + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListHistoricalUsage(this ILoadBalancerService service, LoadBalancerId loadBalancerId, DateTimeOffset? startTime, DateTimeOffset? endTime) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListHistoricalUsageAsync(loadBalancerId, startTime, endTime, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// List all usage for a specific load balancer during a preceding 24 hours. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A collection of objects describing the usage for the load balancer in + /// the preceding 24 hours. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListCurrentUsage(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListCurrentUsageAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Usage Reports + + #region Access Lists + + /// + /// Gets the access list configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A collection of objects describing the access list configuration for the load + /// balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListAccessList(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAccessListAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Add a network item to the access list for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A object describing the network item to add to the load balancer's access list. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void CreateAccessList(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NetworkItem networkItem) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.CreateAccessListAsync(loadBalancerId, networkItem, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Add a collection of network items to the access list for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A collection of objects describing the network items to add to the load balancer's access list. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void CreateAccessList(this ILoadBalancerService service, LoadBalancerId loadBalancerId, IEnumerable networkItems) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.CreateAccessListAsync(loadBalancerId, networkItems, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove a network item from the access list of a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The network item ID. This is obtained from . + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveAccessList(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NetworkItemId networkItemId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveAccessListAsync(loadBalancerId, networkItemId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove a collection of network items from the access list of a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The network item IDs. These are obtained from . + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveAccessListRange(this ILoadBalancerService service, LoadBalancerId loadBalancerId, IEnumerable networkItemIds) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveAccessListRangeAsync(loadBalancerId, networkItemIds, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove all network items from the access list of a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void ClearAccessList(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.ClearAccessListAsync(loadBalancerId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Access Lists + + #region Monitors + + /// + /// Gets the health monitor currently configured for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A object describing the health monitor configured for the + /// load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Monitor Health (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HealthMonitor GetHealthMonitor(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetHealthMonitorAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Sets the health monitor configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The updated health monitor configuration. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Monitor Health (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetHealthMonitor(this ILoadBalancerService service, LoadBalancerId loadBalancerId, HealthMonitor monitor) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetHealthMonitorAsync(loadBalancerId, monitor, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove the health monitor currently configured for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Monitor Health (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveHealthMonitor(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveHealthMonitorAsync(loadBalancerId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Monitors + + #region Sessions + + /// + /// Gets the session persistence configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A object describing the session persistence configuration for the load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Manage Session Persistence (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static SessionPersistence GetSessionPersistence(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetSessionPersistenceAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Sets the session persistence configuration for a load balancer. + /// + /// + /// You can only set one of the session persistence modes on a load balancer, and it can only support one + /// protocol, so if you set mode for an HTTP load balancer, + /// then it will support session persistence for HTTP requests only. Likewise, if you set + /// mode for an HTTPS load balancer, then it will support + /// session persistence for HTTPS requests only. + /// + /// + /// If you want to support session persistence for both HTTP and HTTPS requests concurrently, then you have 2 choices: + /// + /// + /// + /// Use two load balancers, one configured for session persistence for HTTP requests and the other + /// configured for session persistence for HTTPS requests. That way, the load balancers together will support + /// session persistence for both HTTP and HTTPS requests concurrently, with each load balancer supporting one + /// of the protocols. + /// Use one load balancer, configure it for session persistence for HTTP requests, and then enable SSL + /// termination for that load balancer (refer to Section 4.17, "SSL Termination" for details). The load + /// balancer will then support session persistence for both HTTP and HTTPS requests concurrently. + /// + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The session persistence configuration. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Manage Session Persistence (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetSessionPersistence(this ILoadBalancerService service, LoadBalancerId loadBalancerId, SessionPersistence sessionPersistence) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetSessionPersistenceAsync(loadBalancerId, sessionPersistence, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes the session persistence configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Manage Session Persistence (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveSessionPersistence(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveSessionPersistenceAsync(loadBalancerId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Sessions + + #region Connections + + /// + /// Gets whether or not connection logging is enabled for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// if content caching is enabled for the load balancer; otherwise, . + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Log Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static bool GetConnectionLogging(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetConnectionLoggingAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Enables or disables connection logging for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// to enable connection logging on the load balancer; otherwise, . + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Log Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetConnectionLogging(this ILoadBalancerService service, LoadBalancerId loadBalancerId, bool enabled) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetConnectionLoggingAsync(loadBalancerId, enabled, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets the connection throttling configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A object describing the connection throttling configuration in effect on the load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Throttle Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ConnectionThrottles ListThrottles(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListThrottlesAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates the connection throttling configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A object describing the throttling configuration to apply for the load balancer. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Throttle Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateThrottles(this ILoadBalancerService service, LoadBalancerId loadBalancerId, ConnectionThrottles throttleConfiguration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateThrottlesAsync(loadBalancerId, throttleConfiguration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes the connection throttling configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Throttle Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveThrottles(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveThrottlesAsync(loadBalancerId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Connections + + #region Content Caching + + /// + /// Gets whether or not content caching is enabled for a load balancer. + /// + /// + /// When content caching is enabled, recently-accessed files are stored on the load balancer + /// for easy retrieval by web clients. Content caching improves the performance of high + /// traffic web sites by temporarily storing data that was recently accessed. While it's + /// cached, requests for that data will be served by the load balancer, which in turn reduces + /// load off the back end nodes. The result is improved response times for those requests and + /// less load on the web server. + /// + /// + /// For more information about content caching, refer to the following Knowledge Center + /// article: + /// Content Caching for Cloud Load Balancers. + /// + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// if content caching is enabled for the load balancer; otherwise, . + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Content Caching (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static bool GetContentCaching(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetContentCachingAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Enables or disables content caching for a load balancer. + /// + /// + /// When content caching is enabled, recently-accessed files are stored on the load balancer + /// for easy retrieval by web clients. Content caching improves the performance of high + /// traffic web sites by temporarily storing data that was recently accessed. While it's + /// cached, requests for that data will be served by the load balancer, which in turn reduces + /// load off the back end nodes. The result is improved response times for those requests and + /// less load on the web server. + /// + /// + /// For more information about content caching, refer to the following Knowledge Center + /// article: + /// Content Caching for Cloud Load Balancers. + /// + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// to enable content caching on the load balancer; otherwise, . + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Content Caching (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetContentCaching(this ILoadBalancerService service, LoadBalancerId loadBalancerId, bool enabled) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.SetContentCachingAsync(loadBalancerId, enabled, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Content Caching + + #region Protocols + + /// + /// Gets a collection of supported load balancing protocols. + /// + /// The load balancer service instance. + /// + /// A collection of objects describing the load balancing + /// protocols supported by this service. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Load Balancing Protocols (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListProtocols(this ILoadBalancerService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListProtocolsAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Protocols + + #region Algorithms + + /// + /// Gets a collection of supported load balancing algorithms. + /// + /// The load balancer service instance. + /// + /// A collection of objects describing the load balancing + /// algorithms supported by this service. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Load Balancing Algorithms (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListAlgorithms(this ILoadBalancerService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAlgorithmsAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Algorithms + + #region SSL Termination + + /// + /// Gets the SSL termination configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A object describing the SSL termination + /// configuration for the load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// SSL Termination (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static LoadBalancerSslConfiguration GetSslConfiguration(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetSslConfigurationAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Update the SSL termination configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The updated SSL termination configuration. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// SSL Termination (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateSslConfiguration(this ILoadBalancerService service, LoadBalancerId loadBalancerId, LoadBalancerSslConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateSslConfigurationAsync(loadBalancerId, configuration, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Update the SSL termination configuration for a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// SSL Termination (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveSslConfiguration(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveSslConfigurationAsync(loadBalancerId, AsyncCompletionOption.RequestSubmitted, CancellationToken.None, null).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion SSL Termination + + #region Metadata + + /// + /// Gets the metadata associated with a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// + /// A collection of objects describing the metadata + /// associated with a load balancer. + /// + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListLoadBalancerMetadata(this ILoadBalancerService service, LoadBalancerId loadBalancerId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListLoadBalancerMetadataAsync(loadBalancerId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a specific metadata item associated with a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The metadata item ID. This is obtained from LoadBalancerMetadataItem.Id. + /// + /// A object describing the metadata item. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static LoadBalancerMetadataItem GetLoadBalancerMetadataItem(this ILoadBalancerService service, LoadBalancerId loadBalancerId, MetadataId metadataId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetLoadBalancerMetadataItemAsync(loadBalancerId, metadataId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets the metadata associated with a load balancer node. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// + /// A collection of objects describing the metadata + /// associated with the load balancer node. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection ListNodeMetadata(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeId nodeId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListNodeMetadataAsync(loadBalancerId, nodeId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a specific metadata item associated with a load balancer node. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The metadata item ID. This is obtained from LoadBalancerMetadataItem.Id. + /// + /// A object describing the metadata item. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static LoadBalancerMetadataItem GetNodeMetadataItem(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeId nodeId, MetadataId metadataId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetNodeMetadataItemAsync(loadBalancerId, nodeId, metadataId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates the metadata associated with a load balancer. + /// + /// + /// + /// The behavior is unspecified if contains a pair whose key matches the name of an existing metadata item associated with the load balancer. + /// + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A collection of metadata items to associate with the load balancer. + /// + /// A collection of objects describing the updated + /// metadata associated with the load balancer. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a pair whose is or empty, or whose is is . + /// + /// If the REST request does not return successfully. + /// Add Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection AddLoadBalancerMetadata(this ILoadBalancerService service, LoadBalancerId loadBalancerId, IEnumerable> metadata) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.AddLoadBalancerMetadataAsync(loadBalancerId, metadata, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates the metadata associated with a load balancer node. + /// + /// + /// + /// The behavior is unspecified if contains a pair whose key matches the name of an existing metadata item associated with the node. + /// + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// A collection of metadata items to associate with the node. + /// + /// A collection of objects describing the updated + /// metadata associated with the load balancer node. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a pair whose is or empty, or whose is is . + /// + /// If the REST request does not return successfully. + /// Add Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection AddNodeMetadata(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeId nodeId, IEnumerable> metadata) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.AddNodeMetadataAsync(loadBalancerId, nodeId, metadata, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Sets the value for a metadata item associated with a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The metadata item ID. This is obtained from LoadBalancerMetadataItem.Id. + /// The new value for the metadata item. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Modify Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateLoadBalancerMetadataItem(this ILoadBalancerService service, LoadBalancerId loadBalancerId, MetadataId metadataId, string value) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateLoadBalancerMetadataItemAsync(loadBalancerId, metadataId, value, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Sets the value for a metadata item associated with a load balancer node. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The metadata item ID. This is obtained from LoadBalancerMetadataItem.Id. + /// The new value for the metadata item. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Modify Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateNodeMetadataItem(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeId nodeId, MetadataId metadataId, string value) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateNodeMetadataItemAsync(loadBalancerId, nodeId, metadataId, value, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes one or more metadata items associated with a load balancer. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The metadata item IDs. These are obtained from LoadBalancerMetadataItem.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveLoadBalancerMetadataItem(this ILoadBalancerService service, LoadBalancerId loadBalancerId, IEnumerable metadataIds) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveLoadBalancerMetadataItemAsync(loadBalancerId, metadataIds, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Removes one or more metadata items associated with a load balancer node. + /// + /// The load balancer service instance. + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The metadata item IDs. These are obtained from LoadBalancerMetadataItem.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveNodeMetadataItem(this ILoadBalancerService service, LoadBalancerId loadBalancerId, NodeId nodeId, IEnumerable metadataIds) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveNodeMetadataItemAsync(loadBalancerId, nodeId, metadataIds, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Metadata + } +} diff --git a/src/OpenStack/Core/Synchronous/MonitoringServiceExtensions.cs b/src/OpenStack/Core/Synchronous/MonitoringServiceExtensions.cs new file mode 100644 index 000000000..cfdc0de12 --- /dev/null +++ b/src/OpenStack/Core/Synchronous/MonitoringServiceExtensions.cs @@ -0,0 +1,2572 @@ +namespace net.openstack.Core.Synchronous +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using net.openstack.Providers.Rackspace; + using net.openstack.Providers.Rackspace.Objects.Monitoring; + using Newtonsoft.Json.Linq; + using CancellationToken = System.Threading.CancellationToken; + + /// + /// Provides extension methods to allow synchronous calls to the methods in . + /// + /// + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static class MonitoringServiceExtensions + { + #region Core + + #region Account + + /// + /// Gets information about a monitoring account. + /// + /// The monitoring service instance. + /// A object describing the account. + /// If is . + /// If the REST request does not return successfully. + /// Get Account (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static MonitoringAccount GetAccount(this IMonitoringService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetAccountAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates a monitoring account. + /// + /// The monitoring service instance. + /// The account ID. This is obtained from MonitoringAccount.Id. + /// An object describing the changes to apply to the account. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Account (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateAccount(this IMonitoringService service, MonitoringAccountId accountId, AccountConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateAccountAsync(accountId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets the resource and rate limits enforced by the monitoring service. + /// + /// The monitoring service instance. + /// + /// A object describing the resource and rate + /// limits of the monitoring service. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Limits (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static MonitoringLimits GetLimits(this IMonitoringService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetLimitsAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring audits. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , a provider-specific default value is used. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , the current time is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If occurs before . + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// List Audits (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Time Series Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAudits(this IMonitoringService service, AuditId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAuditsAsync(marker, limit, from, to, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Account + + #region Entities + + /// + /// Creates a new monitoring entity. + /// + /// The monitoring service instance. + /// A object describing the new entity. + /// The identifying the new entity. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create Entities (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static EntityId CreateEntity(this IMonitoringService service, NewEntityConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateEntityAsync(configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring entities. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Entities (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListEntities(this IMonitoringService service, EntityId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListEntitiesAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring entity by ID. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// An object describing the entity. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Entity (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Entity GetEntity(this IMonitoringService service, EntityId entityId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetEntityAsync(entityId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates a monitoring entity. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// An object describing the changes to apply to the entity. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Entity (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateEntity(this IMonitoringService service, EntityId entityId, UpdateEntityConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateEntityAsync(entityId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a monitoring entity by ID. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Delete Entity (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveEntity(this IMonitoringService service, EntityId entityId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveEntityAsync(entityId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Entities + + #region Checks + + /// + /// Creates a new check. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// A object describing the new check. + /// The identifying the new check. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static CheckId CreateCheck(this IMonitoringService service, EntityId entityId, NewCheckConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateCheckAsync(entityId, configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Test a monitoring check. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// A object describing the check to test. + /// to include debug information in the result; otherwise, . If the value is , a provider-specific default is used. + /// A collection objects describing the test results. + /// If is . + /// Test Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Test Check and Include Debug Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection TestCheck(this IMonitoringService service, EntityId entityId, NewCheckConfiguration configuration, bool? debug) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.TestCheckAsync(entityId, configuration, debug, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Test an existing check by ID. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// A collection objects describing the test results. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Test Existing Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection TestExistingCheck(this IMonitoringService service, EntityId entityId, CheckId checkId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.TestExistingCheckAsync(entityId, checkId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring checks. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Checks (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListChecks(this IMonitoringService service, EntityId entityId, CheckId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListChecksAsync(entityId, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring check by ID. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// A object describing the check. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Check GetCheck(this IMonitoringService service, EntityId entityId, CheckId checkId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetCheckAsync(entityId, checkId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates a monitoring check. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// An object describing the changes to apply to the check. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateCheck(this IMonitoringService service, EntityId entityId, CheckId checkId, UpdateCheckConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateCheckAsync(entityId, checkId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a monitoring check by ID. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveCheck(this IMonitoringService service, EntityId entityId, CheckId checkId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveCheckAsync(entityId, checkId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Checks + + #region Check Types + + /// + /// Gets a collection of monitoring check types. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Check Types (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListCheckTypes(this IMonitoringService service, CheckTypeId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListCheckTypesAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring check type by ID. + /// + /// The monitoring service instance. + /// The check type ID. This is obtained from CheckType.Id, or from the predefined values in . + /// A object describing the check type. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Check Type (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static CheckType GetCheckType(this IMonitoringService service, CheckTypeId checkTypeId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetCheckTypeAsync(checkTypeId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Check Types + + #region Metrics + + /// + /// Gets a collection of monitoring metrics. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Metrics (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListMetrics(this IMonitoringService service, EntityId entityId, CheckId checkId, MetricName marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListMetricsAsync(entityId, checkId, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of data points collected for a metric by the monitoring service. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// The metric name. This is obtained from Metric.Name. + /// The number of data points to return. + /// The granularity of the returned data points. + /// A collection of objects identifying the statistics to compute for the data. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. + /// + /// A collection of objects describing the data points + /// collected for the metric. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If both and are . + /// -or- + /// If occurs before . + /// + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// Fetch Data Points (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection GetDataPoints(this IMonitoringService service, EntityId entityId, CheckId checkId, MetricName metricName, int? points, DataPointGranularity resolution, IEnumerable select, DateTimeOffset from, DateTimeOffset to) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetDataPointsAsync(entityId, checkId, metricName, points, resolution, select, from, to, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Metrics + + #region Alarms + + /// + /// Creates a new alarm. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// A object describing the new alarm. + /// The identifying the new alarm. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static AlarmId CreateAlarm(this IMonitoringService service, EntityId entityId, NewAlarmConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateAlarmAsync(entityId, configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Test a monitoring alarm. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// A object describing the alarm test configuration. + /// A collection objects describing the test results. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Test Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection TestAlarm(this IMonitoringService service, EntityId entityId, TestAlarmConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.TestAlarmAsync(entityId, configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring entities. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Alarms (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAlarms(this IMonitoringService service, EntityId entityId, AlarmId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAlarmsAsync(entityId, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring alarm by ID. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// An object describing the alarm. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Alarm GetAlarm(this IMonitoringService service, EntityId entityId, AlarmId alarmId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetAlarmAsync(entityId, alarmId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates a monitoring alarm. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// An object describing the changes to apply to the alarm. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateAlarm(this IMonitoringService service, EntityId entityId, AlarmId alarmId, UpdateAlarmConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateAlarmAsync(entityId, alarmId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a monitoring alarm by ID. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Remove Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveAlarm(this IMonitoringService service, EntityId entityId, AlarmId alarmId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveAlarmAsync(entityId, alarmId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Alarms + + #region Notification Plans + + /// + /// Creates a new notification plan. + /// + /// The monitoring service instance. + /// A object describing the new notification plan. + /// The identifying the new notification plan. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create Notification Plan (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static NotificationPlanId CreateNotificationPlan(this IMonitoringService service, NewNotificationPlanConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateNotificationPlanAsync(configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring notification plans. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Notification Plans (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListNotificationPlans(this IMonitoringService service, NotificationPlanId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListNotificationPlansAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring notification plan by ID. + /// + /// The monitoring service instance. + /// The notification plan ID. This is obtained from NotificationPlan.Id. + /// A object describing the notification plan. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Notification Plan (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static NotificationPlan GetNotificationPlan(this IMonitoringService service, NotificationPlanId notificationPlanId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetNotificationPlanAsync(notificationPlanId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates a monitoring notification plan. + /// + /// The monitoring service instance. + /// The notification plan ID. This is obtained from NotificationPlan.Id. + /// An object describing the changes to apply to the notification plan. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Notification Plans (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateNotificationPlan(this IMonitoringService service, NotificationPlanId notificationPlanId, UpdateNotificationPlanConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateNotificationPlanAsync(notificationPlanId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a monitoring notification plan by ID. + /// + /// The monitoring service instance. + /// The notification plan ID. This is obtained from NotificationPlan.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Delete Notification Plans (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveNotificationPlan(this IMonitoringService service, NotificationPlanId notificationPlanId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveNotificationPlanAsync(notificationPlanId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Notification Plans + + #region Monitoring Zones + + /// + /// Gets a collection of monitoring zones. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Monitoring Zones (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListMonitoringZones(this IMonitoringService service, MonitoringZoneId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListMonitoringZonesAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring zone by ID. + /// + /// The monitoring service instance. + /// The monitoring zone ID. This is obtained from MonitoringZone.Id. + /// A object describing the monitoring zone. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Monitoring Zone (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static MonitoringZone GetMonitoringZone(this IMonitoringService service, MonitoringZoneId monitoringZoneId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetMonitoringZoneAsync(monitoringZoneId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Perform a traceroute operation from a monitoring zone to a particular target. + /// + /// The monitoring service instance. + /// The monitoring zone ID. This is obtained from MonitoringZone.Id. + /// A object containing the traceroute parameters. + /// A object describing the results of the traceroute operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Perform a "traceroute" from a Monitoring Zone (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static TraceRoute PerformTraceRouteFromMonitoringZone(this IMonitoringService service, MonitoringZoneId monitoringZoneId, TraceRouteConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.PerformTraceRouteFromMonitoringZoneAsync(monitoringZoneId, configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Monitoring Zones + + #region Alarm Notification History + + /// + /// Gets a collection of objects identifying the particular checks + /// for which an alarm notification history is present for a particular entity/alarm + /// combination. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// + /// A collection of objects identifying the checks for which + /// an alarm notification history is present. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Discover Alarm Notification History (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection DiscoverAlarmNotificationHistory(this IMonitoringService service, EntityId entityId, AlarmId alarmId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.DiscoverAlarmNotificationHistoryAsync(entityId, alarmId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring alarm notification history items. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// The check ID. This is obtained from Check.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , a provider-specific default value is used. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , the current time is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If occurs before . + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// List Alarm Notification History (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Time Series Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAlarmNotificationHistory(this IMonitoringService service, EntityId entityId, AlarmId alarmId, CheckId checkId, AlarmNotificationHistoryItemId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAlarmNotificationHistoryAsync(entityId, alarmId, checkId, marker, limit, from, to, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring alarm notification history item by ID. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// The check ID. This is obtained from Check.Id. + /// The alarm notification history item ID. This is obtained from AlarmNotificationHistoryItem.Id. + /// An object describing the alarm notification history item. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get Alarm Notification History (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static AlarmNotificationHistoryItem GetAlarmNotificationHistory(this IMonitoringService service, EntityId entityId, AlarmId alarmId, CheckId checkId, AlarmNotificationHistoryItemId alarmNotificationHistoryItemId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetAlarmNotificationHistoryAsync(entityId, alarmId, checkId, alarmNotificationHistoryItemId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Alarm Notification History + + #region Notifications + + /// + /// Creates a new notification. + /// + /// The monitoring service instance. + /// A object describing the new notification. + /// The identifying the new notification. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static NotificationId CreateNotification(this IMonitoringService service, NewNotificationConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateNotificationAsync(configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Test a monitoring notification. + /// + /// The monitoring service instance. + /// A object describing the notification to test. + /// A object describing the test results. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Test Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static NotificationData TestNotification(this IMonitoringService service, NewNotificationConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.TestNotificationAsync(configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Test an existing notification by ID. + /// + /// The monitoring service instance. + /// The notification ID. This is obtained from Notification.Id. + /// A object describing the test results. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Test Existing Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static NotificationData TestExistingNotification(this IMonitoringService service, NotificationId notificationId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.TestExistingNotificationAsync(notificationId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring notifications. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Notifications (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListNotifications(this IMonitoringService service, NotificationId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListNotificationsAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring notification by ID. + /// + /// The monitoring service instance. + /// The notification ID. This is obtained from Notification.Id. + /// A object describing the notification. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Notification GetNotification(this IMonitoringService service, NotificationId notificationId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetNotificationAsync(notificationId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates a monitoring notification. + /// + /// The monitoring service instance. + /// The notification ID. This is obtained from Notification.Id. + /// An object describing the changes to apply to the notification. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateNotification(this IMonitoringService service, NotificationId notificationId, UpdateNotificationConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateNotificationAsync(notificationId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a monitoring notification by ID. + /// + /// The monitoring service instance. + /// The notification ID. This is obtained from Notification.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Delete Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveNotification(this IMonitoringService service, NotificationId notificationId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveNotificationAsync(notificationId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Notifications + + #region Notification Types + + /// + /// Gets a collection of monitoring notification types. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Notification Types (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListNotificationTypes(this IMonitoringService service, NotificationTypeId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListNotificationTypesAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring notification type by ID. + /// + /// The monitoring service instance. + /// The notification type ID. This is obtained from NotificationType.Id, or from the predefined values in . + /// A object describing the notification type. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Notification Type (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static NotificationType GetNotificationType(this IMonitoringService service, NotificationTypeId notificationTypeId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetNotificationTypeAsync(notificationTypeId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Notification Types + + #region Changelogs + + /// + /// Gets a collection of monitoring alarm changelogs. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , a provider-specific default value is used. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , the current time is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If occurs before . + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// List Alarm Changelogs (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Time Series Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAlarmChangelogs(this IMonitoringService service, AlarmChangelogId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAlarmChangelogsAsync(marker, limit, from, to, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring alarm changelogs. + /// + /// The monitoring service instance. + /// The entity ID to filter alarm changelogs. This is obtained from Entity.Id. If the value is , changelogs for all entities are returned. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , a provider-specific default value is used. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , the current time is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If occurs before . + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// List Alarm Changelogs (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Time Series Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAlarmChangelogs(this IMonitoringService service, EntityId entityId, AlarmChangelogId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAlarmChangelogsAsync(entityId, marker, limit, from, to, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Changelogs + + #region Views + + /// + /// Gets a collection of monitoring entity overviews. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// Get Overview (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListEntityOverviews(this IMonitoringService service, EntityId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListEntityOverviewsAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring entity overviews, filtered by entity ID. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// A collection of entity IDs for filter the results. If the value is , overviews for all entities are returned. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is non- and contains any values. + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// Get Overview (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListEntityOverviews(this IMonitoringService service, EntityId marker, int? limit, IEnumerable entityIdFilter) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListEntityOverviewsAsync(marker, limit, entityIdFilter, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Views + + #region Alarm Examples + + /// + /// Gets a collection of monitoring alarm examples. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Alarm Examples (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAlarmExamples(this IMonitoringService service, AlarmExampleId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAlarmExamplesAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring alarm example by ID. + /// + /// The monitoring service instance. + /// The alarm example ID. This is obtained from AlarmExample.Id. + /// An object describing the alarm example. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Alarm Example (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static AlarmExample GetAlarmExample(this IMonitoringService service, AlarmExampleId alarmExampleId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetAlarmExampleAsync(alarmExampleId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Evaluate the template of a single alarm example. + /// + /// The monitoring service instance. + /// The alarm example ID. This is obtained from AlarmExample.Id. + /// A dictionary containing the values to insert in the alarm example. The dictionary should contain a key/value pair for each field described in for the alarm example. + /// A object containing the evaluated alarm example. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If contains any empty keys. + /// If the REST request does not return successfully. + /// Evaluate Alarm Example (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static BoundAlarmExample EvaluateAlarmExample(this IMonitoringService service, AlarmExampleId alarmExampleId, IDictionary exampleParameters) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.EvaluateAlarmExampleAsync(alarmExampleId, exampleParameters, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Alarm Examples + + #endregion Core + + #region Agent + + #region Agents + + /// + /// Gets a collection of monitoring agents. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Agents (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAgents(this IMonitoringService service, AgentId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAgentsAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring agent by ID. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// An object describing the agent. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Agent (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Agent GetAgent(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetAgentAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring agent connections. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Agent Connections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAgentConnections(this IMonitoringService service, AgentId agentId, AgentConnectionId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAgentConnectionsAsync(agentId, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring agent connection by ID. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// The agent connection ID. This is obtained from AgentConnection.Id. + /// An object describing the agent connection. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get Agent Connection (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static AgentConnection GetAgentConnection(this IMonitoringService service, AgentId agentId, AgentConnectionId agentConnectionId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetAgentConnectionAsync(agentId, agentConnectionId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Agents + + #region Agent Token + + /// + /// Creates a new agent token. + /// + /// The monitoring service instance. + /// An object describing the new agent token. + /// The identifying the new agent token. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static AgentTokenId CreateAgentToken(this IMonitoringService service, AgentTokenConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.CreateAgentTokenAsync(configuration, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a collection of monitoring agent tokens. + /// + /// The monitoring service instance. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Agent Tokens (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAgentTokens(this IMonitoringService service, AgentTokenId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAgentTokensAsync(marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a monitoring agent token by ID. + /// + /// The monitoring service instance. + /// The agent token ID. This is obtained from AgentToken.Id. + /// An object describing the agent token. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static AgentToken GetAgentToken(this IMonitoringService service, AgentTokenId agentTokenId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetAgentTokenAsync(agentTokenId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Updates a monitoring agent token. + /// + /// The monitoring service instance. + /// The agent token ID. This is obtained from AgentToken.Id. + /// An object describing the changes to apply to the agent token. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateAgentToken(this IMonitoringService service, AgentTokenId agentTokenId, AgentTokenConfiguration configuration) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.UpdateAgentTokenAsync(agentTokenId, configuration, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Remove and delete a monitoring agent token by ID. + /// + /// The monitoring service instance. + /// The agent token ID. This is obtained from AgentToken.Id. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Delete Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void RemoveAgentToken(this IMonitoringService service, AgentTokenId agentTokenId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + service.RemoveAgentTokenAsync(agentTokenId, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Agent Token + + #region Agent Host Information + + /// + /// Gets agent host information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// The host information type. + /// A object containing the host information. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Agent Host Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation GetAgentHostInformation(this IMonitoringService service, AgentId agentId, HostInformationType hostInformation) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetAgentHostInformationAsync(agentId, hostInformation, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets CPU information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A object containing the host information. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get CPUs Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation> GetCpuInformation(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetCpuInformationAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets disk information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A object containing the host information. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Disks Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation> GetDiskInformation(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetDiskInformationAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets filesystem information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A object containing the host information. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Filesystems Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation> GetFilesystemInformation(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetFilesystemInformationAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets memory information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A object containing the host information. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Memory Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation GetMemoryInformation(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetMemoryInformationAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets network interface information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A object containing the host information. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Network Interfaces Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation> GetNetworkInterfaceInformation(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetNetworkInterfaceInformationAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets process information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A object containing the host information. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Processes Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation> GetProcessInformation(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetProcessInformationAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets system information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A object containing the host information. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get System Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation GetSystemInformation(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetSystemInformationAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets login information reported by a monitoring agent. + /// + /// The monitoring service instance. + /// The agent ID. This is obtained from Agent.Id. + /// A object containing the host information. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Logged-in User Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HostInformation> GetLoginInformation(this IMonitoringService service, AgentId agentId) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.GetLoginInformationAsync(agentId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Agent Host Information + + #region Agent Targets + + /// + /// Gets a collection of monitoring agent check targets. + /// + /// The monitoring service instance. + /// The entity ID. This is obtained from Entity.Id. + /// The agent check type ID. This is obtained from CheckType.Id, or from the predefined values in . + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// + /// A object containing the page + /// of results and its associated pagination metadata. + /// + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is not an agent check type (i.e. the property is ). + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Agent Check Targets (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListAgentCheckTargets(this IMonitoringService service, EntityId entityId, CheckTypeId agentCheckType, CheckTargetId marker, int? limit) + { + if (service == null) + throw new ArgumentNullException("service"); + + try + { + return service.ListAgentCheckTargetsAsync(entityId, agentCheckType, marker, limit, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Agent Targets + + #endregion Agent + } +} diff --git a/src/OpenStack/Core/Synchronous/NamespaceDoc.cs b/src/OpenStack/Core/Synchronous/NamespaceDoc.cs new file mode 100644 index 000000000..8064ce728 --- /dev/null +++ b/src/OpenStack/Core/Synchronous/NamespaceDoc.cs @@ -0,0 +1,18 @@ +namespace net.openstack.Core.Synchronous +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines classes providing + /// extension methods for calling asynchronous services in a synchronous manner. + /// + /// These extension methods are not recommended for use in new development, but are + /// provided as a compatibility aid for projects where external restrictions preclude + /// the direct use of the asynchronous APIs. + /// + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/Synchronous/QueueingServiceExtensions.cs b/src/OpenStack/Core/Synchronous/QueueingServiceExtensions.cs new file mode 100644 index 000000000..f8bd863c1 --- /dev/null +++ b/src/OpenStack/Core/Synchronous/QueueingServiceExtensions.cs @@ -0,0 +1,869 @@ +namespace net.openstack.Core.Synchronous +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.ComponentModel; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using net.openstack.Core.Domain.Queues; + using CancellationToken = System.Threading.CancellationToken; + using IQueueingService = net.openstack.Core.Providers.IQueueingService; + using JObject = Newtonsoft.Json.Linq.JObject; + using JsonSerializationException = Newtonsoft.Json.JsonSerializationException; + using WebException = System.Net.WebException; + + /// + /// Provides extension methods to allow synchronous calls to the methods in . + /// + /// + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static class QueueingServiceExtensions + { + #region Base endpoints + + /// + /// Gets the home document describing the operations supported by the service. + /// + /// The queueing service instance. + /// A object describing the operations supported by the service. + /// If is . + /// If the REST request does not return successfully. + /// Get Home Document (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static HomeDocument GetHome(this IQueueingService queueingService) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.GetHomeAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Checks the queueing service node status. + /// + /// The queueing service instance. + /// + /// If the service is available, the operation will complete successfully. If the service + /// is unavailable due to a storage driver failure or some other error, the operation will + /// fail and the exception will contain the reason for the failure. + /// + /// If is . + /// If the REST request does not return successfully. + /// Check Node Health (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void GetNodeHealth(this IQueueingService queueingService) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + queueingService.GetNodeHealthAsync(CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Base endpoints + + #region Queues + + /// + /// Creates a queue, if it does not already exist. + /// + /// The queueing service instance. + /// The queue name. + /// if the queue was created by the call, or if the queue already existed. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Create Queue (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static bool CreateQueue(this IQueueingService queueingService, QueueName queueName) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.CreateQueueAsync(queueName, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets a list of queues. + /// + /// The queueing service instance. + /// The name of the last queue in the previous list. The resulting collection of queues will start with the first queue after this value, when sorted using . If this value is , the list starts at the beginning. + /// The maximum number of queues to return. If this value is , a provider-specific default value is used. + /// to return detailed information about each queue; otherwise, . + /// placeholder + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Queues (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage ListQueues(this IQueueingService queueingService, QueueName marker, int? limit, bool detailed) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.ListQueuesAsync(marker, limit, detailed, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Checks for the existence of a queue with a particular name. + /// + /// The queueing service instance. + /// The queue name. + /// if queue with the specified name exists; otherwise, . + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Checking Queue Existence (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static bool QueueExists(this IQueueingService queueingService, QueueName queueName) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.QueueExistsAsync(queueName, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Deletes a queue. + /// + /// + /// The queue will be deleted whether or not it is empty, even if one or more messages in the queue is currently claimed. + /// + /// The queueing service instance. + /// The queue name. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Delete Queue (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void DeleteQueue(this IQueueingService queueingService, QueueName queueName) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + queueingService.DeleteQueueAsync(queueName, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + + #region Queue metadata + + /// + /// Sets the metadata associated with a queue. + /// + /// The type of data to associate with the queue. + /// The queueing service instance. + /// The queue name. + /// The metadata to associate with the queue. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Set Queue Metadata (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void SetQueueMetadata(this IQueueingService queueingService, QueueName queueName, T metadata) + where T : class + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + queueingService.SetQueueMetadataAsync(queueName, metadata, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets the metadata associated with a queue. + /// + /// The queueing service instance. + /// The queue name. + /// A object containing the metadata associated with the queue. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Queue Metadata (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static JObject GetQueueMetadata(this IQueueingService queueingService, QueueName queueName) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.GetQueueMetadataAsync(queueName, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets the metadata associated with a queue, as a strongly-typed object. + /// + /// The type of metadata associated with the queue. + /// The queueing service instance. + /// The queue name. + /// A deserialized object of type representing the metadata associated with the queue. + /// If is . + /// If is . + /// If an error occurs while deserializing the metadata. + /// If the REST request does not return successfully. + /// Get Queue Metadata (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static T GetQueueMetadata(this IQueueingService queueingService, QueueName queueName) + where T : class + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.GetQueueMetadataAsync(queueName, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets statistics for a queue. + /// + /// The queueing service instance. + /// The queue name. + /// A object containing statistics for the queue. + /// If is . + /// If is . + /// If the REST request does not return successfully. + /// Get Queue Stats (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static QueueStatistics GetQueueStatistics(this IQueueingService queueingService, QueueName queueName) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.GetQueueStatisticsAsync(queueName, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Queue metadata + + #region Messages + + /// + /// Gets a list of messages currently in a queue. + /// + /// The queueing service instance. + /// The queue name. + /// The identifier of the message list page to return. This is obtained from . If this value is , the list starts at the beginning. + /// The maximum number of messages to return. If this value is , a provider-specific default value is used. + /// to include messages created by the current client; otherwise, . + /// to include claimed messages; otherwise to return only unclaimed messages. + /// A collection of objects describing the messages in the queue. + /// If is . + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Messages (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static QueuedMessageList ListMessages(this IQueueingService queueingService, QueueName queueName, QueuedMessageListId marker, int? limit, bool echo, bool includeClaimed) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.ListMessagesAsync(queueName, marker, limit, echo, includeClaimed, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets detailed information about a specific queued message. + /// + /// + /// This method will return information for the specified message regardless of the + /// Client-ID or claim associated with the message. + /// + /// The queueing service instance. + /// The queue name. + /// The message ID. This is obtained from QueuedMessage.Id. + /// A object containing detailed information about the specified message. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get a Specific Message (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static QueuedMessage GetMessage(this IQueueingService queueingService, QueueName queueName, MessageId messageId) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.GetMessageAsync(queueName, messageId, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Get messages from a queue. + /// + /// + /// This method will return information for the specified message regardless of the + /// Client-ID or claim associated with the message. + /// + /// The queueing service instance. + /// The queue name. + /// The message IDs of messages to get. + /// A collection of objects containing detailed information about the specified messages. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Get a Set of Messages by ID (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection GetMessages(this IQueueingService queueingService, QueueName queueName, IEnumerable messageIds) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.GetMessagesAsync(queueName, messageIds, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Posts messages to a queue. + /// + /// The queueing service instance. + /// The queue name. + /// The messages to post. + /// A object representing the result of the operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static MessagesEnqueued PostMessages(this IQueueingService queueingService, QueueName queueName, IEnumerable messages) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.PostMessagesAsync(queueName, messages, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Posts messages to a queue. + /// + /// The queueing service instance. + /// The queue name. + /// The messages to post. + /// A object representing the result of the operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static MessagesEnqueued PostMessages(this IQueueingService queueingService, QueueName queueName, params Message[] messages) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.PostMessagesAsync(queueName, CancellationToken.None, messages).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Posts messages to a queue. + /// + /// The class modeling the JSON representation of the messages to post in the queue. + /// The queueing service instance. + /// The queue name. + /// The messages to post. + /// A object representing the result of the operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static MessagesEnqueued PostMessages(this IQueueingService queueingService, QueueName queueName, IEnumerable> messages) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.PostMessagesAsync(queueName, messages, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Posts messages to a queue. + /// + /// The class modeling the JSON representation of the messages to post in the queue. + /// The queueing service instance. + /// The queue name. + /// The messages to post. + /// A object representing the result of the operation. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Post Message(s) (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static MessagesEnqueued PostMessages(this IQueueingService queueingService, QueueName queueName, params Message[] messages) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.PostMessagesAsync(queueName, CancellationToken.None, messages).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Deletes a message from a queue. + /// + /// The queueing service instance. + /// The queue name. + /// The ID of the message to delete. This is obtained from QueuedMessage.Id. + /// The claim for the message. If this value is , the delete operation will fail if the message is claimed. If this value is non-, the delete operation will fail if the message is not claimed by the specified claim. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete Message (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void DeleteMessage(this IQueueingService queueingService, QueueName queueName, MessageId messageId, Claim claim) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + queueingService.DeleteMessageAsync(queueName, messageId, claim, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Deletes messages from a queue. + /// + /// + /// + /// This method deletes messages from a queue whether or not they are currently claimed. + /// + /// + /// The queueing service instance. + /// The queue name. + /// The IDs of messages to delete. These are obtained from QueuedMessage.Id. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a value. + /// + /// If the REST request does not return successfully. + /// Delete a Set of Messages by ID (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void DeleteMessages(this IQueueingService queueingService, QueueName queueName, IEnumerable messageIds) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + queueingService.DeleteMessagesAsync(queueName, messageIds, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion Messages + + #region Claims + + /// + /// Claim messages from a queue. + /// + /// + /// When the claim is no longer required, the code should call + /// or to ensure the following actions are taken. + /// + /// Messages which are part of this claim which were not processed are made available to other nodes. + /// The claim resource is cleaned up without waiting for the time-to-live to expire. + /// + /// + /// Messages which are not deleted before the claim is released will be eligible for + /// reclaiming by another process. + /// + /// The queueing service instance. + /// The queue name. + /// The maximum number of messages to claim. If this value is , a provider-specific default value is used. + /// The time to wait before the server automatically releases the claim. + /// The time to wait, after the time-to-live for the claim expires, before the server allows the claimed messages to be deleted due to the individual message's time-to-live expiring. + /// A object representing the claim. + /// If is . + /// If is . + /// + /// If is less than or equal to 0. + /// -or- + /// If is negative or . + /// -or- + /// If is negative. + /// + /// If the REST request does not return successfully. + /// Claim Messages (OpenStack Marconi API v1 Blueprint) + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Claim ClaimMessage(this IQueueingService queueingService, QueueName queueName, int? limit, TimeSpan timeToLive, TimeSpan gracePeriod) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.ClaimMessageAsync(queueName, limit, timeToLive, gracePeriod, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets detailed information about the current state of a claim. + /// + /// + /// Use instead of calling this method directly. + /// + /// The queueing service instance. + /// The queue name. + /// The claim to query. + /// A object representing the claim. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Query Claim (OpenStack Marconi API v1 Blueprint) + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static Claim QueryClaim(this IQueueingService queueingService, QueueName queueName, Claim claim) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + return queueingService.QueryClaimAsync(queueName, claim, CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Renews a claim, by updating the time-to-live and resetting the age of the claim to zero. + /// + /// + /// Use instead of calling this method directly. + /// + /// The queueing service instance. + /// The queue name. + /// The claim to renew. + /// The updated time-to-live for the claim. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is negative. + /// If the REST request does not return successfully. + /// Update Claim (OpenStack Marconi API v1 Blueprint) + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void UpdateClaim(this IQueueingService queueingService, QueueName queueName, Claim claim, TimeSpan timeToLive) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + queueingService.UpdateClaimAsync(queueName, claim, timeToLive, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Immediately release a claim, making any (remaining, non-deleted) messages associated + /// with the claim available to other workers. + /// + /// + /// Use instead of calling this method directly. + /// + /// The queueing service instance. + /// The queue name. + /// The claim to release. + /// If is . + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Release Claim (OpenStack Marconi API v1 Blueprint) + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static void ReleaseClaim(this IQueueingService queueingService, QueueName queueName, Claim claim) + { + if (queueingService == null) + throw new ArgumentNullException("queueingService"); + + try + { + queueingService.ReleaseClaimAsync(queueName, claim, CancellationToken.None).Wait(); + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + #endregion + } +} diff --git a/src/OpenStack/Core/Synchronous/ReadOnlyCollectionPageSynchronousExtensions.cs b/src/OpenStack/Core/Synchronous/ReadOnlyCollectionPageSynchronousExtensions.cs new file mode 100644 index 000000000..a4e685c0a --- /dev/null +++ b/src/OpenStack/Core/Synchronous/ReadOnlyCollectionPageSynchronousExtensions.cs @@ -0,0 +1,83 @@ +namespace net.openstack.Core.Synchronous +{ + using System; + using System.Collections.ObjectModel; + using System.Net; + using System.Threading; + using net.openstack.Core.Collections; + + /// + /// Provides extension methods to allow synchronous calls to the methods in , + /// along with the asynchronous extension methods for that class defined in . + /// + /// + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static class ReadOnlyCollectionPageSynchronousExtensions + { + /// + /// Get all pages in a paginated collection. + /// + /// + /// This method determines that the end of the collection is reached when either of + /// the following conditions is true. + /// + /// The property returns . + /// An empty page is reached. + /// + /// + /// The type of elements in the collection. + /// The first page in the collection. + /// A read-only collection containing the complete set of results from the paginated collection. + /// If is . + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollection GetAllPages(this ReadOnlyCollectionPage page) + { + if (page == null) + throw new ArgumentNullException("page"); + + try + { + return page.GetAllPagesAsync(CancellationToken.None, null).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + + /// + /// Gets the next page in the paginated collection. + /// + /// The type of elements in the collection. + /// A page of a paginated collection. + /// A collection containing the next page of results. + /// If is . + /// If the REST request does not return successfully. + /// + [Obsolete("These synchronous wrappers should not be used. For more information, see http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx.")] + public static ReadOnlyCollectionPage GetNextPage(this ReadOnlyCollectionPage page) + { + if (page == null) + throw new ArgumentNullException("page"); + + try + { + return page.GetNextPageAsync(CancellationToken.None).Result; + } + catch (AggregateException ex) + { + ReadOnlyCollection innerExceptions = ex.Flatten().InnerExceptions; + if (innerExceptions.Count == 1) + throw innerExceptions[0]; + + throw; + } + } + } +} diff --git a/src/OpenStack/Core/UriPart.cs b/src/OpenStack/Core/UriPart.cs new file mode 100644 index 000000000..8a3c87af7 --- /dev/null +++ b/src/OpenStack/Core/UriPart.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Core +{ + /// + /// Represents a specific part of a URI. + /// + /// + public enum UriPart + { + /// + /// Represents a non-specific URI part, where all characters except unreserved characters are percent-encoded. + /// + Any, + + /// + /// Represents a non-specific URL part, where all characters except unreserved characters and the characters (, ), !, and * are percent-encoded. + /// + /// + /// When used with , this URI part matches the behavior of , with the exception of space characters (this method percent-encodes space characters as %20). + /// + AnyUrl, + + /// + /// The host part of a URI. + /// + Host, + + /// + /// The complete path of a URI, formed from path segments separated by slashes (/ characters). + /// + Path, + + /// + /// A single segment of a URI path. + /// + PathSegment, + + /// + /// The complete query string of a URI. + /// + Query, + + /// + /// The value assigned to a query parameter within the query string of a URI. + /// + QueryValue, + + /// + /// The fragment part of a URI. + /// + Fragment, + } +} diff --git a/src/OpenStack/Core/UriUtility.cs b/src/OpenStack/Core/UriUtility.cs new file mode 100644 index 000000000..710bcdcd2 --- /dev/null +++ b/src/OpenStack/Core/UriUtility.cs @@ -0,0 +1,392 @@ +namespace net.openstack.Core +{ + using System; + using BitArray = System.Collections.BitArray; + using Encoding = System.Text.Encoding; + using MatchEvaluator = System.Text.RegularExpressions.MatchEvaluator; + using NumberStyles = System.Globalization.NumberStyles; + using Regex = System.Text.RegularExpressions.Regex; + using RegexOptions = System.Text.RegularExpressions.RegexOptions; + using StringBuilder = System.Text.StringBuilder; + + /// + /// Provides static utility methods for encoding and decoding text within + /// RFC 3986 URIs. + /// + /// RFC 3986: URI Generic Syntax + /// + /// + public static class UriUtility + { + private static readonly BitArray _unreservedCharacters; + private static readonly BitArray _generalDelimiters; + private static readonly BitArray _subDelimiters; + private static readonly BitArray _reservedCharacters; + private static readonly BitArray _allowedHostCharacters; + private static readonly BitArray _allowedPathCharacters; + private static readonly BitArray _allowedQueryCharacters; + private static readonly BitArray _allowedFragmentCharacters; + + /// + /// This is the regular expression for a single percent-encoded character. + /// + private static readonly Regex _percentEncodedPattern = new Regex(@"%([0-9A-Fa-f][0-9A-Fa-f])", RegexOptions.Compiled); + + static UriUtility() + { + _unreservedCharacters = new BitArray(256); + for (char i = 'a'; i <= 'z'; i++) + _unreservedCharacters.Set(i, true); + for (char i = 'A'; i <= 'Z'; i++) + _unreservedCharacters.Set(i, true); + for (char i = '0'; i <= '9'; i++) + _unreservedCharacters.Set(i, true); + _unreservedCharacters.Set('-', true); + _unreservedCharacters.Set('.', true); + _unreservedCharacters.Set('_', true); + _unreservedCharacters.Set('~', true); + + _generalDelimiters = new BitArray(256); + _generalDelimiters.Set(':', true); + _generalDelimiters.Set('/', true); + _generalDelimiters.Set('?', true); + _generalDelimiters.Set('#', true); + _generalDelimiters.Set('[', true); + _generalDelimiters.Set(']', true); + _generalDelimiters.Set('@', true); + + _subDelimiters = new BitArray(256); + _subDelimiters.Set('!', true); + _subDelimiters.Set('$', true); + _subDelimiters.Set('&', true); + _subDelimiters.Set('(', true); + _subDelimiters.Set(')', true); + _subDelimiters.Set('*', true); + _subDelimiters.Set('+', true); + _subDelimiters.Set(',', true); + _subDelimiters.Set(';', true); + _subDelimiters.Set('=', true); + _subDelimiters.Set('\'', true); + + _reservedCharacters = new BitArray(256).Or(_generalDelimiters).Or(_subDelimiters); + + _allowedHostCharacters = new BitArray(256).Or(_unreservedCharacters).Or(_subDelimiters); + + _allowedPathCharacters = new BitArray(256).Or(_unreservedCharacters).Or(_subDelimiters); + _allowedPathCharacters.Set(':', true); + _allowedPathCharacters.Set('@', true); + + _allowedQueryCharacters = new BitArray(256).Or(_allowedPathCharacters); + _allowedQueryCharacters.Set('/', true); + _allowedQueryCharacters.Set('?', true); + + _allowedFragmentCharacters = new BitArray(256).Or(_allowedPathCharacters); + _allowedFragmentCharacters.Set('/', true); + _allowedFragmentCharacters.Set('?', true); + } + + /// + /// Decodes the text of a URI by unescaping any percent-encoded character sequences and + /// then evaluating the result using the default encoding. + /// + /// + /// This method calls using the default + /// encoding. + /// + /// The encoded URI. + /// The decoded URI text. + /// If is . + public static string UriDecode(string text) + { + return UriDecode(text, Encoding.UTF8); + } + + /// + /// Decodes the text of a URI by unescaping any percent-encoded character sequences and + /// then evaluating the result using the specified encoding. + /// + /// The encoded URI. + /// The encoding to use for Unicode characters in the URI. If this value is , the encoding will be used. + /// The decoded URI text. + /// If is . + public static string UriDecode(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + + encoding = encoding ?? Encoding.UTF8; + MatchEvaluator matchEvaluator = + match => + { + string hexValue = match.Groups[1].Value; + return ((char)byte.Parse(hexValue, NumberStyles.HexNumber)).ToString(); + }; + string decodedText = _percentEncodedPattern.Replace(text, matchEvaluator); + byte[] data = Array.ConvertAll(decodedText.ToCharArray(), c => (byte)c); + return encoding.GetString(data); + } + + /// + /// Encodes text for inclusion in a URI using the encoding. + /// + /// + /// This method calls using the default + /// encoding. + /// + /// The text to encode for inclusion in a URI. + /// A value indicating where in the URI the specified text will be included. + /// The URI-encoded text, suitable for the specified URI part. + /// If is . + /// If is not a valid . + public static string UriEncode(string text, UriPart uriPart) + { + return UriEncode(text, uriPart, Encoding.UTF8); + } + + /// + /// Encodes text for inclusion in a URI. + /// + /// The text to encode for inclusion in a URI. + /// A value indicating where in the URI the specified text will be included. + /// The encoding to use for Unicode characters in the URI. If this value is , the encoding will be used. + /// The URI-encoded text, suitable for the specified URI part. + /// If is . + /// If is not a valid . + public static string UriEncode(string text, UriPart uriPart, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + + encoding = encoding ?? Encoding.UTF8; + switch (uriPart) + { + case UriPart.Any: + return UriEncodeAny(text, encoding); + + case UriPart.AnyUrl: + return UriEncodeAnyUrl(text, encoding); + + case UriPart.Host: + return UriEncodeHost(text, encoding); + + case UriPart.Path: + return UriEncodePath(text, encoding); + + case UriPart.PathSegment: + return UriEncodePathSegment(text, encoding); + + case UriPart.Query: + return UriEncodeQuery(text, encoding); + + case UriPart.QueryValue: + return UriEncodeQueryValue(text, encoding); + + case UriPart.Fragment: + return UriEncodeFragment(text, encoding); + + default: + throw new ArgumentException("The specified uriPart is not valid.", "uriPart"); + } + } + + private static string UriEncodeAny(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + + if (text.Length == 0) + return text; + + StringBuilder builder = new StringBuilder(); + byte[] data = encoding.GetBytes(text); + for (int i = 0; i < data.Length; i++) + { + if (_unreservedCharacters[data[i]]) + builder.Append((char)data[i]); + else + builder.Append('%').Append(data[i].ToString("x2")); + } + + return builder.ToString(); + } + + private static string UriEncodeAnyUrl(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + + if (text.Length == 0) + return text; + + StringBuilder builder = new StringBuilder(); + byte[] data = encoding.GetBytes(text); + for (int i = 0; i < data.Length; i++) + { + if (_unreservedCharacters[data[i]]) + { + builder.Append((char)data[i]); + } + else + { + switch ((char)data[i]) + { + case '(': + case ')': + case '*': + case '!': + builder.Append((char)data[i]); + break; + + default: + builder.Append('%').Append(data[i].ToString("x2")); + break; + } + } + } + + return builder.ToString(); + } + + private static string UriEncodeHost(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + + if (text.Length == 0) + return text; + + StringBuilder builder = new StringBuilder(); + byte[] data = encoding.GetBytes(text); + for (int i = 0; i < data.Length; i++) + { + if (_allowedHostCharacters[data[i]]) + builder.Append((char)data[i]); + else + builder.Append('%').Append(data[i].ToString("x2")); + } + + return builder.ToString(); + } + + private static string UriEncodePath(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + + if (text.Length == 0) + return text; + + StringBuilder builder = new StringBuilder(); + byte[] data = encoding.GetBytes(text); + for (int i = 0; i < data.Length; i++) + { + if (_allowedPathCharacters[data[i]] || data[i] == '/') + builder.Append((char)data[i]); + else + builder.Append('%').Append(data[i].ToString("x2")); + } + + return builder.ToString(); + } + + private static string UriEncodePathSegment(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + + if (text.Length == 0) + return text; + + StringBuilder builder = new StringBuilder(); + byte[] data = encoding.GetBytes(text); + for (int i = 0; i < data.Length; i++) + { + if (_allowedPathCharacters[data[i]]) + builder.Append((char)data[i]); + else + builder.Append('%').Append(data[i].ToString("x2")); + } + + return builder.ToString(); + } + + private static string UriEncodeQuery(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + + if (text.Length == 0) + return text; + + StringBuilder builder = new StringBuilder(); + byte[] data = encoding.GetBytes(text); + for (int i = 0; i < data.Length; i++) + { + if (_allowedQueryCharacters[data[i]]) + builder.Append((char)data[i]); + else + builder.Append('%').Append(data[i].ToString("x2")); + } + + return builder.ToString(); + } + + private static string UriEncodeQueryValue(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + + if (text.Length == 0) + return text; + + StringBuilder builder = new StringBuilder(); + byte[] data = encoding.GetBytes(text); + for (int i = 0; i < data.Length; i++) + { + if (_allowedQueryCharacters[data[i]] && data[i] != '&') + builder.Append((char)data[i]); + else + builder.Append('%').Append(data[i].ToString("x2")); + } + + return builder.ToString(); + } + + private static string UriEncodeFragment(string text, Encoding encoding) + { + if (text == null) + throw new ArgumentNullException("text"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + + if (text.Length == 0) + return text; + + StringBuilder builder = new StringBuilder(); + byte[] data = encoding.GetBytes(text); + for (int i = 0; i < data.Length; i++) + { + if (_allowedFragmentCharacters[data[i]]) + builder.Append((char)data[i]); + else + builder.Append('%').Append(data[i].ToString("x2")); + } + + return builder.ToString(); + } + } +} diff --git a/src/OpenStack/Core/Validators/IBlockStorageValidator.cs b/src/OpenStack/Core/Validators/IBlockStorageValidator.cs new file mode 100644 index 000000000..342f1b2af --- /dev/null +++ b/src/OpenStack/Core/Validators/IBlockStorageValidator.cs @@ -0,0 +1,22 @@ +namespace net.openstack.Core.Validators +{ + using System; + using net.openstack.Core.Providers; + using net.openstack.Providers.Rackspace.Exceptions; + + /// + /// Represents an object that validates arguments for an implementation of + /// prior to sending the calls to the underlying REST API. + /// + public interface IBlockStorageValidator + { + /// + /// Validates the size parameter when creating a new block storage volume + /// with . + /// + /// The volume size in GB. + /// If is less than 0. + /// If is not a valid volume size. + void ValidateVolumeSize(int size); + } +} diff --git a/src/OpenStack/Core/Validators/IHttpResponseCodeValidator.cs b/src/OpenStack/Core/Validators/IHttpResponseCodeValidator.cs new file mode 100644 index 000000000..43e098907 --- /dev/null +++ b/src/OpenStack/Core/Validators/IHttpResponseCodeValidator.cs @@ -0,0 +1,23 @@ +using System; +using JSIStudios.SimpleRESTServices.Client; +using net.openstack.Core.Exceptions.Response; + +namespace net.openstack.Core.Validators +{ + /// + /// Represents an object that can determine whether a particular response from a + /// REST API call succeeded. + /// + public interface IHttpResponseCodeValidator + { + /// + /// Verifies that represents a successful response + /// for a REST API call, throwing an appropriate + /// if indicates a failure. + /// + /// The response from the REST call. + /// If is . + /// If indicates the REST API call failed. + void Validate(Response response); + } +} diff --git a/src/OpenStack/Core/Validators/INetworksValidator.cs b/src/OpenStack/Core/Validators/INetworksValidator.cs new file mode 100644 index 000000000..35b59677f --- /dev/null +++ b/src/OpenStack/Core/Validators/INetworksValidator.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Core.Validators +{ + using System; + using net.openstack.Core.Exceptions; + using net.openstack.Core.Providers; + + /// + /// Represents an object that validates arguments for an implementation of + /// prior to sending the calls to the underlying REST API. + /// + public interface INetworksValidator + { + /// + /// Validates an IP address range (CIDR) formatted as a string. + /// + /// The IP address range. + /// If is . + /// If is not in the correct format. + void ValidateCidr(string cidr); + } +} diff --git a/src/OpenStack/Core/Validators/IObjectStorageValidator.cs b/src/OpenStack/Core/Validators/IObjectStorageValidator.cs new file mode 100644 index 000000000..d6d787d4d --- /dev/null +++ b/src/OpenStack/Core/Validators/IObjectStorageValidator.cs @@ -0,0 +1,29 @@ +namespace net.openstack.Core.Validators +{ + using System; + using net.openstack.Core.Exceptions; + using net.openstack.Core.Providers; + + /// + /// Represents an object that validates arguments for an implementation of + /// prior to sending the calls to the underlying REST API. + /// + public interface IObjectStorageValidator + { + /// + /// Validates a container name for an object storage provider. + /// + /// The container name. + /// If is . + /// If is not a valid container name. + void ValidateContainerName(string containerName); + + /// + /// Validates an object name for an object storage provider. + /// + /// The object name. + /// If is . + /// If is not a valid object name. + void ValidateObjectName(string objectName); + } +} diff --git a/src/OpenStack/Core/Validators/NamespaceDoc.cs b/src/OpenStack/Core/Validators/NamespaceDoc.cs new file mode 100644 index 000000000..5c05b986f --- /dev/null +++ b/src/OpenStack/Core/Validators/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Core.Validators +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines interfaces + /// for validating request arguments prior to sending them in calls to REST APIs. + /// These interfaces may be implemented in a provider-specific manner. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Core/WebRequestExtensions.cs b/src/OpenStack/Core/WebRequestExtensions.cs new file mode 100644 index 000000000..e0aae8a13 --- /dev/null +++ b/src/OpenStack/Core/WebRequestExtensions.cs @@ -0,0 +1,124 @@ +namespace net.openstack.Core +{ + using System; + using System.Net; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Provides extension methods for asynchronous operations on + /// objects. + /// + /// + /// + public static class WebRequestExtensions + { + /// + /// Returns a response to an Internet request as an asynchronous operation. + /// + /// + /// This operation will not block. The returned object will + /// complete after a response to an Internet request is available. + /// + /// The request. + /// A object which represents the asynchronous operation. + /// If is . + public static Task GetResponseAsync(this WebRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + return GetResponseAsync(request, CancellationToken.None); + } + + /// + /// Returns a response to an Internet request as an asynchronous operation. + /// + /// + /// This operation will not block. The returned object will + /// complete after a response to an Internet request is available. + /// + /// The request. + /// The that will be assigned to the new . + /// A object which represents the asynchronous operation. + /// If is . + /// + /// If was previously called. + /// -or- + /// If the timeout period for the request expired. + /// -or- + /// If an error occurred while processing the request. + /// + public static Task GetResponseAsync(this WebRequest request, CancellationToken cancellationToken) + { + if (request == null) + throw new ArgumentNullException("request"); + + bool timeout = false; + TaskCompletionSource completionSource = new TaskCompletionSource(); + + RegisteredWaitHandle timerRegisteredWaitHandle = null; + RegisteredWaitHandle cancellationRegisteredWaitHandle = null; + AsyncCallback completedCallback = + result => + { + try + { + if (cancellationRegisteredWaitHandle != null) + cancellationRegisteredWaitHandle.Unregister(null); + + if (timerRegisteredWaitHandle != null) + timerRegisteredWaitHandle.Unregister(null); + + completionSource.TrySetResult(request.EndGetResponse(result)); + } + catch (WebException ex) + { + if (timeout) + completionSource.TrySetException(new WebException("No response was received during the time-out period for a request.", WebExceptionStatus.Timeout)); + else if (cancellationToken.IsCancellationRequested) + completionSource.TrySetCanceled(); + else + completionSource.TrySetException(ex); + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + } + }; + + IAsyncResult asyncResult = request.BeginGetResponse(completedCallback, null); + if (!asyncResult.IsCompleted) + { + if (request.Timeout != Timeout.Infinite) + { + WaitOrTimerCallback timedOutCallback = + (object state, bool timedOut) => + { + if (timedOut) + { + timeout = true; + request.Abort(); + } + }; + + timerRegisteredWaitHandle = ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, timedOutCallback, null, request.Timeout, true); + } + + if (cancellationToken.CanBeCanceled) + { + WaitOrTimerCallback cancelledCallback = + (object state, bool timedOut) => + { + if (cancellationToken.IsCancellationRequested) + request.Abort(); + }; + + cancellationRegisteredWaitHandle = ThreadPool.RegisterWaitForSingleObject(cancellationToken.WaitHandle, cancelledCallback, null, Timeout.Infinite, true); + } + } + + return completionSource.Task; + } + } +} diff --git a/src/OpenStack/Exceptions/IdentityRequiredException.cs b/src/OpenStack/Exceptions/IdentityRequiredException.cs new file mode 100644 index 000000000..37a0e16da --- /dev/null +++ b/src/OpenStack/Exceptions/IdentityRequiredException.cs @@ -0,0 +1,33 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Providers; +using OpenStack.Authentication; + +namespace OpenStack +{ + /// + /// The exception that is thrown when an instance is used as an and no default identity was specified. + /// + /// + [Serializable] + public class IdentityRequiredException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public IdentityRequiredException() + : base("You must set the default identity when constructing the IdentityProvider in order to use it as an IAuthenticationProvider.") + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected IdentityRequiredException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Exceptions/RegionRequiredException.cs b/src/OpenStack/Exceptions/RegionRequiredException.cs new file mode 100644 index 000000000..492e0f813 --- /dev/null +++ b/src/OpenStack/Exceptions/RegionRequiredException.cs @@ -0,0 +1,31 @@ +using System; +using System.Runtime.Serialization; + +namespace OpenStack +{ + /// + /// The exception that is thrown when a service requires that a region is explicitly set and one was not provided. + /// + /// + [Serializable] + public class RegionRequiredException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The error message. + /// The message formatting arguments. + public RegionRequiredException(string message, params object[] args) : base(string.Format(message, args)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected RegionRequiredException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Exceptions/ResourceErrorException.cs b/src/OpenStack/Exceptions/ResourceErrorException.cs new file mode 100644 index 000000000..2c7927695 --- /dev/null +++ b/src/OpenStack/Exceptions/ResourceErrorException.cs @@ -0,0 +1,26 @@ +using System; +using System.Runtime.Serialization; + +namespace OpenStack +{ + /// + /// The exception that is thrown when the requested resource is in an error state. + /// + /// + [Serializable] + public sealed class ResourceErrorException : Exception + { + /// + public ResourceErrorException() + { } + + /// + public ResourceErrorException(string message) + : base(message) + { } + + /// + private ResourceErrorException(SerializationInfo info, StreamingContext context) : base(info, context) + { } + } +} diff --git a/src/OpenStack/Exceptions/UserAuthenticationException.cs b/src/OpenStack/Exceptions/UserAuthenticationException.cs new file mode 100644 index 000000000..6595528e0 --- /dev/null +++ b/src/OpenStack/Exceptions/UserAuthenticationException.cs @@ -0,0 +1,37 @@ +using System; +using System.Runtime.Serialization; + +namespace OpenStack +{ + /// + /// The exception thrown when the user authentication process fails, or + /// the authentication process did not provide a value for the ServiceCatalog. + /// + /// + [Serializable] + public class UserAuthenticationException : Exception + { + /// + /// Initializes a new instance of the class + /// with the specified error message. + /// + /// The message that describes the error. + /// The message formatting arguments. + public UserAuthenticationException(string message, params object[] args) + : base(string.Format(message, args)) + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected UserAuthenticationException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Extensions/EnumerableExtensions.cs b/src/OpenStack/Extensions/EnumerableExtensions.cs new file mode 100644 index 000000000..3a925dc28 --- /dev/null +++ b/src/OpenStack/Extensions/EnumerableExtensions.cs @@ -0,0 +1,19 @@ +using System.Linq; + +namespace System.Collections.Generic +{ + internal static class EnumerableExtensions + { + /// + /// Creates a new list wrapping the specified items. + /// If is , returns an empty list. + /// + public static IList ToNonNullList(this IEnumerable items) + { + if(items == null) + return new List(); + + return items.ToList(); + } + } +} diff --git a/src/OpenStack/Extensions/FlurlExtensions.cs b/src/OpenStack/Extensions/FlurlExtensions.cs new file mode 100644 index 000000000..6fec955fa --- /dev/null +++ b/src/OpenStack/Extensions/FlurlExtensions.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Flurl.Http; +using OpenStack; +using OpenStack.Authentication; + +// ReSharper disable once CheckNamespace +namespace Flurl.Extensions +{ + /// + /// Useful Flurl extension methods for custom implementations. + /// + /// + public static class FlurlExtensions + { + /// + /// Converts a to a . + /// + /// The URL. + public static Uri ToUri(this Url url) + { + return new Uri(url.ToString()); + } + + /// + /// Removes any query parameters which have a null or empty value. + /// + /// The URL. + public static Url RemoveNullOrEmptyQueryParams(this string url) + { + return new Url(url).RemoveNullOrEmptyQueryParams(); + } + + /// + /// Removes any query parameters which have a null or empty value. + /// + /// The URL. + public static Url RemoveNullOrEmptyQueryParams(this Url url) + { + foreach (KeyValuePair queryParam in url.QueryParams.ToList()) + { + if (queryParam.Value == null || queryParam.Value.ToString() == string.Empty) + url.QueryParams.Remove(queryParam); + } + + return url; + } + + /// + /// Applies OpenStack authentication to a request. + /// + /// The URL. + /// The authentication provider. + /// + /// An authenticated request. + /// + public static PreparedRequest Authenticate(this string url, IAuthenticationProvider authenticationProvider) + { + return new Url(url).Authenticate(authenticationProvider); + } + + /// + /// Applies OpenStack authentication to a request. + /// + /// The URL. + /// The authentication provider. + /// + /// An authenticated request. + /// + public static PreparedRequest Authenticate(this Url url, IAuthenticationProvider authenticationProvider) + { + return url.PrepareRequest().Authenticate(authenticationProvider); + } + + /// + /// Builds a prepared Flurl request which can be executed at a later time. + /// + /// The URL. + public static PreparedRequest PrepareRequest(this string url) + { + return new Url(url).PrepareRequest(); + } + + /// + /// Builds a prepared Flurl request which can be executed at a later time. + /// + /// The URL. + public static PreparedRequest PrepareRequest(this Url url) + { + return new PreparedRequest(url, autoDispose: true) + { + Settings = OpenStackNet.Configuration.FlurlHttpSettings + }; + } + + /// + /// Applies OpenStack authentication to a request. + /// + /// The request. + /// The authentication provider. + /// + /// An authenticated request. + /// + public static PreparedRequest Authenticate(this PreparedRequest request, IAuthenticationProvider authenticationProvider) + { + var authenticatedMessageHandler = request.HttpMessageHandler as AuthenticatedMessageHandler; + if (authenticatedMessageHandler != null) + { + authenticatedMessageHandler.AuthenticationProvider = authenticationProvider; + } + return request; + } + + /// + public static PreparedRequest WithHeader(this PreparedRequest request, string key, object value) + { + ((FlurlClient)request).WithHeader(key, value); + return request; + } + + /// + /// Sends the . + /// + /// A task which returns the request. + /// The HTTP response message. + public static async Task SendAsync(this Task requestTask) + { + PreparedRequest request = await requestTask.ConfigureAwait(false); + return await request.SendAsync().ConfigureAwait(false); + } + } +} diff --git a/src/OpenStack/Extensions/HttpHeadersExtensions.cs b/src/OpenStack/Extensions/HttpHeadersExtensions.cs new file mode 100644 index 000000000..81b5ea2ae --- /dev/null +++ b/src/OpenStack/Extensions/HttpHeadersExtensions.cs @@ -0,0 +1,17 @@ +using System.Net.Http.Headers; + +namespace System.Net.Http +{ + internal static class HttpHeadersExtensions + { + public const string AuthTokenHeader = "X-Auth-Token"; + + public static void SetAuthToken(this HttpHeaders headers, string value) + { + if (headers.Contains(AuthTokenHeader)) + headers.Remove(AuthTokenHeader); + + headers.Add(AuthTokenHeader, value); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Extensions/HttpRequestMessageExtensions.cs b/src/OpenStack/Extensions/HttpRequestMessageExtensions.cs new file mode 100644 index 000000000..870a4bbe5 --- /dev/null +++ b/src/OpenStack/Extensions/HttpRequestMessageExtensions.cs @@ -0,0 +1,25 @@ +namespace System.Net.Http +{ + internal static class HttpRequestMessageExtensions + { + public static HttpRequestMessage Copy(this HttpRequestMessage request) + { + var message = new HttpRequestMessage(request.Method, request.RequestUri) + { + Content = request.Content, + Version = request.Version + }; + + foreach (var property in request.Properties) + { + message.Properties.Add(property); + } + + foreach (var header in request.Headers) + { + message.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + return message; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Extensions/TaskExtensions.cs b/src/OpenStack/Extensions/TaskExtensions.cs new file mode 100644 index 000000000..eb61d2ef8 --- /dev/null +++ b/src/OpenStack/Extensions/TaskExtensions.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; + +namespace OpenStack.Synchronous.Extensions +{ + /// + /// Extensions to . + /// + /// + public static class TaskExtensions + { + /// + /// Calls an asynchronous method synchronously. Hopefully without causing deadlocks or mucking up any thrown exceptions. + /// + public static T ForceSynchronous(this Task task) + { + return task.ConfigureAwait(false).GetAwaiter().GetResult(); + } + + /// + /// Calls an asynchronous method synchronously. Hopefully without causing deadlocks or mucking up any thrown exceptions. + /// + public static void ForceSynchronous(this Task task) + { + task.ConfigureAwait(false).GetAwaiter().GetResult(); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Extensions/TypeExtensions.cs b/src/OpenStack/Extensions/TypeExtensions.cs new file mode 100644 index 000000000..1bd1dcef4 --- /dev/null +++ b/src/OpenStack/Extensions/TypeExtensions.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using OpenStack.Serialization; + +namespace System.Extensions +{ + /// + /// Useful System.Type extension methods for custom implementations. + /// + /// + public static class TypeExtensions + { + /// + /// Gets the AssemblyFileVersion for the specified type. + /// + /// The type which resides in the desired assembly. + public static string GetAssemblyFileVersion(this Type type) + { + Assembly assembly = type.Assembly; + try + { + var fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); + return fileVersionInfo.FileVersion; + } + catch + { + return assembly.GetName().Version.ToString(); + } + } + + /// + public static T Clone(this T src) + where T : new() + { + var dest = new T(); + src.CopyProperties(dest); + return dest; + } + + /// + public static void CopyProperties(this T src, T dest) + { + foreach (PropertyDescriptor srcProp in TypeDescriptor.GetProperties(src)) + { + srcProp.SetValue(dest, srcProp.GetValue(src)); + } + } + + /// + public static void CopyProperties(this object src, object dest) + { + var destProps = TypeDescriptor.GetProperties(dest).Cast(); + foreach (PropertyDescriptor srcProp in TypeDescriptor.GetProperties(src)) + { + var destProp = destProps.FirstOrDefault(x => x.Name == srcProp.Name && x.PropertyType == srcProp.PropertyType); + destProp?.SetValue(dest, srcProp.GetValue(src)); + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Flurl/PreparedRequest.cs b/src/OpenStack/Flurl/PreparedRequest.cs new file mode 100644 index 000000000..1d96b204a --- /dev/null +++ b/src/OpenStack/Flurl/PreparedRequest.cs @@ -0,0 +1,152 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Flurl.Http.Content; + +// ReSharper disable once CheckNamespace +namespace Flurl.Http +{ + /// + /// Represents a prepared Flurl request which can be executed at a later time. + /// + /// + public class PreparedRequest : FlurlClient + { + /// + /// Initializes a new instance of the class. + /// + public PreparedRequest() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The URL. + public PreparedRequest(string url) : base(url) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The URL. + public PreparedRequest(Url url) : base(url) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The URL. + /// Specifies if the request should be automatically disposed. + public PreparedRequest(string url, bool autoDispose) : base(url, autoDispose) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The URL. + /// Specifies if the request should be automatically disposed. + public PreparedRequest(Url url, bool autoDispose) : base(url, autoDispose) + { + } + + /// + /// The HTTP verb which will be used in the request. + /// + public HttpMethod Verb { get; protected set; } + + /// + /// The HTTP content which will be used in the request. + /// + public HttpContent Content { get; protected set; } + + /// + /// The optional canellation token which will be used in the request, defaults to None. + /// + public CancellationToken CancellationToken { get; protected set; } + + /// + /// Prepares the client to send a DELETE request + /// + public PreparedRequest PrepareDelete(CancellationToken cancellationToken = default(CancellationToken)) + { + Verb = HttpMethod.Delete; + CancellationToken = cancellationToken; + return this; + } + + /// + /// Prepares the client to send a GET request + /// + public PreparedRequest PrepareGet(CancellationToken cancellationToken = default(CancellationToken)) + { + Verb = HttpMethod.Get; + CancellationToken = cancellationToken; + return this; + } + + /// + /// Prepares the client to send a PATCH request containing json + /// + public PreparedRequest PreparePatchJson(object data, CancellationToken cancellationToken = default(CancellationToken)) + { + Verb = new HttpMethod("PATCH"); + Content = new CapturedJsonContent(Settings.JsonSerializer.Serialize(data)); + CancellationToken = cancellationToken; + return this; + } + + /// + /// Prepares the client to send a POST request containing json + /// + public PreparedRequest PreparePostJson(object data, CancellationToken cancellationToken = default(CancellationToken)) + { + Verb = HttpMethod.Post; + Content = new CapturedJsonContent(Settings.JsonSerializer.Serialize(data)); + CancellationToken = cancellationToken; + return this; + } + + /// + /// Prepares the client to send a PUT request containing json + /// + public PreparedRequest PreparePutJson(object data, CancellationToken cancellationToken = default(CancellationToken)) + { + Verb = HttpMethod.Put; + Content = new CapturedJsonContent(Settings.JsonSerializer.Serialize(data)); + CancellationToken = cancellationToken; + return this; + } + + /// + /// Executes the built request + /// + public Task SendAsync() + { + if(Verb == null) + throw new InvalidOperationException("Unable to execute request as nothing has been built yet."); + + return SendAsync(Verb, Content, CancellationToken); + } + } + + /// + public static class PreparedRequestExtensions + { + /// + /// Allow a specific set of HTTP status codes. + /// + /// The prepared request. + /// The allowed status codes. + /// + public static PreparedRequest AllowHttpStatus(this PreparedRequest request, params HttpStatusCode[] statusCodes) + { + return (PreparedRequest)((FlurlClient)request).AllowHttpStatus(statusCodes); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Icons/openstack_net_logo.png b/src/OpenStack/Icons/openstack_net_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..924f00eb664747651c4f58fcc0b2f4e683ed9310 GIT binary patch literal 3746 zcmd5zo?Llp$@@Ck%0x10aUFfQ9;^^yXm5$UW$48S>@c9`ML zpwVL^I~X<~kTjj?>BIGL-HQ)qg(GMiI*6EXw!|6)vayR{(}IsOxWFOCVP=FaY_916 z3}Di2Vf!syQLbzUMktdU$6dfN%zv2E>GiMMU9aY+=9S z;w9@1F%ky+uEITP3;QD|A6F{iz~V3f3k1q67-fk9EYS!w*4)a<$`rt$&?qDdgG6J@ z&{lXX29H7ke-4<$8;2f(cPBah=}WS+g@tmtY&;Sf9UYB`#v)jp!$`EXwe8uBBBhwBaj$T!5k)=%Vb3W8;G<+tYchTm?Y9aQV3_ey8Zc0)-3@-^lBC?I^B0Zvf{*8Ah$Nw+uKWyp$NyU(oV2~TF@qb$7yGYW18_T~MU$Xg&I*bSjUpNwCIKwpy zKp?3S>RwOBE-Y3k6gD+Akw~NyCr-R%GN+1*-@kv4#bWL3?B?d?R8>`BFjz=Ph>D6z zS6A2Q=x9Yn#l?#kpFMl_;K2h)XD@VgAd$$iu`zvpeJ?Ms^@Rl}6ngOBK^BWuU0t1+ znE1Y_=^2se=H`}>kul`&-%p{;R8@T(8Y(U>4hjl-ot)g#(t<*v=I7^Mzka>GzP=(B zFD)(g^z?|u;?d~nwY4<~$*5GSI4jHC+jg1YH$-Hsn#^=wU`}+E7YHA1s0*Axdvu96hYpbH7B9F)W^5sidSXfL< zj7TH`gTej%{g#%NIyyQC1fsC8P+eW!*VlJ?dU|SVDj*zMf1b z8yXt2+3exrVGj?Ffq{Xtva+_ew$;^D2n4dcysWIO?C9tiA0N->^CeeJQc_ZWe!k@1 z`}XZyl#Y9mWOat?PVtaz|4Rla`O)S%5J+C+Od@*5yqqmaiN0j1*`jqD-75VGw{Us_ zeth{J+_lfVA-=geKD;`9uK800|3M>ICWM@*2N+JqBV%)+_IA!=YL-7)qb{xuWRVwQfIprLW=7kZGoPWdh z1!}8^@Fsfum%ZJ#!Ov$2M2FvBLdo>1IUh?bJFD$7h>nTqdR2Wja?pg zzI>XR$SrHR%tObCMt;%|)SnP)!>8PA4Tp{Me2)1HJ)?x#Z8Z}%T-Z9CZLqydq4}

9+RbP3#XH?rny-{onI`)9rg2_qj8 zDyHoU_tK^==_m-53|i*S`M9Z3Z$=q-inigkRnM*(dA8i#YDnJP zz0Y>}Ce@HEOtzgh(A~|M zzux@h^G?yb2|@9p>z>85>3Ul7JU`|3^iCKsPor~M%Cg<8J$MasH7zyeIx+(4*AQcFmHF? z`gPOmQN{6b2f>)n)9%6LNVVfp!I~nM9#y2J+O~1-Vk;DQ3My6Y+mpDDa;WJ(ak{s; z`&tHves6YbnfkEcj&4Mn%OP1N={8`1NYzmo&!r|e057;N9qxaU?o+aE=cwFG=*&`q zPU$9p)~o9c)M#jECc+}85mzp^gBKDEZoXB3k*-Z2&!KztpB!<$#vNgQ{RoaMDxS25 z^nUV=R8-9!GVuwXA9dRXguRHB=ddhx-ubN}x@W5J0Z%ODp4JyaY#L;bHs?i~T>Lt% z_~rxEz8&E7Mpg98d4J_VBB$eC=+^1$k$8nuuVdlnzMsK=41>&$WLLdX(;b22X_Yr39z$v^PHJQ0Kl)j~bPkD(rZ0Dyh0`pd- z#|!`X`No_N^!Po(PpdPJ@&ve%RM#;%E@-7BTP471X`exj|t0Mg? z?qhry@rGWJ6en*`WlDKMadBee(xpqYy#W(#R*{fcdIl&dPhdJabG+$9^ca?0_a<-8 zWMe_y1G6XO7kZ}c>TazHq{g~f7ed*ts}S+Dv6OYRmRy|{Qsfs?`7t34_4J^9{+OJp zYyXM+3n>~N&(GQ>tSm}G;}#r#R>WJK-GguUL#s@boV97(x|Bd)sue_js?_0h5wkq4 zq!gsZagJ%{UN2_qd7mx-mNL6d+}CAtGDb4r7zq=^M@)&()%M9Kw3zVLpy80b;OTBe zVTP70UfkZ6Ag1EN7q%0E% z%J%19=Oe5GbwVvG2aF!|J1NQ%&P{4xwbcmRAJJZUo>=ab3SrDMwCg9c89fn4v&uLH z)9ac&wEI`Me*MJko%?Plepq`v+xgHYFZLE}lT%^7b>4RQ8bvIV`jhL`emNtkdjV{- z@YH7a+~?jdRnU)_;=#;wZ1<7@O9zOFbY?)OJT!lQH@5o)!R5e7eF*rr zXQ|lMnN>)Vf$hzU3?OS#2z{$&6*0{P~&T4nCyp2S$Uxdbp(; zq*N=o)4km9os=+iri^K!PJsqhZdn&(|Ik+H^C*jve&Gm&<>6v3q~)Z!T+)AZWOG;{ zO4*{85AwV9X4en~Z$fl)ovxLGnAA0<>^@02>2>N0yYYE1@x!gonNi`XC#Zq4V>NX` zP$vIi{agK;jlq$E>>N$S4~CrihZQ+sDVo+PxUW*qb;uy(IomIg?#OR7OwxeNK2E!C%7-oHl6zEl#=@FS`&sLRYpSNZGf zHsw+o(eS;AhMV9~0JNbpDo+*C&}yZ1$iC z=b&!fE#kO#f`2Zbh6GO}9I&KqO;aik9P=o{Zyl~HSBDCXBf)vA(kAVuwUv-%p4sQo zLQPVz;gj0!-Zt|u)4b#e>31R0oh$yj{$jK6*a?r0%O%dfelMQ-wNxX0Py2nvkT@g% zL|aZ9yGXd5Bm + /// Represents a uniqe identifier. + /// + /// This is a Guid which has implicit and explicit conversions to/from Guid and String. + /// + ///

+ [JsonConverter(typeof(IdentifierConverter))] + public class Identifier + { + private readonly string _id; + + /// + /// Initializes a new instance of the class. + /// + /// The identifier. + public Identifier(string id) + { + _id = id; + } + + /// + /// Initializes a new instance of the class. + /// + /// The identifier. + public Identifier(Guid id) + { + _id = id.ToString("D"); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return _id; + } + + #region Conversions + /// + /// Performs an implicit conversion from to . + /// + /// The identifier. + /// + /// The result of the conversion. + /// + public static implicit operator Identifier(Guid id) + { + return new Identifier(id); + } + + /// + /// Performs an implicit conversion from to . + /// + /// The identifier. + /// + /// The result of the conversion. + /// + public static implicit operator string(Identifier id) + { + return id?.ToString(); + } + + /// + /// Performs an implicit conversion from to . + /// + /// The identifier. + /// + /// The result of the conversion. + /// + public static implicit operator Identifier(string id) + { + return new Identifier(id); + } + #endregion + + #region Equality + + private bool Equals(Identifier other) + { + return _id.Equals(other._id); + } + + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + + var stringOther = obj as string; + if (stringOther != null) + { + Guid idGuid; + return Guid.TryParse(stringOther, out idGuid) && Equals(new Identifier(idGuid)); + } + + var guidOther = obj as Guid?; + if (guidOther != null) + return Equals(new Identifier(guidOther.Value)); + + var otherId = obj as Identifier; + return otherId != null && Equals(otherId); + } + + /// + public override int GetHashCode() + { + return _id.GetHashCode(); + } + + /// + public static bool operator ==(Identifier left, Identifier right) + { + return Equals(left, right); + } + + /// + public static bool operator !=(Identifier left, Identifier right) + { + return !Equals(left, right); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/OpenStack/Images/v2/ImageStatus.cs b/src/OpenStack/Images/v2/ImageStatus.cs new file mode 100644 index 000000000..74ad836b6 --- /dev/null +++ b/src/OpenStack/Images/v2/ImageStatus.cs @@ -0,0 +1,8 @@ +using OpenStack.Images.v2.Serialization; + +namespace OpenStack.Images.v2 +{ + /// + public class ImageStatus : ImageStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/Images/v2/Serialization/ImageStatus.cs b/src/OpenStack/Images/v2/Serialization/ImageStatus.cs new file mode 100644 index 000000000..f9267247c --- /dev/null +++ b/src/OpenStack/Images/v2/Serialization/ImageStatus.cs @@ -0,0 +1,27 @@ +using OpenStack.Serialization; + +namespace OpenStack.Images.v2.Serialization +{ + /// + /// Server image status. + /// + /// + public class ImageStatus : ResourceStatus + where T : ImageStatus, new() + { + /// + public static readonly T Active = new T {DisplayName = "ACTIVE"}; + + /// + public static readonly T Saving = new T {DisplayName = "SAVING"}; + + /// + public static readonly T Deleted = new T {DisplayName = "DELETED"}; + + /// + public static readonly T Error = new T {DisplayName = "ERROR", IsError = true}; + + /// + public static readonly T Unknown = new T {DisplayName = "UNKNOWN"}; + } +} diff --git a/src/OpenStack/NamespaceDoc.cs b/src/OpenStack/NamespaceDoc.cs new file mode 100644 index 000000000..d5472ef7b --- /dev/null +++ b/src/OpenStack/NamespaceDoc.cs @@ -0,0 +1,28 @@ +namespace OpenStack +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines provider-independent + /// interfaces and implementations of functionality used by all OpenStack APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} + +namespace OpenStack.Synchronous +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines + /// synchronous wrappers for OpenStack service interfaces which are asynchronous by default. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} + diff --git a/src/OpenStack/Networking/IPVersion.cs b/src/OpenStack/Networking/IPVersion.cs new file mode 100644 index 000000000..d8bc8d81f --- /dev/null +++ b/src/OpenStack/Networking/IPVersion.cs @@ -0,0 +1,18 @@ +namespace OpenStack.Networking +{ + /// + /// Internet Protocol Version + /// + public enum IPVersion + { + /// + /// IPv4 + /// + IPv4 = 4, + + /// + /// IPv6 + /// + IPv6 = 6 + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/NamespaceDoc.cs b/src/OpenStack/Networking/NamespaceDoc.cs new file mode 100644 index 000000000..9c175fd7d --- /dev/null +++ b/src/OpenStack/Networking/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace OpenStack.Networking +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines provider-independent + /// interfaces and implementations for the OpenStack Networking API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Networking/v2/AllocationPool.cs b/src/OpenStack/Networking/v2/AllocationPool.cs new file mode 100644 index 000000000..276eb0b77 --- /dev/null +++ b/src/OpenStack/Networking/v2/AllocationPool.cs @@ -0,0 +1,59 @@ +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents a range of IP addresses + /// + /// + public class AllocationPool + { + /// + /// Initializes a new instance of the class. + /// + /// The initial IP address. + /// The final IP address. + public AllocationPool(string start, string end) + { + Start = start; + End = end; + } + + /// + /// The initial IP address. + /// + [JsonProperty("start")] + public string Start { get; set; } + + /// + /// The final IP address. + /// + [JsonProperty("end")] + public string End { get; set; } + + #region Equality + private bool Equals(AllocationPool other) + { + return string.Equals(Start, other.Start) && string.Equals(End, other.End); + } + + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + var other = obj as AllocationPool; + return other != null && Equals(other); + } + + /// + public override int GetHashCode() + { + unchecked + { + return (Start.GetHashCode()*397) ^ End.GetHashCode(); + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/AllowedAddress.cs b/src/OpenStack/Networking/v2/AllowedAddress.cs new file mode 100644 index 000000000..88a4ccd51 --- /dev/null +++ b/src/OpenStack/Networking/v2/AllowedAddress.cs @@ -0,0 +1,71 @@ +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2 +{ + /// + /// Defines an arbitrary MAC address/IP_address(CIDR) pairs that are allowed to pass through a port regardless of the subnet associated with the network. + /// + /// + public class AllowedAddress + { + /// + /// Initializes a new instance of the class. + /// + /// The ip address. + public AllowedAddress(string ipAddress) + { + IPAddress = ipAddress; + } + + /// + /// The IP address or CIDR. + /// + [JsonProperty("ip_address")] + public string IPAddress { get; set; } + + /// + /// The MAC address. + /// + [JsonProperty("mac_address")] + public string MACAddress { get; set; } + + #region Equality + + private bool Equals(AllowedAddress other) + { + return string.Equals(IPAddress, other.IPAddress) && string.Equals(MACAddress, other.MACAddress); + } + + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + var other = obj as AllowedAddress; + return other != null && Equals(other); + } + + /// + public override int GetHashCode() + { + unchecked + { + return ((IPAddress != null ? IPAddress.GetHashCode() : 0)*397) ^ (MACAddress != null ? MACAddress.GetHashCode() : 0); + } + } + + /// + public static bool operator ==(AllowedAddress left, AllowedAddress right) + { + return Equals(left, right); + } + + /// + public static bool operator !=(AllowedAddress left, AllowedAddress right) + { + return !Equals(left, right); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/HostRoute.cs b/src/OpenStack/Networking/v2/HostRoute.cs new file mode 100644 index 000000000..9fce8cb23 --- /dev/null +++ b/src/OpenStack/Networking/v2/HostRoute.cs @@ -0,0 +1,59 @@ +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents a subnet host route. + /// + /// + public class HostRoute + { + /// + /// Initializes a new instance of the class. + /// + /// The destination CIDR. + /// The next hop IP address. + public HostRoute(string destinationCIDR, string nextHop) + { + DestinationCIDR = destinationCIDR; + NextHop = nextHop; + } + + /// + /// The destination CIDR. + /// + [JsonProperty("destination")] + public string DestinationCIDR { get; set; } + + /// + /// The IP address of the next hop. + /// + [JsonProperty("nexthop")] + public string NextHop { get; set; } + + #region Equality + private bool Equals(HostRoute other) + { + return string.Equals(DestinationCIDR, other.DestinationCIDR) && string.Equals(NextHop, other.NextHop); + } + + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + var other = obj as HostRoute; + return other != null && Equals(other); + } + + /// + public override int GetHashCode() + { + unchecked + { + return (DestinationCIDR.GetHashCode() * 397) ^ NextHop.GetHashCode(); + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/IPAddressAssociation.cs b/src/OpenStack/Networking/v2/IPAddressAssociation.cs new file mode 100644 index 000000000..a3c8ed1ef --- /dev/null +++ b/src/OpenStack/Networking/v2/IPAddressAssociation.cs @@ -0,0 +1,100 @@ +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents an IP address associated with a port resource of the + /// + /// + public class IPAddressAssociation + { + /// + /// Initializes a new instance of the class. + /// + /// an available IP from that subnet will be allocated to the port. + /// + /// + /// The subnet identifier. + public IPAddressAssociation(Identifier subnetId) + { + SubnetId = subnetId; + } + + /// + /// Initializes a new instance of the class. + /// + /// The subnet identifier. + /// The ip address. + [JsonConstructor] + public IPAddressAssociation(Identifier subnetId, string ipAddress) + { + SubnetId = subnetId; + IPAddress = ipAddress; + } + + /// + /// The subnet identifier. + /// + [JsonProperty("subnet_id")] + public Identifier SubnetId { get; set; } + + /// + /// The subnet identifier. + /// + [JsonProperty("ip_address")] + public string IPAddress { get; set; } + + #region Equality + + private bool Equals(IPAddressAssociation other) + { + return Equals(SubnetId, other.SubnetId) && string.Equals(IPAddress, other.IPAddress); + } + + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + var other = obj as IPAddressAssociation; + return other != null && Equals(other); + } + + /// + public override int GetHashCode() + { + unchecked + { + return (SubnetId.GetHashCode() * 397) ^ (IPAddress != null ? IPAddress.GetHashCode() : 0); + } + } + + /// + /// Implements the operator ==. + /// + /// The left. + /// The right. + /// + /// The result of the operator. + /// + public static bool operator ==(IPAddressAssociation left, IPAddressAssociation right) + { + return Equals(left, right); + } + + /// + /// Implements the operator !=. + /// + /// The left. + /// The right. + /// + /// The result of the operator. + /// + public static bool operator !=(IPAddressAssociation left, IPAddressAssociation right) + { + return !Equals(left, right); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/IPProtocol.cs b/src/OpenStack/Networking/v2/IPProtocol.cs new file mode 100644 index 000000000..3a1f37096 --- /dev/null +++ b/src/OpenStack/Networking/v2/IPProtocol.cs @@ -0,0 +1,8 @@ +using OpenStack.Networking.v2.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + public class IPProtocol : IPProtocol + { } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/ExternalGateway.cs b/src/OpenStack/Networking/v2/Layer3/ExternalGateway.cs new file mode 100644 index 000000000..947098b4d --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/ExternalGateway.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Defines a connection from a router to an external network. + /// + public class ExternalGateway + { + /// + /// Initializes a new instance of the class. + /// + public ExternalGateway() + { + ExternalFixedIPs = new List(); + } + + /// + /// The external network identifier. + /// + [JsonProperty("network_id")] + public Identifier ExternalNetworkId { get; set; } + + /// + /// Specifies if source NAT is enabled + /// + [JsonProperty("enable_snat")] + public bool IsSourceNATEnabled { get; set; } + + /// + /// External fixed IP addresses assigned to the router. + /// + [JsonProperty("external_fixed_ips")] + public IList ExternalFixedIPs { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/ExternalGatewayDefinition.cs b/src/OpenStack/Networking/v2/Layer3/ExternalGatewayDefinition.cs new file mode 100644 index 000000000..01910bbdf --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/ExternalGatewayDefinition.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Defines the set of fields that can be updated on an external gateway resource. + /// + public class ExternalGatewayDefinition + { + /// + /// Initializes a new instance of the class. + /// + public ExternalGatewayDefinition(Identifier externalNetworkId) + { + ExternalNetworkId = externalNetworkId; + ExternalFixedIPs = new List(); + } + + /// + /// The external network identifier. + /// + [JsonProperty("network_id")] + public Identifier ExternalNetworkId { get; set; } + + /// + /// Specifies if source NAT is enabled + /// + [JsonProperty("enable_snat")] + public bool? IsSourceNATEnabled { get; set; } + + /// + /// External fixed IP addresses assigned to the router. + /// + [JsonProperty("external_fixed_ips")] + public IList ExternalFixedIPs { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/FloatingIP.cs b/src/OpenStack/Networking/v2/Layer3/FloatingIP.cs new file mode 100644 index 000000000..589d55cff --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/FloatingIP.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Extensions; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// An external IP address that you map to a port in an internal network + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "floatingip")] + public class FloatingIP : IHaveExtraData, IServiceResource + { + /// + /// The floating IP identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The associated router. + /// + [JsonProperty("router_id")] + public Identifier RouterId { get; set; } + + /// + /// The network associated with the floating IP. + /// + [JsonProperty("floating_network_id")] + public Identifier NetworkId { get; set; } + + /// + /// The fixed IP address that is associated with the floating IP address. + /// + [JsonProperty("fixed_ip_address")] + public string FixedIPAddress { get; set; } + + /// + /// The floating IP address. + /// + [JsonProperty("floating_ip_address")] + public string FloatingIPAddress { get; set; } + + /// + /// The associated port. + /// + [JsonProperty("port_id")] + public Identifier PortId { get; set; } + + /// + /// The status of the floating IP address. + /// + [JsonProperty("status")] + public FloatingIPStatus Status { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + /// Thrown when a resource as not constructed by the SDK. + public Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var networking = this.GetOwnerOrThrow(); + return networking.DeleteFloatingIPAsync(Id, cancellationToken); + } + + /// + /// Associates the floating IP withe the specified port. + /// + /// The port identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Thrown when a resource as not constructed by the SDK. + public async Task AssociateAsync(Identifier portId, CancellationToken cancellationToken = default(CancellationToken)) + { + var networking = this.GetOwnerOrThrow(); + var request = new FloatingIPUpdateDefinition { PortId = portId }; + var result = await networking.UpdateFloatingIPAsync(Id, request, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + + /// + /// Frees the floating IP from any associations. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Thrown when a resource as not constructed by the SDK. + public async Task DisassociateAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var networking = this.GetOwnerOrThrow(); + var request = new FloatingIPUpdateDefinition { PortId = null }; + var result = await networking.UpdateFloatingIPAsync(Id, request, cancellationToken).ConfigureAwait(false); + result.CopyProperties(this); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/FloatingIPCreateDefinition.cs b/src/OpenStack/Networking/v2/Layer3/FloatingIPCreateDefinition.cs new file mode 100644 index 000000000..b5195e67f --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/FloatingIPCreateDefinition.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Defines a new floating IP instance. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "floatingip")] + public class FloatingIPCreateDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// The network identifier. + public FloatingIPCreateDefinition(Identifier networkId) + { + NetworkId = networkId; + } + + /// + [JsonProperty("floating_network_id")] + public Identifier NetworkId { get; set; } + + /// + [JsonProperty("fixed_ip_address")] + public string FixedIPAddress { get; set; } + + /// + [JsonProperty("floating_ip_address")] + public string FloatingIPAddress { get; set; } + + /// + [JsonProperty("port_id")] + public Identifier PortId { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/FloatingIPExtensions.cs b/src/OpenStack/Networking/v2/Layer3/FloatingIPExtensions.cs new file mode 100644 index 000000000..e8a0ff172 --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/FloatingIPExtensions.cs @@ -0,0 +1,23 @@ +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Networking.v2.Layer3.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class FloatingIPExtensions + { + /// + public static void Associate(this FloatingIP floatingIP, Identifier portId) + { + floatingIP.AssociateAsync(portId).ForceSynchronous(); + } + + /// + public static void Disassociate(this FloatingIP floatingIP) + { + floatingIP.DisassociateAsync().ForceSynchronous(); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/FloatingIPListOptions.cs b/src/OpenStack/Networking/v2/Layer3/FloatingIPListOptions.cs new file mode 100644 index 000000000..716ac01b2 --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/FloatingIPListOptions.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Optional filter and paging options when listing ports. + /// + public class FloatingIPListOptions : FilterOptions + { + /// + /// Filter by status. + /// + public FloatingIPStatus Status { get; set; } + + /// + /// Filter by the network that contains the floating IP address. + /// + public Identifier NetworkId { get; set; } + + /// + /// Filter by the associated router. + /// + public Identifier RouterId { get; set; } + + /// + /// Filter by the associated port. + /// + public Identifier PortId { get; set; } + + /// + /// Filter by the floating ip address. + /// + public string FloatingIPAddress { get; set; } + + /// + /// Filter by the associated fixed ip address. + /// + public string FixedIPAddress { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + var queryString = new Dictionary + { + ["floating_network_id"] = NetworkId, + ["router_id"] = RouterId, + ["port_id"] = PortId, + ["floating_ip_address"] = FloatingIPAddress, + ["fixed_ip_address"] = FixedIPAddress, + ["status"] = Status + }; + + return queryString; + } + } +} diff --git a/src/OpenStack/Networking/v2/Layer3/FloatingIPStatus.cs b/src/OpenStack/Networking/v2/Layer3/FloatingIPStatus.cs new file mode 100644 index 000000000..553a439c1 --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/FloatingIPStatus.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Networking.v2.Layer3 +{ + /// + public class FloatingIPStatus : NetworkResourceStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/FloatingIPUpdateDefinition.cs b/src/OpenStack/Networking/v2/Layer3/FloatingIPUpdateDefinition.cs new file mode 100644 index 000000000..af7b80197 --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/FloatingIPUpdateDefinition.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Defines a set of fields to update on a floating IP. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "floatingip")] + public class FloatingIPUpdateDefinition + { + /// + /// The new port to which the floating IP should be associated, or null to disassociate the floating IP. + /// + [JsonProperty("port_id")] + public Identifier PortId { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/NetworkingService_Layer3_Extensions.cs b/src/OpenStack/Networking/v2/Layer3/NetworkingService_Layer3_Extensions.cs new file mode 100644 index 000000000..0ad8e74bf --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/NetworkingService_Layer3_Extensions.cs @@ -0,0 +1,234 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Networking.v2.Serialization; +using OpenStack.Serialization; +using OpenStack.Synchronous.Extensions; +using Flurl.Extensions; +using Flurl.Http; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Exposes functionality from the Level3 networking extension + /// + /// + public static class NetworkingService_Layer3_Extensions + { + #region Routers + /// + public static Task GetRouterAsync(this NetworkingService service, Identifier routerId, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.GetRouterAsync(routerId, cancellationToken); + } + + /// + public static Task CreateRouterAsync(this NetworkingService service, RouterCreateDefinition router, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.CreateRouterAsync(router, cancellationToken); + } + + /// + public static Task UpdateRouterAsync(this NetworkingService service, RouterUpdateDefinition router, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.CreateRouterAsync(router, cancellationToken); + } + + /// + public static async Task> ListRoutersAsync(this NetworkingService service, RouterListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await service._networkingApiBuilder.ListRoutersAsync(options, cancellationToken).ConfigureAwait(false); + } + + /// + public static Task DeleteRouterAsync(this NetworkingService service, Identifier routerId, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.DeleteRouterAsync(routerId, cancellationToken); + } + + /// + public static Task AttachPortToRouterAsync(this NetworkingService service, Identifier routerId, Identifier portId, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.AttachPortToRouterAsync(routerId, portId, cancellationToken); + } + + /// + public static async Task AttachSubnetToRouterAsync(this NetworkingService service, Identifier routerId, Identifier subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + return await service._networkingApiBuilder.AttachSubnetToRouterAsync(routerId, subnetId, cancellationToken).ConfigureAwait(false); + } + + /// + public static Task DetachPortFromRouterAsync(this NetworkingService service, Identifier routerId, Identifier portId, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.DetachPortFromRouterAsync(routerId, portId, cancellationToken); + } + + /// + public static Task DetachSubnetFromRouterAsync(this NetworkingService service, Identifier routerId, Identifier subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.DetachSubnetFromRouterAsync(routerId, subnetId, cancellationToken); + } + #endregion + + #region Floating IPs + /// + public static Task GetFloatingIPAsync(this NetworkingService service, Identifier floatingIPId, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.GetFloatingIPAsync(floatingIPId, cancellationToken); + } + + /// + public static Task CreateFloatingIPAsync(this NetworkingService service, FloatingIPCreateDefinition floatingIP, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.CreateFloatingIPAsync(floatingIP, cancellationToken); + } + + /// + public static Task UpdateFloatingIPAsync(this NetworkingService service, FloatingIPUpdateDefinition floatingIP, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.CreateFloatingIPAsync(floatingIP, cancellationToken); + } + + /// + public static async Task> ListFloatingIPsAsync(this NetworkingService service, FloatingIPListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await service._networkingApiBuilder.ListFloatingIPsAsync(options, cancellationToken).ConfigureAwait(false); + } + + /// + public static Task DeleteFloatingIPAsync(this NetworkingService service, Identifier floatingIPId, CancellationToken cancellationToken = default(CancellationToken)) + { + return service._networkingApiBuilder.DeleteFloatingIPAsync(floatingIPId, cancellationToken); + } + #endregion + + #region Security Groups + /// + public static async Task> ListSecurityGroupsAsync(this NetworkingService service, SecurityGroupListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await service._networkingApiBuilder.ListSecurityGroupsAsync(options, cancellationToken).ConfigureAwait(false); + } + + /// + public static async Task> ListSecurityGroupRulesAsync(this NetworkingService service, SecurityGroupRuleListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await service._networkingApiBuilder.ListSecurityGroupRulesAsync(options, cancellationToken).ConfigureAwait(false); + } + #endregion + } +} + +namespace OpenStack.Networking.v2.Layer3.Synchronous +{ + /// + /// Exposes synchronous extension methods for the Level3 networking extension + /// + /// + public static class NetworkingService_Layer3_Synchronous_Extensions + { + #region Routers + /// + public static Router GetRouter(this NetworkingService service, Identifier routerId) + { + return service._networkingApiBuilder.GetRouterAsync(routerId).ForceSynchronous(); + } + + /// + public static Router CreateRouter(this NetworkingService service, RouterCreateDefinition router) + { + return service._networkingApiBuilder.CreateRouterAsync(router).ForceSynchronous(); + } + + /// + public static Router UpdateRouter(this NetworkingService service, RouterUpdateDefinition router) + { + return service._networkingApiBuilder.CreateRouterAsync(router).ForceSynchronous(); + } + + /// + public static IEnumerable ListRouters(this NetworkingService service, RouterListOptions options = null) + { + return service._networkingApiBuilder.ListRoutersAsync(options).ForceSynchronous(); + } + + /// + public static void DeleteRouter(this NetworkingService service, Identifier routerId) + { + service._networkingApiBuilder.DeleteRouterAsync(routerId).ForceSynchronous(); + } + + /// + public static void AttachPortToRouter(this NetworkingService service, Identifier routerId, Identifier portId) + { + service._networkingApiBuilder.AttachPortToRouterAsync(routerId, portId).ForceSynchronous(); + } + + /// + public static Identifier AttachSubnetToRouter(this NetworkingService service, Identifier routerId, Identifier subnetId) + { + return service._networkingApiBuilder.AttachSubnetToRouterAsync(routerId, subnetId).ForceSynchronous(); + } + + /// + public static void DetachPortFromRouter(this NetworkingService service, Identifier routerId, Identifier portId) + { + service._networkingApiBuilder.DetachPortFromRouterAsync(routerId, portId).ForceSynchronous(); + } + + /// + public static void DetachSubnetFromRouter(this NetworkingService service, Identifier routerId, Identifier subnetId) + { + service._networkingApiBuilder.DetachSubnetFromRouterAsync(routerId, subnetId).ForceSynchronous(); + } + #endregion + + #region Floating IPs + /// + public static FloatingIP GetFloatingIP(this NetworkingService service, Identifier floatingIPId) + { + return service._networkingApiBuilder.GetFloatingIPAsync(floatingIPId).ForceSynchronous(); + } + + /// + public static FloatingIP CreateFloatingIP(this NetworkingService service, FloatingIPCreateDefinition floatingIP) + { + return service._networkingApiBuilder.CreateFloatingIPAsync(floatingIP).ForceSynchronous(); + } + + /// + public static FloatingIP UpdateFloatingIP(this NetworkingService service, FloatingIPUpdateDefinition floatingIP) + { + return service._networkingApiBuilder.CreateFloatingIPAsync(floatingIP).ForceSynchronous(); + } + + /// + public static IEnumerable ListFloatingIPs(this NetworkingService service, FloatingIPListOptions options = null) + { + return service._networkingApiBuilder.ListFloatingIPsAsync(options).ForceSynchronous(); + } + + /// + public static void DeleteFloatingIP(this NetworkingService service, Identifier floatingIPId) + { + service._networkingApiBuilder.DeleteFloatingIPAsync(floatingIPId).ForceSynchronous(); + } + #endregion + + #region Security Groups + /// + public static IEnumerable ListSecurityGroups(this NetworkingService service, SecurityGroupListOptions options = null) + { + return service.ListSecurityGroupsAsync(options).ForceSynchronous(); + } + /// + public static IEnumerable ListSecurityGroupRules(this NetworkingService service, SecurityGroupRuleListOptions options = null) + { + return service.ListSecurityGroupRulesAsync(options).ForceSynchronous(); + } + #endregion + + } +} diff --git a/src/OpenStack/Networking/v2/Layer3/Router.cs b/src/OpenStack/Networking/v2/Layer3/Router.cs new file mode 100644 index 000000000..eab6eefcd --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/Router.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Networking.v2.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// A logical entity for forwarding packets across internal subnets and NATting them on external networks through an appropriate external gateway. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "router")] + public class Router : IHaveExtraData, IServiceResource + { + /// + /// Initializes a new instance of the class. + /// + public Router() + { + Routes = new List(); + } + + /// + /// The router identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The router name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The network status. + /// + [JsonProperty("status")] + public RouterStatus Status { get; set; } + + /// + /// The external gateway connection information. + /// + [JsonProperty("external_gateway_info")] + public ExternalGateway ExternalGateway { get; set; } + + /// + /// The administrative state of the router. + /// + [JsonProperty("admin_state_up")] + public bool IsUp { get; set; } + + /// + /// The extra routes configuration for L3 router. + /// + [JsonProperty("routes")] + public IList Routes { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + + /// + /// Deletes the router and any attached interfaces. + /// + /// + /// Thrown when a resource as not constructed by the SDK. + public async Task DeleteAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var networking = this.GetOwnerOrThrow(); + + // Remove attached interfaces, these aren't really tracked by the end-user but will prevent deleting the router + var filterByRouter = new PortListOptions {DeviceId = Id}; + var attachedPorts = await networking.ListPortsAsync(filterByRouter, cancellationToken); + Task.WaitAll(attachedPorts.Select(port => DetachPortAsync(port.Id, cancellationToken)).ToArray()); + + await networking.DeleteRouterAsync(Id, cancellationToken).ConfigureAwait(false); + } + + /// + /// Thrown when a resource as not constructed by the SDK. + public Task AttachPortAsync(Identifier portId, CancellationToken cancellationToken = default(CancellationToken)) + { + var networking = this.GetOwnerOrThrow(); + return networking.AttachPortToRouterAsync(Id, portId, cancellationToken); + } + + /// + /// Thrown when a resource as not constructed by the SDK. + public async Task AttachSubnetAsync(Identifier subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + var networking = this.GetOwnerOrThrow(); + return await networking.AttachSubnetToRouterAsync(Id, subnetId, cancellationToken).ConfigureAwait(false); + } + + /// + /// Thrown when a resource as not constructed by the SDK. + public Task DetachPortAsync(Identifier portId, CancellationToken cancellationToken = default(CancellationToken)) + { + var networking = this.GetOwnerOrThrow(); + return networking.DetachPortFromRouterAsync(Id, portId, cancellationToken); + } + + /// + /// Thrown when a resource as not constructed by the SDK. + public Task DetachSubnetAsync(Identifier subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + var networking = this.GetOwnerOrThrow(); + return networking.DetachSubnetFromRouterAsync(Id, subnetId, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/RouterCreateDefinition.cs b/src/OpenStack/Networking/v2/Layer3/RouterCreateDefinition.cs new file mode 100644 index 000000000..cba93235f --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/RouterCreateDefinition.cs @@ -0,0 +1,24 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Defines a new router instance. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "router")] + public class RouterCreateDefinition + { + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("external_gateway_info")] + public ExternalGatewayDefinition ExternalGateway { get; set; } + + /// + [JsonProperty("admin_state_up")] + public bool? IsUp { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/RouterExtensions.cs b/src/OpenStack/Networking/v2/Layer3/RouterExtensions.cs new file mode 100644 index 000000000..dae07ff2a --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/RouterExtensions.cs @@ -0,0 +1,41 @@ +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Networking.v2.Layer3.Synchronous +{ + /// + /// Provides synchronous extention methods for a instance. + /// + public static class RouterExtensions + { + /// + public static void Delete(this Router router) + { + router.DeleteAsync().ForceSynchronous(); + } + + /// + public static void AttachPort(this Router router, Identifier portId) + { + router.AttachPortAsync(portId).ForceSynchronous(); + } + + /// + public static Identifier AttachSubnet(this Router router, Identifier subnetId) + { + return router.AttachSubnetAsync(subnetId).ForceSynchronous(); + } + + /// + public static void DetachPort(this Router router, Identifier portId) + { + router.DetachPortAsync(portId).ForceSynchronous(); + } + + /// + public static void DetachSubnet(this Router router, Identifier subnetId) + { + router.DetachSubnetAsync(subnetId).ForceSynchronous(); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/RouterListOptions.cs b/src/OpenStack/Networking/v2/Layer3/RouterListOptions.cs new file mode 100644 index 000000000..1d41bca4c --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/RouterListOptions.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Optional filter and paging options when listing servers. + /// + public class RouterListOptions : FilterOptions + { + /// + /// Filter by status. + /// + public RouterStatus Status { get; set; } + + /// + /// Filter by router name. + /// + public string Name { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + var queryString = new Dictionary + { + ["status"] = Status, + ["name"] = Name + }; + + return queryString; + } + } +} diff --git a/src/OpenStack/Networking/v2/Layer3/RouterStatus.cs b/src/OpenStack/Networking/v2/Layer3/RouterStatus.cs new file mode 100644 index 000000000..92fb640fd --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/RouterStatus.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Networking.v2.Layer3 +{ + /// + public class RouterStatus : NetworkResourceStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/RouterUpdateDefinition.cs b/src/OpenStack/Networking/v2/Layer3/RouterUpdateDefinition.cs new file mode 100644 index 000000000..759ac4e56 --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/RouterUpdateDefinition.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Defines a set of fields to update on a router. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "router")] + public class RouterUpdateDefinition + { + /// + /// Initializes a new instance of the class. + /// + public RouterUpdateDefinition() + { + Routes = new List(); + } + + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("external_gateway_info")] + public ExternalGatewayDefinition ExternalGateway { get; set; } + + /// + [JsonProperty("admin_state_up")] + public bool? IsUp { get; set; } + + /// + [JsonProperty("routes")] + public IList Routes { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Layer3/SecurityGroup.cs b/src/OpenStack/Networking/v2/Layer3/SecurityGroup.cs new file mode 100644 index 000000000..03e27eabd --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/SecurityGroup.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Represents the security group of the + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "security_group")] + public class SecurityGroup : IHaveExtraData, IServiceResource + { + /// + /// The security group description + /// + [JsonProperty("description")] + public string Description; + + /// + /// The UUID of security group + /// + [JsonProperty("id")] + public Identifier Id; + + /// + /// The security group name + /// + [JsonProperty("name")] + public string Name; + + /// + /// A list of objects. + /// + [JsonProperty("security_group_rules")] + public IList SecurityGroupRules; + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + } +} diff --git a/src/OpenStack/Networking/v2/Layer3/SecurityGroupListOptions.cs b/src/OpenStack/Networking/v2/Layer3/SecurityGroupListOptions.cs new file mode 100644 index 000000000..47ed19ba6 --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/SecurityGroupListOptions.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Optional filter and paging options when listing security groups. + /// + public class SecurityGroupListOptions : FilterOptions + { + /// + /// Filter by the group name. + /// + public string Name { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + var queryString = new Dictionary + { + ["name"] = Name + }; + + return queryString; + } + } +} diff --git a/src/OpenStack/Networking/v2/Layer3/SecurityGroupRule.cs b/src/OpenStack/Networking/v2/Layer3/SecurityGroupRule.cs new file mode 100644 index 000000000..04c46f79c --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/SecurityGroupRule.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "security_group_rule")] + public class SecurityGroupRule : IHaveExtraData, IServiceResource + { + /// + /// ingress or egress: the direction in which the security group rule is applied. + /// For a compute instance, an ingress security group rule is applied to incoming (ingress) traffic for that instance. + /// An egress rule is applied to traffic leaving the instance. + /// + [JsonProperty("direction")] + public TrafficDirection Direction; + + /// + /// The internet protocol version. Addresses represented in CIDR must match the ingress or egress rules. + /// + [JsonProperty("ethertype")] + public IPVersion Ethertype; + + /// + /// The UUID of the security group rule. + /// + [JsonProperty("id")] + public Identifier Id; + + /// + /// The minimum port number in the range that is matched by the security group rule. + /// If the protocol is TCP or UDP, this value must be less than or equal to the port_range_max attribute value. + /// If the protocol is ICMP, this value must be an ICMP type. + /// + [JsonProperty("port_range_min")] + public int MinPort { get; set; } + + /// + /// The maximum port number in the range that is matched by the security group rule. + /// The port_range_min attribute constrains the port_range_max attribute. + /// If the protocol is ICMP, this value must be an ICMP type. + /// + [JsonProperty("port_range_max")] + public int MaxPort { get; set; } + + /// + /// The protocol that is matched by the security group rule. + /// + [JsonProperty("protocol")] + public IPProtocol Protocol; + + /// + /// The remote group UUID to associate with this security group rule. + /// You can specify either the remote_group_id or remote_ip_prefix attribute in the request body. + /// + [JsonProperty("remote_group_id")] + public Identifier RemoteGroupId; + + /// + /// The remote IP prefix or CIDR to associate with this security group rule. + /// You can specify either the remote_group_id or remote_ip_prefix attribute in the request body. + /// This attribute value matches the IP prefix as the source IP address of the IP packet. + /// + [JsonProperty("remote_ip_prefix")] + public string RemoteCIDR; + + /// + /// The UUId of security group + /// + [JsonProperty("security_group_id")] + public Identifier SecurityGroupId; + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + } +} diff --git a/src/OpenStack/Networking/v2/Layer3/SecurityGroupRuleListOptions.cs b/src/OpenStack/Networking/v2/Layer3/SecurityGroupRuleListOptions.cs new file mode 100644 index 000000000..32144f2c5 --- /dev/null +++ b/src/OpenStack/Networking/v2/Layer3/SecurityGroupRuleListOptions.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace OpenStack.Networking.v2.Layer3 +{ + /// + /// Optional filter and paging options when listing security group rules. + /// + public class SecurityGroupRuleListOptions : FilterOptions + { + /// + /// Filter by the group name. + /// + public TrafficDirection Direction { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + var queryString = new Dictionary + { + ["direction"] = Direction + }; + + return queryString; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/NamespaceDoc.cs b/src/OpenStack/Networking/v2/NamespaceDoc.cs new file mode 100644 index 000000000..d65e8bea3 --- /dev/null +++ b/src/OpenStack/Networking/v2/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace OpenStack.Networking.v2 +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines provider-independent + /// interfaces and implementations for the OpenStack Networking API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Networking/v2/Network.cs b/src/OpenStack/Networking/v2/Network.cs new file mode 100644 index 000000000..361f47a30 --- /dev/null +++ b/src/OpenStack/Networking/v2/Network.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents a network resource of the + /// + /// Isolated virtual Layer-2 domains; a network can also be regarded as a virtual (or logical) switch. + /// + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "network")] + public class Network : IHaveExtraData, IServiceResource + { + /// + /// The network identifier. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The network name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The administrative state of the network. + /// + [JsonProperty("admin_state_up")] + public bool IsUp { get; set; } + + /// + /// Indicates whether this network is shared across all tenants. + /// + [JsonProperty("shared")] + public bool IsShared { get; set; } + + /// + /// Indicates whether this network is externally accessible. + /// + [JsonProperty("router:external")] + public bool IsExternal { get; set; } + + /// + /// The network status. + /// + [JsonProperty("status")] + public NetworkStatus Status { get; set; } + + /// + /// The associated subnet identifiers. + /// + [JsonProperty("subnets")] + public IList Subnets { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/NetworkDefinition.cs b/src/OpenStack/Networking/v2/NetworkDefinition.cs new file mode 100644 index 000000000..efe6aadd1 --- /dev/null +++ b/src/OpenStack/Networking/v2/NetworkDefinition.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents the definition of a network resource of the . + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "network")] + public class NetworkDefinition : IHaveExtraData + { + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + [JsonProperty("admin_state_up")] + public bool? IsUp { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/NetworkStatus.cs b/src/OpenStack/Networking/v2/NetworkStatus.cs new file mode 100644 index 000000000..9eaa521eb --- /dev/null +++ b/src/OpenStack/Networking/v2/NetworkStatus.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Networking.v2 +{ + /// + public class NetworkStatus : NetworkResourceStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/NetworkingApiBuilder.cs b/src/OpenStack/Networking/v2/NetworkingApiBuilder.cs new file mode 100644 index 000000000..d5a2fbaf1 --- /dev/null +++ b/src/OpenStack/Networking/v2/NetworkingApiBuilder.cs @@ -0,0 +1,890 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Flurl; +using Flurl.Extensions; +using Flurl.Http; +using OpenStack.Authentication; +using OpenStack.Networking.v2.Serialization; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Builds requests to the Networking API which can be further customized and then executed. + /// Intended for custom implementations. + /// + /// OpenStack Networking API v2 Reference + public class NetworkingApiBuilder + { + /// + protected readonly IAuthenticationProvider AuthenticationProvider; + + /// + protected readonly ServiceEndpoint Endpoint; + + /// + /// Initializes a new instance of the class. + /// + /// The service type for the desired networking provider. + /// The authentication provider. + /// The region. + /// if set to true uses the internal URLs specified in the ServiceCatalog, otherwise the public URLs are used. + public NetworkingApiBuilder(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl) + { + if(serviceType == null) + throw new ArgumentNullException("serviceType"); + if (authenticationProvider == null) + throw new ArgumentNullException("authenticationProvider"); + if (string.IsNullOrEmpty(region)) + throw new ArgumentException("region cannot be null or empty", "region"); + + AuthenticationProvider = authenticationProvider; + Endpoint = new ServiceEndpoint(serviceType, authenticationProvider, region, useInternalUrl); + } + + #region Networks + /// + /// Lists all networks associated with the account. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// A collection of network resources associated with the account. + /// + public async Task ListNetworksAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("networks") + .Authenticate(AuthenticationProvider) + .PrepareGet(cancellationToken); + } + + /// + /// Gets the specified network. + /// + /// The network identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The network associated with the specified identifier. + /// + public virtual async Task GetNetworkAsync(string networkId, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("networks", networkId) + .Authenticate(AuthenticationProvider) + .PrepareGet(cancellationToken); + } + + /// + /// Creates a network. + /// + /// The network definition. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The created network. + /// + public virtual async Task CreateNetworkAsync(object network, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("networks") + .Authenticate(AuthenticationProvider) + .PreparePostJson(network, cancellationToken); + } + + /// + /// Bulk creates multiple networks. + /// + /// The network definitions. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The created networks. + /// + public virtual async Task CreateNetworksAsync(IEnumerable networks, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("networks") + .Authenticate(AuthenticationProvider) + .PreparePostJson(new NetworkDefinitionCollection(networks), cancellationToken); + } + + /// + /// Updates the specified network. + /// + /// + /// The updated network definition. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The updated network. + /// + public virtual async Task UpdateNetworkAsync(string networkId, object network, CancellationToken cancellationToken = default(CancellationToken)) + { + string endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("networks", networkId) + .Authenticate(AuthenticationProvider) + .PreparePutJson(network, cancellationToken); + } + + /// + /// Deletes the specified network. + /// + /// The network identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task DeleteNetworkAsync(string networkId, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return (PreparedRequest)endpoint + .AppendPathSegments("networks", networkId) + .Authenticate(AuthenticationProvider) + .PrepareDelete(cancellationToken) + .AllowHttpStatus(HttpStatusCode.NotFound); + } + #endregion + + #region Subnets + + /// + /// Lists all subnets associated with the account. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// A collection of subnet resources associated with the account. + /// + public virtual async Task ListSubnetsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegment("subnets") + .Authenticate(AuthenticationProvider) + .PrepareGet(cancellationToken); + } + + /// + /// Creates a subnet. + /// + /// The subnet definition. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The created subnet. + /// + public virtual async Task CreateSubnetAsync(object subnet, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("subnets") + .Authenticate(AuthenticationProvider) + .PreparePostJson(subnet, cancellationToken); + } + + /// + /// Bulk creates multiple subnets. + /// + /// The subnet definitions. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The created subnets. + /// + public virtual async Task CreateSubnetsAsync(IEnumerable subnets, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("subnets") + .Authenticate(AuthenticationProvider) + .PreparePostJson(new SubnetDefinitionCollection(subnets), cancellationToken); + } + + /// + /// Gets the specified subnet. + /// + /// The subnet identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The subnet associated with the specified identifier. + /// + public virtual async Task GetSubnetAsync(string subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("subnets", subnetId) + .Authenticate(AuthenticationProvider) + .PrepareGet(cancellationToken); + } + + /// + /// Updates the specified subnet. + /// + /// + /// The updated subnet definition. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The updated subnet. + /// + public virtual async Task UpdateSubnetAsync(string subnetId, object subnet, CancellationToken cancellationToken = default(CancellationToken)) + { + string endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("subnets", subnetId) + .Authenticate(AuthenticationProvider) + .PreparePutJson(subnet, cancellationToken); + } + + /// + /// Deletes the specified subnet. + /// + /// The subnet identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task DeleteSubnetAsync(string subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return (PreparedRequest)endpoint + .AppendPathSegments("subnets", subnetId) + .Authenticate(AuthenticationProvider) + .PrepareDelete(cancellationToken) + .AllowHttpStatus(HttpStatusCode.NotFound); + } + #endregion + + #region Ports + /// + /// Lists all ports associated with the account. + /// + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// A collection of port resources associated with the account. + /// + public virtual async Task ListPortsAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListPortsRequest(queryString, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListPortsRequest(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + PreparedRequest request = await Endpoint.PrepareGetResourceRequest("ports", cancellationToken).ConfigureAwait(false); + + request.Url.SetQueryParams(queryString?.Build()); + + return request; + } + + /// + /// Creates a port. + /// + /// The port definition. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The created port. + /// + public virtual async Task CreatePortAsync(object port, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("ports") + .Authenticate(AuthenticationProvider) + .PreparePostJson(port, cancellationToken); + } + + /// + /// Bulk creates multiple ports. + /// + /// The port definitions. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The created subnets. + /// + public virtual async Task CreatePortsAsync(IEnumerable ports, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("ports") + .Authenticate(AuthenticationProvider) + .PreparePostJson(new PortDefinitionCollection(ports), cancellationToken); + } + + /// + /// Gets the specified port. + /// + /// The port identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The port associated with the specified identifier. + /// + public virtual async Task GetPortAsync(string portId, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("ports", portId) + .Authenticate(AuthenticationProvider) + .PrepareGet(cancellationToken); + } + + /// + /// Updates the specified port. + /// + /// The port identifier. + /// The updated port definition. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The updated port. + /// + public virtual async Task UpdatePortAsync(string portId, object port, CancellationToken cancellationToken = default(CancellationToken)) + { + string endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return endpoint + .AppendPathSegments("ports", portId) + .Authenticate(AuthenticationProvider) + .PreparePutJson(port, cancellationToken); + } + + /// + /// Deletes the specified port. + /// + /// The port identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task DeletePortAsync(string portId, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + return (PreparedRequest)endpoint + .AppendPathSegments("ports", portId) + .Authenticate(AuthenticationProvider) + .PrepareDelete(cancellationToken) + .AllowHttpStatus(HttpStatusCode.NotFound); + } + #endregion + + #region Layer 3 Extension + + #region Routers + /// + /// Shows details for a server group. + /// + /// The return type. + /// The router identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task GetRouterAsync(string routerId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetRouterRequest(routerId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The router identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetRouterRequest(string routerId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (routerId == null) + throw new ArgumentNullException("routerId"); + + return Endpoint.PrepareGetResourceRequest($"routers/{routerId}", cancellationToken); + } + + /// + /// Creates a router. + /// + /// The return type. + /// The router. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task CreateRouterAsync(object router, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildCreateRouterRequest(router, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The router. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildCreateRouterRequest(object router, CancellationToken cancellationToken = default(CancellationToken)) + { + if (router == null) + throw new ArgumentNullException("router"); + + return Endpoint.PrepareCreateResourceRequest("routers", router, cancellationToken); + } + + /// + /// Updates a router. + /// + /// The return type. + /// The router. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task UpdateRouterAsync(object router, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildUpdateRouterRequest(router, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The router. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildUpdateRouterRequest(object router, CancellationToken cancellationToken = default(CancellationToken)) + { + if (router == null) + throw new ArgumentNullException("router"); + + return Endpoint.PrepareUpdateResourceRequest("routers", router, cancellationToken); + } + + /// + /// Lists all routers for the account. + /// + /// The return type. + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListRoutersAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListRoutersRequest(queryString, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListRoutersRequest(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + PreparedRequest request = await Endpoint.PrepareGetResourceRequest("routers", cancellationToken).ConfigureAwait(false); + + request.Url.SetQueryParams(queryString?.Build()); + + return request; + } + + /// + /// Deletes a router. + /// + /// The router identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task DeleteRouterAsync(string routerId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteRouterRequest(routerId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The router identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteRouterRequest(string routerId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (routerId == null) + throw new ArgumentNullException("routerId"); + + return Endpoint.PrepareDeleteResourceRequest($"routers/{routerId}", cancellationToken); + } + + /// + /// Attaches an existing port to the specified router. + /// + /// The router identifier. + /// The port identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task AttachPortToRouterAsync(string routerId, string portId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildAttachPortToRouterRequest(routerId, portId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The router identifier. + /// The port identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildAttachPortToRouterRequest(string routerId, string portId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (routerId == null) + throw new ArgumentNullException("routerId"); + + if (portId == null) + throw new ArgumentNullException("portId"); + + var request = await Endpoint.PrepareRequest($"routers/{routerId}/add_router_interface", cancellationToken).ConfigureAwait(false); + var requestBody = new {port_id = portId}; + return request.PreparePutJson(requestBody, cancellationToken); + } + + /// + /// Creates a new port on the subnet and attaches it to the specified router. + /// + /// The router identifier. + /// The subnet identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The newly created port identifier. + public virtual async Task AttachSubnetToRouterAsync(string routerId, string subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + dynamic result = await BuildAttachSubnetToRouterRequest(routerId, subnetId, cancellationToken) + .SendAsync() + .ReceiveJson().ConfigureAwait(false); + + return result.port_id; + } + + /// + /// Builds the request. + /// + /// The router identifier. + /// The subnet identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildAttachSubnetToRouterRequest(string routerId, string subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (routerId == null) + throw new ArgumentNullException("routerId"); + + if (subnetId == null) + throw new ArgumentNullException("subnetId"); + + var request = await Endpoint.PrepareRequest($"routers/{routerId}/add_router_interface", cancellationToken).ConfigureAwait(false); + var requestBody = new { subnet_id = subnetId }; + return request.PreparePutJson(requestBody, cancellationToken); + } + + /// + /// Detaches a port from the specified router. + /// + /// The router identifier. + /// The port identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task DetachPortFromRouterAsync(string routerId, string portId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDetachPortFromRouterRequest(routerId, portId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The router identifier. + /// The port identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildDetachPortFromRouterRequest(string routerId, string portId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (routerId == null) + throw new ArgumentNullException("routerId"); + + if (portId == null) + throw new ArgumentNullException("portId"); + + var request = await Endpoint.PrepareRequest($"routers/{routerId}/remove_router_interface", cancellationToken).ConfigureAwait(false); + request.AllowHttpStatus(HttpStatusCode.NotFound); + var requestBody = new { port_id = portId }; + return request.PreparePutJson(requestBody, cancellationToken); + } + + /// + /// Finds the port on the subnet attached to the specified router, detaches then deletes it. + /// + /// The router identifier. + /// The subnet identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The newly created port identifier. + public virtual Task DetachSubnetFromRouterAsync(string routerId, string subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDetachSubnetFromRouterRequest(routerId, subnetId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The router identifier. + /// The subnet identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual async Task BuildDetachSubnetFromRouterRequest(string routerId, string subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (routerId == null) + throw new ArgumentNullException("routerId"); + + if (subnetId == null) + throw new ArgumentNullException("subnetId"); + + var request = await Endpoint.PrepareRequest($"routers/{routerId}/remove_router_interface", cancellationToken).ConfigureAwait(false); + var requestBody = new { subnet_id = subnetId }; + return request.PreparePutJson(requestBody, cancellationToken); + } + #endregion + + #region SecurityGroup + /// + /// Lists all network security groups associated with the account. + /// + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// A collection of network security group resources associated with the account. + /// + public async Task ListSecurityGroupsAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListSecurityGroupsRequest(queryString, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds a request. + /// + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public async Task BuildListSecurityGroupsRequest(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + var request = endpoint + .AppendPathSegments("security-groups") + .Authenticate(AuthenticationProvider) + .PrepareGet(cancellationToken); + + request.Url.SetQueryParams(queryString?.Build()); + + return request; + } + + /// + /// Lists all network security group rules associated with the account. + /// + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// A collection of network security group rule resources associated with the account. + /// + public async Task ListSecurityGroupRulesAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListSecurityGroupRulesRequest(queryString, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds a request. + /// + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public async Task BuildListSecurityGroupRulesRequest(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + Url endpoint = await Endpoint.GetEndpoint(cancellationToken).ConfigureAwait(false); + + var request = endpoint + .AppendPathSegments("security-group-rules") + .Authenticate(AuthenticationProvider) + .PrepareGet(cancellationToken); + + request.Url.SetQueryParams(queryString?.Build()); + + return request; + } + #endregion + + #region Floating IPs + /// + /// Shows details for a server group. + /// + /// The return type. + /// The floating IP identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetFloatingIPAsync(string floatingIPId, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildGetFloatingIPRequest(floatingIPId, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The floating IP identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildGetFloatingIPRequest(string floatingIPId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (floatingIPId == null) + throw new ArgumentNullException("floatingIPId"); + + return Endpoint.PrepareGetResourceRequest($"floatingips/{floatingIPId}", cancellationToken); + } + + /// + /// Creates a floating IP. + /// + /// The return type. + /// The floating IP. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task CreateFloatingIPAsync(object floatingIP, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildCreateFloatingIPRequest(floatingIP, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The floating IP. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildCreateFloatingIPRequest(object floatingIP, CancellationToken cancellationToken = default(CancellationToken)) + { + if (floatingIP == null) + throw new ArgumentNullException("floatingIP"); + + return Endpoint.PrepareCreateResourceRequest("floatingips", floatingIP, cancellationToken); + } + + /// + /// Updates a floating IP. + /// + /// The return type. + /// The floating IP identifier. + /// The floating IP. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task UpdateFloatingIPAsync(string floatingIPId, object floatingIP, CancellationToken cancellationToken = default(CancellationToken)) + where T : IServiceResource + { + return await BuildUpdateFloatingIPRequest(floatingIPId, floatingIP, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwner(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// The floating IP identifier. + /// The floating IP. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildUpdateFloatingIPRequest(string floatingIPId, object floatingIP, CancellationToken cancellationToken = default(CancellationToken)) + { + if (floatingIP == null) + throw new ArgumentNullException("floatingIP"); + + return Endpoint.PrepareUpdateResourceRequest($"floatingips/{floatingIPId}", floatingIP, cancellationToken); + } + + /// + /// Lists all floating IPs for the account. + /// + /// The return type. + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task ListFloatingIPsAsync(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + where T : IEnumerable + { + return await BuildListFloatingIPsRequest(queryString, cancellationToken) + .SendAsync() + .ReceiveJson() + .PropogateOwnerToChildren(this).ConfigureAwait(false); + } + + /// + /// Builds the request. + /// + /// Options for filtering. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task BuildListFloatingIPsRequest(IQueryStringBuilder queryString, CancellationToken cancellationToken = default(CancellationToken)) + { + PreparedRequest request = await Endpoint.PrepareGetResourceRequest("floatingips", cancellationToken).ConfigureAwait(false); + + request.Url.SetQueryParams(queryString?.Build()); + + return request; + } + + /// + /// Deletes a floating IP. + /// + /// The floating IP identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual Task DeleteFloatingIPAsync(string floatingIPId, CancellationToken cancellationToken = default(CancellationToken)) + { + return BuildDeleteFloatingIPRequest(floatingIPId, cancellationToken).SendAsync(); + } + + /// + /// Builds the request. + /// + /// The floating IP identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + public virtual Task BuildDeleteFloatingIPRequest(string floatingIPId, CancellationToken cancellationToken = default(CancellationToken)) + { + if (floatingIPId == null) + throw new ArgumentNullException("floatingIPId"); + + return Endpoint.PrepareDeleteResourceRequest($"floatingips/{floatingIPId}", cancellationToken); + } + #endregion + + #endregion + } +} diff --git a/src/OpenStack/Networking/v2/NetworkingService.cs b/src/OpenStack/Networking/v2/NetworkingService.cs new file mode 100644 index 000000000..86abdc4b0 --- /dev/null +++ b/src/OpenStack/Networking/v2/NetworkingService.cs @@ -0,0 +1,195 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Flurl.Extensions; +using Flurl.Http; +using OpenStack.Authentication; +using OpenStack.Networking.v2.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// The OpenStack Networking Service. + /// + /// OpenStack Networking API v2 Overview + /// OpenStack Networking API v2 Reference + public class NetworkingService + { + internal readonly NetworkingApiBuilder _networkingApiBuilder; + + /// + /// Initializes a new instance of the class. + /// + /// The authentication provider. + /// The region. + /// if set to true uses the internal URLs specified in the ServiceCatalog, otherwise the public URLs are used. + public NetworkingService(IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl = false) + { + _networkingApiBuilder = new NetworkingApiBuilder(ServiceType.Networking, authenticationProvider, region, useInternalUrl); + } + + #region Networks + /// + public async Task> ListNetworksAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return await _networkingApiBuilder + .ListNetworksAsync(cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task GetNetworkAsync(Identifier networkId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .GetNetworkAsync(networkId, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task CreateNetworkAsync(NetworkDefinition network, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .CreateNetworkAsync(network, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public async Task> CreateNetworksAsync(IEnumerable networks, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _networkingApiBuilder + .CreateNetworksAsync(networks, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task UpdateNetworkAsync(Identifier networkId, NetworkDefinition network, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .UpdateNetworkAsync(networkId, network, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task DeleteNetworkAsync(Identifier networkId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .DeleteNetworkAsync(networkId, cancellationToken) + .SendAsync(); + } + #endregion + + #region Subnets + + /// + public async Task> ListSubnetsAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + return await _networkingApiBuilder + .ListSubnetsAsync(cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task CreateSubnetAsync(SubnetCreateDefinition subnet, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .CreateSubnetAsync(subnet, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public async Task> CreateSubnetsAsync(IEnumerable subnets, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _networkingApiBuilder + .CreateSubnetsAsync(subnets, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task GetSubnetAsync(Identifier subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .GetSubnetAsync(subnetId, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task UpdateSubnetAsync(Identifier subnetId, SubnetUpdateDefinition subnet, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .UpdateSubnetAsync(subnetId, subnet, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task DeleteSubnetAsync(Identifier subnetId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .DeleteSubnetAsync(subnetId, cancellationToken) + .SendAsync(); + } + #endregion + + #region Ports + + /// + public async Task> ListPortsAsync(PortListOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _networkingApiBuilder.ListPortsAsync(options, cancellationToken); + } + + /// + public Task CreatePortAsync(PortCreateDefinition port, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .CreatePortAsync(port, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public async Task> CreatePortsAsync(IEnumerable ports, CancellationToken cancellationToken = default(CancellationToken)) + { + return await _networkingApiBuilder + .CreatePortsAsync(ports, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task GetPortAsync(Identifier portId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .GetPortAsync(portId, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task UpdatePortAsync(Identifier portId, PortUpdateDefinition port, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .UpdatePortAsync(portId, port, cancellationToken) + .SendAsync() + .ReceiveJson(); + } + + /// + public Task DeletePortAsync(Identifier portId, CancellationToken cancellationToken = default(CancellationToken)) + { + return _networkingApiBuilder + .DeletePortAsync(portId, cancellationToken) + .SendAsync(); + } + #endregion + } +} diff --git a/src/OpenStack/Networking/v2/NetworkingServiceExtensions.cs b/src/OpenStack/Networking/v2/NetworkingServiceExtensions.cs new file mode 100644 index 000000000..ccdd74feb --- /dev/null +++ b/src/OpenStack/Networking/v2/NetworkingServiceExtensions.cs @@ -0,0 +1,241 @@ +using System.Collections.Generic; +using OpenStack.Networking.v2; +using OpenStack.Synchronous.Extensions; + +// ReSharper disable once CheckNamespace +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for an instance. + /// + public static class NetworkingServiceExtensions_v2 + { + #region Networks + /// + /// Lists all networks associated with the account. + /// + /// + /// A collection of network resources associated with the account. + /// + public static IEnumerable ListNetworks(this NetworkingService networkingService) + { + return networkingService.ListNetworksAsync().ForceSynchronous(); + } + + /// + /// Gets the specified network. + /// + /// The networking service. + /// The network identifier. + /// + /// The network associated with the specified identifier. + /// + public static Network GetNetwork(this NetworkingService networkingService, Identifier networkId) + { + return networkingService.GetNetworkAsync(networkId).ForceSynchronous(); + } + + /// + /// Bulk creates multiple networks. + /// + /// The networking service. + /// The network definitions. + /// + /// The created networks. + /// + public static IEnumerable CreateNetworks(this NetworkingService networkingService, IEnumerable networks) + { + return networkingService.CreateNetworksAsync(networks).ForceSynchronous(); + } + + /// + /// Creates a network. + /// + /// The networking service. + /// The network definition. + /// + /// The created network. + /// + public static Network CreateNetwork(this NetworkingService networkingService, NetworkDefinition network) + { + return networkingService.CreateNetworkAsync(network).ForceSynchronous(); + } + + /// + /// Updates the specified network. + /// + /// The networking service. + /// The network identifier. + /// The updated network definition. + /// + /// The updated network. + /// + public static Network UpdateNetwork(this NetworkingService networkingService, Identifier networkId, NetworkDefinition network) + { + return networkingService.UpdateNetworkAsync(networkId, network).ForceSynchronous(); + } + + /// + /// Deletes the specified network. + /// + /// The networking service. + /// The network identifier. + public static void DeleteNetwork(this NetworkingService networkingService, Identifier networkId) + { + networkingService.DeleteNetworkAsync(networkId).ForceSynchronous(); + } + #endregion + + #region Subnets + /// + /// Lists all subnets associated with the account. + /// + /// + /// A collection of subnet resources associated with the account. + /// + public static IEnumerable ListSubnets(this NetworkingService networkingService) + { + return networkingService.ListSubnetsAsync().ForceSynchronous(); + } + + /// + /// Creates a subnet. + /// + /// The networking service. + /// The subnet definition. + /// + /// The created subnet. + /// + public static Subnet CreateSubnet(this NetworkingService networkingService, SubnetCreateDefinition subnet) + { + return networkingService.CreateSubnetAsync(subnet).ForceSynchronous(); + } + + /// + /// Bulk creates multiple subnets. + /// + /// The networking service. + /// The subnet definitions. + /// + /// The created subnets. + /// + public static IEnumerable CreateSubnets(this NetworkingService networkingService, IEnumerable subnets) + { + return networkingService.CreateSubnetsAsync(subnets).ForceSynchronous(); + } + + /// + /// Gets the specified subnet. + /// + /// The networking service. + /// The subnet identifier. + /// + /// The subnet associated with the specified identifier. + /// + public static Subnet GetSubnet(this NetworkingService networkingService, Identifier subnetId) + { + return networkingService.GetSubnetAsync(subnetId).ForceSynchronous(); + } + + /// + /// Updates the specified subnet. + /// + /// The networking service. + /// The subnet identifier. + /// The updated subnet definition. + /// + /// The updated port. + /// + public static Subnet UpdateSubnet(this NetworkingService networkingService, Identifier subnetId, SubnetUpdateDefinition subnet) + { + return networkingService.UpdateSubnetAsync(subnetId, subnet).ForceSynchronous(); + } + + /// + /// Deletes the specified subnet. + /// + /// The networking service. + /// The subnet identifier. + public static void DeleteSubnet(this NetworkingService networkingService, Identifier subnetId) + { + networkingService.DeleteSubnetAsync(subnetId).ForceSynchronous(); + } + #endregion + + #region Ports + /// + /// Lists all ports associated with the account. + /// + /// + /// A collection of port resources associated with the account. + /// + public static IEnumerable ListPorts(this NetworkingService networkingService, PortListOptions options = null) + { + return networkingService.ListPortsAsync(options).ForceSynchronous(); + } + + /// + /// Creates a port. + /// + /// The networking service. + /// The port definition. + /// + /// The created port. + /// + public static Port CreatePort(this NetworkingService networkingService, PortCreateDefinition port) + { + return networkingService.CreatePortAsync(port).ForceSynchronous(); + } + + /// + /// Bulk creates multiple ports. + /// + /// The networking service. + /// The port definitions. + /// + /// The created ports. + /// + public static IEnumerable CreatePorts(this NetworkingService networkingService, IEnumerable ports) + { + return networkingService.CreatePortsAsync(ports).ForceSynchronous(); + } + + /// + /// Gets the specified port. + /// + /// The networking service. + /// The port identifier. + /// + /// The port associated with the specified identifier. + /// + public static Port GetPort(this NetworkingService networkingService, Identifier portId) + { + return networkingService.GetPortAsync(portId).ForceSynchronous(); + } + + /// + /// Updates the specified port. + /// + /// The networking service. + /// The port identifier. + /// The updated port definition. + /// + /// The updated port. + /// + public static Port UpdatePort(this NetworkingService networkingService, Identifier portId, PortUpdateDefinition port) + { + return networkingService.UpdatePortAsync(portId, port).ForceSynchronous(); + } + + /// + /// Deletes the specified port. + /// + /// The networking service. + /// The port identifier. + public static void DeletePort(this NetworkingService networkingService, Identifier portId) + { + networkingService.DeletePortAsync(portId).ForceSynchronous(); + } + #endregion + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Operator/NamespaceDoc.cs b/src/OpenStack/Networking/v2/Operator/NamespaceDoc.cs new file mode 100644 index 000000000..f75146378 --- /dev/null +++ b/src/OpenStack/Networking/v2/Operator/NamespaceDoc.cs @@ -0,0 +1,12 @@ +using System.Runtime.CompilerServices; + +namespace OpenStack.Networking.v2.Operator +{ + /// + /// The namespace defines additional functionality that is restricted to cloud operators only. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Operator/NetworkDefinition.cs b/src/OpenStack/Networking/v2/Operator/NetworkDefinition.cs new file mode 100644 index 000000000..fc222c42c --- /dev/null +++ b/src/OpenStack/Networking/v2/Operator/NetworkDefinition.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2.Operator +{ + /// + /// Extended definition of a network resource, with cloud operator functionality exposed. + /// + public class NetworkDefinition : v2.NetworkDefinition + { + /// + [JsonProperty("router:external")] + public bool? IsExternal { get; set; } + } +} diff --git a/src/OpenStack/Networking/v2/Port.cs b/src/OpenStack/Networking/v2/Port.cs new file mode 100644 index 000000000..57293648a --- /dev/null +++ b/src/OpenStack/Networking/v2/Port.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents a port resource of the . + /// + /// + /// Virtual (or logical) switch ports on a given network. + /// + /// + public class Port : PortCreateDefinition, IHaveExtraData, IServiceResource + { + /// + /// The ID of the port. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The port status. + /// + [JsonProperty("status")] + public PortStatus Status { get; set; } + + /// + /// The administrative state of the port. + /// + [JsonProperty("admin_state_up")] + public bool IsUp { get; set; } + + /// + /// The port security enablement status. + /// + [JsonProperty("port_security_enabled")] + public bool IsPortSecurityEnabled { get; set; } + + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + + object IServiceResource.Owner { get; set; } + } +} diff --git a/src/OpenStack/Networking/v2/PortCreateDefinition.cs b/src/OpenStack/Networking/v2/PortCreateDefinition.cs new file mode 100644 index 000000000..7555b7cfb --- /dev/null +++ b/src/OpenStack/Networking/v2/PortCreateDefinition.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Networking.v2.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents the set of properties which can be initialized when creating a . + /// + /// + public class PortCreateDefinition : PortUpdateDefinition + { + /// + /// Initializes a new instance of the class. + /// + protected PortCreateDefinition() + { + AllowedAddresses = new List(); + DHCPOptions = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The network identifier. + public PortCreateDefinition(Identifier networkId) : this() + { + NetworkId = networkId; + } + + /// + /// The ID of the attached network. + /// + [JsonProperty("network_id")] + public Identifier NetworkId { get; set; } + + /// + /// Allowed address pairs. + /// + [JsonProperty("allowed_address_pairs")] + public IList AllowedAddresses { get; set; } + + /// + /// The MAC address. + /// + [JsonProperty("mac_address")] + public string MACAddress { get; set; } + + /// + /// Additional DHCP options. + /// + /// + [JsonProperty("extra_dhcp_opts")] + [JsonConverter(typeof(DHCPOptionsConverter))] + public IDictionary DHCPOptions { get; set; } + + /// + /// The ID of the entity that uses this port. For example, a DHCP agent. + /// + [JsonProperty("device_owner")] + public string DeviceOwner { get; set; } + + /// + /// The ID of the device that uses this port. For example, a virtual server. + /// + [JsonProperty("device_id")] + public string DeviceId { get; set; } + } +} diff --git a/src/OpenStack/Networking/v2/PortListOptions.cs b/src/OpenStack/Networking/v2/PortListOptions.cs new file mode 100644 index 000000000..976919404 --- /dev/null +++ b/src/OpenStack/Networking/v2/PortListOptions.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; + +namespace OpenStack.Networking.v2 +{ + /// + /// Optional filter and paging options when listing ports. + /// + public class PortListOptions : FilterOptions + { + /// + /// Filter by the associated device identifier. + /// + public Identifier DeviceId { get; set; } + + /// + /// Filter by the entity that is using the port. + /// + public Identifier DeviceOwner { get; set; } + + /// + /// Filter by the associated network. + /// + public Identifier NetworkId { get; set; } + + /// + /// Filter by the MAC address. + /// + public string MACAddress { get; set; } + + /// + /// Filter by the port status. + /// + public PortStatus Status { get; set; } + + /// + /// Filter by the port name. + /// + public string Name { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + var queryString = new Dictionary + { + ["device_id"] = DeviceId, + ["device_owner"] = DeviceOwner, + ["network_id"] = NetworkId, + ["mac_address"] = MACAddress, + ["status"] = Status, + ["display_name"] = Name + }; + + return queryString; + } + } +} diff --git a/src/OpenStack/Networking/v2/PortStatus.cs b/src/OpenStack/Networking/v2/PortStatus.cs new file mode 100644 index 000000000..15d545cbf --- /dev/null +++ b/src/OpenStack/Networking/v2/PortStatus.cs @@ -0,0 +1,6 @@ +namespace OpenStack.Networking.v2 +{ + /// + public class PortStatus : NetworkResourceStatus + { } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/PortUpdateDefinition.cs b/src/OpenStack/Networking/v2/PortUpdateDefinition.cs new file mode 100644 index 000000000..4775f672b --- /dev/null +++ b/src/OpenStack/Networking/v2/PortUpdateDefinition.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents the set of properties which can be modified when updating a . + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "port")] + public class PortUpdateDefinition + { + /// + /// Initializes a new instance of the class. + /// + public PortUpdateDefinition() + { + FixedIPs = new List(); + SecurityGroups = new List(); + } + + /// + /// The port name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// IP addresses for the port. + /// + [JsonProperty("fixed_ips")] + public IList FixedIPs { get; set; } + + /// + /// The IDs of any attached security groups. + /// + [JsonProperty("security_groups")] + public IList SecurityGroups { get; set; } + } +} diff --git a/src/OpenStack/Networking/v2/Serialization/DHCPOptionsConverter.cs b/src/OpenStack/Networking/v2/Serialization/DHCPOptionsConverter.cs new file mode 100644 index 000000000..0527da0c7 --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/DHCPOptionsConverter.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Handles serialization/deserialization for . + /// + /// + /// + public class DHCPOptionsConverter : JsonConverter + { + /// + /// Writes the json. + /// + /// The writer. + /// The value. + /// The serializer. + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + return; + + writer.WriteStartArray(); + var options = (Dictionary) value; + foreach (var option in options) + { + writer.WriteStartObject(); + writer.WritePropertyName("opt_name"); + writer.WriteValue(option.Key); + writer.WritePropertyName("opt_value"); + writer.WriteValue(option.Value); + writer.WriteEndObject(); + } + writer.WriteEndArray(); + } + + /// + /// Reads the json. + /// + /// The reader. + /// Type of the object. + /// The existing value. + /// The serializer. + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var dhcpOptions = new Dictionary(); + + if (reader.TokenType == JsonToken.StartArray) + ReadAndAssert(reader); + + while (reader.TokenType != JsonToken.EndArray) + { + var dhcpOption = ReadItem(reader, serializer); + dhcpOptions.Add(dhcpOption.Key, dhcpOption.Value); + ReadAndAssert(reader); + } + + return dhcpOptions; + } + + private static KeyValuePair ReadItem(JsonReader reader, JsonSerializer serializer) + { + string key = null; + string value = null; + + ReadAndAssert(reader); + + while (reader.TokenType == JsonToken.PropertyName) + { + string propertyName = reader.Value.ToString(); + if (string.Equals(propertyName, "opt_name", StringComparison.OrdinalIgnoreCase)) + { + ReadAndAssert(reader); + key = serializer.Deserialize(reader); + } + else if (string.Equals(propertyName, "opt_value", StringComparison.OrdinalIgnoreCase)) + { + ReadAndAssert(reader); + value = serializer.Deserialize(reader); + } + else + { + reader.Skip(); + } + + ReadAndAssert(reader); + } + + return new KeyValuePair(key, value); + } + + private static void ReadAndAssert(JsonReader reader) + { + if (!reader.Read()) + throw new JsonSerializationException("Unexpected end when reading DHCPOptions."); + } + + /// + /// Determines whether this instance can convert the specified object type. + /// + /// Type of the object. + /// + public override bool CanConvert(Type objectType) + { + return typeof (Dictionary).IsAssignableFrom(objectType); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Serialization/FloatingIPCollection.cs b/src/OpenStack/Networking/v2/Serialization/FloatingIPCollection.cs new file mode 100644 index 000000000..e7301928a --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/FloatingIPCollection.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Networking.v2.Layer3; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of floating IP resources of the . + /// + /// + public class FloatingIPCollection : ResourceCollection + where T : IServiceResource + { + /// + [JsonProperty("floatingips")] + protected IList FloatingIPs => Items; + } + + /// + /// Represents a collection of floating IP resources of the . + /// + /// + public class FloatingIPCollection : FloatingIPCollection + { } +} diff --git a/src/OpenStack/Networking/v2/Serialization/IPProtocol.cs b/src/OpenStack/Networking/v2/Serialization/IPProtocol.cs new file mode 100644 index 000000000..58dc7c80e --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/IPProtocol.cs @@ -0,0 +1,27 @@ +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Internet Protocols. + /// + /// + public class IPProtocol : StringEnumeration + where T : IPProtocol, new() + { + /// + /// ICMP + /// + public static readonly T ICMP = new T {DisplayName = "icmp"}; + + /// + /// TCP + /// + public static readonly T TCP = new T {DisplayName = "tcp"}; + + /// + /// UDP + /// + public static readonly T UDP = new T {DisplayName = "udp"}; + } +} diff --git a/src/OpenStack/Networking/v2/Serialization/NetworkCollection.cs b/src/OpenStack/Networking/v2/Serialization/NetworkCollection.cs new file mode 100644 index 000000000..085a1ecc6 --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/NetworkCollection.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of network resources returned by the . + /// Intended for custom implementations and stubbing responses in unit tests. + /// + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "networks")] + public class NetworkCollection : List + { + /// + /// Initializes a new instance of the class. + /// + public NetworkCollection() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The networks. + public NetworkCollection(IEnumerable networks) : base(networks) + { + } + } +} diff --git a/src/OpenStack/Networking/v2/Serialization/NetworkDefinitionCollection.cs b/src/OpenStack/Networking/v2/Serialization/NetworkDefinitionCollection.cs new file mode 100644 index 000000000..fdeee8c1d --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/NetworkDefinitionCollection.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of network definition resources of the . + /// + /// + /// + [JsonConverterWithConstructor(typeof (RootWrapperConverter), "networks")] + internal class NetworkDefinitionCollection : List + { + public NetworkDefinitionCollection(IEnumerable networks) : base(networks) + { + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Serialization/NetworkResourceStatus.cs b/src/OpenStack/Networking/v2/Serialization/NetworkResourceStatus.cs new file mode 100644 index 000000000..5b583948f --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/NetworkResourceStatus.cs @@ -0,0 +1,27 @@ +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Networking resource status. Applies to networks, routers, interfaces, floating ips etc. + /// + /// + public class NetworkResourceStatus : ResourceStatus + where T : NetworkResourceStatus, new() + { + /// + /// The resource is in an unknown state. + /// + public static readonly T Unknown = new T { DisplayName = "UNKNOWN" }; + + /// + /// The resource is active. + /// + public static readonly T Active = new T { DisplayName = "ACTIVE" }; + + /// + /// The resource is unavilable. + /// + public static readonly T Down = new T { DisplayName = "DOWN" }; + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Serialization/PortCollection.cs b/src/OpenStack/Networking/v2/Serialization/PortCollection.cs new file mode 100644 index 000000000..c87c51af0 --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/PortCollection.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of port resources returned by the . + /// Intended for custom implementations and stubbing responses in unit tests. + /// + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "ports")] + public class PortCollection : List + { + /// + /// Initializes a new instance of the class. + /// + public PortCollection() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The networks. + public PortCollection(IEnumerable ports) : base(ports) + { + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Serialization/PortDefinitionCollection.cs b/src/OpenStack/Networking/v2/Serialization/PortDefinitionCollection.cs new file mode 100644 index 000000000..e84011ba0 --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/PortDefinitionCollection.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of port definition resources of the . + /// + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "ports")] + internal class PortDefinitionCollection : List + { + public PortDefinitionCollection(IEnumerable ports) : base(ports) + { + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Serialization/RouterCollection.cs b/src/OpenStack/Networking/v2/Serialization/RouterCollection.cs new file mode 100644 index 000000000..324bb3249 --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/RouterCollection.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Networking.v2.Layer3; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of router resources of the . + /// + /// + public class RouterCollection : ResourceCollection + where T : IServiceResource + { + /// + [JsonProperty("routers")] + protected IList Routers => Items; + } + + /// + /// Represents a collection of router resources of the . + /// + /// + public class RouterCollection : RouterCollection + { } +} diff --git a/src/OpenStack/Networking/v2/Serialization/SecurityGroupCollection.cs b/src/OpenStack/Networking/v2/Serialization/SecurityGroupCollection.cs new file mode 100644 index 000000000..4e8a5785d --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/SecurityGroupCollection.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using OpenStack.Serialization; +using OpenStack.Networking.v2.Layer3; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of security groups resources returned by the . + /// Intended for custom implementations and stubbing responses in unit tests. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "security_groups")] + public class SecurityGroupCollection : List + { + /// + /// Initializes a new instance of the class. + /// + public SecurityGroupCollection() + { + + } + + /// + /// Initializes a new instance of the class. + /// + /// items + public SecurityGroupCollection(IEnumerable items) + : base(items) + { + + } + } +} diff --git a/src/OpenStack/Networking/v2/Serialization/SecurityGroupRuleCollection.cs b/src/OpenStack/Networking/v2/Serialization/SecurityGroupRuleCollection.cs new file mode 100644 index 000000000..3f1aff34e --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/SecurityGroupRuleCollection.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using OpenStack.Networking.v2.Layer3; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of security group rule resources returned by the . + /// Intended for custom implementations and stubbing responses in unit tests. + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "security_group_rules")] + public class SecurityGroupRuleCollection : List + { + + /// + /// Initializes a new instance of the class. + /// + public SecurityGroupRuleCollection() + { + + } + + /// + /// Initializes a new instance of the class. + /// + /// + public SecurityGroupRuleCollection(IEnumerable items) : base(items) + { + + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Serialization/SubnetCollection.cs b/src/OpenStack/Networking/v2/Serialization/SubnetCollection.cs new file mode 100644 index 000000000..7875fce68 --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/SubnetCollection.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of subnet resources returned by the . + /// Intended for custom implementations and stubbing responses in unit tests. + /// + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "subnets")] + public class SubnetCollection : List + { + /// + /// Initializes a new instance of the class. + /// + public SubnetCollection() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The networks. + public SubnetCollection(IEnumerable subnets) : base(subnets) + { + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Serialization/SubnetDefinitionCollection.cs b/src/OpenStack/Networking/v2/Serialization/SubnetDefinitionCollection.cs new file mode 100644 index 000000000..30f340662 --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/SubnetDefinitionCollection.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Represents a collection of subnet definition resources of the . + /// + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "subnets")] + internal class SubnetDefinitionCollection : List + { + public SubnetDefinitionCollection(IEnumerable subnets) : base(subnets) + { + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/Serialization/TrafficDirection.cs b/src/OpenStack/Networking/v2/Serialization/TrafficDirection.cs new file mode 100644 index 000000000..fc39d32c7 --- /dev/null +++ b/src/OpenStack/Networking/v2/Serialization/TrafficDirection.cs @@ -0,0 +1,22 @@ +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2.Serialization +{ + /// + /// Direction of network traffic. + /// + /// + public class TrafficDirection : StringEnumeration + where T : TrafficDirection, new() + { + /// + /// Incoming network traffic (ingress). + /// + public static readonly T Incoming = new T { DisplayName = "ingress" }; + + /// + /// Outgoing network traffic (egress). + /// + public static readonly T Outgoing = new T { DisplayName = "egress" }; + } +} diff --git a/src/OpenStack/Networking/v2/Subnet.cs b/src/OpenStack/Networking/v2/Subnet.cs new file mode 100644 index 000000000..837848c55 --- /dev/null +++ b/src/OpenStack/Networking/v2/Subnet.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents a subnet resource of the . + /// + /// IPv4 or IPv6 address blocks from which IPs to be assigned to VMs on a given network are selected. + /// + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "subnet")] + public class Subnet : SubnetCreateDefinition + { + /// + /// The ID of the subnet. + /// + [JsonProperty("id")] + public Identifier Id { get; set; } + + /// + /// The ID of the tenant who owns the network. + /// + [JsonProperty("tenant_id")] + public string TenantId { get; set; } + + /// + /// Specifies if DHCP is enabled. + /// + [JsonProperty("enable_dhcp")] + public new bool IsDHCPEnabled { get; set; } + } +} diff --git a/src/OpenStack/Networking/v2/SubnetCreateDefinition.cs b/src/OpenStack/Networking/v2/SubnetCreateDefinition.cs new file mode 100644 index 000000000..747ada27b --- /dev/null +++ b/src/OpenStack/Networking/v2/SubnetCreateDefinition.cs @@ -0,0 +1,49 @@ +using Newtonsoft.Json; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents the set of properties which can be initialized when creating a . + /// + /// + public class SubnetCreateDefinition : SubnetUpdateDefinition + { + /// + /// Initializes a new instance of the class. + /// + protected SubnetCreateDefinition() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The network identifier. + /// The ip version. + /// The cidr. + public SubnetCreateDefinition(Identifier networkId, IPVersion ipVersion, string cidr) + { + NetworkId = networkId; + IPVersion = ipVersion; + CIDR = cidr; + } + + /// + /// The ID of the attached network. + /// + [JsonProperty("network_id")] + public Identifier NetworkId { get; set; } + + /// + /// The IP version. + /// + [JsonProperty("ip_version")] + public IPVersion IPVersion { get; set; } + + /// + /// Classless Inter-Domain Routing (CIDR). A method for allocating IP addresses and routing Internet Protocol packets. + /// + [JsonProperty("cidr")] + public string CIDR { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/SubnetUpdateDefinition.cs b/src/OpenStack/Networking/v2/SubnetUpdateDefinition.cs new file mode 100644 index 000000000..9bb1cca16 --- /dev/null +++ b/src/OpenStack/Networking/v2/SubnetUpdateDefinition.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using OpenStack.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + /// Represents the set of properties which can be modified when updating a . + /// + /// + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "subnet")] + public class SubnetUpdateDefinition + { + /// + /// Initializes a new instance of the class. + /// + public SubnetUpdateDefinition() + { + Nameservers = new List(); + AllocationPools = new List(); + HostRoutes = new List(); + } + + /// + /// The subnet name. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Specifies if DHCP is enabled. + /// + [JsonProperty("enable_dhcp")] + public bool? IsDHCPEnabled { get; set; } + + /// + /// The DNS nameserver IP addresses. + /// + [JsonProperty("dns_nameservers")] + public IList Nameservers { get; set; } + + /// + /// The IP address allocation pools. + /// + [JsonProperty("allocation_pools")] + public IList AllocationPools { get; set; } + + /// + /// The host routes. + /// + [JsonProperty("host_routes")] + public IList HostRoutes { get; set; } + + /// + /// The gateway IP address. + /// + [JsonProperty("gateway_ip")] + public string GatewayIP { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Networking/v2/TrafficDirection.cs b/src/OpenStack/Networking/v2/TrafficDirection.cs new file mode 100644 index 000000000..1a41e415e --- /dev/null +++ b/src/OpenStack/Networking/v2/TrafficDirection.cs @@ -0,0 +1,8 @@ +using OpenStack.Networking.v2.Serialization; + +namespace OpenStack.Networking.v2 +{ + /// + public class TrafficDirection : TrafficDirection + { } +} \ No newline at end of file diff --git a/src/OpenStack/OpenStack.csproj b/src/OpenStack/OpenStack.csproj new file mode 100644 index 000000000..237132fd9 --- /dev/null +++ b/src/OpenStack/OpenStack.csproj @@ -0,0 +1,21 @@ + + + + net45 + + + + + + + + + + + + + + + + + diff --git a/src/OpenStack/OpenStackNet.cs b/src/OpenStack/OpenStackNet.cs new file mode 100644 index 000000000..a8eff122f --- /dev/null +++ b/src/OpenStack/OpenStackNet.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Extensions; +using System.Net.Http.Headers; +using Flurl.Http; +using Flurl.Http.Configuration; +using Newtonsoft.Json; +using OpenStack.Authentication; +using OpenStack.Serialization; + +namespace OpenStack +{ + /// + /// A static container for global configuration settings affecting OpenStack.NET behavior. + /// + /// + public static class OpenStackNet + { + /// + /// Global configuration which affects OpenStack.NET's behavior. + /// Customize using the event. + /// + public static OpenStackNetConfigurationOptions Configuration + { + get + { + if (!_isConfigured) + Configure(); + return _config; + } + } + + private static OpenStackNetConfigurationOptions _config; + private static readonly object ConfigureLock = new object(); + private static bool _isConfigured; + + /// + /// Occurs when initializing the global configuration for OpenStack.NET. + /// + public static event Action Configuring; + + /// + /// DEPRECATED, use the event instead. + /// Provides thread-safe accesss to OpenStack.NET's global configuration options. + /// Can only be called once at application start-up, before instantiating any OpenStack.NET objects. + /// + /// Addtional configuration of the OpenStack.NET Flurl client settings . + /// Additional configuration of OpenStack.NET's global settings. + [Obsolete("This will be removed in v2.0. Use the OpenStackNet.Configuring event instead.")] + public static void Configure(Action configureFlurl = null, Action configure = null) + { + lock (ConfigureLock) + { + if (_isConfigured) + { + // Check if a user is attempting to apply custom configuration after the default config has been applied + if(configureFlurl != null || configure != null) + Trace.TraceError("Ignoring additional call to OpenStackNet.Configure. It can only be called once at application start-up, before instantiating any OpenStack.NET objects."); + + return; + } + + // Give the application an opportunity to tweak the default config + _config = OpenStackNetConfigurationOptions.Create(); + Configuring?.Invoke(_config); + + // Apply legacy custom configuration, removed in 2.0 as it's replaced by the Configuring event + configureFlurl?.Invoke(_config.FlurlHttpSettings); + + // Finish configuration and lock it + _config.CompleteInitialization(); + + _isConfigured = true; + } + } + + /// + /// Resets all configuration (OpenStack.NET, Flurl and Json.NET). + /// After this is called, you must re-register any event handlers. + /// + public static void ResetDefaults() + { + lock (ConfigureLock) + { + _config = null; + Configuring = null; + _isConfigured = false; + } + } + + /// + /// Deserializes an object from a json string representation. + /// + /// The object type. + /// The json string. + public static T Deserialize(string json) + { + return Configuration.FlurlHttpSettings.JsonSerializer.Deserialize(json); + } + + /// + /// Serializes an object to a json string representation + /// + /// The object. + /// The json string representation of the object. + public static string Serialize(object obj) + { + return Configuration.FlurlHttpSettings.JsonSerializer.Serialize(obj); + } + + /// + /// Provides global point for programmatically configuraing tracing + /// + public static class Tracing + { + /// + /// Trace source for all HTTP requests. Default level is Error. + /// + /// In your app or web.config the trace soruce name is "Flurl.Http". + /// + /// + public static readonly TraceSource Http = new TraceSource("Flurl.Http", SourceLevels.Error); + + /// + /// Traces a failed HTTP request + /// + /// The Flurl HTTP call instance, containing information about the request and response. + public static void TraceFailedHttpCall(HttpCall httpCall) + { + Http.TraceData(TraceEventType.Error, 0, SerializeHttpCall(httpCall)); + Http.Flush(); + } + + /// + /// Traces an HTTP request + /// + /// The Flurl HTTP call instance, containing information about the request and response. + public static void TraceHttpCall(HttpCall httpCall) + { + Http.TraceData(TraceEventType.Information, 0, SerializeHttpCall(httpCall)); + } + + private static string SerializeHttpCall(HttpCall httpCall) + { + var settings = new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore + }; + return JsonConvert.SerializeObject(httpCall, Formatting.Indented, settings); + } + } + } + + /// + /// A readonly set of properties that affect OpenStack.NET's behavior. + /// To customize, register an event handler for . + /// + public class OpenStackNetConfigurationOptions + { + private bool _isInitialized; + private readonly FlurlHttpSettings _flurlHttpSettings; + private readonly JsonSerializerSettings _jsonSerializerSettings; + private readonly List _userAgents; + + /// + protected OpenStackNetConfigurationOptions() + { + _flurlHttpSettings = new FlurlHttpSettings(); + _jsonSerializerSettings = new JsonSerializerSettings(); + _userAgents = new List(); + } + + /// + public static event Action Creating; + + /// + internal static OpenStackNetConfigurationOptions Create() + { + var createEvent = new CreateEvent(); + Creating?.Invoke(createEvent); + return createEvent.Result; + } + + /// + public void CompleteInitialization() + { + OnCompleteInitialization(); + ApplyDefaults(); + _isInitialized = true; + } + + /// + protected virtual void OnCompleteInitialization() + {} + + /// + /// Custom Flurl.Http configuration settings which are specific to requests made by this SDK. + /// + public FlurlHttpSettings FlurlHttpSettings + { + get + { + if(_isInitialized) + return _flurlHttpSettings.Clone(); + + return _flurlHttpSettings; + } + } + + /// + /// Custom Json.NET configuration settings which are specific to requests made by this SDK. + /// + public JsonSerializerSettings JsonSerializerSettings + { + get + { + if (_isInitialized) + return _jsonSerializerSettings.Clone(); + + return _jsonSerializerSettings; + } + } + + /// + /// Additional application specific user agents which should be set in the UserAgent header on all requests made by this SDK. + /// + public IList UserAgents + { + get + { + if(_isInitialized) + return _userAgents.AsReadOnly(); + + return _userAgents; + } + } + + private void ApplyDefaults() + { + // + // Apply our default settings on top of user customizations, hopefully without clobbering anything + // + UserAgents.Add(new ProductInfoHeaderValue("openstack.net", GetType().GetAssemblyFileVersion())); + + _jsonSerializerSettings.DefaultValueHandling = DefaultValueHandling.Ignore; + _jsonSerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore; + _jsonSerializerSettings.NullValueHandling = NullValueHandling.Ignore; + if(!(_jsonSerializerSettings.ContractResolver is OpenStackContractResolver)) + _jsonSerializerSettings.ContractResolver = new OpenStackContractResolver(); + + _flurlHttpSettings.JsonSerializer = new NewtonsoftJsonSerializer(_jsonSerializerSettings); + + // When in test mode (set via HttpTest), this will be a custom class (TestHttpClientFactory) + if (_flurlHttpSettings.HttpClientFactory?.GetType() == typeof(DefaultHttpClientFactory)) + _flurlHttpSettings.HttpClientFactory = new AuthenticatedHttpClientFactory(); + + // Apply our event handling and optionally include any custom application handlers + var applicationBeforeCall = _flurlHttpSettings.BeforeCall; + _flurlHttpSettings.BeforeCall = call => + { + SetUserAgentHeader(call); + applicationBeforeCall?.Invoke(call); + }; + + var applicationAfterCall = _flurlHttpSettings.AfterCall; + _flurlHttpSettings.AfterCall = call => + { + OpenStackNet.Tracing.TraceHttpCall(call); + applicationAfterCall?.Invoke(call); + }; + + var applicationOnError = _flurlHttpSettings.OnError; + _flurlHttpSettings.OnError = call => + { + OpenStackNet.Tracing.TraceFailedHttpCall(call); + applicationOnError?.Invoke(call); + }; + } + + private void SetUserAgentHeader(HttpCall call) + { + foreach (ProductInfoHeaderValue userAgent in UserAgents) + { + call.Request.Headers.UserAgent.Add(userAgent); + } + } + + /// + /// Raised when creating the SDK configuration options class. + /// Intended for vendors to override. + /// + /// + public class CreateEvent + { + /// + /// An instance of the configuration class to use when configuring the SDK. + /// + public OpenStackNetConfigurationOptions Result = new OpenStackNetConfigurationOptions(); + } + } +} diff --git a/src/OpenStack/Page.cs b/src/OpenStack/Page.cs new file mode 100644 index 000000000..d2db5b386 --- /dev/null +++ b/src/OpenStack/Page.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace OpenStack +{ + /// + /// A page of resources. + /// + /// The item type. + public interface IPage : IEnumerable + { + /// + /// Specifies if another page can be retrieved with additional items + /// + bool HasNextPage { get; } + + /// + /// Retrieves the next page of items, if one is available. If is false, an empty page is returned. + /// + Task> GetNextPageAsync(CancellationToken cancellation = default(CancellationToken)); + } +} \ No newline at end of file diff --git a/src/OpenStack/PageExtensions.cs b/src/OpenStack/PageExtensions.cs new file mode 100644 index 000000000..38949034b --- /dev/null +++ b/src/OpenStack/PageExtensions.cs @@ -0,0 +1,18 @@ +using OpenStack.Synchronous.Extensions; + +namespace OpenStack.Synchronous +{ + /// + /// Provides synchronous extention methods for an instance. + /// + public static class PageExtensions + { + /// + /// Retrieves the next page of items, if one is available. If is false, an empty page is returned. + /// + public static IPage GetNextPage(this IPage page) + { + return page.GetNextPageAsync().ForceSynchronous(); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/PageOptions.cs b/src/OpenStack/PageOptions.cs new file mode 100644 index 000000000..82d6e7296 --- /dev/null +++ b/src/OpenStack/PageOptions.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using OpenStack.Serialization; + +namespace OpenStack +{ + /// + /// Paging options when listing a resource that supports paging. + /// + public class PageOptions : FilterOptions + { + /// + /// The number of resources to return per page. + /// + public int? PageSize { get; set; } + + /// + /// The identifier of the first resource to return on the page. + /// + public Identifier StartingAt { get; set; } + + /// + protected override IDictionary BuildQueryString() + { + return new Dictionary + { + {"marker", StartingAt}, + {"limit", PageSize} + }; + } + } + + /// + /// Options when list a resource that supports filtering. + /// + public abstract class FilterOptions : IQueryStringBuilder + { + /// + protected abstract IDictionary BuildQueryString(); + + IDictionary IQueryStringBuilder.Build() + { + return BuildQueryString(); + } + } +} diff --git a/src/OpenStack/Providers/Hp/HpIdentityProvider.cs b/src/OpenStack/Providers/Hp/HpIdentityProvider.cs new file mode 100644 index 000000000..ce9d1fc85 --- /dev/null +++ b/src/OpenStack/Providers/Hp/HpIdentityProvider.cs @@ -0,0 +1,198 @@ +using System.Collections.Generic; +using OpenStack; +using OpenStack.Authentication; + +namespace net.openstack.Providers.Hp +{ + using System; + using net.openstack.Core.Caching; + using net.openstack.Core.Domain; + using Newtonsoft.Json.Linq; + using CloudIdentityProvider = net.openstack.Providers.Rackspace.CloudIdentityProvider; + using HttpMethod = JSIStudios.SimpleRESTServices.Client.HttpMethod; + using IIdentityProvider = net.openstack.Core.Providers.IIdentityProvider; + using IRestService = JSIStudios.SimpleRESTServices.Client.IRestService; + using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices; + + /// + /// Provides an implementation of for operating with + /// HP's Cloud Identity product. This provider supports authentication using a username/password + /// combination or an access key/secret key combinatiton, and supports scoped tokens + /// when credentials are represented with . + /// + /// OpenStack Identity Service API v2.0 Reference + /// HP Cloud v12.12 Identity Services API + /// + /// + public class HpIdentityProvider : CloudIdentityProvider + { + /// + /// Initializes a new instance of the class + /// with no default identity, the base URL, and the default REST service + /// implementation and token cache. + /// + public HpIdentityProvider() + : this(PredefinedHpIdentityEndpoints.Default, null, null, null) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified default identity, the base URL, and the default REST service + /// implementation and token cache. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + public HpIdentityProvider(CloudIdentity defaultIdentity) + : this(PredefinedHpIdentityEndpoints.Default, defaultIdentity, null, null) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, the base URL, and the default REST service + /// implementation, and token cache. + /// + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + public HpIdentityProvider(IRestService restService, ICache tokenCache) + : this(PredefinedHpIdentityEndpoints.Default, null, restService, tokenCache) + { + } + + /// + /// Initializes a new instance of the class + /// using the base URL and provided values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + public HpIdentityProvider(CloudIdentity defaultIdentity, IRestService restService, ICache tokenCache) + : this(PredefinedHpIdentityEndpoints.Default, defaultIdentity, restService, tokenCache) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, the specified base URL, and the default REST service + /// implementation and token cache. + /// + /// The base URL for the cloud instance. Predefined URLs are available in . + /// If is . + public HpIdentityProvider(Uri urlBase) + : this(urlBase, null, null, null) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified default identity and base URL, and the default REST service + /// implementation and token cache. + /// + /// The base URL for the cloud instance. Predefined URLs are available in . + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// If is . + public HpIdentityProvider(Uri urlBase, CloudIdentity defaultIdentity) + : this(urlBase, defaultIdentity, null, null) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, and the specified base URL, REST service + /// implementation, and token cache. + /// + /// The base URL for the cloud instance. Predefined URLs are available in . + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + /// If is . + public HpIdentityProvider(Uri urlBase, IRestService restService, ICache tokenCache) + : this(urlBase, null, restService, tokenCache) + { + } + + /// + /// Initializes a new instance of the class + /// using the provided values. + /// + /// The base URL for the cloud instance. Predefined URLs are available in . + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + /// If is . + public HpIdentityProvider(Uri urlBase, CloudIdentity defaultIdentity, IRestService restService, ICache tokenCache) + : base(defaultIdentity, restService, tokenCache, urlBase) + { + if (urlBase == null) + throw new ArgumentNullException("urlBase"); + } + + /// + public override UserAccess GetUserAccess(CloudIdentity identity, bool forceCacheRefresh = false) + { + if (identity == null) + throw new ArgumentNullException("identity"); + + CloudIdentityWithProject identityWithProject = identity as CloudIdentityWithProject; + if (identityWithProject == null) + { + if (identity.GetType() != typeof(CloudIdentity)) + throw new NotSupportedException(string.Format("{0} does not support credentials of type {1}", GetType().Name, identity.GetType().Name)); + } + + Func refreshCallback = + () => + { + JObject credentialsObject; + if (!string.IsNullOrEmpty(identity.APIKey)) + { + credentialsObject = new JObject( + new JProperty("apiAccessKeyCredentials", new JObject( + new JProperty("accessKey", identity.APIKey), + new JProperty("secretKey", identity.Password)))); + } + else + { + credentialsObject = new JObject( + new JProperty("passwordCredentials", new JObject( + new JProperty("username", identity.Username), + new JProperty("password", identity.Password)))); + } + + JObject authObject = new JObject(credentialsObject); + if (identityWithProject != null && identityWithProject.ProjectId != null) + authObject.Add("tenantId", JToken.FromObject(identityWithProject.ProjectId)); + if (identityWithProject != null && !string.IsNullOrEmpty(identityWithProject.ProjectName)) + authObject.Add("tenantName", JToken.FromObject(identityWithProject.ProjectName)); + + JObject requestBody = new JObject( + new JProperty("auth", authObject)); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "/v2.0/tokens"), HttpMethod.POST, requestBody, isTokenRequest: true); + if (response == null || response.Data == null) + return null; + + JToken userAccessObject = response.Data["access"]; + if (userAccessObject == null) + return null; + + UserAccess access = userAccessObject.ToObject(); + if (access == null || access.Token == null) + return null; + + return access; + }; + string key = string.Format("{0}:{1}/{2}/{3}/{4}", UrlBase, identityWithProject != null ? identityWithProject.ProjectId : null, identity.Username, identity.APIKey, identity.Password); + var userAccess = TokenCache.Get(key, refreshCallback, forceCacheRefresh); + + return userAccess; + } + + /// + protected override string LookupServiceTypeKey(IServiceType serviceType) + { + if (ServiceType.ContentDeliveryNetwork.Equals(serviceType)) + return "hpext:cdn"; + return serviceType.Type; + } + } +} diff --git a/src/OpenStack/Providers/Hp/NamespaceDoc.cs b/src/OpenStack/Providers/Hp/NamespaceDoc.cs new file mode 100644 index 000000000..d2367457c --- /dev/null +++ b/src/OpenStack/Providers/Hp/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Hp +{ + using System.Runtime.CompilerServices; + + /// + /// The namespaces provide an + /// implementation of the core OpenStack interfaces for accessing HP cloud + /// products and services, as well as additional HP-specific functionality. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Hp/PredefinedHpIdentityEndpoints.cs b/src/OpenStack/Providers/Hp/PredefinedHpIdentityEndpoints.cs new file mode 100644 index 000000000..b873fb119 --- /dev/null +++ b/src/OpenStack/Providers/Hp/PredefinedHpIdentityEndpoints.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Hp +{ + using System; + + /// + /// Provides endpoints for the HP Cloud Identity Service. + /// + /// + /// As HP accounts are global, any region can be used for conducting identity + /// operations. Choose the region closest to you for improved performance, or + /// use for general API operations. + /// + /// + /// + public static class PredefinedHpIdentityEndpoints + { + /// + /// Gets the HP Cloud Identity Service endpoint for the US-West region. + /// + /// + /// As HP accounts are global, any region can be used for conducting identity + /// operations. Choose the region closest to you for improved performance, or + /// use for general API operations. + /// + public static readonly Uri UsWest = new Uri("https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/"); + + /// + /// Gets the HP Cloud Identity Service endpoint for the US-East region. + /// + /// + /// As HP accounts are global, any region can be used for conducting identity + /// operations. Choose the region closest to you for improved performance, or + /// use for general API operations. + /// + public static readonly Uri UsEast = new Uri("https://region-b.geo-1.identity.hpcloudsvc.com:35357/v2.0/"); + + /// + /// Gets the default endpoint for the HP Cloud Identity Service. + /// + public static readonly Uri Default = UsEast; + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudAutoScaleProvider.cs b/src/OpenStack/Providers/Rackspace/CloudAutoScaleProvider.cs new file mode 100644 index 000000000..e53d2eeff --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudAutoScaleProvider.cs @@ -0,0 +1,840 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Net; + using System.Threading.Tasks; + using net.openstack.Core; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using net.openstack.Core.Providers; + using net.openstack.Providers.Rackspace.Objects.AutoScale; + using Newtonsoft.Json.Linq; + using CancellationToken = System.Threading.CancellationToken; + using HttpMethod = JSIStudios.SimpleRESTServices.Client.HttpMethod; + using HttpResponseCodeValidator = net.openstack.Providers.Rackspace.Validators.HttpResponseCodeValidator; + using IHttpResponseCodeValidator = net.openstack.Core.Validators.IHttpResponseCodeValidator; + using InternalTaskExtensions = net.openstack.Core.InternalTaskExtensions; + using IRestService = JSIStudios.SimpleRESTServices.Client.IRestService; + using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices; + + /// + /// Provides an implementation of for operating + /// with Rackspace's Auto Scale product. + /// + /// Rackspace Auto Scale Developer Guide - API v1.0 + /// + /// + public class CloudAutoScaleProvider : ProviderBase, IAutoScaleService + { + /// + /// This field caches the base URI used for accessing the Auto Scale service. + /// + /// + private Uri _baseUri; + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudAutoScaleProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider) + : base(defaultIdentity, defaultRegion, identityProvider, null, null) + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing synchronous REST requests. If this value is , the provider will use a new instance of . + /// The HTTP status code validator to use for synchronous REST requests. If this value is , the provider will use . + protected CloudAutoScaleProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService, IHttpResponseCodeValidator httpStatusCodeValidator) + : base(defaultIdentity, defaultRegion, identityProvider, restService, httpStatusCodeValidator) + { + } + + #region IAutoScaleService Members + + /// + public Task> ListScalingGroupsAsync(ScalingGroupId marker, int? limit, CancellationToken cancellationToken) + { + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/groups/?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["groups"]; + if (valuesToken == null) + return null; + + JToken linksToken = result["groups_links"]; + Link[] links = linksToken != null ? linksToken.ToObject() : null; + + ScalingGroup[] values = valuesToken.ToObject(); + + ScalingGroupId nextMarker = values.Any() && (links == null || links.Any(i => string.Equals(i.Rel, "next", StringComparison.OrdinalIgnoreCase))) ? values.Last().Id : null; + Func>> getNextPageAsync = null; + if (nextMarker != null) + getNextPageAsync = nextCancellationToken => ListScalingGroupsAsync(nextMarker, limit, cancellationToken); + + return new BasicReadOnlyCollectionPage(values, getNextPageAsync); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CreateGroupAsync(ScalingGroupConfiguration configuration, CancellationToken cancellationToken) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/groups"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ScalingGroup> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["group"]; + if (valueToken == null) + return null; + + return valueToken.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetGroupAsync(ScalingGroupId groupId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ScalingGroup> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["group"]; + if (valueToken == null) + return null; + + return valueToken.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task DeleteGroupAsync(ScalingGroupId groupId, bool? force, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}?force={force}"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + if (force ?? false) + parameters.Add("force", force.ToString().ToLowerInvariant()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task GetGroupStateAsync(ScalingGroupId groupId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/state"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, GroupState> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["group"]; + if (valueToken == null) + return null; + + return valueToken.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task PauseGroupAsync(ScalingGroupId groupId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/pause"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task ResumeGroupAsync(ScalingGroupId groupId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/resume"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task GetGroupConfigurationAsync(ScalingGroupId groupId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/config"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, GroupConfiguration> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["groupConfiguration"]; + if (valueToken == null) + return null; + + return valueToken.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task SetGroupConfigurationAsync(ScalingGroupId groupId, GroupConfiguration configuration, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/config"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task GetLaunchConfigurationAsync(ScalingGroupId groupId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/launch"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, LaunchConfiguration> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JObject valueToken = result["launchConfiguration"] as JObject; + if (valueToken == null) + return null; + + return LaunchConfiguration.FromJObject(valueToken); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task SetLaunchConfigurationAsync(ScalingGroupId groupId, LaunchConfiguration configuration, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/launch"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListPoliciesAsync(ScalingGroupId groupId, PolicyId marker, int? limit, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/?marker={marker}&limit={limit}"); + var parameters = new Dictionary() { { "groupId", groupId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["policies"]; + if (valuesToken == null) + return null; + + JToken linksToken = result["policies_links"]; + Link[] links = linksToken != null ? linksToken.ToObject() : null; + + Policy[] values = valuesToken.ToObject(); + + PolicyId nextMarker = values.Any() && (links == null || links.Any(i => string.Equals(i.Rel, "next", StringComparison.OrdinalIgnoreCase))) ? values.Last().Id : null; + Func>> getNextPageAsync = null; + if (nextMarker != null) + getNextPageAsync = nextCancellationToken => ListPoliciesAsync(groupId, nextMarker, limit, cancellationToken); + + return new BasicReadOnlyCollectionPage(values, getNextPageAsync); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CreatePolicyAsync(ScalingGroupId groupId, PolicyConfiguration configuration, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies"); + var parameters = new Dictionary { { "groupId", groupId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, new[] { configuration }); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Policy> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["policies"]; + if (valueToken == null) + return null; + + Policy[] policies = valueToken.ToObject(); + return policies[0]; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetPolicyAsync(ScalingGroupId groupId, PolicyId policyId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Policy> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["policy"]; + if (valueToken == null) + return null; + + return valueToken.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task SetPolicyAsync(ScalingGroupId groupId, PolicyId policyId, PolicyConfiguration configuration, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task DeletePolicyAsync(ScalingGroupId groupId, PolicyId policyId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task ExecutePolicyAsync(ScalingGroupId groupId, PolicyId policyId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}/execute"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListWebhooksAsync(ScalingGroupId groupId, PolicyId policyId, WebhookId marker, int? limit, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}/webhooks/?marker={marker}&limit={limit}"); + var parameters = new Dictionary() { { "groupId", groupId.Value }, { "policyId", policyId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["webhooks"]; + if (valuesToken == null) + return null; + + JToken linksToken = result["webhooks_links"]; + Link[] links = linksToken != null ? linksToken.ToObject() : null; + + Webhook[] values = valuesToken.ToObject(); + + WebhookId nextMarker = values.Any() && (links == null || links.Any(i => string.Equals(i.Rel, "next", StringComparison.OrdinalIgnoreCase))) ? values.Last().Id : null; + Func>> getNextPageAsync = null; + if (nextMarker != null) + getNextPageAsync = nextCancellationToken => ListWebhooksAsync(groupId, policyId, nextMarker, limit, cancellationToken); + + return new BasicReadOnlyCollectionPage(values, getNextPageAsync); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CreateWebhookAsync(ScalingGroupId groupId, PolicyId policyId, NewWebhookConfiguration configuration, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}/webhooks"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, new[] { configuration }); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Webhook> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["webhooks"]; + if (valueToken == null) + return null; + + Webhook[] webhooks = valueToken.ToObject(); + return webhooks[0]; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> CreateWebhookRangeAsync(ScalingGroupId groupId, PolicyId policyId, IEnumerable configurations, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + if (configurations == null) + throw new ArgumentNullException("configurations"); + + NewWebhookConfiguration[] configurationsArray = configurations.ToArray(); + if (configurationsArray.Contains(null)) + throw new ArgumentException("configurations cannot contain any null values", "configurations"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}/webhooks"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configurations); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["webhooks"]; + if (valueToken == null) + return null; + + ReadOnlyCollection webhooks = valueToken.ToObject>(); + return webhooks; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetWebhookAsync(ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + if (webhookId == null) + throw new ArgumentNullException("webhookId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}/webhooks/{webhookId}"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value }, { "webhookId", webhookId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Webhook> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valueToken = result["webhook"]; + if (valueToken == null) + return null; + + return valueToken.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task UpdateWebhookAsync(ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId, UpdateWebhookConfiguration configuration, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + if (webhookId == null) + throw new ArgumentNullException("webhookId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}/webhooks/{webhookId}"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value }, { "webhookId", webhookId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task DeleteWebhookAsync(ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId, CancellationToken cancellationToken) + { + if (groupId == null) + throw new ArgumentNullException("groupId"); + if (policyId == null) + throw new ArgumentNullException("policyId"); + if (webhookId == null) + throw new ArgumentNullException("webhookId"); + + UriTemplate template = new UriTemplate("/groups/{groupId}/policies/{policyId}/webhooks/{webhookId}"); + var parameters = new Dictionary { { "groupId", groupId.Value }, { "policyId", policyId.Value }, { "webhookId", webhookId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + #endregion + + /// + /// + /// This method returns a cached base address if one is available. If no cached address is + /// available, is called to obtain + /// an with the type rax:autoscale and preferred name autoscale. + /// + protected override Task GetBaseUriAsync(CancellationToken cancellationToken) + { + if (_baseUri != null) + { + return InternalTaskExtensions.CompletedTask(_baseUri); + } + + return Task.Factory.StartNew( + () => + { + Endpoint endpoint = GetServiceEndpoint(null, "rax:autoscale", "autoscale", null); + _baseUri = new Uri(endpoint.PublicURL); + return _baseUri; + }); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudBlockStorageProvider.cs b/src/OpenStack/Providers/Rackspace/CloudBlockStorageProvider.cs new file mode 100644 index 000000000..8e213e6b5 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudBlockStorageProvider.cs @@ -0,0 +1,511 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using JSIStudios.SimpleRESTServices.Client; +using JSIStudios.SimpleRESTServices.Client.Json; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Providers; +using net.openstack.Core.Validators; +using net.openstack.Providers.Rackspace.Objects.Request; +using net.openstack.Providers.Rackspace.Objects.Response; +using net.openstack.Providers.Rackspace.Validators; + +namespace net.openstack.Providers.Rackspace +{ + /// + /// Provides an implementation of + /// for operating with Rackspace's Cloud Block Storage product. + /// + /// + /// The Cloud Block Storage Provider enables simple access to the Rackspace Cloud Block Storage Volumes as well as Cloud Block Storage Volume Snapshot services. + /// Rackspace Cloud Block Storage is a block level storage solution that allows customers to mount drives or volumes to their Rackspace Next Generation Cloud Servers. + /// The two primary use cases are (1) to allow customers to scale their storage independently from their compute resources, + /// and (2) to allow customers to utilize high performance storage to serve database or I/O-intensive applications. + /// + /// Highlights of Rackspace Cloud Block Storage include: + /// + /// Mount a drive to a Cloud Server to scale storage without paying for more compute capability. + /// A high performance option for databases and high performance applications, leveraging solid state drives for speed. + /// A standard speed option for customers who just need additional storage on their Cloud Server. + /// + /// + /// + /// + /// Cloud Block Storage is an add-on feature to Next Generation Cloud Servers. Customers may not attach Cloud Block Storage volumes to other instances, like first generation Cloud Servers. + /// Cloud Block Storage is multi-tenant rather than dedicated. + /// When volumes are destroyed, Rackspace keeps that disk space unavailable until zeros have been written to the space to ensure that data is not accessible by any other customers. + /// Cloud Block Storage allows you to create snapshots that you can save, list, and restore. + /// + /// + /// + /// + /// + /// OpenStack Block Storage Service API v2 Reference + /// Rackspace Cloud Block Storage Developer Guide - API v1.0 + /// + public class CloudBlockStorageProvider : ProviderBase, IBlockStorageProvider + { + /// + /// The HTTP response codes indicating a successful result from an API call. + /// + private readonly HttpStatusCode[] _validResponseCode = new[] { HttpStatusCode.OK, HttpStatusCode.Created, HttpStatusCode.Accepted }; + + /// + /// The to use for validating requests to + /// this service. The default value is . + /// + private readonly IBlockStorageValidator _cloudBlockStorageValidator; + + /// + /// Initializes a new instance of the class with + /// no default identity or region, and the default identity provider and REST + /// service implementation. + /// + public CloudBlockStorageProvider() + : this(null, null, null, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, no default region, and the default identity + /// provider and REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + public CloudBlockStorageProvider(CloudIdentity identity) + : this(identity, null, null, null) { } + + /// + /// Initializes a new instance of the class with + /// no default identity or region, the default identity provider, and the specified + /// REST service implementation. + /// + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudBlockStorageProvider(IRestService restService) + : this(null, null, null, restService) { } + + /// + /// Initializes a new instance of the class with + /// no default identity or region, the specified identity provider, and the default + /// REST service implementation. + /// + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created with no default identity. + public CloudBlockStorageProvider(IIdentityProvider identityProvider) + : this(null, null, identityProvider, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity and identity provider, no default region, and + /// the default REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudBlockStorageProvider(CloudIdentity identity, IIdentityProvider identityProvider) + : this(identity, null, identityProvider, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity and REST service implementation, no default region, + /// and the default identity provider. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudBlockStorageProvider(CloudIdentity identity, IRestService restService) + : this(identity, null, null, restService) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, no default region, and the specified identity + /// provider and REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudBlockStorageProvider(CloudIdentity identity, IIdentityProvider identityProvider, IRestService restService) + : this(identity, null, identityProvider, restService) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, default region, identity provider, and REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudBlockStorageProvider(CloudIdentity identity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService) + : this(identity, defaultRegion, identityProvider, restService, CloudBlockStorageValidator.Default) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, default region, identity provider, REST service + /// implementation, and block storage validator. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created with no default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The to use for validating requests to this service. + /// If is . + internal CloudBlockStorageProvider(CloudIdentity identity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService, IBlockStorageValidator cloudBlockStorageValidator) + : base(identity, defaultRegion, identityProvider, restService) + { + if (cloudBlockStorageValidator == null) + throw new ArgumentNullException("cloudBlockStorageValidator"); + + _cloudBlockStorageValidator = cloudBlockStorageValidator; + } + + #region Volumes + + /// + public Volume CreateVolume(int size, string displayDescription = null, string displayName = null, string snapshotId = null, string volumeType = null, string region = null, CloudIdentity identity = null) + { + if (size < 0) + throw new ArgumentOutOfRangeException("size"); + CheckIdentity(identity); + + _cloudBlockStorageValidator.ValidateVolumeSize(size); + + var urlPath = new Uri(string.Format("{0}/volumes", GetServiceEndpoint(identity, region))); + var requestBody = new CreateCloudBlockStorageVolumeRequest(new CreateCloudBlockStorageVolumeDetails(size, displayDescription, displayName, snapshotId, volumeType)); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, requestBody); + + if (response == null || response.Data == null) + return null; + + return response.Data.Volume; + } + + /// + public IEnumerable ListVolumes(string region = null, CloudIdentity identity = null) + { + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/volumes", GetServiceEndpoint(identity, region))); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Volumes; + } + + /// + public Volume ShowVolume(string volumeId, string region = null, CloudIdentity identity = null) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/volumes/{1}", GetServiceEndpoint(identity, region), volumeId)); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Volume; + } + + /// + public bool DeleteVolume(string volumeId, string region = null, CloudIdentity identity = null) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/volumes/{1}", GetServiceEndpoint(identity, region), volumeId)); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE); + + return response != null && _validResponseCode.Contains(response.StatusCode); + } + + /// + public IEnumerable ListVolumeTypes(string region = null, CloudIdentity identity = null) + { + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/types", GetServiceEndpoint(identity, region))); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.VolumeTypes; + } + + /// + public VolumeType DescribeVolumeType(string volumeTypeId, string region = null, CloudIdentity identity = null) + { + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/types/{1}", GetServiceEndpoint(identity, region), volumeTypeId)); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.VolumeType; + } + + /// + public Volume WaitForVolumeAvailable(string volumeId, int refreshCount = 600, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + return WaitForVolumeState(volumeId, VolumeState.Available, new[] { VolumeState.Error, VolumeState.ErrorDeleting }, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), region, identity); + } + + /// + public bool WaitForVolumeDeleted(string volumeId, int refreshCount = 360, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + return WaitForItemToBeDeleted(ShowVolume, volumeId, refreshCount, refreshDelay ?? TimeSpan.FromSeconds(10), region, identity); + } + + /// + public Volume WaitForVolumeState(string volumeId, VolumeState expectedState, VolumeState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (expectedState == null) + throw new ArgumentNullException("expectedState"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + var volumeInfo = ShowVolume(volumeId, region, identity); + + var count = 0; + while (!volumeInfo.Status.Equals(expectedState) && !errorStates.Contains(volumeInfo.Status) && count < refreshCount) + { + Thread.Sleep(refreshDelay ?? TimeSpan.FromMilliseconds(2400)); + volumeInfo = ShowVolume(volumeId, region, identity); + count++; + } + + if (errorStates.Contains(volumeInfo.Status)) + throw new VolumeEnteredErrorStateException(volumeInfo.Status); + + return volumeInfo; + } + + #endregion + + #region Snapshots + + /// + public Snapshot CreateSnapshot(string volumeId, bool force = false, string displayName = "None", string displayDescription = "None", string region = null, CloudIdentity identity = null) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/snapshots", GetServiceEndpoint(identity, region))); + var requestBody = new CreateCloudBlockStorageSnapshotRequest(new CreateCloudBlockStorageSnapshotDetails(volumeId, force, displayName, displayDescription)); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, requestBody); + if (response == null || response.Data == null) + return null; + + return response.Data.Snapshot; + } + + /// + public IEnumerable ListSnapshots(string region = null, CloudIdentity identity = null) + { + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/snapshots", GetServiceEndpoint(identity, region))); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Snapshots; + } + + /// + public Snapshot ShowSnapshot(string snapshotId, string region = null, CloudIdentity identity = null) + { + if (snapshotId == null) + throw new ArgumentNullException("snapshotId"); + if (string.IsNullOrEmpty(snapshotId)) + throw new ArgumentException("snapshotId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/snapshots/{1}", GetServiceEndpoint(identity, region), snapshotId)); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Snapshot; + } + + /// + public bool DeleteSnapshot(string snapshotId, string region = null, CloudIdentity identity = null) + { + if (snapshotId == null) + throw new ArgumentNullException("snapshotId"); + if (string.IsNullOrEmpty(snapshotId)) + throw new ArgumentException("snapshotId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/snapshots/{1}", GetServiceEndpoint(identity, region), snapshotId)); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE); + + return response != null && _validResponseCode.Contains(response.StatusCode); + } + + /// + public Snapshot WaitForSnapshotAvailable(string snapshotId, int refreshCount = 360, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null) + { + if (snapshotId == null) + throw new ArgumentNullException("snapshotId"); + if (string.IsNullOrEmpty(snapshotId)) + throw new ArgumentException("snapshotId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + return WaitForSnapshotState(snapshotId, SnapshotState.Available, new[] { SnapshotState.Error, SnapshotState.ErrorDeleting }, refreshCount, refreshDelay ?? TimeSpan.FromSeconds(10), region, identity); + } + + /// + public bool WaitForSnapshotDeleted(string snapshotId, int refreshCount = 180, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null) + { + if (snapshotId == null) + throw new ArgumentNullException("snapshotId"); + if (string.IsNullOrEmpty(snapshotId)) + throw new ArgumentException("snapshotId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + return WaitForItemToBeDeleted(ShowSnapshot, snapshotId, refreshCount, refreshDelay ?? TimeSpan.FromSeconds(10), region, identity); + } + + /// + public Snapshot WaitForSnapshotState(string snapshotId, SnapshotState expectedState, SnapshotState[] errorStates, int refreshCount = 60, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null) + { + if (snapshotId == null) + throw new ArgumentNullException("snapshotId"); + if (expectedState == null) + throw new ArgumentNullException("expectedState"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (string.IsNullOrEmpty(snapshotId)) + throw new ArgumentException("snapshotId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + var snapshotInfo = ShowSnapshot(snapshotId, region, identity); + + var count = 0; + while (!snapshotInfo.Status.Equals(expectedState) && !errorStates.Contains(snapshotInfo.Status) && count < refreshCount) + { + Thread.Sleep(refreshDelay ?? TimeSpan.FromSeconds(10)); + snapshotInfo = ShowSnapshot(snapshotId, region, identity); + count++; + } + + if (errorStates.Contains(snapshotInfo.Status)) + throw new SnapshotEnteredErrorStateException(snapshotInfo.Status); + + return snapshotInfo; + } + + #endregion + + #region Private methods + + /// + /// Gets the public service endpoint to use for Cloud Block Storage requests for the specified identity and region. + /// + /// + /// This method uses volume for the service type, and cloudBlockStorage for the preferred service name. + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The preferred region for the service. If this value is , the user's default region will be used. + /// The public URL for the requested Cloud Block Storage endpoint. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If is and no default region is available for the identity or provider. + /// If no service catalog is available for the user. + /// If no endpoint is available for the requested service. + /// If the REST API request failed. + protected string GetServiceEndpoint(CloudIdentity identity, string region) + { + return base.GetPublicServiceEndpoint(identity, "volume", "cloudBlockStorage", region); + } + + private bool WaitForItemToBeDeleted(Func retrieveItemMethod, string id, int refreshCount = 360, TimeSpan? refreshDelay = null, string region = null, CloudIdentity identity = null) + { + try + { + retrieveItemMethod(id, region, identity); + + var count = 0; + while (count < refreshCount) + { + Thread.Sleep(refreshDelay ?? TimeSpan.FromSeconds(10)); + retrieveItemMethod(id, region, identity); + count++; + } + } + catch (ItemNotFoundException) + { + return true; + } + + return false; + } + + #endregion + + + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudDatabasesProvider.cs b/src/OpenStack/Providers/Rackspace/CloudDatabasesProvider.cs new file mode 100644 index 000000000..77d6f2ab9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudDatabasesProvider.cs @@ -0,0 +1,1222 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using System.Threading.Tasks; + using net.openstack.Core; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using net.openstack.Core.Providers; + using net.openstack.Providers.Rackspace.Objects.Databases; + using Newtonsoft.Json.Linq; + using CancellationToken = System.Threading.CancellationToken; + using FlavorId = net.openstack.Providers.Rackspace.Objects.Databases.FlavorId; + using HttpMethod = JSIStudios.SimpleRESTServices.Client.HttpMethod; + using HttpResponseCodeValidator = net.openstack.Providers.Rackspace.Validators.HttpResponseCodeValidator; + using IHttpResponseCodeValidator = net.openstack.Core.Validators.IHttpResponseCodeValidator; + using IRestService = JSIStudios.SimpleRESTServices.Client.IRestService; + using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices; + + /// + /// Provides an implementation of for operating + /// with Rackspace's Cloud Databases product. + /// + /// Rackspace Cloud Databases Developer Guide - API v1.0 + /// + /// + public class CloudDatabasesProvider : ProviderBase, IDatabaseService + { + /// + /// This field caches the base URI used for accessing the Cloud Databases service. + /// + /// + private Uri _baseUri; + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudDatabasesProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider) + : base(defaultIdentity, defaultRegion, identityProvider, null, null) + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing synchronous REST requests. If this value is , the provider will use a new instance of . + /// The HTTP status code validator to use for synchronous REST requests. If this value is , the provider will use . + protected CloudDatabasesProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService, IHttpResponseCodeValidator httpStatusCodeValidator) + : base(defaultIdentity, defaultRegion, identityProvider, restService, httpStatusCodeValidator) + { + } + + #region IDatabaseService Members + + /// + public Task CreateDatabaseInstanceAsync(DatabaseInstanceConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/instances"); + var parameters = new Dictionary(); + + JObject requestBody = new JObject( + new JProperty("instance", JObject.FromObject(configuration))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DatabaseInstance> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken flavor = result["instance"]; + if (flavor == null) + return null; + + return flavor.ToObject(); + }; + + Func, Task> completionSelector = + task => + { + DatabaseInstance databaseInstance = task.Result; + if (databaseInstance != null && completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForDatabaseInstanceToLeaveStateAsync(databaseInstance.Id, DatabaseInstanceStatus.Build, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(databaseInstance); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector) + .Then(completionSelector); + } + + /// + public Task> ListDatabaseInstancesAsync(DatabaseInstanceId marker, int? limit, CancellationToken cancellationToken) + { + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/instances?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken instances = result["instances"]; + if (instances == null) + return null; + + DatabaseInstance[] currentPage = instances.ToObject(); + if (currentPage == null || currentPage.Length == 0) + return ReadOnlyCollectionPage.Empty; + + DatabaseInstanceId nextMarker = currentPage[currentPage.Length - 1].Id; + Func>> getNextPageAsync = + nextCancellationToken => ListDatabaseInstancesAsync(nextMarker, limit, nextCancellationToken); + return new BasicReadOnlyCollectionPage(currentPage, getNextPageAsync); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetDatabaseInstanceAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DatabaseInstance> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken flavor = result["instance"]; + if (flavor == null) + return null; + + return flavor.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task RemoveDatabaseInstanceAsync(DatabaseInstanceId instanceId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> completionSelector = + task => + { + string databaseInstance = task.Result; + if (databaseInstance != null && completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForDatabaseInstanceToLeaveStateAsync(instanceId, DatabaseInstanceStatus.Shutdown, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(DatabaseInstance)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(completionSelector); + } + + /// + public Task EnableRootUserAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/root"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, RootUser> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken user = result["user"]; + if (user == null) + return null; + + return user.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CheckRootEnabledStatusAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/root"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, bool?> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken rootEnabled = result["rootEnabled"]; + if (rootEnabled == null) + return null; + + return rootEnabled.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task RestartDatabaseInstanceAsync(DatabaseInstanceId instanceId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/action"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + JObject requestBody = + new JObject( + new JProperty("restart", new JObject())); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForDatabaseInstanceToLeaveStateAsync(instanceId, DatabaseInstanceStatus.Reboot, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(DatabaseInstance)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task ResizeDatabaseInstanceAsync(DatabaseInstanceId instanceId, FlavorRef flavorRef, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (flavorRef == null) + throw new ArgumentNullException("flavorRef"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/action"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + JObject requestBody = + new JObject( + new JProperty("resize", new JObject( + new JProperty("flavorRef", JValue.FromObject(flavorRef.Value))))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForDatabaseInstanceToLeaveStateAsync(instanceId, DatabaseInstanceStatus.Resize, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(DatabaseInstance)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task ResizeDatabaseInstanceVolumeAsync(DatabaseInstanceId instanceId, int volumeSize, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (volumeSize <= 0) + throw new ArgumentOutOfRangeException("volumeSize"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/action"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + JObject requestBody = + new JObject( + new JProperty("resize", new JObject( + new JProperty("volume", new JObject( + new JProperty("size", JValue.FromObject(volumeSize))))))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForDatabaseInstanceToLeaveStateAsync(instanceId, DatabaseInstanceStatus.Reboot, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(DatabaseInstance)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task CreateDatabaseAsync(DatabaseInstanceId instanceId, DatabaseConfiguration configuration, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/databases"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + JObject requestBody = + new JObject( + new JProperty("databases", new JArray( + JObject.FromObject(configuration)))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListDatabasesAsync(DatabaseInstanceId instanceId, DatabaseName marker, int? limit, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/databases?marker={marker}&limit={limit}"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken databases = result["databases"]; + if (databases == null) + return null; + + Database[] currentPage = databases.ToObject(); + if (currentPage == null || currentPage.Length == 0) + return ReadOnlyCollectionPage.Empty; + + DatabaseName nextMarker = currentPage[currentPage.Length - 1].Name; + Func>> getNextPageAsync = + nextCancellationToken => ListDatabasesAsync(instanceId, nextMarker, limit, nextCancellationToken); + return new BasicReadOnlyCollectionPage(currentPage, getNextPageAsync); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task RemoveDatabaseAsync(DatabaseInstanceId instanceId, DatabaseName databaseName, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (databaseName == null) + throw new ArgumentNullException("databaseName"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/databases/{databaseName}"); + var parameters = new Dictionary { { "instanceId", instanceId.Value }, { "databaseName", EscapeDatabaseName(databaseName) } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task CreateUserAsync(DatabaseInstanceId instanceId, UserConfiguration configuration, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + JObject requestBody = + new JObject( + new JProperty("users", new JArray( + JObject.FromObject(configuration)))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListDatabaseUsersAsync(DatabaseInstanceId instanceId, UserName marker, int? limit, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users?marker={marker}&limit={limit}"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken users = result["users"]; + if (users == null) + return null; + + DatabaseUser[] currentPage = users.ToObject(); + if (currentPage == null || currentPage.Length == 0) + return ReadOnlyCollectionPage.Empty; + + UserName nextMarker = currentPage[currentPage.Length - 1].UserName; + Func>> getNextPageAsync = + nextCancellationToken => ListDatabaseUsersAsync(instanceId, nextMarker, limit, nextCancellationToken); + return new BasicReadOnlyCollectionPage(currentPage, getNextPageAsync); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task SetUserPasswordAsync(DatabaseInstanceId instanceId, UserName userName, string password, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (userName == null) + throw new ArgumentNullException("userName"); + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + JObject requestBody = + new JObject( + new JProperty("users", new JArray( + new JObject( + new JProperty("name", JValue.CreateString(userName.Value)), + new JProperty("password", JValue.CreateString(password)))))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateUserAsync(DatabaseInstanceId instanceId, UserName userName, UpdateUserConfiguration configuration, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (userName == null) + throw new ArgumentNullException("userName"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users/{name}"); + var parameters = new Dictionary { { "instanceId", instanceId.Value }, { "name", EscapeUserName(userName) } }; + + JObject requestBody = + new JObject( + new JProperty("user", JObject.FromObject(configuration))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task GetUserAsync(DatabaseInstanceId instanceId, UserName userName, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (userName == null) + throw new ArgumentNullException("userName"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users/{name}"); + var parameters = new Dictionary { { "instanceId", instanceId.Value }, { "name", EscapeUserName(userName) } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DatabaseUser> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken user = result["user"]; + if (user == null) + return null; + + return user.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task RemoveUserAsync(DatabaseInstanceId instanceId, UserName userName, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (userName == null) + throw new ArgumentNullException("userName"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users/{name}"); + var parameters = new Dictionary { { "instanceId", instanceId.Value }, { "name", EscapeUserName(userName) } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListUserAccessAsync(DatabaseInstanceId instanceId, UserName userName, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (userName == null) + throw new ArgumentNullException("userName"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users/{name}/databases"); + var parameters = new Dictionary { { "instanceId", instanceId.Value }, { "name", EscapeUserName(userName) } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JArray databases = result["databases"] as JArray; + if (databases == null) + return null; + + List names = new List(); + foreach (JObject @obj in databases) + names.Add(@obj["name"].ToObject()); + + return names.AsReadOnly(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GrantUserAccessAsync(DatabaseInstanceId instanceId, DatabaseName databaseName, UserName userName, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (databaseName == null) + throw new ArgumentNullException("databaseName"); + if (userName == null) + throw new ArgumentNullException("userName"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users/{name}/databases"); + var parameters = new Dictionary { { "instanceId", instanceId.Value }, { "name", EscapeUserName(userName) } }; + + JObject requestBody = + new JObject( + new JProperty("databases", new JArray( + new JObject( + new JProperty("name", JToken.FromObject(databaseName)))))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task RevokeUserAccessAsync(DatabaseInstanceId instanceId, DatabaseName databaseName, UserName userName, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (databaseName == null) + throw new ArgumentNullException("databaseName"); + if (userName == null) + throw new ArgumentNullException("userName"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/users/{name}/databases/{databaseName}"); + var parameters = new Dictionary + { + { "instanceId", instanceId.Value }, + { "name", EscapeUserName(userName) }, + { "databaseName", EscapeDatabaseName(databaseName) }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListFlavorsAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/flavors"); + var parameters = new Dictionary(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken records = result["flavors"]; + if (records == null) + return null; + + return records.ToObject>(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetFlavorAsync(FlavorId flavorId, CancellationToken cancellationToken) + { + if (flavorId == null) + throw new ArgumentNullException("flavorId"); + + UriTemplate template = new UriTemplate("/flavors/{flavorId}"); + var parameters = new Dictionary { { "flavorId", flavorId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DatabaseFlavor> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken flavor = result["flavor"]; + if (flavor == null) + return null; + + return flavor.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CreateBackupAsync(BackupConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/backups"); + var parameters = new Dictionary(); + + JObject requestBody = + new JObject( + new JProperty("backup", JObject.FromObject(configuration))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Backup> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken backup = result["backup"]; + if (backup == null) + return null; + + return backup.ToObject(); + }; + + Func, Task> completionSelector = + task => + { + Func, Task> finalResultSelector = + subTask => GetBackupAsync(task.Result.Id, cancellationToken); + + if (completionOption == AsyncCompletionOption.RequestCompleted) + { + return WaitForDatabaseInstanceToLeaveStateAsync(configuration.InstanceId, DatabaseInstanceStatus.Backup, cancellationToken, progress) + .Then(finalResultSelector); + } + + return InternalTaskExtensions.CompletedTask(task.Result); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector) + .Then(completionSelector); + } + + /// + public Task> ListBackupsAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/backups"); + var parameters = new Dictionary(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken backups = result["backups"]; + if (backups == null) + return null; + + return backups.ToObject>(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetBackupAsync(BackupId backupId, CancellationToken cancellationToken) + { + if (backupId == null) + throw new ArgumentNullException("backupId"); + + UriTemplate template = new UriTemplate("/backups/{backupId}"); + var parameters = new Dictionary { { "backupId", backupId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Backup> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken backup = result["backup"]; + if (backup == null) + return null; + + return backup.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task RemoveBackupAsync(BackupId backupId, CancellationToken cancellationToken) + { + if (backupId == null) + throw new ArgumentNullException("backupId"); + + UriTemplate template = new UriTemplate("/backups/{backupId}"); + var parameters = new Dictionary { { "backupId", backupId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListBackupsForInstanceAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + + UriTemplate template = new UriTemplate("/instances/{instanceId}/backups"); + var parameters = new Dictionary { { "instanceId", instanceId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken backups = result["backups"]; + if (backups == null) + return null; + + return backups.ToObject>(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + #endregion + + /// + /// Creates a that will complete after a database instance leaves a particular state. + /// + /// + /// The task is considered complete as soon as a call to + /// indicates that the database instance is not in the state specified by . The method + /// does not perform any other checks related to the initial or final state of the database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A representing the state the database instance should not be in at the end of the wait operation. + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// object representing the database instance. In addition, + /// the property of the database instance will not + /// be equal to . + /// + /// + /// If is . + /// -or- + /// If is . + /// + protected Task WaitForDatabaseInstanceToLeaveStateAsync(DatabaseInstanceId instanceId, DatabaseInstanceStatus state, CancellationToken cancellationToken, IProgress progress) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (state == null) + throw new ArgumentNullException("state"); + + TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); + Func> pollDatabaseInstance = () => PollDatabaseInstanceStateAsync(instanceId, cancellationToken, progress); + + IEnumerator backoffPolicy = BackoffPolicy.GetBackoffIntervals().GetEnumerator(); + Func> moveNext = + () => + { + if (!backoffPolicy.MoveNext()) + throw new OperationCanceledException(); + + if (backoffPolicy.Current == TimeSpan.Zero) + { + return pollDatabaseInstance(); + } + else + { + return Task.Factory.StartNewDelayed((int)backoffPolicy.Current.TotalMilliseconds, cancellationToken) + .Then(task => pollDatabaseInstance()); + } + }; + + Task currentTask = moveNext(); + Action> continuation = null; + continuation = + previousTask => + { + if (previousTask.Status != TaskStatus.RanToCompletion) + { + taskCompletionSource.SetFromTask(previousTask); + return; + } + + DatabaseInstance result = previousTask.Result; + if (result == null || result.Status != state) + { + // finished waiting + taskCompletionSource.SetResult(result); + return; + } + + // reschedule + currentTask = moveNext(); + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + }; + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + + return taskCompletionSource.Task; + } + + /// + /// Converts a database name to the form required by the Cloud Databases service + /// by twice percent-encoding the . characters. + /// + /// The database name to encode. + /// A string representation of the database name suitable for inclusion in the URI for a Cloud Databases API call. + /// If is . + protected static string EscapeDatabaseName(DatabaseName databaseName) + { + return databaseName.Value.Replace(".", "%252e"); + } + + /// + /// Converts a username to the form required by the Cloud Databases service + /// by twice percent-encoding the . characters. + /// + /// The username to encode. + /// A string representation of the username suitable for inclusion in the URI for a Cloud Databases API call. + /// If is . + protected static string EscapeUserName(UserName username) + { + return username.Value.Replace(".", "%252e"); + } + + /// + /// Asynchronously poll the current state of a database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object containing the + /// updated state information for the database instance. + /// + /// If is . + /// If the REST request does not return successfully. + private Task PollDatabaseInstanceStateAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken, IProgress progress) + { + Task chain = GetDatabaseInstanceAsync(instanceId, cancellationToken); + chain = chain.Select( + task => + { + if (task.IsFaulted) + { + AggregateException flattened = task.Exception.Flatten(); + if (flattened.InnerExceptions.Count == 1) + { + WebException webException = flattened.InnerExceptions[0] as WebException; + HttpWebResponse httpWebResponse = webException != null ? webException.Response as HttpWebResponse : null; + if (httpWebResponse != null && httpWebResponse.StatusCode == HttpStatusCode.NotFound) + return null; + } + } + + if (task.Result == null || task.Result.Id != instanceId) + throw new InvalidOperationException("Could not obtain status for database instance"); + + return task.Result; + }, true); + + if (progress != null) + { + chain = chain.Select( + task => + { + progress.Report(task.Result); + return task.Result; + }); + } + + return chain; + } + + /// + /// + /// This method returns a cached base address if one is available. If no cached address is + /// available, is called to obtain + /// an with the type rax:database and preferred type cloudDatabases. + /// + protected override Task GetBaseUriAsync(CancellationToken cancellationToken) + { + if (_baseUri != null) + { + return InternalTaskExtensions.CompletedTask(_baseUri); + } + + return Task.Factory.StartNew( + () => + { + Endpoint endpoint = GetServiceEndpoint(null, "rax:database", "cloudDatabases", null); + _baseUri = new Uri(endpoint.PublicURL); + return _baseUri; + }); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudDnsProvider.cs b/src/OpenStack/Providers/Rackspace/CloudDnsProvider.cs new file mode 100644 index 000000000..47813fb98 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudDnsProvider.cs @@ -0,0 +1,1369 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Net; + using System.Threading.Tasks; + using JSIStudios.SimpleRESTServices.Client; + using net.openstack.Core; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using net.openstack.Core.Providers; + using net.openstack.Providers.Rackspace.Objects.Dns; + using Newtonsoft.Json.Linq; + using CancellationToken = System.Threading.CancellationToken; + using HttpResponseCodeValidator = net.openstack.Providers.Rackspace.Validators.HttpResponseCodeValidator; + using IHttpResponseCodeValidator = net.openstack.Core.Validators.IHttpResponseCodeValidator; + using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices; + + /// + /// Provides an implementation of for operating + /// with Rackspace's Cloud DNS product. + /// + /// Rackspace Cloud DNS Developer Guide - API v1.0 + /// + /// + public class CloudDnsProvider : ProviderBase, IDnsService + { + /// + /// Specifies whether the or + /// should be used for accessing the Cloud DNS API. + /// + private readonly bool _internalUrl; + + /// + /// This field caches the base URI used for accessing the Cloud DNS service. + /// + /// + private Uri _baseUri; + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudDnsProvider(CloudIdentity defaultIdentity, string defaultRegion, bool internalUrl, IIdentityProvider identityProvider) + : this(defaultIdentity, defaultRegion, internalUrl, identityProvider, null, null) + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing synchronous REST requests. If this value is , the provider will use a new instance of . + /// The HTTP status code validator to use for synchronous REST requests. If this value is , the provider will use . + protected CloudDnsProvider(CloudIdentity defaultIdentity, string defaultRegion, bool internalUrl, IIdentityProvider identityProvider, IRestService restService, IHttpResponseCodeValidator httpStatusCodeValidator) + : base(defaultIdentity, defaultRegion, identityProvider, restService, httpStatusCodeValidator) + { + _internalUrl = internalUrl; + } + + #region IDnsService Members + + /// + public Task ListLimitsAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/limits"); + var parameters = new Dictionary(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsServiceLimits> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken limits = result["limits"]; + if (limits == null) + return null; + + return limits.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListLimitTypesAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/limits/types"); + var parameters = new Dictionary(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken limitTypes = result["limitTypes"]; + if (limitTypes == null) + return null; + + return limitTypes.ToObject>(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task ListLimitsAsync(LimitType type, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/limits/{type}"); + var parameters = new Dictionary + { + { "type", type.Name.ToLowerInvariant() } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsServiceLimits> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken limits = result["limits"]; + if (limits == null) + return null; + + return limits.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetJobStatusAsync(DnsJob job, bool showDetails, CancellationToken cancellationToken) + { + if (job == null) + throw new ArgumentNullException("job"); + + UriTemplate template = new UriTemplate("/status/{jobId}?showDetails={showDetails}"); + var parameters = new Dictionary + { + { "jobId", job.Id.Value }, + { "showDetails", showDetails ? "true" : "false" }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsJob> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + return result.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> GetJobStatusAsync(DnsJob job, bool showDetails, CancellationToken cancellationToken) + { + if (job == null) + throw new ArgumentNullException("job"); + + UriTemplate template = new UriTemplate("/status/{jobId}?showDetails={showDetails}"); + var parameters = new Dictionary + { + { "jobId", job.Id.Value }, + { "showDetails", showDetails ? "true" : "false" }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsJob> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + return result.ToObject>(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task, int?>> ListDomainsAsync(string domainName, int? offset, int? limit, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/domains/?name={name}&offset={offset}&limit={limit}"); + var parameters = new Dictionary(); + if (domainName != null) + parameters.Add("name", domainName); + if (offset != null) + parameters.Add("offset", offset.ToString()); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Tuple, int?>> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken domains = result["domains"]; + if (domains == null) + return null; + + int? totalEntries = null; + JToken totalEntriesToken = result["totalEntries"]; + if (totalEntriesToken != null) + totalEntries = totalEntriesToken.ToObject(); + + DnsDomain[] currentPage = domains.ToObject(); + if (currentPage == null || currentPage.Length == 0) + return Tuple.Create(ReadOnlyCollectionPage.Empty, totalEntries); + else if (!HasNextLink(result)) + return Tuple.Create((ReadOnlyCollectionPage)new BasicReadOnlyCollectionPage(currentPage, null), totalEntries); + + int nextOffset = (offset ?? 0) + currentPage.Length; + Func>> getNextPageAsync = + nextCancellationToken => + { + return ListDomainsAsync(domainName, nextOffset, limit, nextCancellationToken) + .Select(i => i.Result.Item1); + }; + ReadOnlyCollectionPage page = new BasicReadOnlyCollectionPage(currentPage, getNextPageAsync); + return Tuple.Create(page, totalEntries); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task ListDomainDetailsAsync(DomainId domainId, bool showRecords, bool showSubdomains, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/domains/{domainId}?showRecords={showRecords}&showSubdomains={showSubdomains}"); + var parameters = new Dictionary() + { + { "domainId", domainId.Value }, + { "showRecords", showRecords ? "true" : "false" }, + { "showSubdomains", showSubdomains ? "true" : "false" }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsDomain> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + return result.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task ListDomainChangesAsync(DomainId domainId, DateTimeOffset? since, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/changes?since={since}"); + var parameters = new Dictionary() + { + { "domainId", domainId.Value }, + }; + if (since.HasValue) + parameters.Add("since", since.Value.ToString("G")); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsDomainChanges> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + return result.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ExportDomainAsync(DomainId domainId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/export"); + var parameters = new Dictionary() + { + { "domainId", domainId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsJob> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject>(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + job = WaitForJobAsync(job, true, cancellationToken, progress).Result; + + return job; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> CreateDomainsAsync(DnsConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/domains"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsJob> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject>(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + job = WaitForJobAsync(job, true, cancellationToken, progress).Result; + + return job; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task UpdateDomainsAsync(DnsUpdateConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/domains"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForJobAsync(job, true, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(job); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task> CloneDomainAsync(DomainId domainId, string cloneName, bool? cloneSubdomains, bool? modifyRecordData, bool? modifyEmailAddress, bool? modifyComment, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/clone?cloneName={cloneName}&cloneSubdomains={cloneSubdomains}&modifyRecordData={modifyRecordData}&modifyEmailAddress={modifyEmailAddress}&modifyComment={modifyComment}"); + var parameters = new Dictionary { { "domainId", domainId.Value }, { "cloneName", cloneName } }; + if (cloneSubdomains != null) + parameters.Add("cloneSubdomains", cloneSubdomains.Value ? "true" : "false"); + if (modifyRecordData != null) + parameters.Add("modifyRecordData", modifyRecordData.Value ? "true" : "false"); + if (modifyEmailAddress != null) + parameters.Add("modifyEmailAddress", modifyEmailAddress.Value ? "true" : "false"); + if (modifyComment != null) + parameters.Add("modifyComment", modifyComment.Value ? "true" : "false"); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsJob> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject>(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + job = WaitForJobAsync(job, true, cancellationToken, progress).Result; + + return job; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ImportDomainAsync(IEnumerable serializedDomains, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress) + { + if (serializedDomains == null) + throw new ArgumentNullException("serializedDomains"); + + UriTemplate template = new UriTemplate("/domains/import"); + var parameters = new Dictionary(); + + JObject request = new JObject(new JProperty("domains", JArray.FromObject(serializedDomains))); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, request); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsJob> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject>(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + job = WaitForJobAsync(job, true, cancellationToken, progress).Result; + + return job; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task RemoveDomainsAsync(IEnumerable domainIds, bool deleteSubdomains, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + UriTemplate template = new UriTemplate("/domains?deleteSubdomains={deleteSubdomains}"); + var parameters = new Dictionary() + { + { "deleteSubdomains", deleteSubdomains ? "true" : "false" }, + }; + + Func transform = + uri => + { + UriBuilder builder = new UriBuilder(uri); + builder.Query = builder.Query.TrimStart('?') + string.Concat(domainIds.Select(domainId => "&id=" + domainId.Value)); + return builder.Uri; + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, transform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForJobAsync(job, true, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(job); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task, int?>> ListSubdomainsAsync(DomainId domainId, int? offset, int? limit, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/subdomains?offset={offset}&limit={limit}"); + var parameters = new Dictionary + { + { "domainId", domainId.Value } + }; + if (offset != null) + parameters.Add("offset", offset.ToString()); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Tuple, int?>> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken domains = result["domains"]; + if (domains == null) + return null; + + int? totalEntries = null; + JToken totalEntriesToken = result["totalEntries"]; + if (totalEntriesToken != null) + totalEntries = totalEntriesToken.ToObject(); + + DnsSubdomain[] currentPage = domains.ToObject(); + if (currentPage == null || currentPage.Length == 0) + return Tuple.Create(ReadOnlyCollectionPage.Empty, totalEntries); + else if (!HasNextLink(result)) + return Tuple.Create((ReadOnlyCollectionPage)new BasicReadOnlyCollectionPage(currentPage, null), totalEntries); + + int nextOffset = (offset ?? 0) + currentPage.Length; + Func>> getNextPageAsync = + nextCancellationToken => + { + return ListSubdomainsAsync(domainId, nextOffset, limit, nextCancellationToken) + .Select(i => i.Result.Item1); + }; + ReadOnlyCollectionPage page = new BasicReadOnlyCollectionPage(currentPage, getNextPageAsync); + return Tuple.Create(page, totalEntries); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task, int?>> ListRecordsAsync(DomainId domainId, DnsRecordType recordType, string recordName, string recordData, int? offset, int? limit, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/records?type={recordType}&name={recordName}&data={recordData}&offset={offset}&limit={limit}"); + var parameters = new Dictionary + { + { "domainId", domainId.Value } + }; + if (recordType != null) + parameters.Add("recordType", recordType.Name); + if (recordName != null) + parameters.Add("recordName", recordName); + if (recordData != null) + parameters.Add("recordData", recordData); + if (offset != null) + parameters.Add("offset", offset.ToString()); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Tuple, int?>> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken records = result["records"]; + if (records == null) + return null; + + int? totalEntries = null; + JToken totalEntriesToken = result["totalEntries"]; + if (totalEntriesToken != null) + totalEntries = totalEntriesToken.ToObject(); + + DnsRecord[] currentPage = records.ToObject(); + if (currentPage == null || currentPage.Length == 0) + return Tuple.Create(ReadOnlyCollectionPage.Empty, totalEntries); + else if (!HasNextLink(result)) + return Tuple.Create((ReadOnlyCollectionPage)new BasicReadOnlyCollectionPage(currentPage, null), totalEntries); + + int nextOffset = (offset ?? 0) + currentPage.Length; + Func>> getNextPageAsync = + nextCancellationToken => + { + return ListRecordsAsync(domainId, recordType, recordName, recordData, nextOffset, limit, nextCancellationToken) + .Select(i => i.Result.Item1); + }; + ReadOnlyCollectionPage page = new BasicReadOnlyCollectionPage(currentPage, getNextPageAsync); + return Tuple.Create(page, totalEntries); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task ListRecordDetailsAsync(DomainId domainId, RecordId recordId, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/records/{recordId}"); + var parameters = new Dictionary + { + { "domainId", domainId.Value }, + { "recordId", recordId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsRecord> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + return result.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> AddRecordsAsync(DomainId domainId, IEnumerable recordConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/records"); + var parameters = new Dictionary() + { + { "domainId", domainId.Value } + }; + + JObject request = new JObject(new JProperty("records", JArray.FromObject(recordConfigurations))); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, request); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsJob> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject>(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + job = WaitForJobAsync(job, true, cancellationToken, progress).Result; + + return job; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task UpdateRecordsAsync(DomainId domainId, IEnumerable recordConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/records"); + var parameters = new Dictionary() + { + { "domainId", domainId.Value } + }; + + JObject request = new JObject(new JProperty("records", JArray.FromObject(recordConfigurations))); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, request); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForJobAsync(job, true, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(job); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveRecordsAsync(DomainId domainId, IEnumerable recordIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + UriTemplate template = new UriTemplate("/domains/{domainId}/records"); + var parameters = new Dictionary() + { + { "domainId", domainId.Value }, + }; + + Func transform = + uri => + { + UriBuilder builder = new UriBuilder(uri); + builder.Query = builder.Query.TrimStart('?') + string.Concat(recordIds.Select(recordId => "&id=" + recordId.Value)); + return builder.Uri; + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, transform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForJobAsync(job, true, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(job); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task, int?>> ListPtrRecordsAsync(string serviceName, Uri deviceResourceUri, int? offset, int? limit, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/rdns/{serviceName}?href={deviceResourceUri}&offset={offset}&limit={limit}"); + var parameters = new Dictionary + { + { "serviceName", serviceName }, + { "deviceResourceUri", deviceResourceUri.AbsoluteUri }, + }; + if (offset != null) + parameters.Add("offset", offset.ToString()); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Tuple, int?>> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken records = result["records"]; + if (records == null) + return null; + + int? totalEntries = null; + JToken totalEntriesToken = result["totalEntries"]; + if (totalEntriesToken != null) + totalEntries = totalEntriesToken.ToObject(); + + DnsRecord[] currentPage = records.ToObject(); + if (currentPage == null || currentPage.Length == 0) + return Tuple.Create(ReadOnlyCollectionPage.Empty, totalEntries); + else if (!HasNextLink(result)) + return Tuple.Create((ReadOnlyCollectionPage)new BasicReadOnlyCollectionPage(currentPage, null), totalEntries); + + int nextOffset = (offset ?? 0) + currentPage.Length; + Func>> getNextPageAsync = + nextCancellationToken => + { + return ListPtrRecordsAsync(serviceName, deviceResourceUri, nextOffset, limit, nextCancellationToken) + .Select(i => i.Result.Item1); + }; + ReadOnlyCollectionPage page = new BasicReadOnlyCollectionPage(currentPage, getNextPageAsync); + return Tuple.Create(page, totalEntries); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task ListPtrRecordDetailsAsync(string serviceName, Uri deviceResourceUri, RecordId recordId, CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/rdns/{serviceName}/{recordId}?href={deviceResourceUri}"); + var parameters = new Dictionary + { + { "serviceName", serviceName }, + { "deviceResourceUri", deviceResourceUri.AbsoluteUri }, + { "recordId", recordId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsRecord> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + return result.ToObject(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> AddPtrRecordsAsync(string serviceName, Uri deviceResourceUri, IEnumerable recordConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress) + { + if (serviceName == null) + throw new ArgumentNullException("serviceName"); + if (deviceResourceUri == null) + throw new ArgumentNullException("deviceResourceUri"); + if (string.IsNullOrEmpty(serviceName)) + throw new ArgumentException("serviceName cannot be empty"); + + UriTemplate template = new UriTemplate("/rdns"); + var parameters = new Dictionary(); + + JObject request = new JObject( + new JProperty("link", new JObject( + new JProperty("href", new JValue(deviceResourceUri.AbsoluteUri)), + new JProperty("rel", new JValue(serviceName)), + new JProperty("content", new JValue(string.Empty)))), + new JProperty("recordsList", new JObject( + new JProperty("records", JArray.FromObject(recordConfigurations))))); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, request); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, DnsJob> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject>(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + job = WaitForJobAsync(job, true, cancellationToken, progress).Result; + + return job; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task UpdatePtrRecordsAsync(string serviceName, Uri deviceResourceUri, IEnumerable recordConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (serviceName == null) + throw new ArgumentNullException("serviceName"); + if (deviceResourceUri == null) + throw new ArgumentNullException("deviceResourceUri"); + if (string.IsNullOrEmpty(serviceName)) + throw new ArgumentException("serviceName cannot be empty"); + + UriTemplate template = new UriTemplate("/rdns"); + var parameters = new Dictionary(); + + JObject request = new JObject( + new JProperty("link", new JObject( + new JProperty("href", new JValue(deviceResourceUri.AbsoluteUri)), + new JProperty("rel", new JValue(serviceName)), + new JProperty("content", new JValue(string.Empty)))), + new JProperty("recordsList", new JObject( + new JProperty("records", JArray.FromObject(recordConfigurations))))); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, request); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForJobAsync(job, true, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(job); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemovePtrRecordsAsync(string serviceName, Uri deviceResourceUri, IPAddress ipAddress, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + UriTemplate template = new UriTemplate("/rdns/{serviceName}?href={deviceResourceUri}&ip={ipAddress}"); + var parameters = new Dictionary() + { + { "serviceName", serviceName }, + { "deviceResourceUri", deviceResourceUri.AbsoluteUri }, + }; + if (ipAddress != null) + parameters.Add("ipAddress", ipAddress.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + DnsJob job = task.Result.ToObject(); + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForJobAsync(job, true, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(job); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + #endregion + + /// + /// Waits for an asynchronous server job to complete. + /// + /// The to wait for. + /// to include detailed information about the job; otherwise, . + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. The job will additionally be in one of the following + /// states. + /// + /// + /// + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// If is . + /// If the REST request does not return successfully. + /// Synchronous and Asynchronous Responses (Rackspace Cloud DNS Developer Guide - API v1.0) + protected Task WaitForJobAsync(DnsJob job, bool showDetails, CancellationToken cancellationToken, IProgress progress) + { + if (job == null) + throw new ArgumentNullException("job"); + + TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); + Func> pollJob = () => PollJobStateAsync(job, showDetails, cancellationToken, progress); + + IEnumerator backoffPolicy = BackoffPolicy.GetBackoffIntervals().GetEnumerator(); + Func> moveNext = + () => + { + if (!backoffPolicy.MoveNext()) + throw new OperationCanceledException(); + + if (backoffPolicy.Current == TimeSpan.Zero) + { + return pollJob(); + } + else + { + return Task.Factory.StartNewDelayed((int)backoffPolicy.Current.TotalMilliseconds, cancellationToken) + .Then(task => pollJob()); + } + }; + + Task currentTask = moveNext(); + Action> continuation = null; + continuation = + previousTask => + { + if (previousTask.Status != TaskStatus.RanToCompletion) + { + taskCompletionSource.SetFromTask(previousTask); + return; + } + + DnsJob result = previousTask.Result; + if (result == null || result.Status == DnsJobStatus.Completed || result.Status == DnsJobStatus.Error) + { + // finished waiting + taskCompletionSource.SetResult(result); + return; + } + + // reschedule + currentTask = moveNext(); + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + }; + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + + return taskCompletionSource.Task; + } + + /// + /// Waits for an asynchronous server job with a strongly-typed result to complete. + /// + /// The class modeling the JSON result of the asynchronous operation. + /// The to wait for. + /// to include detailed information about the job; otherwise, . + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. The job will additionally be in one of the following + /// states. + /// + /// + /// : In this case the + /// property provides the strongly-typed object which is the result of the + /// operation. + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// If is . + /// If the REST request does not return successfully. + /// Synchronous and Asynchronous Responses (Rackspace Cloud DNS Developer Guide - API v1.0) + protected Task> WaitForJobAsync(DnsJob job, bool showDetails, CancellationToken cancellationToken, IProgress> progress) + { + if (job == null) + throw new ArgumentNullException("job"); + + TaskCompletionSource> taskCompletionSource = new TaskCompletionSource>(); + Func>> pollJob = () => PollJobStateAsync(job, showDetails, cancellationToken, progress); + + IEnumerator backoffPolicy = BackoffPolicy.GetBackoffIntervals().GetEnumerator(); + Func>> moveNext = + () => + { + if (!backoffPolicy.MoveNext()) + throw new OperationCanceledException(); + + if (backoffPolicy.Current == TimeSpan.Zero) + { + return pollJob(); + } + else + { + return Task.Factory.StartNewDelayed((int)backoffPolicy.Current.TotalMilliseconds, cancellationToken) + .Then(task => pollJob()); + } + }; + + Task> currentTask = moveNext(); + Action>> continuation = null; + continuation = + previousTask => + { + if (previousTask.Status != TaskStatus.RanToCompletion) + { + taskCompletionSource.SetFromTask(previousTask); + return; + } + + DnsJob result = previousTask.Result; + if (result == null || result.Status == DnsJobStatus.Completed || result.Status == DnsJobStatus.Error) + { + // finished waiting + taskCompletionSource.SetResult(result); + return; + } + + // reschedule + currentTask = moveNext(); + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + }; + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + + return taskCompletionSource.Task; + } + + /// + /// Determines if the JSON representation of a single page of a paginated collection includes a "next" link. + /// + /// The JSON object representing a page of a paginated collection. + /// if the paginated collection result includes a "next" link; otherwise, . + /// If is . + protected virtual bool HasNextLink(JObject result) + { + if (result == null) + throw new ArgumentNullException("result"); + + JToken linksToken = result["links"]; + if (linksToken == null) + return false; + + Link[] links = linksToken.ToObject(); + return links.Any(i => string.Equals(i.Rel, "next", StringComparison.OrdinalIgnoreCase)); + } + + /// + /// + /// This method returns a cached base address if one is available. If no cached address is + /// available, is called to obtain + /// an with the type rax:dns and preferred type cloudDNS. + /// + protected override Task GetBaseUriAsync(CancellationToken cancellationToken) + { + if (_baseUri != null) + { + return InternalTaskExtensions.CompletedTask(_baseUri); + } + + return Task.Factory.StartNew( + () => + { + Endpoint endpoint = GetServiceEndpoint(null, "rax:dns", "cloudDNS", null); + Uri baseUri = new Uri(_internalUrl ? endpoint.InternalURL : endpoint.PublicURL); + _baseUri = baseUri; + return baseUri; + }); + } + + /// + /// Asynchronously poll the current state of a DNS job. + /// + /// The job in the DNS service. + /// to include detailed information about the job; otherwise, . + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object containing the + /// updated state information for the job in the DNS service. + /// + /// If is . + /// If the REST request does not return successfully. + private Task PollJobStateAsync(DnsJob job, bool showDetails, CancellationToken cancellationToken, IProgress progress) + { + if (job == null) + throw new ArgumentNullException("job"); + + Task chain = GetJobStatusAsync(job, showDetails, cancellationToken); + chain = chain.Select( + task => + { + if (task.Result == null || task.Result.Id != job.Id) + throw new InvalidOperationException("Could not obtain status for job"); + + return task.Result; + }); + + if (progress != null) + { + chain = chain.Select( + task => + { + progress.Report(task.Result); + return task.Result; + }); + } + + return chain; + } + + /// + /// Asynchronously poll the current state of a DNS job. + /// + /// The job in the DNS service. + /// to include detailed information about the job; otherwise, . + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object containing the + /// updated state information for the job in the DNS service. + /// + /// If is . + /// If the REST request does not return successfully. + private Task> PollJobStateAsync(DnsJob job, bool showDetails, CancellationToken cancellationToken, IProgress> progress) + { + if (job == null) + throw new ArgumentNullException("job"); + + Task> chain = GetJobStatusAsync(job, showDetails, cancellationToken); + chain = chain.Select( + task => + { + if (task.Result == null || task.Result.Id != job.Id) + throw new InvalidOperationException("Could not obtain status for job"); + + return task.Result; + }); + + if (progress != null) + { + chain = chain.Select( + task => + { + progress.Report(task.Result); + return task.Result; + }); + } + + return chain; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudFilesMetadataProcessor.cs b/src/OpenStack/Providers/Rackspace/CloudFilesMetadataProcessor.cs new file mode 100644 index 000000000..2484244c4 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudFilesMetadataProcessor.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Text; +using JSIStudios.SimpleRESTServices.Client; +using net.openstack.Core; + +namespace net.openstack.Providers.Rackspace +{ + internal class CloudFilesMetadataProcessor : IObjectStorageMetadataProcessor + { + /// + /// A default instance of . + /// + private static readonly CloudFilesMetadataProcessor _default = new CloudFilesMetadataProcessor(); + + /// + /// Gets a default instance of . + /// + public static CloudFilesMetadataProcessor Default + { + get + { + return _default; + } + } + + /// + /// Extracts metadata information from a collection of HTTP headers. + /// + /// + /// The returned collection has two keys: + /// and . + /// + /// The value for + /// contains the processed Cloud Files + /// metadata included in HTTP headers such as X-Account-Meta-*, + /// X-Container-Meta-*, and X-Object-Meta-*. The metadata prefix + /// has been removed from the keys stored in this value. + /// + /// The value for contains the + /// HTTP headers which were not in the form of a known Cloud Files metadata prefix. + /// + /// + public virtual Dictionary> ProcessMetadata(IList httpHeaders) + { + if (httpHeaders == null) + throw new ArgumentNullException("httpHeaders"); + + var pheaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + var metadata = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var header in httpHeaders) + { + if (header == null) + throw new ArgumentException("httpHeaders cannot contain any null values"); + if (string.IsNullOrEmpty(header.Key)) + throw new ArgumentException("httpHeaders cannot contain any values with a null or empty key"); + + if (header.Key.StartsWith(CloudFilesProvider.AccountMetaDataPrefix, StringComparison.OrdinalIgnoreCase)) + { + metadata.Add(header.Key.Substring(CloudFilesProvider.AccountMetaDataPrefix.Length), DecodeUnicodeValue(header.Value)); + } + else if (header.Key.StartsWith(CloudFilesProvider.ContainerMetaDataPrefix, StringComparison.OrdinalIgnoreCase)) + { + metadata.Add(header.Key.Substring(CloudFilesProvider.ContainerMetaDataPrefix.Length), DecodeUnicodeValue(header.Value)); + } + else if (header.Key.StartsWith(CloudFilesProvider.ObjectMetaDataPrefix, StringComparison.OrdinalIgnoreCase)) + { + metadata.Add(header.Key.Substring(CloudFilesProvider.ObjectMetaDataPrefix.Length), DecodeUnicodeValue(header.Value)); + } + else + { + pheaders.Add(header.Key, header.Value); + } + } + + var processedHeaders = new Dictionary>(StringComparer.OrdinalIgnoreCase) + { + {CloudFilesProvider.ProcessedHeadersHeaderKey, pheaders}, + {CloudFilesProvider.ProcessedHeadersMetadataKey, metadata} + }; + + return processedHeaders; + } + + private string DecodeUnicodeValue(string value) + { + return Encoding.UTF8.GetString(Encoding.GetEncoding("ISO-8859-1").GetBytes(value)); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudFilesProvider.cs b/src/OpenStack/Providers/Rackspace/CloudFilesProvider.cs new file mode 100644 index 000000000..cc7b51014 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudFilesProvider.cs @@ -0,0 +1,2597 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using JSIStudios.SimpleRESTServices.Client; +using JSIStudios.SimpleRESTServices.Client.Json; +using net.openstack.Core; +using net.openstack.Core.Collections; +using net.openstack.Core.Domain; +using net.openstack.Core.Domain.Mapping; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Providers; +using net.openstack.Core.Validators; +using net.openstack.Providers.Rackspace.Exceptions; +using net.openstack.Providers.Rackspace.Objects; +using net.openstack.Providers.Rackspace.Objects.Mapping; +using net.openstack.Providers.Rackspace.Objects.Monitoring; +using net.openstack.Providers.Rackspace.Objects.Response; +using net.openstack.Providers.Rackspace.Validators; +using Newtonsoft.Json; + +namespace net.openstack.Providers.Rackspace +{ + /// + /// Provides an implementation of + /// for operating with Rackspace's Cloud Files product. + /// + /// OpenStack Object Storage API v1 Reference + /// Rackspace Cloud Files Developer Guide - API v1 + /// + public class CloudFilesProvider : ProviderBase, IObjectStorageProvider + { + /// + /// The to use for this provider. This is + /// typically set to . + /// + private readonly IObjectStorageValidator _cloudFilesValidator; + + /// + /// The to use for this provider. This is + /// typically set to . + /// + private readonly IObjectStorageMetadataProcessor _cloudFilesMetadataProcessor; + + /// + /// The to use for this provider. This is + /// typically set to . + /// + private readonly IEncodeDecodeProvider _encodeDecodeProvider; + + /// + /// The to use for this provider. This is + /// typically set to . + /// + private readonly IStatusParser _statusParser; + + /// + /// The to use for + /// this provider. This is typically set to a new instance of . + /// + private readonly IObjectMapper _bulkDeletionResultMapper; + + #region Constructors + + /// + /// Initializes a new instance of the class with + /// no default identity or region, and the default identity provider and REST service + /// implementation. + /// + public CloudFilesProvider() + : this(null, null, null, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, no default region, and the default identity provider + /// and REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + public CloudFilesProvider(CloudIdentity defaultIdentity) + : this(defaultIdentity, null, null, null) { } + + /// + /// Initializes a new instance of the class with + /// no default identity or region, the default identity provider, and the specified + /// REST service implementation. + /// + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudFilesProvider(IRestService restService) + : this(null, null, null, restService) { } + + /// + /// Initializes a new instance of the class with + /// no default identity or region, the specified identity provider, and the default + /// REST service implementation. + /// + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created with no default identity. + public CloudFilesProvider(IIdentityProvider identityProvider) + : this(null, null, identityProvider, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity and identity provider, no default region, and + /// the default REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudFilesProvider(CloudIdentity defaultIdentity, IIdentityProvider identityProvider) + : this(defaultIdentity, null, identityProvider, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity and REST service implementation, no default region, + /// and the default identity provider. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudFilesProvider(CloudIdentity defaultIdentity, IRestService restService) + : this(defaultIdentity, null, null, restService) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, no default region, the specified identity + /// provider and REST service implementation, and the default + /// Rackspace-Cloud-Files-specific implementations of the object storage validator, + /// metadata processor, encoder, status parser, and bulk delete results mapper. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudFilesProvider(CloudIdentity defaultIdentity, IIdentityProvider identityProvider, IRestService restService) + : this(defaultIdentity, null, identityProvider, restService) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, default region, identity provider, and REST service + /// implementation, and the default Rackspace-Cloud-Files-specific implementations of + /// the object storage validator, metadata processor, encoder, status parser, and bulk + /// delete results mapper. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudFilesProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService) + : this(defaultIdentity, defaultRegion, identityProvider, restService, CloudFilesValidator.Default, CloudFilesMetadataProcessor.Default, EncodeDecodeProvider.Default, HttpStatusCodeParser.Default, new BulkDeletionResultMapper(HttpStatusCodeParser.Default)) { } + + /// + /// Initializes a new instance of the class with + /// no default identity, the specified default region, and the default identity + /// provider, REST service implementation, validator, metadata processor, encoder, + /// status parser, and bulk delete results mapper. + /// + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created with no default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The to use for validating requests to this service. + /// The to use for processing metadata returned in HTTP headers. + /// The to use for encoding data in URI query strings. + /// The to use for parsing HTTP status codes. + /// The object mapper to use for mapping objects to objects. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + internal CloudFilesProvider(string defaultRegion, IIdentityProvider identityProvider, IRestService restService, IObjectStorageValidator cloudFilesValidator, IObjectStorageMetadataProcessor cloudFilesMetadataProcessor, IEncodeDecodeProvider encodeDecodeProvider, IStatusParser statusParser, IObjectMapper mapper) + : this(null, defaultRegion, identityProvider, restService, cloudFilesValidator, cloudFilesMetadataProcessor, encodeDecodeProvider, statusParser, mapper) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, default region, identity provider, REST service + /// implementation, validator, metadata processor, encoder, status parser, and bulk + /// delete results mapper. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The to use for validating requests to this service. + /// The to use for processing metadata returned in HTTP headers. + /// The to use for encoding data in URI query strings. + /// The to use for parsing HTTP status codes. + /// The object mapper to use for mapping objects to objects. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + internal CloudFilesProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService, IObjectStorageValidator cloudFilesValidator, IObjectStorageMetadataProcessor cloudFilesMetadataProcessor, IEncodeDecodeProvider encodeDecodeProvider, IStatusParser statusParser, IObjectMapper bulkDeletionResultMapper) + : base(defaultIdentity, defaultRegion, identityProvider, restService) + { + if (cloudFilesValidator == null) + throw new ArgumentNullException("cloudFilesValidator"); + if (cloudFilesMetadataProcessor == null) + throw new ArgumentNullException("cloudFilesMetadataProcessor"); + if (encodeDecodeProvider == null) + throw new ArgumentNullException("encodeDecodeProvider"); + if (statusParser == null) + throw new ArgumentNullException("statusParser"); + if (bulkDeletionResultMapper == null) + throw new ArgumentNullException("bulkDeletionResultMapper"); + + _cloudFilesValidator = cloudFilesValidator; + _cloudFilesMetadataProcessor = cloudFilesMetadataProcessor; + _encodeDecodeProvider = encodeDecodeProvider; + _statusParser = statusParser; + _bulkDeletionResultMapper = bulkDeletionResultMapper; + } + + + #endregion + + #region Containers + + /// + public IEnumerable ListContainers(int? limit = null, string marker = null, string markerEnd = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl))); + + var queryStringParameter = new Dictionary(); + + if (limit != null) + queryStringParameter.Add("limit", limit.ToString()); + + if (!string.IsNullOrEmpty(marker)) + queryStringParameter.Add("marker", marker); + + if (!string.IsNullOrEmpty(markerEnd)) + queryStringParameter.Add("end_marker", markerEnd); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, null, queryStringParameter); + + if (response == null || response.Data == null) + return null; + + return response.Data; + } + + /// + public ObjectStore CreateContainer(string container, Dictionary headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, headers: headers); + + switch (response.StatusCode) + { + case HttpStatusCode.Created: + return ObjectStore.ContainerCreated; + + case HttpStatusCode.Accepted: + return ObjectStore.ContainerExists; + + default: + throw new ResponseException(string.Format("Unexpected status {0} returned by Create Container.", response.StatusCode), response); + } + } + + /// + public void DeleteContainer(string container, bool deleteObjects = false, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + + if (deleteObjects) + { + var headers = GetContainerHeader(container, region, useInternalUrl, identity); + var countHeader = headers.FirstOrDefault(h => h.Key.Equals(ContainerObjectCount, StringComparison.OrdinalIgnoreCase)); + if (!EqualityComparer>.Default.Equals(countHeader, default(KeyValuePair))) + { + int count; + if (!int.TryParse(countHeader.Value, out count)) + throw new Exception(string.Format("Unable to parse the object count header for container: {0}. Actual count value: {1}", container, countHeader.Value)); + + if (count > 0) + { + var objects = ListObjects(container, count, region: region, useInternalUrl: useInternalUrl, identity: identity); + + if(objects.Any()) + DeleteObjects(container, objects.Select(o => o.Name), region: region, useInternalUrl: useInternalUrl, identity: identity); + } + } + } + + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container))); + + try + { + ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE); + } + catch (ServiceConflictException ex) + { + throw new ContainerNotEmptyException(null, ex); + } + } + + /// + public Dictionary GetContainerHeader(string container, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.HEAD); + + var processedHeaders = _cloudFilesMetadataProcessor.ProcessMetadata(response.Headers); + + return processedHeaders[ProcessedHeadersHeaderKey]; + } + + /// + public Dictionary GetContainerMetaData(string container, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); // Should be HEAD + + var processedHeaders = _cloudFilesMetadataProcessor.ProcessMetadata(response.Headers); + + return processedHeaders[ProcessedHeadersMetadataKey]; + } + + /// + public ContainerCDN GetContainerCDNHeader(string container, string region = null, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFilesCDN(identity, region), _encodeDecodeProvider.UrlEncode(container))); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.HEAD); + + string name = container; + string uri = null; + string streamingUri = null; + string sslUri = null; + string iosUri = null; + bool enabled = false; + long ttl = 0; + bool logRetention = false; + + foreach (var header in response.Headers) + { + if (header.Key.Equals(CdnUri, StringComparison.OrdinalIgnoreCase)) + { + uri = header.Value; + } + else if (header.Key.Equals(CdnSslUri, StringComparison.OrdinalIgnoreCase)) + { + sslUri = header.Value; + } + else if (header.Key.Equals(CdnStreamingUri, StringComparison.OrdinalIgnoreCase)) + { + streamingUri = header.Value; + } + else if (header.Key.Equals(CdnTTL, StringComparison.OrdinalIgnoreCase)) + { + ttl = long.Parse(header.Value); + } + else if (header.Key.Equals(CdnEnabled, StringComparison.OrdinalIgnoreCase)) + { + enabled = bool.Parse(header.Value); + } + else if (header.Key.Equals(CdnLogRetention, StringComparison.OrdinalIgnoreCase)) + { + logRetention = bool.Parse(header.Value); + } + else if (header.Key.Equals(CdnIosUri, StringComparison.OrdinalIgnoreCase)) + { + iosUri = header.Value; + } + } + + ContainerCDN result = new ContainerCDN(name, uri, streamingUri, sslUri, iosUri, enabled, ttl, logRetention); + return result; + } + + /// + public IEnumerable ListCDNContainers(int? limit = null, string markerId = null, string markerEnd = null, bool cdnEnabled = false, string region = null, CloudIdentity identity = null) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}", GetServiceEndpointCloudFilesCDN(identity, region))); + + var queryStringParameter = new Dictionary + { + {"format", "json"}, + {"enabled_only", cdnEnabled.ToString().ToLower()} + }; + + if (limit != null) + queryStringParameter.Add("limit", limit.ToString()); + + if (!string.IsNullOrEmpty(markerId)) + queryStringParameter.Add("marker", markerId); + + if (!string.IsNullOrEmpty(markerEnd)) + queryStringParameter.Add("end_marker", markerEnd); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, null, queryStringParameter); + + if (response == null || response.Data == null) + return null; + + return response.Data; + } + + /// + public Dictionary EnableCDNOnContainer(string container, long timeToLive, string region = null, CloudIdentity identity = null) + { + return EnableCDNOnContainer(container, timeToLive, false, region, identity); + } + + /// + public Dictionary EnableCDNOnContainer(string container, bool logRetention, string region = null, CloudIdentity identity = null) + { + return EnableCDNOnContainer(container, 259200, logRetention, region, identity); + } + + /// + public Dictionary EnableCDNOnContainer(string container, long timeToLive, bool logRetention, string region = null, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (timeToLive < 0) + throw new ArgumentOutOfRangeException("timeToLive"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + + if (timeToLive > 1577836800 || timeToLive < 900) + { + throw new TTLLengthException("TTL range must be 900 to 1577836800 seconds TTL: " + timeToLive.ToString(CultureInfo.InvariantCulture)); + } + + var headers = new Dictionary + { + {CdnTTL, timeToLive.ToString(CultureInfo.InvariantCulture)}, + {CdnLogRetention, logRetention.ToString(CultureInfo.InvariantCulture)}, + {CdnEnabled, "true"} + }; + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFilesCDN(identity, region), _encodeDecodeProvider.UrlEncode(container))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, headers: headers); + + if (response == null) + return null; + + return response.Headers.ToDictionary(header => header.Key, header => header.Value); + } + + /// + public Dictionary DisableCDNOnContainer(string container, string region = null, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + + var headers = new Dictionary + { + {CdnEnabled, "false"} + }; + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFilesCDN(identity, region), _encodeDecodeProvider.UrlEncode(container))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, headers: headers); + + if (response == null) + return null; + + return response.Headers.ToDictionary(header => header.Key, header => header.Value); + } + + /// + public void UpdateContainerMetadata(string container, Dictionary metadata, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + + var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (KeyValuePair m in metadata) + { + if (string.IsNullOrEmpty(m.Key)) + throw new ArgumentException("metadata keys cannot be null or empty"); + if (m.Key.Contains('_')) + throw new NotSupportedException("This provider does not support metadata keys containing an underscore."); + if (m.Key.Contains('\'')) + throw new NotSupportedException("This provider does not support metadata keys containing an apostrophe."); + + headers.Add(ContainerMetaDataPrefix + m.Key, EncodeUnicodeValue(m.Value)); + } + + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container))); + + ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, headers: headers); + } + + /// + public void DeleteContainerMetadata(string container, IEnumerable keys, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (keys == null) + throw new ArgumentNullException("keys"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + Dictionary headers = keys.ToDictionary(i => i, i => default(string), StringComparer.OrdinalIgnoreCase); + UpdateContainerMetadata(container, headers, region, useInternalUrl, identity); + } + + /// + public void DeleteContainerMetadata(string container, string key, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (key == null) + throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + + DeleteContainerMetadata(container, new[] { key }, region, useInternalUrl, identity); + } + + /// + public void UpdateContainerCdnHeaders(string container, Dictionary headers, string region = null, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (headers == null) + throw new ArgumentNullException("headers"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + VerifyContainerIsCDNEnabled(container, region, identity); + + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFilesCDN(identity, region), _encodeDecodeProvider.UrlEncode(container))); + ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, headers: headers); + } + + /// + public void EnableStaticWebOnContainer(string container, string index, string error, string css, bool listing, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (index == null) + throw new ArgumentNullException("index"); + if (error == null) + throw new ArgumentNullException("error"); + if (css == null) + throw new ArgumentNullException("css"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(index)) + throw new ArgumentException("index cannot be empty"); + if (string.IsNullOrEmpty(error)) + throw new ArgumentException("error cannot be empty"); + if (string.IsNullOrEmpty(css)) + throw new ArgumentException("css cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(index); + _cloudFilesValidator.ValidateObjectName(error); + _cloudFilesValidator.ValidateObjectName(css); + VerifyContainerIsCDNEnabled(container, region, identity); + + var metadata = new Dictionary + { + {WebIndex, UriUtility.UriEncode(index, UriPart.AnyUrl, Encoding.UTF8)}, + {WebError, UriUtility.UriEncode(error, UriPart.AnyUrl, Encoding.UTF8)}, + {WebListingsCSS, UriUtility.UriEncode(css, UriPart.AnyUrl, Encoding.UTF8)}, + {WebListings, listing.ToString()} + }; + UpdateContainerMetadata(container, metadata, region, useInternalUrl, identity); + } + + /// + public void EnableStaticWebOnContainer(string container, string index, string error, bool listing, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (index == null) + throw new ArgumentNullException("index"); + if (error == null) + throw new ArgumentNullException("error"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(index)) + throw new ArgumentException("index cannot be empty"); + if (string.IsNullOrEmpty(error)) + throw new ArgumentException("error cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(index); + _cloudFilesValidator.ValidateObjectName(error); + VerifyContainerIsCDNEnabled(container, region, identity); + + var headers = new Dictionary + { + {WebIndex, UriUtility.UriEncode(index, UriPart.AnyUrl, Encoding.UTF8)}, + {WebError, UriUtility.UriEncode(error, UriPart.AnyUrl, Encoding.UTF8)}, + {WebListings, listing.ToString()} + }; + UpdateContainerMetadata(container, headers, region, useInternalUrl, identity); + } + + /// + public void EnableStaticWebOnContainer(string container, string css, bool listing, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (css == null) + throw new ArgumentNullException("css"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(css)) + throw new ArgumentException("css cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(css); + VerifyContainerIsCDNEnabled(container, region, identity); + + var headers = new Dictionary + { + {WebListingsCSS, UriUtility.UriEncode(css, UriPart.AnyUrl, Encoding.UTF8)}, + {WebListings, listing.ToString()} + }; + UpdateContainerMetadata(container, headers, region, useInternalUrl, identity); + } + + /// + public void EnableStaticWebOnContainer(string container, string index, string error, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (index == null) + throw new ArgumentNullException("index"); + if (error == null) + throw new ArgumentNullException("error"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(index)) + throw new ArgumentException("index cannot be empty"); + if (string.IsNullOrEmpty(error)) + throw new ArgumentException("error cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(index); + _cloudFilesValidator.ValidateObjectName(error); + VerifyContainerIsCDNEnabled(container, region, identity); + + var headers = new Dictionary + { + {WebIndex, UriUtility.UriEncode(index, UriPart.AnyUrl, Encoding.UTF8)}, + {WebError, UriUtility.UriEncode(error, UriPart.AnyUrl, Encoding.UTF8)} + }; + UpdateContainerMetadata(container, headers, region, useInternalUrl, identity); + } + + /// + public void DisableStaticWebOnContainer(string container, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + VerifyContainerIsCDNEnabled(container, region, identity); + + var headers = new Dictionary + { + {WebIndex, string.Empty}, + {WebError, string.Empty}, + {WebListingsCSS, string.Empty}, + {WebListings, string.Empty} + }; + UpdateContainerMetadata(container, headers, region, useInternalUrl, identity); + } + + #endregion + + #region Container Objects + + /// + public Dictionary GetObjectHeaders(string container, string objectName, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.HEAD); + + var processedHeaders = _cloudFilesMetadataProcessor.ProcessMetadata(response.Headers); + + return processedHeaders[ProcessedHeadersHeaderKey]; + } + + /// + public Dictionary GetObjectMetaData(string container, string objectName, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.HEAD); + + var processedHeaders = _cloudFilesMetadataProcessor.ProcessMetadata(response.Headers); + + return processedHeaders[ProcessedHeadersMetadataKey]; + } + + /// + public void UpdateObjectHeaders(string container, string objectName, Dictionary headers, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (headers == null) + throw new ArgumentNullException("headers"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + var hdrs = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (KeyValuePair m in headers) + { + if (string.IsNullOrEmpty(m.Key)) + throw new ArgumentException("cors cannot contain any empty keys"); + + hdrs.Add(m.Key, EncodeUnicodeValue(m.Value)); + } + + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + + RequestSettings settings = BuildDefaultRequestSettings(); + // make sure the content type is not changed by the metadata operation + settings.ContentType = null; + + ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, headers: hdrs, settings: settings); + + } + + /// + public void UpdateObjectContentType(string container, string objectName, string contentType, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (contentType == null) + throw new ArgumentNullException("contentType"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + var hdrs = new Dictionary(StringComparer.OrdinalIgnoreCase); + + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + + RequestSettings settings = BuildDefaultRequestSettings(); + settings.ContentType = contentType; + CopyObject(container, objectName, container, objectName, contentType, region: region); + } + + /// + public void UpdateObjectMetadata(string container, string objectName, Dictionary metadata, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (KeyValuePair m in metadata) + { + if (string.IsNullOrEmpty(m.Key)) + throw new ArgumentException("metadata cannot contain any empty keys"); + + headers.Add(ObjectMetaDataPrefix + m.Key, EncodeUnicodeValue(m.Value)); + } + + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + + RequestSettings settings = BuildDefaultRequestSettings(); + // make sure the content type is not changed by the metadata operation + settings.ContentType = null; + + ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, headers: headers, settings: settings); + } + + /// + public void DeleteObjectMetadata(string container, string objectName, IEnumerable keys, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (keys == null) + throw new ArgumentNullException("keys"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + var headers = new Dictionary(GetObjectMetaData(container, objectName, region, useInternalUrl, identity), StringComparer.OrdinalIgnoreCase); + foreach (string key in keys) + { + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("keys cannot contain any null or empty values"); + + headers.Remove(key); + } + + UpdateObjectMetadata(container, objectName, headers, region, useInternalUrl, identity); + } + + /// + public void DeleteObjectMetadata(string container, string objectName, string key, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (key == null) + throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + + DeleteObjectMetadata(container, objectName, new[] { key }, region, useInternalUrl, identity); + } + + /// + public IEnumerable ListObjects(string container, int? limit = null, string marker = null, string markerEnd = null, string prefix = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container))); + + var queryStringParameter = new Dictionary(); + + if (limit != null) + queryStringParameter.Add("limit", limit.ToString()); + + if (!string.IsNullOrEmpty(marker)) + queryStringParameter.Add("marker", marker); + + if (!string.IsNullOrEmpty(markerEnd)) + queryStringParameter.Add("end_marker", markerEnd); + + if (!string.IsNullOrEmpty(prefix)) + queryStringParameter.Add("prefix", prefix); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, null, queryStringParameter); + + if (response == null || response.Data == null) + return null; + + return response.Data; + } + + /// + public void CreateObjectFromFile(string container, string filePath, string objectName = null, string contentType = null, int chunkSize = 4096, Dictionary headers = null, string region = null, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (filePath == null) + throw new ArgumentNullException("filePath"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(filePath)) + throw new ArgumentException("filePath cannot be empty"); + if (chunkSize < 0) + throw new ArgumentOutOfRangeException("chunkSize"); + CheckIdentity(identity); + + if (string.IsNullOrEmpty(objectName)) + objectName = Path.GetFileName(filePath); + + using (var stream = File.OpenRead(filePath)) + { + CreateObject(container, stream, objectName, contentType, chunkSize, headers, region, progressUpdated, useInternalUrl, identity); + } + } + + /// + public void CreateObject(string container, Stream stream, string objectName, string contentType = null, int chunkSize = 4096, Dictionary headers = null, string region = null, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (stream == null) + throw new ArgumentNullException("stream"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + if (chunkSize < 0) + throw new ArgumentOutOfRangeException("chunkSize"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + if (stream.Length > LargeFileBatchThreshold) + { + CreateObjectInSegments(_encodeDecodeProvider.UrlEncode(container), stream, _encodeDecodeProvider.UrlEncode(objectName), contentType, chunkSize, headers, region, progressUpdated, useInternalUrl, identity); + return; + } + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + + RequestSettings settings = BuildDefaultRequestSettings(); + settings.ChunkRequest = true; + settings.ContentType = contentType; + + StreamRESTRequest(identity, urlPath, HttpMethod.PUT, stream, chunkSize, headers: headers, progressUpdated: progressUpdated, requestSettings: settings); + } + + /// + public void GetObject(string container, string objectName, Stream outputStream, int chunkSize = 4096, Dictionary headers = null, string region = null, bool verifyEtag = false, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (outputStream == null) + throw new ArgumentNullException("outputStream"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + if (chunkSize < 0) + throw new ArgumentOutOfRangeException("chunkSize"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + + long? initialPosition; + try + { + initialPosition = outputStream.Position; + } + catch (NotSupportedException) + { + if (verifyEtag) + throw; + + initialPosition = null; + } + + // This flag indicates whether the outputStream needs to be set prior to copying data. + // See: https://github.com/openstacknetsdk/openstack.net/issues/297 + bool requiresPositionReset = false; + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, (resp, isError) => + { + if (resp == null) + return new Response(0, null, null); + + string body; + + if (!isError) + { + using (var respStream = resp.GetResponseStream()) + { + // The second condition will throw a proper NotSupportedException if the position + // cannot be checked. + if (requiresPositionReset && outputStream.Position != initialPosition) + outputStream.Position = initialPosition.Value; + + requiresPositionReset = true; + CopyStream(respStream, outputStream, chunkSize, progressUpdated); + } + + body = "[Binary]"; + } + else + { + using (StreamReader reader = new StreamReader(resp.GetResponseStream())) + { + body = reader.ReadToEnd(); + } + } + + var respHeaders = resp.Headers.AllKeys.Select(key => new HttpHeader(key, resp.GetResponseHeader(key))).ToList(); + + return new Response(resp.StatusCode, respHeaders, body); + }, headers: headers); + + string etag; + if (verifyEtag && response.TryGetHeader(Etag, out etag)) + { + // flush the contents of the stream to the output device + outputStream.Flush(); + // reset the head of the stream to the beginning + outputStream.Position = initialPosition.Value; + + string objectManifest; + if (response.TryGetHeader(ObjectManifest, out objectManifest) && !string.IsNullOrEmpty(objectManifest)) + { + throw new NotSupportedException("ETag validation for dynamic large objects is not yet supported."); + } + else + { + string staticLargeObject; + if (response.TryGetHeader(StaticLargeObject, out staticLargeObject) && string.Equals(bool.TrueString, staticLargeObject, StringComparison.OrdinalIgnoreCase)) + { + throw new NotSupportedException("ETag validation for static large objects is not yet supported."); + } + } + + bool weakETag = etag.StartsWith("W/", StringComparison.Ordinal); + if (weakETag) + etag = etag.Substring("W/".Length); + + etag = etag.Trim('"'); + using (var md5 = MD5.Create()) + { + md5.ComputeHash(outputStream); + + var sbuilder = new StringBuilder(); + var hash = md5.Hash; + foreach (var b in hash) + { + sbuilder.Append(b.ToString("x2")); + } + var convertedMd5 = sbuilder.ToString(); + if (!string.Equals(convertedMd5, etag, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidETagException(); + } + } + } + } + + /// + public void GetObjectSaveToFile(string container, string saveDirectory, string objectName, string fileName = null, int chunkSize = 65536, Dictionary headers = null, string region = null, bool verifyEtag = false, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (saveDirectory == null) + throw new ArgumentNullException("saveDirectory"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(saveDirectory)) + throw new ArgumentException("saveDirectory cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + if (chunkSize < 0) + throw new ArgumentOutOfRangeException("chunkSize"); + CheckIdentity(identity); + + if (string.IsNullOrEmpty(fileName)) + fileName = objectName; + + var filePath = Path.Combine(saveDirectory, string.IsNullOrEmpty(fileName) ? objectName : fileName); + + try + { + using (var fileStream = File.Open(filePath, FileMode.Create, FileAccess.ReadWrite)) + { + GetObject(container, objectName, fileStream, chunkSize, headers, region, verifyEtag, progressUpdated, useInternalUrl, identity); + } + } + catch (InvalidETagException) + { + File.Delete(filePath); + throw; + } + } + + /// + public void CopyObject(string sourceContainer, string sourceObjectName, string destinationContainer, string destinationObjectName, string destinationContentType = null, Dictionary headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (sourceContainer == null) + throw new ArgumentNullException("sourceContainer"); + if (sourceObjectName == null) + throw new ArgumentNullException("sourceObjectName"); + if (destinationContainer == null) + throw new ArgumentNullException("destinationContainer"); + if (destinationObjectName == null) + throw new ArgumentNullException("destinationObjectName"); + if (string.IsNullOrEmpty(sourceContainer)) + throw new ArgumentException("sourceContainer cannot be empty"); + if (string.IsNullOrEmpty(sourceObjectName)) + throw new ArgumentException("sourceObjectName cannot be empty"); + if (string.IsNullOrEmpty(destinationContainer)) + throw new ArgumentException("destinationContainer cannot be empty"); + if (string.IsNullOrEmpty(destinationObjectName)) + throw new ArgumentException("destinationObjectName cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(sourceContainer); + _cloudFilesValidator.ValidateObjectName(sourceObjectName); + + _cloudFilesValidator.ValidateContainerName(destinationContainer); + _cloudFilesValidator.ValidateObjectName(destinationObjectName); + + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(sourceContainer), _encodeDecodeProvider.UrlEncode(sourceObjectName))); + + if (headers == null) + headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + + headers.Add(Destination, string.Format("{0}/{1}", UriUtility.UriEncode(destinationContainer, UriPart.AnyUrl, Encoding.UTF8), UriUtility.UriEncode(destinationObjectName, UriPart.AnyUrl, Encoding.UTF8))); + + RequestSettings settings = BuildDefaultRequestSettings(); + if (destinationContentType != null) + { + settings.ContentType = destinationContentType; + } + else + { + // make sure to preserve the content type during the copy operation + settings.ContentType = null; + } + + ExecuteRESTRequest(identity, urlPath, HttpMethod.COPY, headers: headers, settings: settings); + } + + /// + public void DeleteObject(string container, string objectName, Dictionary headers = null, bool deleteSegments = true, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + Dictionary objectHeader = null; + if(deleteSegments) + objectHeader = GetObjectHeaders(container, objectName, region, useInternalUrl, identity); + + if (deleteSegments && objectHeader != null && objectHeader.Any(h => h.Key.Equals(ObjectManifest, StringComparison.OrdinalIgnoreCase))) + { + var objects = ListObjects(container, region: region, useInternalUrl: useInternalUrl, + identity: identity); + + if (objects != null && objects.Any()) + { + var segments = objects.Where(f => f.Name.StartsWith(string.Format("{0}.seg", objectName))); + var delObjects = new List { objectName }; + if (segments.Any()) + delObjects.AddRange(segments.Select(s => s.Name)); + + DeleteObjects(container, delObjects, headers, region, useInternalUrl, identity); + } + else + throw new Exception(string.Format("Object \"{0}\" in container \"{1}\" does not exist.", objectName, container)); + } + else + { + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + + ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE, headers: headers); + } + } + + /// + /// Deletes a collection of objects from a container. + /// + /// The container name. + /// A names of objects to delete. + /// A collection of custom HTTP headers to include with the request. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any null or empty values. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// If contains an item that is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Bulk Delete (Rackspace Cloud Files Developer Guide - API v1) + public void DeleteObjects(string container, IEnumerable objects, Dictionary headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objects == null) + throw new ArgumentNullException("objects"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + + BulkDelete(objects.Select(o => new KeyValuePair(container, o)), headers, region, useInternalUrl, identity); + } + + /// + /// Deletes a collection of objects stored in object storage. + /// + /// The collection of items to delete. The keys of each pair specifies the container name, and the value specifies the object name. + /// A collection of custom HTTP headers to include with the request. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// + /// + /// If contains any values with empty keys or values. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If contains a pair where the key is not a valid container name. + /// If contains a pair where the value is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Bulk Delete (Rackspace Cloud Files Developer Guide - API v1) + public void BulkDelete(IEnumerable> items, Dictionary headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + var urlPath = new Uri(string.Format("{0}/?bulk-delete", GetServiceEndpointCloudFiles(identity, region, useInternalUrl))); + + var encoded = items.Select( + pair => + { + if (string.IsNullOrEmpty(pair.Key)) + throw new ArgumentException("items", "items cannot contain any entries with a null or empty key (container name)"); + if (string.IsNullOrEmpty(pair.Value)) + throw new ArgumentException("items", "items cannot contain any entries with a null or empty value (object name)"); + _cloudFilesValidator.ValidateContainerName(pair.Key); + _cloudFilesValidator.ValidateObjectName(pair.Value); + + return string.Format("/{0}/{1}", _encodeDecodeProvider.UrlEncode(pair.Key), _encodeDecodeProvider.UrlEncode(pair.Value)); + }); + var body = string.Join("\n", encoded.ToArray()); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, body: body, headers: headers, settings: new JsonRequestSettings { ContentType = "text/plain" }); + + Status status; + if (_statusParser.TryParse(response.Data.Status, out status)) + { + if (status.Code != 200 && !response.Data.Errors.Any()) + { + response.Data.AllItems = encoded; + throw new BulkDeletionException(response.Data.Status, _bulkDeletionResultMapper.Map(response.Data)); + } + } + } + + /// + /// Upload and automatically extract an archive of files. + /// + /// The source file path. Example c:\folder1\folder2\archive_name.tar.gz + /// The target path for the extracted files. For details about this value, see the Extract Archive reference link in the documentation for this method. + /// The archive format. + /// The content type of the files extracted from the archive. If the value is or empty, the content type of the extracted files is unspecified. + /// The buffer size to use for copying streaming data. + /// A collection of custom HTTP headers to associate with the object (see ). + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// A callback for progress updates. If the value is , no progress updates are reported. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// An object containing the detailed result of the extract archive operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is less than 0. + /// If the file could not be found. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported by the provider. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Extract Archive (Rackspace Cloud Files Developer Guide - API v1) + /// + public ExtractArchiveResponse ExtractArchiveFromFile(string filePath, string uploadPath, ArchiveFormat archiveFormat, string contentType = null, int chunkSize = 4096, Dictionary headers = null, string region = null, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (filePath == null) + throw new ArgumentNullException("filePath"); + if (uploadPath == null) + throw new ArgumentNullException("uploadPath"); + if (archiveFormat == null) + throw new ArgumentNullException("archiveFormat"); + if (string.IsNullOrEmpty(filePath)) + throw new ArgumentException("filePath cannot be empty"); + if (chunkSize < 0) + throw new ArgumentOutOfRangeException("chunkSize"); + CheckIdentity(identity); + + using (var stream = File.OpenRead(filePath)) + { + return ExtractArchive(stream, uploadPath, archiveFormat, contentType, chunkSize, headers, region, progressUpdated, useInternalUrl, identity); + } + } + + /// + /// Upload and automatically extract an archive of files. + /// + /// A providing the data for the archive. + /// The target path for the extracted files. For details about this value, see the Extract Archive reference link in the documentation for this method. + /// The archive format. + /// The content type of the files extracted from the archive. If the value is or empty, the content type of the extracted files is unspecified. + /// The buffer size to use for copying streaming data. + /// A collection of custom HTTP headers to associate with the object (see ). + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// A callback for progress updates. If the value is , no progress updates are reported. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// An object containing the detailed result of the extract archive operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains two equivalent keys when compared using . + /// + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported by the provider. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Extract Archive (Rackspace Cloud Files Developer Guide - API v1) + /// + public ExtractArchiveResponse ExtractArchive(Stream stream, string uploadPath, ArchiveFormat archiveFormat, string contentType = null, int chunkSize = 4096, Dictionary headers = null, string region = null, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (stream == null) + throw new ArgumentNullException("stream"); + if (uploadPath == null) + throw new ArgumentNullException("uploadPath"); + if (archiveFormat == null) + throw new ArgumentNullException("archiveFormat"); + if (chunkSize < 0) + throw new ArgumentOutOfRangeException("chunkSize"); + CheckIdentity(identity); + + UriTemplate template; + if (!string.IsNullOrEmpty(uploadPath)) + template = new UriTemplate("{uploadPath}?extract-archive={archiveFormat}"); + else + template = new UriTemplate("?extract-archive={archiveFormat}"); + + Uri baseAddress = new Uri(GetServiceEndpointCloudFiles(identity, region, useInternalUrl)); + Dictionary parameters = new Dictionary { { "archiveFormat", archiveFormat.ToString() } }; + if (!string.IsNullOrEmpty(uploadPath)) + parameters.Add("uploadPath", UriUtility.UriEncode(uploadPath, UriPart.AnyUrl, Encoding.UTF8)); + + Uri urlPath = template.BindByName(baseAddress, parameters); + + RequestSettings settings = BuildDefaultRequestSettings(); + settings.ChunkRequest = true; + settings.ContentType = contentType; + + Response response = StreamRESTRequest(identity, urlPath, HttpMethod.PUT, stream, chunkSize, headers: headers, progressUpdated: progressUpdated, requestSettings: settings); + return JsonConvert.DeserializeObject(response.RawBody); + } + + /// + public void MoveObject(string sourceContainer, string sourceObjectName, string destinationContainer, string destinationObjectName, string destinationContentType = null, Dictionary headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + // Do nothing if the source and destination locations are the same. Prevents the object from being deleted accidentally. + var prefix = GetServiceEndpointCloudFiles(identity, region, useInternalUrl); + var src = new Uri($"{prefix}/{_encodeDecodeProvider.UrlEncode(sourceContainer)}/{_encodeDecodeProvider.UrlEncode(sourceObjectName)}"); + var dest = new Uri($"{prefix}/{_encodeDecodeProvider.UrlEncode(destinationContainer)}/{_encodeDecodeProvider.UrlEncode(destinationObjectName)}"); + if (src == dest) + return; + + CopyObject(sourceContainer, sourceObjectName, destinationContainer, destinationObjectName, destinationContentType, headers, region, useInternalUrl, identity); + DeleteObject(sourceContainer, sourceObjectName, headers, true, region, useInternalUrl, identity); + } + + /// + public void PurgeObjectFromCDN(string container, string objectName, IEnumerable emails = null, string region = null, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + if (emails != null && emails.Any(string.IsNullOrEmpty)) + throw new ArgumentException("emails cannot contain any null or empty values"); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + VerifyContainerIsCDNEnabled(container, region, identity); + + string email = emails != null ? string.Join(",", emails.ToArray()) : null; + var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + if (!string.IsNullOrEmpty(email)) + { + headers[CdnPurgeEmail] = email; + } + + var urlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFilesCDN(identity, region), _encodeDecodeProvider.UrlEncode(container), _encodeDecodeProvider.UrlEncode(objectName))); + ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE, headers: headers); + } + + #endregion + + #region Accounts + + /// + public Dictionary GetAccountHeaders(string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.HEAD); + + var processedHeaders = _cloudFilesMetadataProcessor.ProcessMetadata(response.Headers); + + return processedHeaders[ProcessedHeadersHeaderKey]; + + } + + /// + public Dictionary GetAccountMetaData(string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl))); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.HEAD); + + var processedHeaders = _cloudFilesMetadataProcessor.ProcessMetadata(response.Headers); + + return processedHeaders[ProcessedHeadersMetadataKey]; + } + + /// + public void UpdateAccountMetadata(Dictionary metadata, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + CheckIdentity(identity); + + var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (KeyValuePair m in metadata) + { + if (string.IsNullOrEmpty(m.Key)) + throw new ArgumentException("metadata keys cannot be null or empty"); + if (m.Key.Contains('_')) + throw new NotSupportedException("This provider does not support metadata keys containing an underscore."); + if (m.Key.Contains('\'')) + throw new NotSupportedException("This provider does not support metadata keys containing an apostrophe."); + + headers.Add(AccountMetaDataPrefix + m.Key, EncodeUnicodeValue(m.Value)); + } + + var urlPath = new Uri(string.Format("{0}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl))); + ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, headers: headers); + } + + /// + /// Construct a which allows public access to an object hosted in Cloud Files. + /// + /// The HTTP method that will be used to access the object. This is typically or . + /// The container name. + /// The object name. Example image_name.jpeg + /// The account key to use with the TempURL feature, as specified in the account metadata. + /// The expiration time for the generated URI. + /// The region in which to access the object. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// An absolute which allows unauthenticated (public) access to the specified object until the time passes or the account key is changed. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// Temporary URL middleware (OpenStack Object Storage API v1 Reference) + /// Create the TempURL (Rackspace Cloud Files Developer Guide - API v1) + /// + public Uri CreateTemporaryPublicUri(HttpMethod method, string container, string objectName, string key, DateTimeOffset expiration, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (key == null) + throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + Uri baseAddress = new Uri(GetServiceEndpointCloudFiles(identity, region, useInternalUrl), UriKind.Absolute); + + StringBuilder body = new StringBuilder(); + body.Append(method.ToString().ToUpperInvariant()).Append('\n'); + body.Append(expiration.ToTimestamp() / 1000).Append('\n'); + body.Append(baseAddress.PathAndQuery).Append('/').Append(container).Append('/').Append(objectName); + + using (HMAC hmac = HMAC.Create()) + { + hmac.HashName = "SHA1"; + hmac.Key = Encoding.UTF8.GetBytes(key); + byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(body.ToString())); + string sig = string.Join(string.Empty, Array.ConvertAll(hash, i => i.ToString("x2"))); + + UriTemplate uriTemplate = new UriTemplate("{container}/{objectName}?temp_url_sig={sig}&temp_url_expires={expires}"); + Dictionary parameters = new Dictionary() + { + { "container", container }, + { "objectName", objectName }, + { "sig", sig }, + { "expires", (expiration.ToTimestamp() / 1000).ToString() }, + }; + + return uriTemplate.BindByName(baseAddress, parameters); + } + } + + /// + /// Construct a and field information supporting the public upload of objects to a Cloud Files container via an HTTP form submission. + /// + /// + /// The HTTP form used for uploading files has the following form, where uri is a placeholder + /// for the URI described in the return value from this method. + /// + /// + /// <form action="uri" method="POST" enctype="multipart/form-data"> + /// <input type="file" name="file1"/><br/> + /// <input type="submit"/> + /// </form> + /// + /// + /// + /// In addition to the above <input> fields, the form should include one hidden input + /// for each of the key/value pairs described in the return value from this method. Each of these + /// fields should have the following form, where key and value are placeholders + /// for one key/value pair. + /// + /// + /// + /// <input type="hidden" name="key" value="value"/> + /// + /// + /// The container name where uploaded files are placed. + /// The prefix applied to uploaded objects. + /// The account key to use with the Form POST feature, as specified in the account metadata. + /// The expiration time for the generated URI. + /// The URI to redirect the user to after the upload operation completes. + /// Specifies the maximum size in bytes of a single file. + /// The maximum number of files which can be uploaded in a single request. + /// The region in which to access the object. If not specified, the user's default region will be used. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// A object containing the information necessary to submit a POST operation uploading one or more files to Cloud Files. + /// The first item in the tuple is the absolute URI where the form data should be submitted, which is valid until the + /// time passes or the account key is changed. The value is a collection of key/value pairs describing + /// the names/values of additional fields to submit with the form. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is less than 0. + /// -or- + /// If is less or equal to 0. + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is greater than . + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// + /// Form POST middleware (OpenStack Object Storage API v1 Reference) + /// FormPost (Rackspace Cloud Files Developer Guide - API v1) + /// + public Tuple> CreateFormPostUri(string container, string objectPrefix, string key, DateTimeOffset expiration, Uri redirectUri, long maxFileSize, int maxFileCount, string region = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (objectPrefix == null) + throw new ArgumentNullException("objectPrefix"); + if (key == null) + throw new ArgumentNullException("key"); + if (redirectUri == null) + throw new ArgumentNullException("redirectUri"); + if (maxFileSize < 0) + throw new ArgumentOutOfRangeException("maxFileSize"); + if (maxFileCount <= 0) + throw new ArgumentOutOfRangeException("maxFileCount"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectPrefix)) + throw new ArgumentException("objectPrefix cannot be empty"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + if (maxFileSize > LargeFileBatchThreshold) + throw new ArgumentException("maxFileSize cannot exceed LargeFileBatchThreshold"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectPrefix); + + Uri baseAddress = new Uri(GetServiceEndpointCloudFiles(identity, region, useInternalUrl), UriKind.Absolute); + + StringBuilder body = new StringBuilder(); + body.Append(baseAddress.PathAndQuery).Append('/').Append(container).Append('/').Append(objectPrefix).Append('\n'); + body.Append(redirectUri.AbsoluteUri).Append('\n'); + body.Append(maxFileSize).Append('\n'); + body.Append(maxFileCount).Append('\n'); + body.Append(expiration.ToTimestamp() / 1000); + + using (HMAC hmac = HMAC.Create()) + { + hmac.HashName = "SHA1"; + hmac.Key = Encoding.UTF8.GetBytes(key); + byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(body.ToString())); + string sig = string.Join(string.Empty, Array.ConvertAll(hash, i => i.ToString("x2"))); + + UriTemplate uriTemplate = new UriTemplate("{container}/{objectPrefix}"); + Dictionary parameters = new Dictionary() + { + { "container", container }, + { "objectPrefix", objectPrefix }, + }; + + Uri uri = uriTemplate.BindByName(baseAddress, parameters); + Dictionary fields = new Dictionary + { + { "expires", (expiration.ToTimestamp() / 1000).ToString() }, + { "redirect", redirectUri.AbsoluteUri }, + { "max_file_size", maxFileSize.ToString() }, + { "max_file_count", maxFileCount.ToString() }, + { "signature", sig }, + }; + + return Tuple.Create(uri, new ReadOnlyDictionary(fields)); + } + } + + private static string EncodeUnicodeValue(string value) + { + if (value == null) + return null; + + return Encoding.GetEncoding("ISO-8859-1").GetString(Encoding.UTF8.GetBytes(value)); + } + + #endregion + + #region Private methods + + /// + /// Gets the public or internal service endpoint to use for Cloud Files requests for the specified identity and region. + /// + /// + /// This method uses object-store for the service type, and cloudFiles for the preferred service name. + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The preferred region for the service. If this value is , the user's default region will be used. + /// to use the internal service endpoint; otherwise to use the public service endpoint. + /// The URL for the requested Cloud Files endpoint. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If is and no default region is available for the identity or provider. + /// If no service catalog is available for the user. + /// If no endpoint is available for the requested service. + /// If the REST API request failed. + protected string GetServiceEndpointCloudFiles(CloudIdentity identity, string region = null, bool useInternalUrl = false) + { + return useInternalUrl ? base.GetInternalServiceEndpoint(identity, "object-store", "cloudFiles", region) : base.GetPublicServiceEndpoint(identity, "object-store", "cloudFiles", region); + } + + /// + /// Gets the public service endpoint to use for Cloud Files CDN requests for the specified identity and region. + /// + /// + /// This method uses rax:object-cdn for the service type, and cloudFilesCDN for the preferred service name. + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The preferred region for the service. If this value is , the user's default region will be used. + /// The public URL for the requested Cloud Files CDN endpoint. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If is and no default region is available for the identity or provider. + /// If no service catalog is available for the user. + /// If no endpoint is available for the requested service. + /// If the REST API request failed. + protected string GetServiceEndpointCloudFilesCDN(CloudIdentity identity, string region = null) + { + return base.GetPublicServiceEndpoint(identity, "rax:object-cdn", "cloudFilesCDN", region); + } + + /// + /// Copy data from an input stream to an output stream. + /// + /// + /// The argument to the callback method is the total number of bytes written to the output stream thus far. + /// Note that is not called on prior to reporting a + /// progress update, so data may remain in the stream's buffer. + /// + /// The input stream. + /// The output stream. + /// The size of the buffer to use for copying data. + /// A callback for progress updates. If the value is , no progress updates are reported. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is less than or equal to 0. + public static void CopyStream(Stream input, Stream output, int bufferSize, Action progressUpdated) + { + if (input == null) + throw new ArgumentNullException("input"); + if (output == null) + throw new ArgumentNullException("output"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + + var buffer = new byte[bufferSize]; + int len; + long bytesWritten = 0; + + while ((len = input.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer, 0, len); + bytesWritten += len; + + if (progressUpdated != null) + progressUpdated(bytesWritten); + } + } + + /// + /// Creates an object consisting of multiple segments, each no larger than + /// , using data from a . + /// If the destination file already exists, the contents are overwritten. + /// + /// + /// In addition to the individual segments containing file data, this method creates + /// the manifest required for treating the segments as a single object in future GET + /// requests. + /// + /// The container name. + /// A providing the data for the file. + /// The destination object name. Example image_name.jpeg + /// The content type of the created object. If the value is or empty, the content type of the created object is unspecified. + /// The buffer size to use for copying streaming data. + /// A collection of custom HTTP headers to associate with the object (see ). + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// A callback for progress updates. If the value is , no progress updates are reported. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If contains two equivalent keys when compared using . + /// + /// If is not a valid container name. + /// If is not a valid object name. + /// If is less than 0. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// -or- + /// is and the provider does not support internal URLs. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + /// Create or replace object (OpenStack Object Storage API v1 Reference) + /// Manifest objects (OpenStack Object Storage API v1 Reference) + private void CreateObjectInSegments(string container, Stream stream, string objectName, string contentType = null, int chunkSize = 4096, Dictionary headers = null, string region = null, Action progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null) + { + if (container == null) + throw new ArgumentNullException("container"); + if (stream == null) + throw new ArgumentNullException("stream"); + if (objectName == null) + throw new ArgumentNullException("objectName"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentException("objectName cannot be empty"); + if (chunkSize < 0) + throw new ArgumentOutOfRangeException("chunkSize"); + CheckIdentity(identity); + + _cloudFilesValidator.ValidateContainerName(container); + _cloudFilesValidator.ValidateObjectName(objectName); + + long totalLength = stream.Length - stream.Position; + long segmentCount = (totalLength / LargeFileBatchThreshold) + (((totalLength % LargeFileBatchThreshold) != 0) ? 1 : 0); + + long totalBytesWritten = 0; + for (int i = 0; i < segmentCount; i++) + { + // the total amount of data left to write + long remaining = (totalLength - LargeFileBatchThreshold * i); + // the size of the current segment + long length = Math.Min(remaining, LargeFileBatchThreshold); + + Uri urlPath = new Uri(string.Format("{0}/{1}/{2}.seg{3}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), UriUtility.UriEncode(container, UriPart.AnyUrl, Encoding.UTF8), UriUtility.UriEncode(objectName, UriPart.AnyUrl, Encoding.UTF8), i.ToString("0000"))); + long segmentBytesWritten = 0; + + RequestSettings settings = BuildDefaultRequestSettings(); + settings.ChunkRequest = true; + settings.ContentType = contentType; + + StreamRESTRequest(identity, urlPath, HttpMethod.PUT, stream, chunkSize, length, headers: headers, requestSettings: settings, progressUpdated: + bytesWritten => + { + if (progressUpdated != null) + { + segmentBytesWritten = bytesWritten; + progressUpdated(totalBytesWritten + segmentBytesWritten); + } + }); + + totalBytesWritten += length; + } + + // upload the manifest file + Uri segmentUrlPath = new Uri(string.Format("{0}/{1}/{2}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), UriUtility.UriEncode(container, UriPart.AnyUrl, Encoding.UTF8), UriUtility.UriEncode(objectName, UriPart.AnyUrl, Encoding.UTF8))); + string objectManifestValue = string.Format("{0}.seg", objectName); + + if (headers == null) + headers = new Dictionary(); + + headers.Add(ObjectManifest, string.Format("{0}/{1}", UriUtility.UriEncode(container, UriPart.Any, Encoding.UTF8), UriUtility.UriEncode(objectManifestValue, UriPart.Any, Encoding.UTF8))); + + RequestSettings requestSettings = BuildDefaultRequestSettings(); + requestSettings.ChunkRequest = true; + requestSettings.ContentType = contentType; + + StreamRESTRequest(identity, segmentUrlPath, HttpMethod.PUT, new MemoryStream(new Byte[0]), chunkSize, headers: headers, requestSettings: requestSettings, progressUpdated: + (bytesWritten) => + { + if (progressUpdated != null) + { + progressUpdated(totalBytesWritten); + } + }); + } + + /// + /// Verifies that a particular container is CDN-enabled. + /// + /// + /// Normally, the property is used to check if a container is + /// CDN-enabled. However, if a container has never been CDN-enabled, the + /// method throws a misleading . + /// This method uses to distinguish between these cases, ensuring + /// that a gets thrown whenever a container exists but is not + /// CDN-enabled. + /// + /// The container name. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// If is . + /// If is empty. + /// If is not a valid container name. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the container does not have a CDN header, or if the property is . + /// If the REST API request failed. + protected void VerifyContainerIsCDNEnabled(string container, string region, CloudIdentity identity) + { + if (container == null) + throw new ArgumentNullException("container"); + if (string.IsNullOrEmpty(container)) + throw new ArgumentException("container cannot be empty"); + _cloudFilesValidator.ValidateContainerName(container); + CheckIdentity(identity); + + try + { + // If the container is currently CDN enabled, or was CDN enabled at some + // point in the past, GetContainerCDNHeader returns non-null and the CDNEnabled + // property determines whether or not the container is currently CDN enabled. + if (!GetContainerCDNHeader(container, region, identity).CDNEnabled) + { + throw new CDNNotEnabledException("The specified container is not CDN-enabled."); + } + } + catch (ItemNotFoundException ex) + { + // In response to an ItemNotFoundException, the GetContainerHeader method is used + // to distinguish between cases where the container does not exist (or is not + // accessible), and cases where the container exists but has never been CDN enabled. + GetContainerHeader(container, region, false, identity); + + // If we get to this line, we know the container exists but has never been CDN enabled. + throw new CDNNotEnabledException("The specified container is not CDN-enabled.", ex); + } + } + + #endregion + + #region constants + + #region Headers + + #region Auth Constants + + /// + /// The X-Auth-Token header, which specifies the token to use for authenticated requests. + /// + /// Authentication (OpenStack Object Storage API v1 Reference) + /// Authentication (Rackspace Cloud Files Developer Guide - API v1) + public const string AuthToken = "x-auth-token"; + + /// + /// The X-Cdn-Management-Url header. + /// The value of this header is not defined. Do not use. + /// + public const string CdnManagementUrl = "x-cdn-management-url"; + + /// + /// The X-Storage-Url header, which specifies the base URI for all object storage requests. + /// + /// Authentication (OpenStack Object Storage API v1 Reference) + /// Authentication (Rackspace Cloud Files Developer Guide - API v1) + public const string StorageUrl = "x-storage-url"; + + #endregion + + #region Account Constants + + /// + /// The X-Account-Meta- header prefix, which specifies the HTTP header prefix for metadata keys associated with an account. + /// + /// Create, update, or delete account metadata (OpenStack Object Storage API v1 Reference) + public const string AccountMetaDataPrefix = "x-account-meta-"; + + /// + /// The X-Account-Bytes-Used header, which specifies the total number of bytes that are stored in Object Storage for the account. + /// + /// Show account metadata (OpenStack Object Storage API v1 Reference) + /// Show Account Details and List Containers (Rackspace Cloud Files Developer Guide - API v1) + public const string AccountBytesUsed = "x-account-bytes-used"; + + /// + /// The X-Account-Container-Count header, which specifies the number of containers associated with an account. + /// + /// Show account metadata (OpenStack Object Storage API v1 Reference) + /// Show Account Details and List Containers (Rackspace Cloud Files Developer Guide - API v1) + public const string AccountContainerCount = "x-account-container-count"; + + /// + /// The X-Account-Object-Count header, which specifies the number of objects in an account. + /// + /// Show account details and list containers (OpenStack Object Storage API v1 Reference) + /// Show Account Details and List Containers (Rackspace Cloud Files Developer Guide - API v1) + public const string AccountObjectCount = "x-account-object-count"; + + /// + /// The Temp-Url-Key account metadata key for use with . + /// + /// + /// This account metadata value is passed as the key parameter to . + /// + /// + /// + /// Set Account TempURL Metadata Key (Rackspace Cloud Files Developer Guide - API v1) + public const string TempUrlKey = "Temp-Url-Key"; + + #endregion + + #region Container Constants + + /// + /// The X-Container-Meta- header prefix, which specifies the HTTP header prefix for metadata keys associated with a container. + /// + /// Create, update, or delete container metadata (OpenStack Object Storage API v1 Reference) + public const string ContainerMetaDataPrefix = "x-container-meta-"; + + /// + /// The X-Remove-Container-Meta- header prefix, which specifies the HTTP header prefix for removing metadata keys from a container. + /// + /// Create, update, or delete container metadata (OpenStack Object Storage API v1 Reference) + [Obsolete("This value is not required in the .NET SDK, since a shorter way to remove metadata is to simply assign an empty string as the value for a metadata key.")] + public const string ContainerRemoveMetaDataPrefix = "x-remove-container-meta-"; + + /// + /// The X-Container-Bytes-Used header, which specifies the total size of all objects stored in a container. + /// + /// Show container metadata (OpenStack Object Storage API v1 Reference) + public const string ContainerBytesUsed = "x-container-bytes-used"; + + /// + /// The X-Container-Object-Count header, which specifies the total number of objects stored in a container. + /// + /// Show container metadata (OpenStack Object Storage API v1 Reference) + public const string ContainerObjectCount = "x-container-object-count"; + + /// + /// The Web-Index metadata key, which specifies the index page for every pseudo-directory in a website. + /// + /// + /// If your pseudo-directory does not have a file with the same name as your index file, visits to the sub-directory return a 404 error. + /// + /// Create static website (OpenStack Object Storage API v1 Reference) + /// Create Static Website (Rackspace Cloud Files Developer Guide - API v1) + public const string WebIndex = "web-index"; + + /// + /// The Web-Error metadata key, which specifies the suffix for error pages displayed for a website. + /// + /// + /// You may create and set custom error pages for visitors to your website; currently, only + /// 401 (Unauthorized) and 404 (Not Found) errors are supported. To do this, set the metadata + /// value . + /// + /// + /// Error pages are served with the <status> code prepended to the name of the error + /// page you set. For instance, if you set to error.html, + /// 401 errors will display the page 401error.html. Similarly, 404 + /// errors will display 404error.html. You must have both of these + /// pages created in your container when you set the metadata, or your site + /// will display generic error pages. + /// + /// + /// + /// You need only set the metadata once for your entire static website. + /// + /// + /// Set Error Pages for Static Website (OpenStack Object Storage API v1 Reference - API v1) + /// Set Error Pages for Static Website (Rackspace Cloud Files Developer Guide - API v1) + public const string WebError = "web-error"; + + /// + /// The Web-Listings metadata key, which specifies whether or not pseudo-directories should + /// display a list of files instead of returning a 404 error when the pseudo-directory does + /// not contain an index file. + /// + /// + /// To display a list of files in pseudo-directories instead of an index, set the + /// metadata value to "TRUE" for a container. + /// + /// Create static website (OpenStack Object Storage API v1 Reference) + public const string WebListings = "web-listings"; + + /// + /// The Web-Listings-CSS metadata key, which specifies the stylesheet to use for file listings + /// when is and a pseudo-directory does not contain an + /// index file. + /// + /// Create static website (OpenStack Object Storage API v1 Reference) + public const string WebListingsCSS = "web-listings-css"; + + /// + /// The X-Versions-Location header, which specifies the name of the container where previous + /// versions of objects are stored for a container. + /// + /// Object versioning (OpenStack Object Storage API v1 Reference - API v1) + public const string VersionsLocation = "x-versions-location"; + + #endregion + + #region CDN Container Constants + + /// + /// The X-Cdn-Uri header, which specifies the publicly-available URL + /// for a CDN-enabled container. + /// + /// + /// + /// This header is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + public const string CdnUri = "x-cdn-uri"; + + /// + /// The X-Cdn-Ssl-Uri header, which specifies the publicly-available + /// URL for SSL access to a CDN-enabled container. + /// + /// + /// + /// This header is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + public const string CdnSslUri = "x-cdn-ssl-uri"; + + /// + /// The X-Cdn-Streaming-Uri header, which specifies the publicly-available + /// URL for streaming access to a CDN-enabled container (using Adobe HTTP Dynamic Streaming). + /// + /// + /// + /// This header is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + public const string CdnStreamingUri = "x-cdn-streaming-uri"; + + /// + /// The X-Ttl header, which specifies the Time To Live (TTL) in seconds for a CDN-enabled container. + /// + /// + /// + /// This header is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + public const string CdnTTL = "x-ttl"; + + /// + /// The X-Log-Retention header, which specifies whether or not log retention is enabled for a CDN-enabled container. + /// + /// + /// + /// This header is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + public const string CdnLogRetention = "x-log-retention"; + + /// + /// The X-Cdn-Enabled header, which specifies whether or not a container is CDN-enabled. + /// + /// + /// + /// This header is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// + /// List a CDN-Enabled Container's Metadata (Rackspace Cloud Files Developer Guide - API v1) + public const string CdnEnabled = "x-cdn-enabled"; + + /// + /// The X-Cdn-Ios-Uri header, which specifies the publicly-available URL for + /// iOS streaming access to a CDN-enabled container (using Apple HTTP Live Streaming). + /// + /// + /// + /// This header is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// + /// iOS Streaming (Rackspace Cloud Files Developer Guide - API v1) + public const string CdnIosUri = "x-cdn-ios-uri"; + + #endregion + + #region Object Constants + + /// + /// The X-Object-Meta- header prefix, which specifies the HTTP header prefix for metadata keys associated with an object. + /// + /// Create or update object metadata (OpenStack Object Storage API v1 Reference) + public const string ObjectMetaDataPrefix = "x-object-meta-"; + + /// + /// The X-Delete-After header, which specifies the relative time (in seconds + /// from "now") after which an object should expire, not be served, and be + /// deleted completely from the storage system. + /// + /// Schedule objects for deletion (OpenStack Object Storage API v1 Reference) + public const string ObjectDeleteAfter = "x-delete-after"; + + /// + /// The X-Delete-At header, which specifies the absolute time (in Unix Epoch + /// format) after which an object should expire, not be served, and be deleted + /// completely from the storage system. + /// + /// + /// Unix time is specified as the number of seconds elapsed since 00:00:00 UTC, + /// 1 January 1970, not counting leap seconds. + /// + /// Unix time (Wikipedia) + /// Schedule objects for deletion (OpenStack Object Storage API v1 Reference) + public const string ObjectDeleteAt = "x-delete-at"; + + /// + /// The ETag header, which specifies the MD5 checksum of the data in an object stored in Object Storage. + /// + /// Create or replace object (OpenStack Object Storage API v1 Reference) + public const string Etag = "etag"; + + /// + /// The Destination header, which specifies the destination container and object + /// name for a Copy Object operation. + /// + /// Copy object (OpenStack Object Storage API v1 Reference) + public const string Destination = "destination"; + + /// + /// The If-None-Match header, which allows calls to create or update objects to + /// query whether the server already has a copy of the object before any data is sent. + /// + /// + /// Currently the service only supports specifying the header If-None-Match: *, which + /// results in a response if the Object + /// Storage Service contains any file matching the name of the object being updated. Neither + /// the content of the object nor its associated metadata are checked by the service. + /// + /// Create or replace object (OpenStack Object Storage API v1 Reference) + /// + public const string IfNoneMatch = "if-none-match"; + + /// + /// The X-Object-Manifest header, which specifies the container and prefix for the segments of a + /// dynamic large object. + /// + /// Dynamic large objects (OpenStack Object Storage API v1 Reference) + public const string ObjectManifest = "x-object-manifest"; + + /// + /// The X-Static-Large-Object header, which specifies whether an object is a manifest for a static + /// large object. + /// + /// Static large objects (OpenStack Object Storage API v1 Reference) + /// + public const string StaticLargeObject = "x-static-large-object"; + + /// + /// The X-Detect-Content-Type header, which specifies that the Object Storage service should + /// automatically assign the content type for the object. + /// + /// + /// The provider may use any algorithm to assign the content type for the object, including but not limited + /// to filename extension analysis and file contents analysis. The resulting content type is not required + /// to accurately reflect the true contents of the file. + /// + /// If this header is set to True, the Content-Type header is ignored. + /// + /// Create or replace object (OpenStack Object Storage API v1 Reference) + public const string DetectContentType = "x-detect-content-type"; + + #endregion + + #region CDN Object Constants + + /// + /// The X-Purge-Email header, which specifies the comma-separated list of email addresses to notify when a CDN purge request completes. + /// + /// + /// + /// This header is a Rackspace-specific extension to the OpenStack Object Storage Service. + /// + /// + /// Delete CDN-Enabled Object (Rackspace Cloud Files Developer Guide - API v1) + public const string CdnPurgeEmail = "x-purge-email"; + + #endregion + + /// + /// The X-Newest header, which indicates that Cloud Files should locate + /// the most recent version of an object or container listing rather than return the + /// first response provided by an underlying storage node. + /// + /// + /// Setting this header to True can have a substantial performance impact on the + /// or request. It should only + /// be used when absolutely necessary. + /// + /// Show account details and list containers (OpenStack Object Storage API v1 Reference) + /// Show account metadata (OpenStack Object Storage API v1 Reference) + /// Show container metadata (OpenStack Object Storage API v1 Reference) + /// Get object content and metadata (OpenStack Object Storage API v1 Reference) + /// Show object metadata (OpenStack Object Storage API v1 Reference) + public const string Newest = "x-newest"; + + #endregion + + /// + /// The maximum value of supported by this provider. + /// This value is set to the minimum value for which creation of a single object larger than + /// the value may result in the server closing the TCP/IP connection and purging the object's + /// data. + /// + /// Large objects (OpenStack Object Storage API v1 Reference) + public static readonly long MaxLargeFileBatchThreshold = 5368709120; // 5GB + + /// + /// This is the backing field for . The + /// default value is . + /// + private long _largeFileBatchThreshold = MaxLargeFileBatchThreshold; + + /// + /// Gets or sets the maximum allowable size of a single object stored in this provider. + /// + /// If is less than 0. + /// If exceeds . + public long LargeFileBatchThreshold + { + get + { + return _largeFileBatchThreshold; + } + + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + if (value > MaxLargeFileBatchThreshold) + throw new ArgumentException(string.Format("The large file threshold cannot exceed the provider's maximum value {0}", MaxLargeFileBatchThreshold), "value"); + + _largeFileBatchThreshold = value; + } + } + + /// + /// This value is used as the key for storing metadata information in the dictionary + /// returned by . + /// + /// + public const string ProcessedHeadersMetadataKey = "metadata"; + + /// + /// This value is used as the key for storing non-metadata header information in the + /// dictionary returned by . + /// + /// + public const string ProcessedHeadersHeaderKey = "headers"; + + #endregion + + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudIdentityProvider.cs b/src/OpenStack/Providers/Rackspace/CloudIdentityProvider.cs new file mode 100644 index 000000000..5befc40f9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudIdentityProvider.cs @@ -0,0 +1,1173 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using JSIStudios.SimpleRESTServices.Client; +using JSIStudios.SimpleRESTServices.Client.Json; +using net.openstack.Core; +using net.openstack.Core.Caching; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Providers; +using net.openstack.Providers.Rackspace.Objects; +using net.openstack.Providers.Rackspace.Objects.Request; +using net.openstack.Providers.Rackspace.Objects.Response; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack; +using OpenStack.Authentication; +using OpenStack.Core; + +namespace net.openstack.Providers.Rackspace +{ + /// + /// Provides an implementation of and + /// for operating with Rackspace's Cloud Identity product. + /// + /// OpenStack Identity Service API v2.0 Reference + /// Rackspace Cloud Identity Client Developer Guide - API v2.0 + /// + public class CloudIdentityProvider : ProviderBase, IExtendedCloudIdentityProvider, IIdentityProvider, IIdentityService + { + /// + /// This is the backing field for the property. + /// + private readonly ICache _userAccessCache; + + /// + /// This is the backing field for the property. + /// + private readonly Uri _urlBase; + + /// + /// Initializes a new instance of the class + /// with no default identity, and the default base URL, REST service implementation, + /// and token cache. + /// + public CloudIdentityProvider() : this(null, null, null, null) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified default identity, and the default base URL, REST service + /// implementation, and token cache. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// + /// The following example demonstrates the use of this method to create an identity provider that + /// authenticates using username and API key credentials. + /// + /// + /// + /// + /// The following example demonstrates the use of this method to create an identity provider that + /// authenticates using username and password credentials. + /// + /// + /// + /// + /// + public CloudIdentityProvider(CloudIdentity defaultIdentity) + : this(defaultIdentity, null, null, null) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, the specified base URL, and the default REST service + /// implementation and token cache. + /// + /// The base URL for the cloud instance. If this value is , the provider will use https://identity.api.rackspacecloud.com. + public CloudIdentityProvider(Uri urlBase) + : this(null, null, null, urlBase) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified default identity and base URL, and the default REST service + /// implementation and token cache. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The base URL for the cloud instance. If this value is , the provider will use https://identity.api.rackspacecloud.com. + public CloudIdentityProvider(CloudIdentity defaultIdentity, Uri urlBase) + : this(defaultIdentity, null, null, urlBase) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, and the specified base URL, REST service + /// implementation, and token cache. + /// + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + /// The base URL for the cloud instance. If this value is , the provider will use https://identity.api.rackspacecloud.com. + public CloudIdentityProvider(IRestService restService, ICache tokenCache, Uri urlBase) + : this(null, restService, tokenCache, urlBase) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, the default base URL, the default REST service + /// implementation, and the specified token cache. + /// + /// The cache to use for caching user access tokens. If this value is , the provider will use . + public CloudIdentityProvider(ICache tokenCache) + : this(null, tokenCache) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, the default base URL, the specified REST service + /// implementation, and the + /// token cache. + /// + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudIdentityProvider(IRestService restService) + : this(restService, null) + { + } + + /// + /// Initializes a new instance of the class + /// with no default identity, the default base URL, and the specified REST service + /// implementation and token cache. + /// + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + public CloudIdentityProvider(IRestService restService, ICache tokenCache) + : this(null, restService, tokenCache, null) + { + } + + /// + /// Initializes a new instance of the class + /// using the provided values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The cache to use for caching user access tokens. If this value is , the provider will use . + /// The base URL for the cloud instance. If this value is , the provider will use https://identity.api.rackspacecloud.com. + public CloudIdentityProvider(CloudIdentity defaultIdentity, IRestService restService, ICache tokenCache, Uri urlBase) + : base(defaultIdentity, null, null, restService) + { + _userAccessCache = tokenCache ?? UserAccessCache.Instance; + _urlBase = urlBase ?? new Uri("https://identity.api.rackspacecloud.com"); + } + + /// + /// Gets the cache to use for caching user access tokens. + /// + protected ICache TokenCache + { + get { return _userAccessCache; } + } + + /// + /// Gets the base URL for the cloud instance. + /// + protected Uri UrlBase + { + get { return _urlBase; } + } + + #region Roles + + /// + public virtual IEnumerable ListRoles(string serviceId = null, int? marker = null, int? limit = null, CloudIdentity identity = null) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var parameters = BuildOptionalParameterList(new Dictionary + { + {"serviceId", serviceId}, + {"marker", !marker.HasValue ? null : marker.Value.ToString()}, + {"limit", !limit.HasValue ? null : limit.Value.ToString()}, + }); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "/v2.0/OS-KSADM/roles"), HttpMethod.GET, queryStringParameter: parameters); + + if (response == null || response.Data == null) + return null; + + return response.Data.Roles; + } + + /// + public virtual Role AddRole(string name, string description, CloudIdentity identity) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + CheckIdentity(identity); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "/v2.0/OS-KSADM/roles"), HttpMethod.POST, new AddRoleRequest(new Role(name, description))); + + if (response == null || response.Data == null) + return null; + + return response.Data.Role; + } + + /// + public virtual Role GetRole(string roleId, CloudIdentity identity) + { + if (roleId == null) + throw new ArgumentNullException("roleId"); + if (string.IsNullOrEmpty(roleId)) + throw new ArgumentException("roleId cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("/v2.0/OS-KSADM/roles/{0}", roleId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Role; + } + + /// + public virtual IEnumerable GetRolesByUser(string userId, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("/v2.0/users/{0}/roles", userId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Roles; + } + + /// + public virtual bool AddRoleToUser(string userId, string roleId, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (roleId == null) + throw new ArgumentNullException("roleId"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + if (string.IsNullOrEmpty(roleId)) + throw new ArgumentException("roleId cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("/v2.0/users/{0}/roles/OS-KSADM/{1}", userId, roleId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.PUT); + + // If the response status code is 409, that mean the user is already apart of the role, so we want to return true; + if (response == null || (response.StatusCode >= HttpStatusCode.BadRequest && response.StatusCode != HttpStatusCode.Conflict)) + return false; + + return true; + } + + /// + public virtual bool DeleteRoleFromUser(string userId, string roleId, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (roleId == null) + throw new ArgumentNullException("roleId"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + if (string.IsNullOrEmpty(roleId)) + throw new ArgumentException("roleId cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("/v2.0/users/{0}/roles/OS-KSADM/{1}", userId, roleId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.DELETE); + + if (response != null && response.StatusCode == HttpStatusCode.NoContent) + return true; + + return false; + } + + /// + public virtual IEnumerable ListUsersByRole(string roleId, bool? enabled = null, int? marker = null, int? limit = null, CloudIdentity identity = null) + { + if (limit < 0 || limit > 1000) + throw new ArgumentOutOfRangeException("limit"); + + CheckIdentity(identity); + + var parameters = BuildOptionalParameterList(new Dictionary + { + {"enabled", !enabled.HasValue ? null : enabled.Value ? "true" : "false"}, + {"marker", !marker.HasValue ? null : marker.Value.ToString()}, + {"limit", !limit.HasValue ? null : limit.Value.ToString()}, + }); + + var urlPath = string.Format("/v2.0/OS-KSADM/roles/{0}/RAX-AUTH/users", roleId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.GET, queryStringParameter: parameters); + + if (response == null || response.Data == null) + return null; + // Due to the fact the sometimes the API returns a JSON array of users and sometimes it returns a single JSON user object. + // Therefore if we get a null data object (which indicates that the deserializer could not parse to an array) we need to try and parse as a single User object. + if (response.Data.Users == null) + { + var userResponse = JsonConvert.DeserializeObject(response.RawBody); + + if (response == null || response.Data == null) + return null; + + return new[] {userResponse.User}; + } + + return response.Data.Users; + } + + #endregion + + #region Credentials + + /// + public virtual bool SetUserPassword(string userId, string password, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + CheckIdentity(identity); + + var user = GetUser(userId, identity); + + return SetUserPassword(user, password, identity); + } + + /// + public virtual bool SetUserPassword(User user, string password, CloudIdentity identity) + { + if (user == null) + throw new ArgumentNullException("user"); + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + if (string.IsNullOrEmpty(user.Id)) + throw new ArgumentException("user.Id cannot be null or empty"); + if (string.IsNullOrEmpty(user.Username)) + throw new ArgumentException("user.Username cannot be null or empty"); + CheckIdentity(identity); + + return SetUserPassword(user.Id, user.Username, password, identity); + } + + /// + public virtual bool SetUserPassword(string userId, string username, string password, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (username == null) + throw new ArgumentNullException("username"); + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + if (string.IsNullOrEmpty(username)) + throw new ArgumentException("username cannot be empty"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("v2.0/users/{0}/OS-KSADM/credentials", userId); + var request = new SetPasswordRequest(username, password); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.POST, request); + + if (response == null || response.StatusCode != HttpStatusCode.Created || response.Data == null) + return false; + + return response.Data.PasswordCredential.Password.Equals(password); + } + + /// + public virtual IEnumerable ListUserCredentials(string userId, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("v2.0/users/{0}/OS-KSADM/credentials", userId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.GET); + + if (response == null || string.IsNullOrEmpty(response.RawBody)) + return null; + + var jObject = JObject.Parse(response.RawBody); + var credsArray = (JArray) jObject["credentials"]; + var creds = new List(); + + foreach (JObject jToken in credsArray) + { + foreach (JProperty property in jToken.Properties()) + { + var cred = (JObject) property.Value; + creds.Add(new UserCredential(property.Name, cred["username"].ToString(), cred["apiKey"].ToString())); + } + + } + + return creds.ToArray(); + } + + /// + public virtual UserCredential GetUserCredential(string userId, string credentialKey, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (credentialKey == null) + throw new ArgumentNullException("credentialKey"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + if (string.IsNullOrEmpty(credentialKey)) + throw new ArgumentException("credentialKey cannot be empty"); + CheckIdentity(identity); + + var creds = ListUserCredentials(userId, identity); + + var cred = creds.FirstOrDefault(c => c.Name.Equals(credentialKey, StringComparison.OrdinalIgnoreCase)); + + return cred; + } + + /// + /// Reset the API key credentials for a user. + /// + /// The user ID. This is obtained from or . + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// A object containing the new API key for the user. + /// If is . + /// If is empty. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method. For more information about creating the + /// provider, see . + /// + /// + /// + /// + /// + /// Reset API key credentials (Rackspace Cloud Identity Client Developer Guide - API v2.0) + public virtual UserCredential ResetApiKey(string userId, CloudIdentity identity = null) + { + if (userId == null) + throw new ArgumentNullException("userId"); + CheckIdentity(identity); + + var urlPath = string.Format("v2.0/users/{0}/OS-KSADM/credentials/RAX-KSKEY:apiKeyCredentials/RAX-AUTH/reset", userId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.POST); + if (response == null || response.Data == null) + return null; + + return response.Data.UserCredential; + } + + /// + public new virtual CloudIdentity DefaultIdentity + { + get { return base.DefaultIdentity; } + } + + /// + public virtual UserCredential UpdateUserCredentials(string userId, string apiKey, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (apiKey == null) + throw new ArgumentNullException("apiKey"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + if (string.IsNullOrEmpty(apiKey)) + throw new ArgumentException("apiKey cannot be empty"); + CheckIdentity(identity); + + var user = GetUser(userId, identity); + + return UpdateUserCredentials(user, apiKey, identity); + } + + /// + public virtual UserCredential UpdateUserCredentials(User user, string apiKey, CloudIdentity identity) + { + if (user == null) + throw new ArgumentNullException("user"); + if (apiKey == null) + throw new ArgumentNullException("apiKey"); + if (string.IsNullOrEmpty(apiKey)) + throw new ArgumentException("apiKey cannot be empty"); + if (string.IsNullOrEmpty(user.Id)) + throw new ArgumentException("user.Id cannot be null or empty"); + if (string.IsNullOrEmpty(user.Username)) + throw new ArgumentException("user.Username cannot be null or empty"); + CheckIdentity(identity); + + return UpdateUserCredentials(user.Id, user.Username, apiKey, identity); + } + + /// + public virtual UserCredential UpdateUserCredentials(string userId, string username, string apiKey, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (username == null) + throw new ArgumentNullException("username"); + if (apiKey == null) + throw new ArgumentNullException("apiKey"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + if (string.IsNullOrEmpty(username)) + throw new ArgumentException("username cannot be empty"); + if (string.IsNullOrEmpty(apiKey)) + throw new ArgumentException("apiKey cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("v2.0/users/{0}/OS-KSADM/credentials/RAX-KSKEY:apiKeyCredentials", userId); + var request = new UpdateUserCredentialRequest(username, apiKey); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.POST, request); + + if (response == null || response.Data == null) + return null; + + return response.Data.UserCredential; + } + + /// + public virtual bool DeleteUserCredentials(string userId, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("v2.0/users/{0}/OS-KSADM/credentials/RAX-KSKEY:apiKeyCredentials", userId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.DELETE); + + if (response == null || response.StatusCode != HttpStatusCode.OK) + return false; + + return true; + } + + #endregion + + #region Users + + /// + public virtual IEnumerable ListUsers(CloudIdentity identity) + { + CheckIdentity(identity); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "/v2.0/users"), HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + // Due to the fact the sometimes the API returns a JSON array of users and sometimes it returns a single JSON user object. + // Therefore if we get a null data object (which indicates that the deserializer could not parse to an array) we need to try and parse as a single User object. + if (response.Data.Users == null) + { + var userResponse = JsonConvert.DeserializeObject(response.RawBody); + + if (response == null || response.Data == null) + return null; + + return new[] {userResponse.User}; + } + + return response.Data.Users; + } + + /// + public virtual User GetUserByName(string name, CloudIdentity identity) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("/v2.0/users/?name={0}", name); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.User; + } + + /// + /// Gets the details for users with the specified email address. + /// + /// The email address. + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// A collection of objects describing the users with the specified email address. + /// If is . + /// If is empty. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Get User by Email (Rackspace Cloud Identity Client Developer Guide - API v2.0) + public virtual IEnumerable GetUsersByEmail(string email, CloudIdentity identity) + { + if (email == null) + throw new ArgumentNullException("email"); + if (string.IsNullOrEmpty(email)) + throw new ArgumentException("email cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("/v2.0/users/?email={0}", EncodeDecodeProvider.Default.UrlEncode(email)); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Users; + } + + /// + public virtual User GetUser(string id, CloudIdentity identity) + { + if (id == null) + throw new ArgumentNullException("id"); + if (string.IsNullOrEmpty(id)) + throw new ArgumentException("id cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("v2.0/users/{0}", id); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.GET); + + return response.Data.User; + } + + /// + public virtual NewUser AddUser(NewUser user, CloudIdentity identity) + { + if (user == null) + throw new ArgumentNullException("user"); + if (string.IsNullOrEmpty(user.Username)) + throw new ArgumentException("user.Username cannot be null or empty"); + if (user.Id != null) + throw new InvalidOperationException("user.Id must be null"); + CheckIdentity(identity); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "/v2.0/users"), HttpMethod.POST, new AddUserRequest(user)); + + if (response == null || response.Data == null) + return null; + + // If the user specifies a password, then the password will not be in the response, so we need to fill it in on the return object. + if (string.IsNullOrEmpty(response.Data.NewUser.Password)) + response.Data.NewUser.Password = user.Password; + + return response.Data.NewUser; + } + + /// + public virtual User UpdateUser(User user, CloudIdentity identity) + { + if (user == null) + throw new ArgumentNullException("user"); + if (string.IsNullOrEmpty(user.Id)) + throw new ArgumentException("user.Id cannot be null or empty"); + CheckIdentity(identity); + + var urlPath = string.Format("v2.0/users/{0}", user.Id); + + var updateUserRequest = new UpdateUserRequest(user); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.POST, updateUserRequest); + + // If the response status code is 409, that mean the user is already apart of the role, so we want to return true; + if (response == null || response.Data == null || (response.StatusCode >= HttpStatusCode.BadRequest && response.StatusCode != HttpStatusCode.Conflict)) + return null; + + return response.Data.User; + } + + /// + public virtual bool DeleteUser(string userId, CloudIdentity identity) + { + if (userId == null) + throw new ArgumentNullException("userId"); + if (string.IsNullOrEmpty(userId)) + throw new ArgumentException("userId cannot be empty"); + CheckIdentity(identity); + + var urlPath = string.Format("/v2.0/users/{0}", userId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, urlPath), HttpMethod.DELETE); + + if (response != null && response.StatusCode == HttpStatusCode.NoContent) + return true; + + return false; + } + + #endregion + + #region Tenants + + /// + public virtual IEnumerable ListTenants(CloudIdentity identity) + { + CheckIdentity(identity); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "v2.0/tenants"), HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Tenants; + } + + /// + /// Lists the endpoints in a tenant's service catalog. + /// + /// + /// This call is part of the OS-KSCATALOG extension to the OpenStack Identity Service V2. + /// + /// The tenant ID. This is obtained from + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// A collection of objects containing endpoint details. + /// If is . + /// If is empty. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed or the token does not exist. + /// OS-KSCATALOG admin extension (Identity API v2.0 - OpenStack Complete API Reference) + /// + public virtual ReadOnlyCollection ListServiceCatalogEndpoints(string tenantId, CloudIdentity identity) + { + if (tenantId == null) + throw new ArgumentNullException("tenantId"); + if (string.IsNullOrEmpty(tenantId)) + throw new ArgumentException("tenantId cannot be empty"); + + CheckIdentity(identity); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, string.Format("/v2.0/tenants/{0}/OS-KSCATALOG/endpoints", tenantId)), HttpMethod.GET); + + if (response == null || response.Data == null || response.Data.Endpoints == null) + return null; + + return new ReadOnlyCollection(response.Data.Endpoints); + } + + /// + /// Gets an endpoint by ID from the service catalog for a tenant. + /// + /// + /// This call is part of the OS-KSCATALOG extension to the OpenStack Identity Service V2. + /// + /// The tenant ID. This is obtained from + /// The endpoint ID. This is obtained from + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// An object containing the endpoint details. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed or the token does not exist. + /// OS-KSCATALOG admin extension (Identity API v2.0 - OpenStack Complete API Reference) + /// + public virtual ExtendedEndpoint GetServiceCatalogEndpoint(string tenantId, string endpointId, CloudIdentity identity) + { + if (tenantId == null) + throw new ArgumentNullException("tenantId"); + if (endpointId == null) + throw new ArgumentNullException("endpointId"); + if (string.IsNullOrEmpty(tenantId)) + throw new ArgumentException("tenantId cannot be empty"); + if (string.IsNullOrEmpty(endpointId)) + throw new ArgumentException("endpointId cannot be empty"); + + CheckIdentity(identity); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, string.Format("/v2.0/tenants/{0}/OS-KSCATALOG/endpoints/{1}", tenantId, endpointId)), HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Endpoint; + } + + /// + /// Adds an endpoint to the service catalog for a tenant. + /// + /// + /// This call is part of the OS-KSCATALOG extension to the OpenStack Identity Service V2. + /// + /// The tenant ID. This is obtained from + /// The endpoint template ID. + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// An object containing the endpoint details. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed or the token does not exist. + /// OS-KSCATALOG admin extension (Identity API v2.0 - OpenStack Complete API Reference) + /// + public virtual ExtendedEndpoint AddServiceCatalogEndpoint(string tenantId, EndpointTemplateId endpointTemplateId, CloudIdentity identity) + { + if (tenantId == null) + throw new ArgumentNullException("tenantId"); + if (endpointTemplateId == null) + throw new ArgumentNullException("endpointTemplateId"); + if (string.IsNullOrEmpty(tenantId)) + throw new ArgumentException("tenantId cannot be empty"); + + CheckIdentity(identity); + + var request = new AddServiceCatalogEndpointRequest(endpointTemplateId); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, string.Format("/v2.0/tenants/{0}/OS-KSCATALOG/endpoints", tenantId)), HttpMethod.POST, request); + + if (response == null || response.Data == null) + return null; + + return response.Data.Endpoint; + } + + /// + /// Removes an endpoint from the service catalog for a tenant. + /// + /// + /// This call is part of the OS-KSCATALOG extension to the OpenStack Identity Service V2. + /// + /// The tenant Id. This is obtained from + /// The endpoint Id. This is obtained from + /// The cloud identity to use for this request. If not specified, the for the current provider instance will be used. + /// if the endpoint was successfully deleted; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed or the token does not exist. + /// OS-KSCATALOG admin extension (Identity API v2.0 - OpenStack Complete API Reference) + /// + public virtual bool DeleteServiceCatalogEndpoint(string tenantId, string endpointId, CloudIdentity identity) + { + if (tenantId == null) + throw new ArgumentNullException("tenantId"); + if (endpointId == null) + throw new ArgumentNullException("endpointId"); + if (string.IsNullOrEmpty(tenantId)) + throw new ArgumentException("tenantId cannot be empty"); + if (string.IsNullOrEmpty(endpointId)) + throw new ArgumentException("endpointId cannot be empty"); + + CheckIdentity(identity); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, string.Format("/v2.0/tenants/{0}/OS-KSCATALOG/endpoints/{1}", tenantId, endpointId)), HttpMethod.DELETE); + + if (response == null && response.StatusCode != HttpStatusCode.NoContent) + return false; + + return true; + } + + #endregion + + #region Token and Authentication + + /// + public virtual IdentityToken GetToken(CloudIdentity identity, bool forceCacheRefresh = false) + { + CheckIdentity(identity); + + var auth = GetUserAccess(identity, forceCacheRefresh); + + if (auth == null || auth.Token == null) + return null; + + return auth.Token; + } + + /// + public virtual Task GetTokenAsync(CloudIdentity identity, CancellationToken cancellationToken) + { + return GetUserAccessAsync(identity, false, cancellationToken) + .Select(task => task.Result.Token); + } + + /// + public virtual UserAccess Authenticate(CloudIdentity identity = null) + { + CheckIdentity(identity); + + return GetUserAccess(identity, true); + } + + /// + public virtual Task AuthenticateAsync(CloudIdentity identity, CancellationToken cancellationToken) + { + CheckIdentity(identity); + return GetUserAccessAsync(identity, true, cancellationToken); + } + + /// + public virtual UserAccess GetUserAccess(CloudIdentity identity, bool forceCacheRefresh = false) + { + CheckIdentity(identity); + + if (identity == null) + identity = DefaultIdentity; + + if (identity is RackspaceImpersonationIdentity) + return Impersonate(identity as RackspaceImpersonationIdentity, forceCacheRefresh); + + var rackspaceCloudIdentity = identity as RackspaceCloudIdentity; + + if (rackspaceCloudIdentity == null) + rackspaceCloudIdentity = new RackspaceCloudIdentity(identity); + + var userAccess = TokenCache.Get(string.Format("{0}:{1}/{2}", UrlBase, rackspaceCloudIdentity.Domain, rackspaceCloudIdentity.Username), () => + { + var auth = new AuthRequest(identity); + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, "/v2.0/tokens"), HttpMethod.POST, auth, isTokenRequest: true); + + + if (response == null || response.Data == null || response.Data.UserAccess == null || response.Data.UserAccess.Token == null) + return null; + + return response.Data.UserAccess; + }, forceCacheRefresh); + + return userAccess; + } + + /// + public virtual Task GetUserAccessAsync(CloudIdentity identity, bool forceCacheRefresh, CancellationToken cancellationToken) + { + return Task.Factory.StartNew(() => GetUserAccess(identity, forceCacheRefresh), cancellationToken); + } + + /// + /// Gets the authentication token for the specified impersonation identity. If necessary, the + /// identity is authenticated on the server to obtain a token. + /// + /// + /// If is and a cached + /// is available for the specified , this method may return the cached + /// value without performing an authentication against the server. If + /// is , this method always authenticates the identity with the server. + /// + /// The identity of the user to authenticate. If this value is , the authentication is performed with the . + /// If , the user is always authenticated against the server; otherwise a cached may be returned. + /// The user's authentication token. + /// If is . + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the authentication request failed. + protected virtual UserAccess Impersonate(RackspaceImpersonationIdentity identity, bool forceCacheRefresh) + { + if (identity == null) + throw new ArgumentNullException("identity"); + + var impToken = TokenCache.Get(string.Format("{0}:{1}/imp/{2}/{3}", UrlBase, identity.Username, identity.UserToImpersonate.Domain == null ? "none" : identity.UserToImpersonate.Domain.Name, identity.UserToImpersonate.Username), () => + { + const string urlPath = "/v2.0/RAX-AUTH/impersonation-tokens"; + var request = BuildImpersonationRequestJson(identity.UserToImpersonate.Username, 600); + var parentIdentity = new RackspaceCloudIdentity(identity); + var response = ExecuteRESTRequest(parentIdentity, new Uri(UrlBase, urlPath), HttpMethod.POST, request); + if (response == null || response.Data == null || response.Data.UserAccess == null) + return null; + + IdentityToken impersonationToken = response.Data.UserAccess.Token; + if (impersonationToken == null) + return null; + + var userAccess = ValidateToken(impersonationToken.Id, identity: parentIdentity); + if (userAccess == null) + return null; + + var endpoints = ListEndpoints(impersonationToken.Id, parentIdentity); + + var serviceCatalog = BuildServiceCatalog(endpoints); + + return new UserAccess(userAccess.Token, userAccess.User, serviceCatalog); + }, forceCacheRefresh); + + return impToken; + } + + /// + /// Converts a collection of objects describing service endpoints + /// for an impersonated identity to a collection of objects used by + /// the provider implementations for endpoint resolution. + /// + /// A collection of objects describing the available endpoints. + /// A collection of objects describing the same endpoints as . + /// If is . + /// If contains any values. + protected virtual ServiceCatalog[] BuildServiceCatalog(IEnumerable endpoints) + { + if (endpoints == null) + throw new ArgumentNullException("endpoints"); + if (endpoints.Contains(null)) + throw new ArgumentException("endpoints cannot contain any null values", "endpoints"); + + var serviceCatalog = new List(); + var services = endpoints.Select(e => Tuple.Create(e.Type, e.Name)).Distinct(); + + foreach (var service in services) + { + string type = service.Item1; + string name = service.Item2; + IEnumerable serviceEndpoints = endpoints.Where(endpoint => string.Equals(type, endpoint.Type, StringComparison.OrdinalIgnoreCase) && string.Equals(name, endpoint.Name, StringComparison.OrdinalIgnoreCase)); + serviceCatalog.Add(new ServiceCatalog(name, type, serviceEndpoints.ToArray())); + } + + return serviceCatalog.ToArray(); + } + + /// + public virtual UserAccess ValidateToken(string token, string tenantId = null, CloudIdentity identity = null) + { + if (token == null) + throw new ArgumentNullException("token"); + if (string.IsNullOrEmpty(token)) + throw new ArgumentException("token cannot be empty"); + + var queryStringParameters = BuildOptionalParameterList(new Dictionary + { + {"belongsTo", tenantId} + }); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, string.Format("/v2.0/tokens/{0}", token)), HttpMethod.GET, queryStringParameter: queryStringParameters); + + + if (response == null || response.Data == null || response.Data.UserAccess == null || response.Data.UserAccess.Token == null) + return null; + + return response.Data.UserAccess; + } + + /// + public virtual IEnumerable ListEndpoints(string token, CloudIdentity identity = null) + { + if (token == null) + throw new ArgumentNullException("token"); + if (string.IsNullOrEmpty(token)) + throw new ArgumentException("token cannot be empty"); + + var response = ExecuteRESTRequest(identity, new Uri(UrlBase, string.Format("/v2.0/tokens/{0}/endpoints", token)), HttpMethod.GET); + + + if (response == null || response.Data == null) + return null; + + return response.Data.Endpoints; + } + + /// + /// Constructs the JSON representation used for an impersonation request. + /// + /// The username of the user to impersonate. + /// The time until the impersonation token will expire. + /// A representing the JSON body of the impersonation request. + /// If is . + /// If is empty. + /// If is less than or equal to 0. + protected virtual JObject BuildImpersonationRequestJson(string userName, int expirationInSeconds) + { + if (userName == null) + throw new ArgumentNullException("userName"); + if (string.IsNullOrEmpty(userName)) + throw new ArgumentException("userName cannot be empty"); + if (expirationInSeconds <= 0) + throw new ArgumentOutOfRangeException("expirationInSeconds"); + + return new JObject( + new JProperty("RAX-AUTH:impersonation", new JObject( + new JProperty("user", new JObject( + new JProperty("username", userName), + new JProperty("expire-in-seconds", expirationInSeconds)))))); + } + + #endregion + + #region IAuthenticationProvider + + /* Provides compatibility with the new services until the old providers are deprecated */ + + async Task IAuthenticationProvider.GetEndpoint(IServiceType serviceType, string region, bool useInternalUrl, CancellationToken cancellationToken) + { + string serviceTypeKey = LookupServiceTypeKey(serviceType); + if (DefaultIdentity == null) + throw new IdentityRequiredException(); + + UserAccess userAccess = await GetUserAccessAsync(DefaultIdentity, false, cancellationToken).ConfigureAwait(false); + + string requestedRegion = region ?? DefaultRegion; + return LegacyAuthenticationProviderHelper.GetEndpoint(serviceTypeKey, userAccess, DefaultIdentity, requestedRegion, useInternalUrl); + } + + async Task IAuthenticationProvider.GetToken(CancellationToken cancellationToken) + { + IdentityToken identityToken = await GetTokenAsync(DefaultIdentity, cancellationToken).ConfigureAwait(false); + return identityToken.Id; + } + + /// + /// Looks up the type key to use when searching for an endpoint in the service catalog for a particular service. + /// + protected virtual string LookupServiceTypeKey(IServiceType serviceType) + { + if (ServiceType.ContentDeliveryNetwork.Equals(serviceType)) + return "rax:cdn"; + return serviceType.Type; + } + #endregion + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudLoadBalancerProvider.cs b/src/OpenStack/Providers/Rackspace/CloudLoadBalancerProvider.cs new file mode 100644 index 000000000..7d4b97dc3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudLoadBalancerProvider.cs @@ -0,0 +1,2671 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Net; + using System.Net.Sockets; + using System.Threading.Tasks; + using JSIStudios.SimpleRESTServices.Client; + using net.openstack.Core; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using net.openstack.Core.Providers; + using net.openstack.Providers.Rackspace.Objects.LoadBalancers; + using net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request; + using net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response; + using net.openstack.Providers.Rackspace.Validators; + using Newtonsoft.Json.Linq; + using CancellationToken = System.Threading.CancellationToken; + using IHttpResponseCodeValidator = net.openstack.Core.Validators.IHttpResponseCodeValidator; + using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices; + + /// + /// Provides an implementation of for operating + /// with Rackspace's Cloud Load Balancers product. + /// + /// Rackspace Cloud Load Balancers Developer Guide - API v1.0 + /// + /// + public class CloudLoadBalancerProvider : ProviderBase, ILoadBalancerService + { + /// + /// This field caches the base URI used for accessing the Cloud Load Balancers service. + /// + /// + private Uri _baseUri; + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudLoadBalancerProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider) + : base(defaultIdentity, defaultRegion, identityProvider, null, null) + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing synchronous REST requests. If this value is , the provider will use a new instance of . + /// The HTTP status code validator to use for synchronous REST requests. If this value is , the provider will use . + protected CloudLoadBalancerProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService, IHttpResponseCodeValidator httpStatusCodeValidator) + : base(defaultIdentity, defaultRegion, identityProvider, restService, httpStatusCodeValidator) + { + } + + #region ILoadBalancerService Members + + /// + public Task> ListLoadBalancersAsync(LoadBalancerId markerId, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/loadbalancers?marker={markerId}&limit={limit}"); + var parameters = new Dictionary(); + if (markerId != null) + parameters.Add("markerId", markerId.Value); + if (limit != null) + { + if (markerId != null) + { + // the server includes the item with the ID "markerId" in the result. + parameters.Add("limit", (limit + 1).ToString()); + } + else + { + parameters.Add("limit", limit.ToString()); + } + } + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + if (task.Result == null || task.Result.LoadBalancers == null) + return ReadOnlyCollectionPage.Empty; + + ReadOnlyCollection result = task.Result.LoadBalancers; + if (markerId != null && result.Count > 0) + { + if (result[0].Id != markerId) + throw new InvalidOperationException("Expected the pagination result to include the marked load balancer."); + + // remove the marker so pagination behaves normally + result = new List(result.Skip(1)).AsReadOnly(); + } + + if (!result.Any()) + return ReadOnlyCollectionPage.Empty; + + LoadBalancerId nextMarker = result[result.Count - 1].Id; + Func>> getNextPageAsync = + nextCancellationToken => ListLoadBalancersAsync(nextMarker, limit, nextCancellationToken); + return new BasicReadOnlyCollectionPage(result, getNextPageAsync); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetLoadBalancerAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value } }; + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, LoadBalancer> resultSelector = + task => task.Result.LoadBalancer; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CreateLoadBalancerAsync(LoadBalancerConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/loadbalancers"); + var parameters = new Dictionary(); + + CreateLoadBalancerRequest requestBody = new CreateLoadBalancerRequest(configuration); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + LoadBalancer loadBalancer = task.Result.LoadBalancer; + if (loadBalancer != null && completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancer.Id, LoadBalancerStatus.Build, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(loadBalancer); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task UpdateLoadBalancerAsync(LoadBalancerId loadBalancerId, LoadBalancerUpdate configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value } }; + + UpdateLoadBalancerRequest requestBody = new UpdateLoadBalancerRequest(configuration); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveLoadBalancerAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value } }; + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingDelete, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveLoadBalancerRangeAsync(IEnumerable loadBalancerIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerIds == null) + throw new ArgumentNullException("loadBalancerIds"); + + return RemoveLoadBalancerRangeAsync(loadBalancerIds.ToArray(), completionOption, cancellationToken, progress); + } + + /// + /// Removes one or more load balancers. + /// + /// The IDs of load balancers to remove. These is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// A object representing the asynchronous operation. + /// + /// A object representing the asynchronous operation. If + /// is , + /// the task will not be considered complete until all of the load balancers + /// transition out of the state. + /// + /// If is . + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Load Balancer (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + public Task RemoveLoadBalancerRangeAsync(LoadBalancerId[] loadBalancerIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerIds == null) + throw new ArgumentNullException("loadBalancerIds"); + if (loadBalancerIds.Contains(null)) + throw new ArgumentException("loadBalancerIds cannot contain any null values", "loadBalancerIds"); + + if (loadBalancerIds.Length == 0) + { + return InternalTaskExtensions.CompletedTask(); + } + else if (loadBalancerIds.Length == 1) + { + IProgress wrapper = null; + if (progress != null) + wrapper = new ArrayElementProgressWrapper(progress); + + return RemoveLoadBalancerAsync(loadBalancerIds[0], completionOption, cancellationToken, wrapper); + } + else + { + UriTemplate template = new UriTemplate("/loadbalancers?id={id}"); + var parameters = new Dictionary { { "id", string.Join(",", Array.ConvertAll(loadBalancerIds, i => i.Value)) } }; + + Func uriTransform = + uri => + { + string path = uri.GetLeftPart(UriPartial.Path); + string query = uri.Query.Replace(",", "&id=").Replace("%2c", "&id="); + return new Uri(path + query); + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, uriTransform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancersToLeaveStateAsync(loadBalancerIds, LoadBalancerStatus.PendingDelete, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer[])); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + } + + /// + public Task GetErrorPageAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/errorpage"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, string> resultSelector = + task => task.Result != null ? task.Result.Content : null; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task SetErrorPageAsync(LoadBalancerId loadBalancerId, string content, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (content == null) + throw new ArgumentNullException("content"); + if (string.IsNullOrEmpty(content)) + throw new ArgumentException("content cannot be empty"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/errorpage"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + SetLoadBalancerErrorPageRequest requestBody = new SetLoadBalancerErrorPageRequest(content); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveErrorPageAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/errorpage"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task GetStatisticsAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/stats"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListNodesAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.Nodes : null) ?? new ReadOnlyCollection(new Node[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetNodeAsync(LoadBalancerId loadBalancerId, NodeId nodeId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeId == null) + throw new ArgumentNullException("nodeId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value }, { "nodeId", nodeId.Value } }; + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Node> resultSelector = + task => task.Result.Node; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task AddNodeAsync(LoadBalancerId loadBalancerId, NodeConfiguration nodeConfiguration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (nodeConfiguration == null) + throw new ArgumentNullException("nodeConfiguration"); + + Func>, Node> resultSelector = + task => task.Result.Single(); + + return + AddNodeRangeAsync(loadBalancerId, new[] { nodeConfiguration }, completionOption, cancellationToken, progress) + .Select(resultSelector); + } + + /// + public Task> AddNodeRangeAsync(LoadBalancerId loadBalancerId, IEnumerable nodeConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (nodeConfigurations == null) + throw new ArgumentNullException("nodeConfigurations"); + + return AddNodeRangeAsync(loadBalancerId, nodeConfigurations.ToArray(), completionOption, cancellationToken, progress); + } + + /// + /// Add one or more nodes to a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A collection of objects describing the load balancer nodes to add. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the new load balancer nodes. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Add Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + public Task> AddNodeRangeAsync(LoadBalancerId loadBalancerId, NodeConfiguration[] nodeConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeConfigurations == null) + throw new ArgumentNullException("nodeConfigurations"); + if (nodeConfigurations.Contains(null)) + throw new ArgumentException("nodeConfigurations cannot contain any null values", "nodeConfigurations"); + + if (nodeConfigurations.Length == 0) + { + return InternalTaskExtensions.CompletedTask(new ReadOnlyCollection(new Node[0])); + } + else + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + }; + + AddNodesRequest requestBody = new AddNodesRequest(nodeConfigurations); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task>> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + { + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress) + .Select(t => task.Result.Nodes); + } + + return InternalTaskExtensions.CompletedTask(task.Result.Nodes); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + } + + /// + public Task UpdateNodeAsync(LoadBalancerId loadBalancerId, NodeId nodeId, NodeUpdate configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeId == null) + throw new ArgumentNullException("nodeId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value }, { "nodeId", nodeId.Value } }; + + UpdateLoadBalancerNodeRequest requestBody = new UpdateLoadBalancerNodeRequest(configuration); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveNodeAsync(LoadBalancerId loadBalancerId, NodeId nodeId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeId == null) + throw new ArgumentNullException("nodeId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value }, { "nodeId", nodeId.Value } }; + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveNodeRangeAsync(LoadBalancerId loadBalancerId, IEnumerable nodeIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (nodeIds == null) + throw new ArgumentNullException("nodeIds"); + + return RemoveNodeRangeAsync(loadBalancerId, nodeIds.ToArray(), completionOption, cancellationToken, progress); + } + + /// + /// Remove one or more nodes from a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node IDs of nodes to remove. These are obtained from Node.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + public Task RemoveNodeRangeAsync(LoadBalancerId loadBalancerId, NodeId[] nodeIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeIds == null) + throw new ArgumentNullException("nodeIds"); + if (nodeIds.Contains(null)) + throw new ArgumentException("nodeIds cannot contain any null values", "nodeIds"); + + if (nodeIds.Length == 0) + { + return InternalTaskExtensions.CompletedTask(); + } + else if (nodeIds.Length == 1) + { + return RemoveNodeAsync(loadBalancerId, nodeIds[0], completionOption, cancellationToken, progress); + } + else + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes?id={id}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value }, { "id", string.Join(",", Array.ConvertAll(nodeIds, i => i.Value)) } }; + + Func uriTransform = + uri => + { + string path = uri.GetLeftPart(UriPartial.Path); + string query = uri.Query.Replace(",", "&id=").Replace("%2c", "&id="); + return new Uri(path + query); + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, uriTransform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + } + + /// + public Task> ListNodeServiceEventsAsync(LoadBalancerId loadBalancerId, NodeServiceEventId markerId, int? limit, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/events?marker={markerId}&limit={limit}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value } }; + if (markerId != null) + parameters.Add("markerId", markerId.Value); + if (limit != null) + { + if (markerId != null) + { + // the server includes the item with the ID "markerId" in the result. + parameters.Add("limit", (limit + 1).ToString()); + } + else + { + parameters.Add("limit", limit.ToString()); + } + } + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + if (task.Result == null || task.Result.NodeServiceEvents == null) + return ReadOnlyCollectionPage.Empty; + + ReadOnlyCollection result = task.Result.NodeServiceEvents; + if (markerId != null && result.Count > 0) + { + if (result[0].Id != markerId) + throw new InvalidOperationException("Expected the pagination result to include the marked node service event."); + + // remove the marker so pagination behaves normally + result = new List(result.Skip(1)).AsReadOnly(); + } + + if (!result.Any()) + return ReadOnlyCollectionPage.Empty; + + NodeServiceEventId nextMarker = result[result.Count - 1].Id; + Func>> getNextPageAsync = + nextCancellationToken => ListNodeServiceEventsAsync(loadBalancerId, nextMarker, limit, nextCancellationToken); + return new BasicReadOnlyCollectionPage(result, getNextPageAsync); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListVirtualAddressesAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/virtualips"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.VirtualAddresses : null) ?? new ReadOnlyCollection(new LoadBalancerVirtualAddress[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task AddVirtualAddressAsync(LoadBalancerId loadBalancerId, LoadBalancerVirtualAddressType type, AddressFamily addressFamily, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (type == null) + throw new ArgumentNullException("type"); + if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) + throw new ArgumentException("Unsupported address family.", "addressFamily"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/virtualips"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + }; + + LoadBalancerVirtualAddress requestBody = new LoadBalancerVirtualAddress(type, addressFamily); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + { + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress) + .Select(t => task.Result); + } + + return InternalTaskExtensions.CompletedTask(task.Result); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveVirtualAddressAsync(LoadBalancerId loadBalancerId, VirtualAddressId virtualAddressId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/virtualips/{virtualipId}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "virtualipId", virtualAddressId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveVirtualAddressRangeAsync(LoadBalancerId loadBalancerId, IEnumerable virtualAddressIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (virtualAddressIds == null) + throw new ArgumentNullException("virtualAddressIds"); + + return RemoveVirtualAddressRangeAsync(loadBalancerId, virtualAddressIds.ToArray(), completionOption, cancellationToken, progress); + } + + /// + /// Remove a collection of virtual addresses associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The virtual address IDs. These are obtained from LoadBalancerVirtualAddress.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Virtual IP (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + public Task RemoveVirtualAddressRangeAsync(LoadBalancerId loadBalancerId, VirtualAddressId[] virtualAddressIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (virtualAddressIds == null) + throw new ArgumentNullException("metadataIds"); + if (virtualAddressIds.Contains(null)) + throw new ArgumentException("virtualAddressIds cannot contain any null values", "virtualAddressIds"); + + if (virtualAddressIds.Length == 0) + { + return InternalTaskExtensions.CompletedTask(); + } + else if (virtualAddressIds.Length == 1) + { + return RemoveVirtualAddressAsync(loadBalancerId, virtualAddressIds[0], completionOption, cancellationToken, progress); + } + else + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/virtualips?id={id}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "id", string.Join(",", Array.ConvertAll(virtualAddressIds, i => i.Value)) } + }; + + Func uriTransform = + uri => + { + string path = uri.GetLeftPart(UriPartial.Path); + string query = uri.Query.Replace(",", "&id=").Replace("%2c", "&id="); + return new Uri(path + query); + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, uriTransform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + } + + /// + public Task> ListAllowedDomainsAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/loadbalancers/alloweddomains"); + Dictionary parameters = new Dictionary(); + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => new ReadOnlyCollection(task.Result.AllowedDomains.ToArray()); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListBillableLoadBalancersAsync(DateTimeOffset? startTime, DateTimeOffset? endTime, int? offset, int? limit, CancellationToken cancellationToken) + { + if (endTime < startTime) + throw new ArgumentOutOfRangeException("endTime"); + if (offset < 0) + throw new ArgumentOutOfRangeException("offset"); + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/loadbalancers/billable?startTime={startTime}&endTime={endTime}&offset={offset}&limit={limit}"); + var parameters = new Dictionary(); + if (startTime != null) + parameters.Add("startTime", startTime.Value.ToString("yyyy-MM-dd")); + if (endTime != null) + parameters.Add("endTime", endTime.Value.ToString("yyyy-MM-dd")); + if (offset != null) + parameters.Add("offset", offset.ToString()); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + ReadOnlyCollectionPage page = null; + if (task.Result != null && task.Result.LoadBalancers != null && task.Result.LoadBalancers.Count > 0) + { + int nextOffset = (offset ?? 0) + task.Result.LoadBalancers.Count; + Func>> getNextPageAsync = + nextCancellationToken => ListBillableLoadBalancersAsync(startTime, endTime, nextOffset, limit, nextCancellationToken); + page = new BasicReadOnlyCollectionPage(task.Result.LoadBalancers, getNextPageAsync); + } + + return page ?? ReadOnlyCollectionPage.Empty; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListAccountLevelUsageAsync(DateTimeOffset? startTime, DateTimeOffset? endTime, CancellationToken cancellationToken) + { + if (endTime < startTime) + throw new ArgumentOutOfRangeException("endTime"); + + UriTemplate template = new UriTemplate("/loadbalancers/usage?startTime={startTime}&endTime={endTime}"); + var parameters = new Dictionary(); + if (startTime != null) + parameters.Add("startTime", startTime.Value.ToString("yyyy-MM-dd")); + if (endTime != null) + parameters.Add("endTime", endTime.Value.ToString("yyyy-MM-dd")); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.UsageRecords : null) ?? new ReadOnlyCollection(new LoadBalancerUsage[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListHistoricalUsageAsync(LoadBalancerId loadBalancerId, DateTimeOffset? startTime, DateTimeOffset? endTime, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (endTime < startTime) + throw new ArgumentOutOfRangeException("endTime"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/usage?startTime={startTime}&endTime={endTime}"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value } }; + if (startTime != null) + parameters.Add("startTime", startTime.Value.ToString("yyyy-MM-dd")); + if (endTime != null) + parameters.Add("endTime", endTime.Value.ToString("yyyy-MM-dd")); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.UsageRecords : null) ?? new ReadOnlyCollection(new LoadBalancerUsage[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListCurrentUsageAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/usage/current"); + var parameters = new Dictionary { { "loadBalancerId", loadBalancerId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.UsageRecords : null) ?? new ReadOnlyCollection(new LoadBalancerUsage[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListAccessListAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/accesslist"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => task.Result.AccessList; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CreateAccessListAsync(LoadBalancerId loadBalancerId, NetworkItem networkItem, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (networkItem == null) + throw new ArgumentNullException("networkItem"); + + return CreateAccessListAsync(loadBalancerId, new[] { networkItem }, completionOption, cancellationToken, progress); + } + + /// + public Task CreateAccessListAsync(LoadBalancerId loadBalancerId, IEnumerable networkItems, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (networkItems == null) + throw new ArgumentNullException("networkItems"); + + return CreateAccessListAsync(loadBalancerId, networkItems.ToArray(), completionOption, cancellationToken, progress); + } + + /// + /// Add a collection of network items to the access list for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A collection of objects describing the network items to add to the load balancer's access list. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the network items added to the access list + /// for the load balancer. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + public Task CreateAccessListAsync(LoadBalancerId loadBalancerId, NetworkItem[] networkItems, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (networkItems == null) + throw new ArgumentNullException("networkItems"); + if (networkItems.Contains(null)) + throw new ArgumentException("networkItems cannot contain any null values"); + + if (networkItems.Length == 0) + { + return InternalTaskExtensions.CompletedTask(Enumerable.Empty()); + } + else + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/accesslist"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + }; + + CreateAccessListRequest requestBody = new CreateAccessListRequest(networkItems); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + } + + /// + public Task RemoveAccessListAsync(LoadBalancerId loadBalancerId, NetworkItemId networkItemId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (networkItemId == null) + throw new ArgumentNullException("networkItemId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/accesslist/{networkItemId}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "networkItemId", networkItemId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveAccessListRangeAsync(LoadBalancerId loadBalancerId, IEnumerable networkItemIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (networkItemIds == null) + throw new ArgumentNullException("networkItemIds"); + + return RemoveAccessListRangeAsync(loadBalancerId, networkItemIds.ToArray(), completionOption, cancellationToken, progress); + } + + /// + /// Remove a collection of network items from the access list of a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The network item IDs. These are obtained from . + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + public Task RemoveAccessListRangeAsync(LoadBalancerId loadBalancerId, NetworkItemId[] networkItemIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (networkItemIds == null) + throw new ArgumentNullException("networkItemIds"); + if (networkItemIds.Contains(null)) + throw new ArgumentException("networkItemIds cannot contain any null values", "networkItemIds"); + + if (networkItemIds.Length == 0) + { + return InternalTaskExtensions.CompletedTask(); + } + else if (networkItemIds.Length == 1) + { + return RemoveAccessListAsync(loadBalancerId, networkItemIds[0], completionOption, cancellationToken, progress); + } + else + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/accesslist?id={id}"); + var parameters = new Dictionary + { + { "loadBalancerId", loadBalancerId.Value }, + { "id", string.Join(",", Array.ConvertAll(networkItemIds, i => i.Value)) } + }; + + Func uriTransform = + uri => + { + string path = uri.GetLeftPart(UriPartial.Path); + string query = uri.Query.Replace(",", "&id=").Replace("%2c", "&id="); + return new Uri(path + query); + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, uriTransform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + } + + /// + public Task ClearAccessListAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/accesslist"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task GetHealthMonitorAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/healthmonitor"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, HealthMonitor> resultSelector = + task => + { + if (task.Result == null) + return null; + + JObject healthMonitorObject = task.Result["healthMonitor"] as JObject; + if (healthMonitorObject == null) + return null; + + return HealthMonitor.FromJObject(healthMonitorObject); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task SetHealthMonitorAsync(LoadBalancerId loadBalancerId, HealthMonitor monitor, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (monitor == null) + throw new ArgumentNullException("monitor"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/healthmonitor"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, monitor); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveHealthMonitorAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/healthmonitor"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task GetSessionPersistenceAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/sessionpersistence"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task SetSessionPersistenceAsync(LoadBalancerId loadBalancerId, SessionPersistence sessionPersistence, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (sessionPersistence == null) + throw new ArgumentNullException("sessionPersistence"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/sessionpersistence"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, sessionPersistence); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveSessionPersistenceAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/sessionpersistence"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task GetConnectionLoggingAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/connectionlogging"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, bool> resultSelector = + task => task.Result != null ? task.Result.Enabled ?? false : false; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task SetConnectionLoggingAsync(LoadBalancerId loadBalancerId, bool enabled, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/connectionlogging"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + SetLoadBalancerConnectionLoggingRequest request = new SetLoadBalancerConnectionLoggingRequest(enabled); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, request); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task ListThrottlesAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/connectionthrottle"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ConnectionThrottles> resultSelector = + task => task.Result.Throttles; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task UpdateThrottlesAsync(LoadBalancerId loadBalancerId, ConnectionThrottles throttleConfiguration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (throttleConfiguration == null) + throw new ArgumentNullException("throttleConfiguration"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/connectionthrottle"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, throttleConfiguration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveThrottlesAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/connectionthrottle"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task GetContentCachingAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/contentcaching"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, bool> resultSelector = + task => task.Result != null ? task.Result.Enabled ?? false : false; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task SetContentCachingAsync(LoadBalancerId loadBalancerId, bool enabled, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/contentcaching"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + SetLoadBalancerContentCachingRequest request = new SetLoadBalancerContentCachingRequest(enabled); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, request); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task> ListProtocolsAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/loadbalancers/protocols"); + var parameters = new Dictionary(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.Protocols : null) ?? new ReadOnlyCollection(new LoadBalancingProtocol[0]); + + // authenticate -> request resource -> check result -> parse result -> cache result -> return + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListAlgorithmsAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/loadbalancers/algorithms"); + var parameters = new Dictionary(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? new ReadOnlyCollection(task.Result.Algorithms.ToArray()) : null) ?? new ReadOnlyCollection(new LoadBalancingAlgorithm[0]); + + // authenticate -> request resource -> check result -> parse result -> cache result -> return + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetSslConfigurationAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/ssltermination"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, LoadBalancerSslConfiguration> resultSelector = + task => task.Result != null ? task.Result.SslConfiguration : null; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task UpdateSslConfigurationAsync(LoadBalancerId loadBalancerId, LoadBalancerSslConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/ssltermination"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + LoadBalancerSslConfiguration requestBody = configuration; + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task RemoveSslConfigurationAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/ssltermination"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, Task> resultSelector = + task => + { + if (completionOption == AsyncCompletionOption.RequestCompleted) + return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress); + + return InternalTaskExtensions.CompletedTask(default(LoadBalancer)); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Then(resultSelector); + } + + /// + public Task> ListLoadBalancerMetadataAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/metadata"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.Metadata : null) ?? new ReadOnlyCollection(new LoadBalancerMetadataItem[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetLoadBalancerMetadataItemAsync(LoadBalancerId loadBalancerId, MetadataId metadataId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (metadataId == null) + throw new ArgumentNullException("metadataId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/metadata/{metaId}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "metaId", metadataId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, LoadBalancerMetadataItem> resultSelector = + task => task.Result != null ? task.Result.MetadataItem : null; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListNodeMetadataAsync(LoadBalancerId loadBalancerId, NodeId nodeId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeId == null) + throw new ArgumentNullException("nodeId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}/metadata"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "nodeId", nodeId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.Metadata : null) ?? new ReadOnlyCollection(new LoadBalancerMetadataItem[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetNodeMetadataItemAsync(LoadBalancerId loadBalancerId, NodeId nodeId, MetadataId metadataId, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeId == null) + throw new ArgumentNullException("nodeId"); + if (metadataId == null) + throw new ArgumentNullException("metadataId"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}/metadata/{metaId}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "nodeId", nodeId.Value }, + { "metaId", metadataId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, LoadBalancerMetadataItem> resultSelector = + task => task.Result != null ? task.Result.MetadataItem : null; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> AddLoadBalancerMetadataAsync(LoadBalancerId loadBalancerId, IEnumerable> metadata, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/metadata"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + }; + + AddLoadBalancerMetadataRequest requestBody = new AddLoadBalancerMetadataRequest(metadata); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.Metadata : null) ?? new ReadOnlyCollection(new LoadBalancerMetadataItem[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> AddNodeMetadataAsync(LoadBalancerId loadBalancerId, NodeId nodeId, IEnumerable> metadata, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeId == null) + throw new ArgumentNullException("nodeId"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}/metadata"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "nodeId", nodeId.Value }, + }; + + AddLoadBalancerMetadataRequest requestBody = new AddLoadBalancerMetadataRequest(metadata); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => (task.Result != null ? task.Result.Metadata : null) ?? new ReadOnlyCollection(new LoadBalancerMetadataItem[0]); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task UpdateLoadBalancerMetadataItemAsync(LoadBalancerId loadBalancerId, MetadataId metadataId, string value, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (metadataId == null) + throw new ArgumentNullException("metadataId"); + if (value == null) + throw new ArgumentNullException("value"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/metadata/{metaId}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "metaId", metadataId.Value } + }; + + UpdateLoadBalancerMetadataItemRequest requestBody = new UpdateLoadBalancerMetadataItemRequest(value); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateNodeMetadataItemAsync(LoadBalancerId loadBalancerId, NodeId nodeId, MetadataId metadataId, string value, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeId == null) + throw new ArgumentNullException("nodeId"); + if (metadataId == null) + throw new ArgumentNullException("metadataId"); + if (value == null) + throw new ArgumentNullException("value"); + + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}/metadata/{metaId}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "nodeId", nodeId.Value }, + { "metaId", metadataId.Value } + }; + + UpdateLoadBalancerMetadataItemRequest requestBody = new UpdateLoadBalancerMetadataItemRequest(value); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, requestBody); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task RemoveLoadBalancerMetadataItemAsync(LoadBalancerId loadBalancerId, IEnumerable metadataIds, CancellationToken cancellationToken) + { + if (metadataIds == null) + throw new ArgumentNullException("metadataIds"); + + return RemoveLoadBalancerMetadataItemAsync(loadBalancerId, metadataIds.ToArray(), cancellationToken); + } + + /// + /// Removes one or more metadata items associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The metadata item IDs. These are obtained from LoadBalancerMetadataItem.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + public Task RemoveLoadBalancerMetadataItemAsync(LoadBalancerId loadBalancerId, MetadataId[] metadataIds, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (metadataIds == null) + throw new ArgumentNullException("metadataIds"); + if (metadataIds.Contains(null)) + throw new ArgumentException("metadataIds cannot contain any null values", "metadataIds"); + + if (metadataIds.Length == 0) + { + return InternalTaskExtensions.CompletedTask(); + } + else if (metadataIds.Length == 1) + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/metadata/{metaId}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "metaId", metadataIds[0].Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + else + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/metadata?id={id}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "id", string.Join(",", Array.ConvertAll(metadataIds, i => i.Value)) } + }; + + Func uriTransform = + uri => + { + string path = uri.GetLeftPart(UriPartial.Path); + string query = uri.Query.Replace(",", "&id=").Replace("%2c", "&id="); + return new Uri(path + query); + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, uriTransform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + } + + /// + public Task RemoveNodeMetadataItemAsync(LoadBalancerId loadBalancerId, NodeId nodeId, IEnumerable metadataIds, CancellationToken cancellationToken) + { + if (metadataIds == null) + throw new ArgumentNullException("metadataIds"); + + return RemoveNodeMetadataItemAsync(loadBalancerId, nodeId, metadataIds.ToArray(), cancellationToken); + } + + /// + /// Removes one or more metadata items associated with a load balancer node. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The metadata item IDs. These are obtained from LoadBalancerMetadataItem.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + public Task RemoveNodeMetadataItemAsync(LoadBalancerId loadBalancerId, NodeId nodeId, MetadataId[] metadataIds, CancellationToken cancellationToken) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (nodeId == null) + throw new ArgumentNullException("nodeId"); + if (metadataIds == null) + throw new ArgumentNullException("metadataIds"); + if (metadataIds.Contains(null)) + throw new ArgumentException("metadataIds cannot contain any null values", "metadataIds"); + + if (metadataIds.Length == 0) + { + return InternalTaskExtensions.CompletedTask(); + } + else if (metadataIds.Length == 1) + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}/metadata/{metaId}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "nodeId", nodeId.Value }, + { "metaId", metadataIds[0].Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + else + { + UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/nodes/{nodeId}/metadata?id={id}"); + var parameters = new Dictionary() + { + { "loadBalancerId", loadBalancerId.Value }, + { "nodeId", nodeId.Value }, + { "id", string.Join(",", Array.ConvertAll(metadataIds, i => i.Value)) } + }; + + Func uriTransform = + uri => + { + string path = uri.GetLeftPart(UriPartial.Path); + string query = uri.Query.Replace(",", "&id=").Replace("%2c", "&id="); + return new Uri(path + query); + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, uriTransform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + } + + #endregion + + /// + /// Creates a that will complete after a load balancer leaves a particular state. + /// + /// + /// The task is considered complete as soon as a call to + /// indicates that the load balancer is not in the state specified by . The method + /// does not perform any other checks related to the initial or final state of the load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A representing the state the load balancer should not be in at the end of the wait operation. + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// object representing the load balancer. In addition, the load + /// property of the load balancer will not be + /// equal to . + /// + /// + /// If is . + /// -or- + /// If is . + /// + protected Task WaitForLoadBalancerToLeaveStateAsync(LoadBalancerId loadBalancerId, LoadBalancerStatus state, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (state == null) + throw new ArgumentNullException("state"); + + TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); + Func> pollLoadBalancer = () => PollLoadBalancerStateAsync(loadBalancerId, cancellationToken, progress); + + IEnumerator backoffPolicy = BackoffPolicy.GetBackoffIntervals().GetEnumerator(); + Func> moveNext = + () => + { + if (!backoffPolicy.MoveNext()) + throw new OperationCanceledException(); + + if (backoffPolicy.Current == TimeSpan.Zero) + { + return pollLoadBalancer(); + } + else + { + return Task.Factory.StartNewDelayed((int)backoffPolicy.Current.TotalMilliseconds, cancellationToken) + .Then(task => pollLoadBalancer()); + } + }; + + Task currentTask = moveNext(); + Action> continuation = null; + continuation = + previousTask => + { + if (previousTask.Status != TaskStatus.RanToCompletion) + { + taskCompletionSource.SetFromTask(previousTask); + return; + } + + LoadBalancer result = previousTask.Result; + if (result == null || result.Status != state) + { + // finished waiting + taskCompletionSource.SetResult(result); + return; + } + + // reschedule + currentTask = moveNext(); + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + }; + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + + return taskCompletionSource.Task; + } + + /// + /// Asynchronously poll the current state of a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object containing the + /// updated state information for the load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + private Task PollLoadBalancerStateAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken, IProgress progress) + { + Task chain = GetLoadBalancerAsync(loadBalancerId, cancellationToken); + chain = chain.Select( + task => + { + if (task.Result == null || task.Result.Id != loadBalancerId) + throw new InvalidOperationException("Could not obtain status for load balancer"); + + return task.Result; + }); + + if (progress != null) + { + chain = chain.Select( + task => + { + progress.Report(task.Result); + return task.Result; + }); + } + + return chain; + } + + /// + /// Creates a that will complete after a group of load balancers all leave a particular state. + /// + /// + /// The task is considered complete as soon as calls to + /// indicates that none of the load balancers are in the state specified by . The method + /// does not perform any other checks related to the initial or final state of the load balancers. + /// + /// The load balancer IDs. These are obtained from LoadBalancer.Id. + /// A representing the state the load balancers should not be in at the end of the wait operation. + /// The that the task will observe. + /// An optional callback object to receive progress notifications. If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// collection of objects representing the load balancers. In + /// addition, the load property of the load balancer will + /// not be equal to for any of the load balancer + /// instances. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If contains any values. + protected Task WaitForLoadBalancersToLeaveStateAsync(LoadBalancerId[] loadBalancerIds, LoadBalancerStatus state, CancellationToken cancellationToken, IProgress progress) + { + if (loadBalancerIds == null) + throw new ArgumentNullException("loadBalancerIds"); + if (state == null) + throw new ArgumentNullException("state"); + if (loadBalancerIds.Contains(null)) + throw new ArgumentException("loadBalancerIds cannot contain any null values"); + + TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); + Func> pollLoadBalancers = + () => + { + Task[] tasks = Array.ConvertAll( + loadBalancerIds, + loadBalancerId => + { + return PollLoadBalancerStateAsync(loadBalancerId, cancellationToken, null); + }); + + return Task.Factory.WhenAll(tasks).Select( + completedTasks => + { + LoadBalancer[] loadBalancers = Array.ConvertAll(completedTasks.Result, completedTask => completedTask.Result); + if (progress != null) + progress.Report(loadBalancers); + + return loadBalancers; + }); + }; + + IEnumerator backoffPolicy = BackoffPolicy.GetBackoffIntervals().GetEnumerator(); + Func> moveNext = + () => + { + if (!backoffPolicy.MoveNext()) + throw new OperationCanceledException(); + + if (backoffPolicy.Current == TimeSpan.Zero) + { + return pollLoadBalancers(); + } + else + { + return Task.Factory.StartNewDelayed((int)backoffPolicy.Current.TotalMilliseconds, cancellationToken) + .Then(task => pollLoadBalancers()); + } + }; + + Task currentTask = moveNext(); + Action> continuation = null; + continuation = + previousTask => + { + if (previousTask.Status != TaskStatus.RanToCompletion) + { + taskCompletionSource.SetFromTask(previousTask); + return; + } + + LoadBalancer[] results = previousTask.Result; + if (results.All(result => result == null || result.Status == state)) + { + // finished waiting + taskCompletionSource.SetResult(results); + return; + } + + // reschedule + currentTask = moveNext(); + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + }; + // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks + currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously); + + return taskCompletionSource.Task; + } + + /// + /// + /// This method returns a cached base address if one is available. If no cached address is + /// available, is called to obtain + /// an with the type rax:load-balancer and preferred type cloudLoadBalancers. + /// + protected override Task GetBaseUriAsync(CancellationToken cancellationToken) + { + if (_baseUri != null) + { + return InternalTaskExtensions.CompletedTask(_baseUri); + } + + return Task.Factory.StartNew( + () => + { + Endpoint endpoint = GetServiceEndpoint(null, "rax:load-balancer", "cloudLoadBalancers", null); + _baseUri = new Uri(endpoint.PublicURL); + return _baseUri; + }); + } + + /// + /// This class provides a wrapper implementation of which + /// wraps a single progress report values into a single-element array. + /// + /// The type of progress update value. + private class ArrayElementProgressWrapper : IProgress + { + /// + /// The delegate progress handler to dispatch progress reports to. + /// + private readonly IProgress _delegate; + + /// + /// Initializes a new instance of the class + /// that dispatches progress reports to the specified delegate. The reported progress + /// values are wrapped in a single-element array. + /// + /// The delegate to dispatch progress reports to. + /// If is . + public ArrayElementProgressWrapper(IProgress @delegate) + { + if (@delegate == null) + throw new ArgumentNullException("delegate"); + + _delegate = @delegate; + } + + /// + public void Report(T value) + { + _delegate.Report(new T[] { value }); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudMonitoringProvider.cs b/src/OpenStack/Providers/Rackspace/CloudMonitoringProvider.cs new file mode 100644 index 000000000..6e1511712 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudMonitoringProvider.cs @@ -0,0 +1,2103 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Net; + using System.Threading.Tasks; + using net.openstack.Core; + using net.openstack.Core.Domain; + using net.openstack.Core.Providers; + using net.openstack.Providers.Rackspace.Objects.Monitoring; + using Newtonsoft.Json.Linq; + using CancellationToken = System.Threading.CancellationToken; + using HttpMethod = JSIStudios.SimpleRESTServices.Client.HttpMethod; + using HttpResponseCodeValidator = net.openstack.Providers.Rackspace.Validators.HttpResponseCodeValidator; + using IHttpResponseCodeValidator = net.openstack.Core.Validators.IHttpResponseCodeValidator; + using IRestService = JSIStudios.SimpleRESTServices.Client.IRestService; + using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices; + + /// + /// Provides an implementation of for operating + /// with Rackspace's Cloud Monitoring product. + /// + /// Rackspace Cloud Monitoring Developer Guide - API v1.0 + /// + /// + public class CloudMonitoringProvider : ProviderBase, IMonitoringService + { + /// + /// This field caches the base URI used for accessing the Cloud Monitoring service. + /// + /// + private Uri _baseUri; + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudMonitoringProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider) + : base(defaultIdentity, defaultRegion, identityProvider, null, null) + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing synchronous REST requests. If this value is , the provider will use a new instance of . + /// The HTTP status code validator to use for synchronous REST requests. If this value is , the provider will use . + protected CloudMonitoringProvider(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService, IHttpResponseCodeValidator httpStatusCodeValidator) + : base(defaultIdentity, defaultRegion, identityProvider, restService, httpStatusCodeValidator) + { + } + + #region IMonitoringService Members + + /// + public Task GetAccountAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/account"); + var parameters = new Dictionary(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateAccountAsync(MonitoringAccountId accountId, AccountConfiguration configuration, CancellationToken cancellationToken) + { + if (accountId == null) + throw new ArgumentNullException("accountId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/account"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task GetLimitsAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/limits"); + var parameters = new Dictionary(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListAuditsAsync(AuditId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/audits?marker={marker}&limit={limit}&from={from}&to={to}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + if (from != null) + parameters.Add("from", from.Value.ToTimestamp().ToString()); + if (to != null) + parameters.Add("to", to.Value.ToTimestamp().ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + Audit[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAuditsAsync(nextMarker, limit, from, to, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CreateEntityAsync(NewEntityConfiguration configuration, CancellationToken cancellationToken) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/entities"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func>, Task> parseResult = + task => + { + UriTemplate entityTemplate = new UriTemplate("/entities/{entityId}"); + string location = task.Result.Item1.Headers[HttpResponseHeader.Location]; + UriTemplateMatch match = entityTemplate.Match(_baseUri, new Uri(location)); + return InternalTaskExtensions.CompletedTask(new EntityId(match.BoundVariables["entityId"])); + }; + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken, parseResult); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListEntitiesAsync(EntityId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/entities?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + Entity[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListEntitiesAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetEntityAsync(EntityId entityId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateEntityAsync(EntityId entityId, UpdateEntityConfiguration configuration, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/entities/{entityId}"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task RemoveEntityAsync(EntityId entityId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task CreateCheckAsync(EntityId entityId, NewCheckConfiguration configuration, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/checks"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func>, Task> parseResult = + task => + { + UriTemplate entityTemplate = new UriTemplate("/entities/{entityId}/checks/{checkId}"); + string location = task.Result.Item1.Headers[HttpResponseHeader.Location]; + UriTemplateMatch match = entityTemplate.Match(_baseUri, new Uri(location)); + return InternalTaskExtensions.CompletedTask(new CheckId(match.BoundVariables["checkId"])); + }; + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken, parseResult); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> TestCheckAsync(EntityId entityId, NewCheckConfiguration configuration, bool? debug, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/test-check?debug={debug}"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + if (debug != null) + parameters.Add("debug", debug.ToString()); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func, Task>> requestResource = + GetResponseAsyncFunc>(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> TestExistingCheckAsync(EntityId entityId, CheckId checkId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (checkId == null) + throw new ArgumentNullException("checkId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/checks/{checkId}/test"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "checkId", checkId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters); + + Func, Task>> requestResource = + GetResponseAsyncFunc>(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListChecksAsync(EntityId entityId, CheckId marker, int? limit, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/checks?marker={marker}&limit={limit}"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + Check[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListChecksAsync(entityId, nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetCheckAsync(EntityId entityId, CheckId checkId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (checkId == null) + throw new ArgumentNullException("checkId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/checks/{checkId}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "checkId", checkId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateCheckAsync(EntityId entityId, CheckId checkId, UpdateCheckConfiguration configuration, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (checkId == null) + throw new ArgumentNullException("checkId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/checks/{checkId}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "checkId", checkId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task RemoveCheckAsync(EntityId entityId, CheckId checkId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (checkId == null) + throw new ArgumentNullException("checkId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/checks/{checkId}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "checkId", checkId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListCheckTypesAsync(CheckTypeId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/check_types?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + CheckType[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListCheckTypesAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetCheckTypeAsync(CheckTypeId checkTypeId, CancellationToken cancellationToken) + { + if (checkTypeId == null) + throw new ArgumentNullException("checkTypeId"); + + UriTemplate template = new UriTemplate("/check_types/{checkTypeId}"); + var parameters = new Dictionary { { "checkTypeId", checkTypeId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListMetricsAsync(EntityId entityId, CheckId checkId, MetricName marker, int? limit, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (checkId == null) + throw new ArgumentNullException("checkId"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/checks/{checkId}/metrics?marker={marker}&limit={limit}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "checkId", checkId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + Metric[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListMetricsAsync(entityId, checkId, nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> GetDataPointsAsync(EntityId entityId, CheckId checkId, MetricName metricName, int? points, DataPointGranularity resolution, IEnumerable select, DateTimeOffset from, DateTimeOffset to, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (checkId == null) + throw new ArgumentNullException("checkId"); + if (metricName == null) + throw new ArgumentNullException("metricName"); + if (points <= 0) + throw new ArgumentOutOfRangeException("points"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/checks/{checkId}/metrics/{metricName}/plot?points={points}&resolution={resolution}&SELECT={select}&from={from}&to={to}"); + var parameters = new Dictionary + { + { "entityId", entityId.Value }, + { "checkId", checkId.Value }, + { "metricName", metricName.Value }, + { "from",from.ToTimestamp().ToString() }, + { "to", to.ToTimestamp().ToString() } + }; + if (points != null) + parameters.Add("points", points.ToString()); + if (resolution != null) + parameters.Add("resolution", resolution.Name); + if (select != null) + parameters.Add("select", "select"); + + Func transform = + uri => + { + UriBuilder builder = new UriBuilder(uri); + if (builder.Query != null && select != null) + builder.Query = builder.Query.Substring(1).Replace("SELECT=select", string.Join("&", select.Select(i => "select=" + i.Name).ToArray())); + + return builder.Uri; + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters, transform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + return valuesToken.ToObject>(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task CreateAlarmAsync(EntityId entityId, NewAlarmConfiguration configuration, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/alarms"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func>, Task> parseResult = + task => + { + UriTemplate entityTemplate = new UriTemplate("/entities/{entityId}/alarms/{alarmId}"); + string location = task.Result.Item1.Headers[HttpResponseHeader.Location]; + UriTemplateMatch match = entityTemplate.Match(_baseUri, new Uri(location)); + return InternalTaskExtensions.CompletedTask(new AlarmId(match.BoundVariables["alarmId"])); + }; + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken, parseResult); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> TestAlarmAsync(EntityId entityId, TestAlarmConfiguration configuration, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/test-alarm"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func, Task>> requestResource = + GetResponseAsyncFunc>(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListAlarmsAsync(EntityId entityId, AlarmId marker, int? limit, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/alarms?marker={marker}&limit={limit}"); + var parameters = new Dictionary { { "entityId", entityId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + Alarm[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAlarmsAsync(entityId, nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetAlarmAsync(EntityId entityId, AlarmId alarmId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (alarmId == null) + throw new ArgumentNullException("alarmId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/alarms/{alarmId}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "alarmId", alarmId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateAlarmAsync(EntityId entityId, AlarmId alarmId, UpdateAlarmConfiguration configuration, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (alarmId == null) + throw new ArgumentNullException("alarmId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/alarms/{alarmId}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "alarmId", alarmId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task RemoveAlarmAsync(EntityId entityId, AlarmId alarmId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (alarmId == null) + throw new ArgumentNullException("alarmId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/alarms/{alarmId}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "alarmId", alarmId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task CreateNotificationPlanAsync(NewNotificationPlanConfiguration configuration, CancellationToken cancellationToken) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/notification_plans"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func>, Task> parseResult = + task => + { + UriTemplate entityTemplate = new UriTemplate("/notification_plans/{notificationPlanId}"); + string location = task.Result.Item1.Headers[HttpResponseHeader.Location]; + UriTemplateMatch match = entityTemplate.Match(_baseUri, new Uri(location)); + return InternalTaskExtensions.CompletedTask(new NotificationPlanId(match.BoundVariables["notificationPlanId"])); + }; + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken, parseResult); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListNotificationPlansAsync(NotificationPlanId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/notification_plans?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + NotificationPlan[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListNotificationPlansAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetNotificationPlanAsync(NotificationPlanId notificationPlanId, CancellationToken cancellationToken) + { + if (notificationPlanId == null) + throw new ArgumentNullException("notificationPlanId"); + + UriTemplate template = new UriTemplate("/notification_plans/{notificationPlanId}"); + var parameters = new Dictionary { { "notificationPlanId", notificationPlanId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateNotificationPlanAsync(NotificationPlanId notificationPlanId, UpdateNotificationPlanConfiguration configuration, CancellationToken cancellationToken) + { + if (notificationPlanId == null) + throw new ArgumentNullException("notificationPlanId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/notification_plans/{notificationPlanId}"); + var parameters = new Dictionary { { "notificationPlanId", notificationPlanId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task RemoveNotificationPlanAsync(NotificationPlanId notificationPlanId, CancellationToken cancellationToken) + { + if (notificationPlanId == null) + throw new ArgumentNullException("notificationPlanId"); + + UriTemplate template = new UriTemplate("/notification_plans/{notificationPlanId}"); + var parameters = new Dictionary { { "notificationPlanId", notificationPlanId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListMonitoringZonesAsync(MonitoringZoneId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/monitoring_zones?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + MonitoringZone[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListMonitoringZonesAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetMonitoringZoneAsync(MonitoringZoneId monitoringZoneId, CancellationToken cancellationToken) + { + if (monitoringZoneId == null) + throw new ArgumentNullException("monitoringZoneId"); + + UriTemplate template = new UriTemplate("/monitoring_zones/{monitoringZoneId}"); + var parameters = new Dictionary { { "monitoringZoneId", monitoringZoneId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task PerformTraceRouteFromMonitoringZoneAsync(MonitoringZoneId monitoringZoneId, TraceRouteConfiguration configuration, CancellationToken cancellationToken) + { + if (monitoringZoneId == null) + throw new ArgumentNullException("monitoringZoneId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/monitoring_zones/{monitoringZoneId}/traceroute"); + var parameters = new Dictionary { { "monitoringZoneId", monitoringZoneId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> DiscoverAlarmNotificationHistoryAsync(EntityId entityId, AlarmId alarmId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (alarmId == null) + throw new ArgumentNullException("alarmId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/alarms/{alarmId}/notification_history"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "alarmId", alarmId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollection> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken checkIdsToken = result["check_ids"]; + if (checkIdsToken == null) + return null; + + return checkIdsToken.ToObject>(); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListAlarmNotificationHistoryAsync(EntityId entityId, AlarmId alarmId, CheckId checkId, AlarmNotificationHistoryItemId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (alarmId == null) + throw new ArgumentNullException("alarmId"); + if (checkId == null) + throw new ArgumentNullException("checkId"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/alarms/{alarmId}/notification_history/{checkId}?marker={marker}&limit={limit}&from={from}&to={to}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "alarmId", alarmId.Value }, { "checkId", checkId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + if (from != null) + parameters.Add("from", from.Value.ToTimestamp().ToString()); + if (to != null) + parameters.Add("to", to.Value.ToTimestamp().ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + AlarmNotificationHistoryItem[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAlarmNotificationHistoryAsync(entityId, alarmId, checkId, nextMarker, limit, from, to, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetAlarmNotificationHistoryAsync(EntityId entityId, AlarmId alarmId, CheckId checkId, AlarmNotificationHistoryItemId alarmNotificationHistoryItemId, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (alarmId == null) + throw new ArgumentNullException("alarmId"); + if (checkId == null) + throw new ArgumentNullException("checkId"); + if (alarmNotificationHistoryItemId == null) + throw new ArgumentNullException("alarmNotificationHistoryItemId"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/alarms/{alarmId}/notification_history/{checkId}/{uuid}"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "alarmId", alarmId.Value }, { "checkId", checkId.Value }, { "uuid", alarmNotificationHistoryItemId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task CreateNotificationAsync(NewNotificationConfiguration configuration, CancellationToken cancellationToken) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/notifications"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func>, Task> parseResult = + task => + { + UriTemplate entityTemplate = new UriTemplate("/notifications/{notificationId}"); + string location = task.Result.Item1.Headers[HttpResponseHeader.Location]; + UriTemplateMatch match = entityTemplate.Match(_baseUri, new Uri(location)); + return InternalTaskExtensions.CompletedTask(new NotificationId(match.BoundVariables["notificationId"])); + }; + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken, parseResult); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task TestNotificationAsync(NewNotificationConfiguration configuration, CancellationToken cancellationToken) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/test-notification"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task TestExistingNotificationAsync(NotificationId notificationId, CancellationToken cancellationToken) + { + if (notificationId == null) + throw new ArgumentNullException("notificationId"); + + UriTemplate template = new UriTemplate("/notifications/{notificationId}/test"); + var parameters = new Dictionary { { "notificationId", notificationId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListNotificationsAsync(NotificationId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/notifications?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + Notification[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListNotificationsAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetNotificationAsync(NotificationId notificationId, CancellationToken cancellationToken) + { + if (notificationId == null) + throw new ArgumentNullException("notificationId"); + + UriTemplate template = new UriTemplate("/notifications/{notificationId}"); + var parameters = new Dictionary { { "notificationId", notificationId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateNotificationAsync(NotificationId notificationId, UpdateNotificationConfiguration configuration, CancellationToken cancellationToken) + { + if (notificationId == null) + throw new ArgumentNullException("notificationId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/notifications/{notificationId}"); + var parameters = new Dictionary { { "notificationId", notificationId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task RemoveNotificationAsync(NotificationId notificationId, CancellationToken cancellationToken) + { + if (notificationId == null) + throw new ArgumentNullException("notificationId"); + + UriTemplate template = new UriTemplate("/notifications/{notificationId}"); + var parameters = new Dictionary { { "notificationId", notificationId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListNotificationTypesAsync(NotificationTypeId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/notification_types?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + NotificationType[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListNotificationTypesAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetNotificationTypeAsync(NotificationTypeId notificationTypeId, CancellationToken cancellationToken) + { + if (notificationTypeId == null) + throw new ArgumentNullException("notificationTypeId"); + + UriTemplate template = new UriTemplate("/notification_types/{notificationTypeId}"); + var parameters = new Dictionary { { "notificationTypeId", notificationTypeId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListAlarmChangelogsAsync(AlarmChangelogId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to, CancellationToken cancellationToken) + { + return ListAlarmChangelogsAsync(null, marker, limit, from, to, cancellationToken); + } + + /// + public Task> ListAlarmChangelogsAsync(EntityId entityId, AlarmChangelogId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/changelogs/alarms?entityId={entityId}&marker={marker}&limit={limit}&from={from}&to={to}"); + var parameters = new Dictionary(); + if (entityId != null) + parameters.Add("entityId", entityId.Value); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + if (from != null) + parameters.Add("from", from.Value.ToTimestamp().ToString()); + if (to != null) + parameters.Add("to", to.Value.ToTimestamp().ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + AlarmChangelog[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAlarmChangelogsAsync(entityId, nextMarker, limit, from, to, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListEntityOverviewsAsync(EntityId marker, int? limit, CancellationToken cancellationToken) + { + IEnumerable entityIdFilter = null; + return ListEntityOverviewsAsync(marker, limit, entityIdFilter, cancellationToken); + } + + /// + public Task> ListEntityOverviewsAsync(EntityId marker, int? limit, IEnumerable entityIdFilter, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/views/overview?ENTITYID={entityIdFilter}&marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + if (entityIdFilter != null) + parameters.Add("entityIdFilter", "entityIdFilter"); + + Func transform = + uri => + { + UriBuilder builder = new UriBuilder(uri); + if (builder.Query != null && entityIdFilter != null) + builder.Query = builder.Query.Substring(1).Replace("ENTITYID=entityIdFilter", string.Join("&", entityIdFilter.Select(i => "entityId=" + i.Value).ToArray())); + + return builder.Uri; + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters, transform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + EntityOverview[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListEntityOverviewsAsync(nextMarker, limit, entityIdFilter, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task> ListAlarmExamplesAsync(AlarmExampleId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/alarm_examples?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + AlarmExample[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAlarmExamplesAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetAlarmExampleAsync(AlarmExampleId alarmExampleId, CancellationToken cancellationToken) + { + if (alarmExampleId == null) + throw new ArgumentNullException("alarmExampleId"); + + UriTemplate template = new UriTemplate("/alarm_examples/{alarmExampleId}"); + var parameters = new Dictionary { { "alarmExampleId", alarmExampleId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task EvaluateAlarmExampleAsync(AlarmExampleId alarmExampleId, IDictionary exampleParameters, CancellationToken cancellationToken) + { + if (alarmExampleId == null) + throw new ArgumentNullException("alarmExampleId"); + + UriTemplate template = new UriTemplate("/alarm_examples/{alarmExampleId}"); + var parameters = new Dictionary { { "alarmExampleId", alarmExampleId.Value } }; + + JObject body = new JObject( + new JProperty("values", JObject.FromObject(exampleParameters))); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, body); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListAgentsAsync(AgentId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/agents?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + Agent[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAgentsAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetAgentAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + UriTemplate template = new UriTemplate("/agents/{agentId}"); + var parameters = new Dictionary { { "agentId", agentId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListAgentConnectionsAsync(AgentId agentId, AgentConnectionId marker, int? limit, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/agents/{agentId}/connections?marker={marker}&limit={limit}"); + var parameters = new Dictionary { { "agentId", agentId.Value } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + AgentConnection[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAgentConnectionsAsync(agentId, nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetAgentConnectionAsync(AgentId agentId, AgentConnectionId agentConnectionId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + if (agentConnectionId == null) + throw new ArgumentNullException("agentConnectionId"); + + UriTemplate template = new UriTemplate("/agents/{agentId}/connections/{connId}"); + var parameters = new Dictionary { { "agentId", agentId.Value }, { "connId", agentConnectionId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task CreateAgentTokenAsync(AgentTokenConfiguration configuration, CancellationToken cancellationToken) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/agent_tokens"); + var parameters = new Dictionary(); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, configuration); + + Func>, Task> parseResult = + task => + { + UriTemplate agentTokenTemplate = new UriTemplate("/agent_tokens/{tokenId}"); + string location = task.Result.Item1.Headers[HttpResponseHeader.Location]; + UriTemplateMatch match = agentTokenTemplate.Match(_baseUri, new Uri(location)); + return InternalTaskExtensions.CompletedTask(new AgentTokenId(match.BoundVariables["tokenId"])); + }; + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken, parseResult); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListAgentTokensAsync(AgentTokenId marker, int? limit, CancellationToken cancellationToken) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/agent_tokens?marker={marker}&limit={limit}"); + var parameters = new Dictionary(); + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + AgentToken[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAgentTokensAsync(nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetAgentTokenAsync(AgentTokenId agentTokenId, CancellationToken cancellationToken) + { + if (agentTokenId == null) + throw new ArgumentNullException("agentTokenId"); + + UriTemplate template = new UriTemplate("/agent_tokens/{tokenId}"); + var parameters = new Dictionary { { "tokenId", agentTokenId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task UpdateAgentTokenAsync(AgentTokenId agentTokenId, AgentTokenConfiguration configuration, CancellationToken cancellationToken) + { + if (agentTokenId == null) + throw new ArgumentNullException("agentTokenId"); + if (configuration == null) + throw new ArgumentNullException("configuration"); + + UriTemplate template = new UriTemplate("/agent_tokens/{tokenId}"); + var parameters = new Dictionary { { "tokenId", agentTokenId.Value } }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, configuration); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task RemoveAgentTokenAsync(AgentTokenId agentTokenId, CancellationToken cancellationToken) + { + if (agentTokenId == null) + throw new ArgumentNullException("agentTokenId"); + + UriTemplate template = new UriTemplate("/agent_tokens/{tokenId}"); + var parameters = new Dictionary { { "tokenId", agentTokenId.Value } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> GetAgentHostInformationAsync(AgentId agentId, HostInformationType hostInformation, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + if (hostInformation == null) + throw new ArgumentNullException("hostInformation"); + + return GetAgentHostInformationAsync(agentId, hostInformation, cancellationToken); + } + + /// + public Task>> GetCpuInformationAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + return GetAgentHostInformationAsync>(agentId, HostInformationType.Cpus, cancellationToken); + } + + /// + public Task>> GetDiskInformationAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + return GetAgentHostInformationAsync>(agentId, HostInformationType.Disks, cancellationToken); + } + + /// + public Task>> GetFilesystemInformationAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + return GetAgentHostInformationAsync>(agentId, HostInformationType.Filesystems, cancellationToken); + } + + /// + public Task> GetMemoryInformationAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + return GetAgentHostInformationAsync(agentId, HostInformationType.Memory, cancellationToken); + } + + /// + public Task>> GetNetworkInterfaceInformationAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + return GetAgentHostInformationAsync>(agentId, HostInformationType.NetworkInterfaces, cancellationToken); + } + + /// + public Task>> GetProcessInformationAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + return GetAgentHostInformationAsync>(agentId, HostInformationType.Processes, cancellationToken); + } + + /// + public Task> GetSystemInformationAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + return GetAgentHostInformationAsync(agentId, HostInformationType.System, cancellationToken); + } + + /// + public Task>> GetLoginInformationAsync(AgentId agentId, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + + return GetAgentHostInformationAsync>(agentId, HostInformationType.Who, cancellationToken); + } + + /// + public Task> ListAgentCheckTargetsAsync(EntityId entityId, CheckTypeId agentCheckType, CheckTargetId marker, int? limit, CancellationToken cancellationToken) + { + if (entityId == null) + throw new ArgumentNullException("entityId"); + if (agentCheckType == null) + throw new ArgumentNullException("agentCheckType"); + if (!agentCheckType.IsAgent) + throw new ArgumentException(string.Format("The specified check type '{0}' is not an agent check.", agentCheckType), "agentCheckType"); + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/entities/{entityId}/agent/check_types/{agentCheckType}/targets"); + var parameters = new Dictionary { { "entityId", entityId.Value }, { "agentCheckType", agentCheckType.ToString() } }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit != null) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + JObject result = task.Result; + if (result == null) + return null; + + JToken valuesToken = result["values"]; + if (valuesToken == null) + return null; + + JToken metadataToken = result["metadata"]; + + CheckTarget[] values = valuesToken.ToObject(); + Func>> getNextPageAsync = + (nextMarker, nextCancellationToken) => ListAgentCheckTargetsAsync(entityId, agentCheckType, nextMarker, limit, nextCancellationToken); + IDictionary metadata = metadataToken != null ? metadataToken.ToObject>() : null; + return new ReadOnlyCollectionPage(values, getNextPageAsync, metadata); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + #endregion + + /// + /// Get generic agent host information. + /// + /// The type of the object modeling the JSON representation of the host information reported by the agent. + /// The agent ID. This is obtained from Agent.Id. + /// The type of information to check. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Agent Host Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + protected Task> GetAgentHostInformationAsync(AgentId agentId, HostInformationType hostInformation, CancellationToken cancellationToken) + { + if (agentId == null) + throw new ArgumentNullException("agentId"); + if (hostInformation == null) + throw new ArgumentNullException("hostInformation"); + + UriTemplate template = new UriTemplate("/agents/{agentId}/host_info/{hostInfo}"); + var parameters = new Dictionary { { "agentId", agentId.Value }, { "hostInfo", hostInformation.ToString() } }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task>> requestResource = + GetResponseAsyncFunc>(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + /// + /// This method returns a cached base address if one is available. If no cached address is + /// available, is called to obtain + /// an with the type rax:monitor and preferred type cloudMonitoring. + /// + protected override Task GetBaseUriAsync(CancellationToken cancellationToken) + { + if (_baseUri != null) + { + return InternalTaskExtensions.CompletedTask(_baseUri); + } + + return Task.Factory.StartNew( + () => + { + Endpoint endpoint = GetServiceEndpoint(null, "rax:monitor", "cloudMonitoring", null); + _baseUri = new Uri(endpoint.PublicURL); + return _baseUri; + }); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudNetworksProvider.cs b/src/OpenStack/Providers/Rackspace/CloudNetworksProvider.cs new file mode 100644 index 000000000..ed5286f9f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudNetworksProvider.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using JSIStudios.SimpleRESTServices.Client; +using JSIStudios.SimpleRESTServices.Client.Json; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Providers; +using net.openstack.Providers.Rackspace.Objects.Request; +using net.openstack.Providers.Rackspace.Objects.Response; + +namespace net.openstack.Providers.Rackspace +{ + /// + /// DEPRECATED. Use or Rackspace.CloudNetworks.v2.CloudNetworkService (from the Rackspace NuGet package). + /// The Cloud Networks Provider enable simple access to the Rackspace Cloud Network Services. + /// Cloud Networks lets you create a virtual Layer 2 network, known as an isolated network, + /// which gives you greater control and security when you deploy web applications. + /// + /// Documentation URL: http://docs.rackspace.com/servers/api/v2/cn-gettingstarted/content/ch_overview.html + /// + /// + /// + /// + [Obsolete("This will be removed in v2.0. Use OpenStack.Networking.v2.NetworkingService or Rackspace.CloudNetworks.v2.CloudNetworkService (from the Rackspace NuGet package).")] + public class CloudNetworksProvider : ProviderBase, INetworksProvider + { + private readonly HttpStatusCode[] _validResponseCode = new[] { HttpStatusCode.OK, HttpStatusCode.Created, HttpStatusCode.Accepted }; + + #region Constructors + + /// + /// Initializes a new instance of the class with + /// no default identity or region, and the default identity provider and REST + /// service implementation. + /// + public CloudNetworksProvider() + : this(null, null, null, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, no default region, and the default identity + /// provider and REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + public CloudNetworksProvider(CloudIdentity identity) + : this(identity, null, null, null) { } + + /// + /// Initializes a new instance of the class with + /// no default identity or region, the default identity provider, and the specified + /// REST service implementation. + /// + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudNetworksProvider(IRestService restService) + : this(null, null, null, restService) { } + + /// + /// Initializes a new instance of the class with + /// no default identity or region, the specified identity provider, and the default + /// REST service implementation. + /// + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created with no default identity. + public CloudNetworksProvider(IIdentityProvider identityProvider) + : this(null, null, identityProvider, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity and identity provider, no default region, and + /// the default REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudNetworksProvider(CloudIdentity identity, IIdentityProvider identityProvider) + : this(identity, null, identityProvider, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity and REST service implementation, no default region, + /// and the default identity provider. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudNetworksProvider(CloudIdentity identity, IRestService restService) + : this(identity, null, null, restService) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, no default region, and the specified identity + /// provider and REST service implementation. + /// + /// An instance of a object. If not provided, the user will be required to pass a object to each method individually. + /// An instance of an to override the default + /// An instance of an to override the default + public CloudNetworksProvider(CloudIdentity identity, IIdentityProvider identityProvider, IRestService restService) + : this(identity, null, identityProvider, restService) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, default region, identity provider, and REST + /// service implementation. + /// + /// An instance of a object. If not provided, the user will be required to pass a object to each method individually. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// An instance of an to override the default + /// An instance of an to override the default + public CloudNetworksProvider(CloudIdentity identity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService) + : base(identity, defaultRegion, identityProvider, restService) { } + + #endregion + + + #region Networks + + /// + public IEnumerable ListNetworks(string region = null, CloudIdentity identity = null) + { + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/os-networksv2", GetServiceEndpoint(identity, region))); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Networks; + } + + /// + public CloudNetwork CreateNetwork(string cidr, string label, string region = null, CloudIdentity identity = null) + { + if (cidr == null) + throw new ArgumentNullException("cidr"); + if (label == null) + throw new ArgumentNullException("label"); + if (string.IsNullOrEmpty(cidr)) + throw new ArgumentException("cidr cannot be empty"); + if (string.IsNullOrEmpty(label)) + throw new ArgumentException("label cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/os-networksv2", GetServiceEndpoint(identity, region))); + var cloudNetworkRequest = new CreateCloudNetworkRequest(new CreateCloudNetworksDetails(cidr, label)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, cloudNetworkRequest); + + if (response == null || response.Data == null) + return null; + + return response.Data.Network; + } + + /// + public CloudNetwork ShowNetwork(string networkId, string region = null, CloudIdentity identity = null) + { + if (networkId == null) + throw new ArgumentNullException("networkId"); + if (string.IsNullOrEmpty(networkId)) + throw new ArgumentException("networkId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/os-networksv2/{1}", GetServiceEndpoint(identity, region), networkId)); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Network; + } + + /// + public bool DeleteNetwork(string networkId, string region = null, CloudIdentity identity = null) + { + if (networkId == null) + throw new ArgumentNullException("networkId"); + if (string.IsNullOrEmpty(networkId)) + throw new ArgumentException("networkId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/os-networksv2/{1}", GetServiceEndpoint(identity, region), networkId)); + + Response response = null; + try + { + response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE); + } + catch(UserNotAuthorizedException ex) + { + if(ex.Response.StatusCode == HttpStatusCode.Forbidden) + throw new UserAuthorizationException("ERROR: Cannot delete network. Ensure that all servers are removed from this network first."); + } + + return response != null && _validResponseCode.Contains(response.StatusCode); + } + + #endregion + + + #region Private methods + + /// + /// Gets the public service endpoint to use for Cloud Networks requests for the specified identity and region. + /// + /// + /// This method uses compute for the service type, and cloudServersOpenStack for the preferred service name. + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The preferred region for the service. If this value is , the user's default region will be used. + /// The public URL for the requested Cloud Networks endpoint. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If is and no default region is available for the identity or provider. + /// If no service catalog is available for the user. + /// If no endpoint is available for the requested service. + /// If the REST API request failed. + protected string GetServiceEndpoint(CloudIdentity identity, string region) + { + return base.GetPublicServiceEndpoint(identity, "compute", "cloudServersOpenStack", region); + } + + #endregion + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudQueuesProvider.cs b/src/OpenStack/Providers/Rackspace/CloudQueuesProvider.cs new file mode 100644 index 000000000..de6b35305 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudQueuesProvider.cs @@ -0,0 +1,860 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Net; + using System.Threading; + using System.Threading.Tasks; + using JSIStudios.SimpleRESTServices.Client; + using JSIStudios.SimpleRESTServices.Client.Json; + using net.openstack.Core; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using net.openstack.Core.Domain.Queues; + using net.openstack.Core.Providers; + using net.openstack.Providers.Rackspace.Objects.Queues.Request; + using net.openstack.Providers.Rackspace.Objects.Queues.Response; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using HttpResponseCodeValidator = net.openstack.Providers.Rackspace.Validators.HttpResponseCodeValidator; + using IHttpResponseCodeValidator = net.openstack.Core.Validators.IHttpResponseCodeValidator; + + /// + /// Provides an implementation of for operating + /// with Rackspace's Cloud Queues product. + /// + /// OpenStack Marconi API v1 Blueprint + /// + /// + public class CloudQueuesProvider : ProviderBase, IQueueingService + { + /// + /// Specifies whether the or + /// should be used for accessing the Cloud Queues API. + /// + private readonly bool _internalUrl; + + /// + /// The value of the Client-Id header to send with message requests from this service. + /// + private readonly Guid _clientId; + + /// + /// This field caches the base URI used for accessing the Cloud Queues service. + /// + /// + private Uri _baseUri; + + /// + /// This field caches the home document returned by . + /// + private HomeDocument _homeDocument; + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , the provides the default identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The value of the Client-Id header to send with message requests from this service. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// If both and are . + public CloudQueuesProvider(CloudIdentity defaultIdentity, string defaultRegion, Guid clientId, bool internalUrl, IIdentityProvider identityProvider) + : this(defaultIdentity, defaultRegion, clientId, internalUrl, identityProvider, null, null) + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// + /// + /// The default implementation does not rely on or + /// for any services. If a derived class + /// uses synchronous methods for any web API calls, the constructor for the derived + /// class can either specify or expose these parameters. + /// + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , the provides the default identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The value of the Client-Id header to send with message requests from this service. + /// to use the endpoint's ; otherwise to use the endpoint's . + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing synchronous REST requests. If this value is , the provider will use a new instance of . + /// The HTTP status code validator to use for synchronous REST requests. If this value is , the provider will use . + /// If both and are . + protected CloudQueuesProvider(CloudIdentity defaultIdentity, string defaultRegion, Guid clientId, bool internalUrl, IIdentityProvider identityProvider, IRestService restService, IHttpResponseCodeValidator httpStatusCodeValidator) + : base(defaultIdentity, defaultRegion, identityProvider, restService, httpStatusCodeValidator) + { + if (defaultIdentity == null && identityProvider == null) + throw new ArgumentException("defaultIdentity and identityProvider cannot both be null"); + + _clientId = clientId; + _internalUrl = internalUrl; + } + + #region IQueueingService Members + + /// + public Task GetHomeAsync(CancellationToken cancellationToken) + { + if (_homeDocument != null) + { + return InternalTaskExtensions.CompletedTask(_homeDocument); + } + + UriTemplate template = new UriTemplate("/"); + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, new Dictionary()); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, HomeDocument> cacheResult = + task => + { + _homeDocument = task.Result; + return task.Result; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(cacheResult); + } + + /// + public Task GetNodeHealthAsync(CancellationToken cancellationToken) + { + UriTemplate template = new UriTemplate("/health"); + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.HEAD, template, new Dictionary()); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task CreateQueueAsync(QueueName queueName, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}"); + var parameters = new Dictionary + { + { "queue_name", queueName.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters); + + Func>, Task> parseResult = + task => + { + if (task.Result.Item1.StatusCode == HttpStatusCode.Created) + return InternalTaskExtensions.CompletedTask(true); + else + return InternalTaskExtensions.CompletedTask(false); + }; + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken, parseResult); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> ListQueuesAsync(QueueName marker, int? limit, bool detailed, CancellationToken cancellationToken) + { + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/queues?marker={marker}&limit={limit}&detailed={detailed}"); + var parameters = new Dictionary + { + { "detailed", detailed.ToString().ToLowerInvariant() }, + }; + if (marker != null) + parameters.Add("marker", marker.Value); + if (limit.HasValue) + parameters.Add("limit", limit.ToString()); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, ReadOnlyCollectionPage> resultSelector = + task => + { + ReadOnlyCollectionPage page = null; + if (task.Result != null && task.Result.Queues != null) + { + CloudQueue lastQueue = task.Result.Queues.LastOrDefault(); + QueueName nextMarker = lastQueue != null ? lastQueue.Name : marker; + Func>> getNextPageAsync = + nextCancellationToken => ListQueuesAsync(nextMarker, limit, detailed, nextCancellationToken); + page = new BasicReadOnlyCollectionPage(task.Result.Queues, getNextPageAsync); + } + + return page ?? ReadOnlyCollectionPage.Empty; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task QueueExistsAsync(QueueName queueName, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}"); + var parameters = new Dictionary() { { "queue_name", queueName.Value } }; + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.HEAD, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, bool> interpretResult = + task => + { + // a WebException would have been thrown if the queue didn't exist + if (task.Status == TaskStatus.RanToCompletion) + return true; + + task.Exception.Flatten().Handle( + ex => + { + WebException webException = ex as WebException; + if (webException == null) + return false; + + HttpWebResponse response = webException.Response as HttpWebResponse; + if (response == null) + return false; + + if (response.StatusCode != HttpStatusCode.NotFound) + return false; + + // a 404 error means the queue does not exist + return true; + }); + + return false; + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(interpretResult, true); + } + + /// + public Task DeleteQueueAsync(QueueName queueName, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}"); + var parameters = new Dictionary + { + { "queue_name", queueName.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task SetQueueMetadataAsync(QueueName queueName, T metadata, CancellationToken cancellationToken) + where T : class + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/metadata"); + var parameters = new Dictionary + { + { "queue_name", queueName.Value } + }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, metadata); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task GetQueueMetadataAsync(QueueName queueName, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + + return GetQueueMetadataAsync(queueName, cancellationToken); + } + + /// + public Task GetQueueMetadataAsync(QueueName queueName, CancellationToken cancellationToken) + where T : class + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/metadata"); + var parameters = new Dictionary + { + { "queue_name", queueName.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task GetQueueStatisticsAsync(QueueName queueName, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/stats"); + var parameters = new Dictionary() { { "queue_name", queueName.Value } }; + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task ListMessagesAsync(QueueName queueName, QueuedMessageListId marker, int? limit, bool echo, bool includeClaimed, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (limit <= 0) + throw new ArgumentOutOfRangeException("limit"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/messages?marker={marker}&limit={limit}&echo={echo}&include_claimed={include_claimed}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + { "echo", echo.ToString() }, + { "include_claimed", includeClaimed.ToString() } + }; + if (marker != null) + parameters["marker"] = marker.Value; + if (limit != null) + parameters["limit"] = limit.ToString(); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + Func, QueuedMessageList> resultSelector = + task => + { + ReadOnlyCollection messages = null; + if (task.Result != null) + messages = task.Result.Messages; + + QueuedMessageListId nextMarker = null; + if (task.Result != null && task.Result.Links != null) + { + Link nextLink = task.Result.Links.FirstOrDefault(i => string.Equals(i.Rel, "next", StringComparison.OrdinalIgnoreCase)); + if (nextLink != null) + { + Uri baseUri = new Uri("https://example.com"); + Uri absoluteUri; + if (nextLink.Href.StartsWith("/v1")) + absoluteUri = new Uri(baseUri, nextLink.Href.Substring("/v1".Length)); + else + absoluteUri = new Uri(baseUri, nextLink.Href); + + UriTemplateMatch match = template.Match(baseUri, absoluteUri); + if (!string.IsNullOrEmpty(match.BoundVariables["marker"])) + nextMarker = new QueuedMessageListId(match.BoundVariables["marker"]); + } + } + + if (messages == null || messages.Count == 0) + { + // use the same marker again + messages = messages ?? new ReadOnlyCollection(new QueuedMessage[0]); + nextMarker = marker; + } + + Func>> getNextPageAsync = null; + if (nextMarker != null || messages.Count == 0) + { + getNextPageAsync = + nextCancellationToken => ListMessagesAsync(queueName, nextMarker, limit, echo, includeClaimed, nextCancellationToken) + .Select(t => (ReadOnlyCollectionPage)t.Result); + } + + return new QueuedMessageList(messages, getNextPageAsync, nextMarker); + }; + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task GetMessageAsync(QueueName queueName, MessageId messageId, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messageId == null) + throw new ArgumentNullException("messageId"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/messages/{message_id}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + { "message_id", messageId.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task> GetMessagesAsync(QueueName queueName, IEnumerable messageIds, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messageIds == null) + throw new ArgumentNullException("messageIds"); + if (messageIds.Contains(null)) + throw new ArgumentException("messageIds cannot contain any null values"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/messages?ids={ids}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + { "ids", string.Join(",", messageIds.Select(i => i.Value).ToArray()) }, + }; + + Func uriTransform = + uri => new Uri(uri.GetLeftPart(UriPartial.Path) + uri.Query.Replace("%2c", ",")); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters, uriTransform); + + Func, Task>> requestResource = + GetResponseAsyncFunc>(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task PostMessagesAsync(QueueName queueName, IEnumerable messages, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messages == null) + throw new ArgumentNullException("messages"); + + return PostMessagesAsync(queueName, cancellationToken, messages.ToArray()); + } + + /// + public Task PostMessagesAsync(QueueName queueName, CancellationToken cancellationToken, params Message[] messages) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messages == null) + throw new ArgumentNullException("messages"); + if (messages.Contains(null)) + throw new ArgumentException("messages cannot contain any null values"); + + if (messages.Length == 0) + { + return QueueExistsAsync(queueName, cancellationToken) + .Select(_ => MessagesEnqueued.Empty); + } + + UriTemplate template = new UriTemplate("/queues/{queue_name}/messages"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, messages); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task PostMessagesAsync(QueueName queueName, IEnumerable> messages, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messages == null) + throw new ArgumentNullException("messages"); + + return PostMessagesAsync(queueName, cancellationToken, messages.ToArray()); + } + + /// + public Task PostMessagesAsync(QueueName queueName, CancellationToken cancellationToken, params Message[] messages) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messages == null) + throw new ArgumentNullException("messages"); + if (messages.Contains(null)) + throw new ArgumentException("messages cannot contain any null values"); + + if (messages.Length == 0) + { + return QueueExistsAsync(queueName, cancellationToken) + .Select(_ => MessagesEnqueued.Empty); + } + + UriTemplate template = new UriTemplate("/queues/{queue_name}/messages"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + }; + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, messages); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task DeleteMessageAsync(QueueName queueName, MessageId messageId, Claim claim, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messageId == null) + throw new ArgumentNullException("messageId"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/messages/{message_id}?claim_id={claim_id}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + { "message_id", messageId.Value }, + }; + if (claim != null) + parameters["claim_id"] = claim.Id.Value; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task DeleteMessagesAsync(QueueName queueName, IEnumerable messageIds, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (messageIds == null) + throw new ArgumentNullException("messageIds"); + if (messageIds.Contains(null)) + throw new ArgumentException("messageIds cannot contain any null values"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/messages?ids={ids}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + { "ids", string.Join(",", messageIds.Select(i => i.Value).ToArray()) }, + }; + + Func uriTransform = + uri => new Uri(uri.GetLeftPart(UriPartial.Path) + uri.Query.Replace("%2c", ",")); + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters, uriTransform); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + /// + public Task ClaimMessageAsync(QueueName queueName, int? limit, TimeSpan timeToLive, TimeSpan gracePeriod, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + if (timeToLive <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeToLive"); + if (gracePeriod < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("gracePeriod"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/claims?limit={limit}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + }; + if (limit != null) + parameters["limit"] = limit.ToString(); + + var request = new ClaimMessagesRequest(timeToLive, gracePeriod); + + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.POST, template, parameters, request); + + Func>, Task>>> parseResult = + task => + { + string location = task.Result.Item1.Headers[HttpResponseHeader.Location]; + Uri locationUri = location != null ? new Uri(_baseUri, location) : null; + + if (task.Result.Item1.StatusCode == HttpStatusCode.NoContent) + { + // the queue did not contain any messages to claim + Tuple> result = Tuple.Create(locationUri, Enumerable.Empty()); + return InternalTaskExtensions.CompletedTask(result); + } + + IEnumerable messages = JsonConvert.DeserializeObject>(task.Result.Item2); + + return InternalTaskExtensions.CompletedTask(Tuple.Create(locationUri, messages)); + }; + Func, Task>>> requestResource = + GetResponseAsyncFunc>>(cancellationToken, parseResult); + + Func>>, Claim> resultSelector = + task => new Claim(this, queueName, task.Result.Item1, timeToLive, TimeSpan.Zero, true, task.Result.Item2); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task QueryClaimAsync(QueueName queueName, Claim claim, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (claim == null) + throw new ArgumentNullException("claim"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/claims/{claim_id}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + { "claim_id", claim.Id.Value } + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters); + + Func>, Task>>> parseResult = + task => + { + // this response uses ContentLocation instead of Location + string location = task.Result.Item1.Headers[HttpResponseHeader.ContentLocation]; + Uri locationUri = location != null ? new Uri(_baseUri, location) : null; + + JObject result = JsonConvert.DeserializeObject(task.Result.Item2); + TimeSpan age = TimeSpan.FromSeconds((int)result["age"]); + TimeSpan ttl = TimeSpan.FromSeconds((int)result["ttl"]); + IEnumerable messages = result["messages"].ToObject>(); + return InternalTaskExtensions.CompletedTask(Tuple.Create(locationUri, ttl, age, messages)); + }; + Func, Task>>> requestResource = + GetResponseAsyncFunc(cancellationToken, parseResult); + + Func>>, Claim> resultSelector = + task => new Claim(this, queueName, task.Result.Item1, task.Result.Item2, task.Result.Item3, false, task.Result.Item4); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource) + .Select(resultSelector); + } + + /// + public Task UpdateClaimAsync(QueueName queueName, Claim claim, TimeSpan timeToLive, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (claim == null) + throw new ArgumentNullException("claim"); + if (timeToLive <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeToLive"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/claims/{claim_id}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + { "claim_id", claim.Id.Value } + }; + + JObject request = new JObject(new JProperty("ttl", new JValue((int)timeToLive.TotalSeconds))); + Func>, Task> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.PATCH, template, parameters, request); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Then(prepareRequest) + .Then(requestResource); + } + + /// + public Task ReleaseClaimAsync(QueueName queueName, Claim claim, CancellationToken cancellationToken) + { + if (queueName == null) + throw new ArgumentNullException("queueName"); + if (claim == null) + throw new ArgumentNullException("claim"); + + UriTemplate template = new UriTemplate("/queues/{queue_name}/claims/{claim_id}"); + + var parameters = + new Dictionary() + { + { "queue_name", queueName.Value }, + { "claim_id", claim.Id.Value }, + }; + + Func>, HttpWebRequest> prepareRequest = + PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters); + + Func, Task> requestResource = + GetResponseAsyncFunc(cancellationToken); + + return AuthenticateServiceAsync(cancellationToken) + .Select(prepareRequest) + .Then(requestResource); + } + + #endregion + + /// + /// + /// This method returns a cached base address if one is available. If no cached address is + /// available, is called to obtain + /// an with the type rax:queues and preferred type cloudQueues. + /// + protected override Task GetBaseUriAsync(CancellationToken cancellationToken) + { + if (_baseUri != null) + { + return InternalTaskExtensions.CompletedTask(_baseUri); + } + + return Task.Factory.StartNew( + () => + { + Endpoint endpoint = GetServiceEndpoint(null, "rax:queues", "cloudQueues", null); + Uri baseUri = new Uri(_internalUrl ? endpoint.InternalURL : endpoint.PublicURL); + _baseUri = baseUri; + return baseUri; + }); + } + + /// + /// + /// This method calls to create the + /// initial , and then sets the Client-Id header according + /// to the Marconi (Cloud Queues) specification before returning. + /// + protected override HttpWebRequest PrepareRequestImpl(HttpMethod method, IdentityToken identityToken, UriTemplate template, Uri baseUri, IDictionary parameters, Func uriTransform) + { + HttpWebRequest request = base.PrepareRequestImpl(method, identityToken, template, baseUri, parameters, uriTransform); + request.Headers["Client-Id"] = _clientId.ToString("D"); + return request; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/CloudServersProvider.cs b/src/OpenStack/Providers/Rackspace/CloudServersProvider.cs new file mode 100644 index 000000000..96f7d2b67 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/CloudServersProvider.cs @@ -0,0 +1,1543 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using JSIStudios.SimpleRESTServices.Client; +using JSIStudios.SimpleRESTServices.Client.Json; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Providers; +using net.openstack.Providers.Rackspace.Objects.Request; +using net.openstack.Providers.Rackspace.Objects.Response; + +namespace net.openstack.Providers.Rackspace +{ + /// + /// DEPRECATED. Use or Rackspace.CloudServers.v2.CloudServerService (from the Rackspace NuGet package). + /// The Cloud Servers Provider enables simple access go the Rackspace next generation Cloud Servers powered by OpenStack. + /// The next generation service is a fast, reliable, and scalable cloud compute solution without the risk of proprietary lock-in. + /// It provides the core features of the OpenStack Compute API v2 and also deploys certain extensions as permitted by the OpenStack Compute API contract. + /// Some of these extensions are generally available through OpenStack while others implement Rackspace-specific features + /// to meet customers’ expectations and for operational compatibility. The OpenStack Compute API and the Rackspace extensions are + /// known collectively as API v2. + /// + /// Documentation URL: http://docs.rackspace.com/servers/api/v2/cs-gettingstarted/content/overview.html + /// + /// + /// + /// + [Obsolete("This will be removed in v2.0. Use OpenStack.Compute.v2_1.ComputeService or Rackspace.CloudServers.v2.CloudServerService (from the Rackspace NuGet package).")] + public class CloudServersProvider : ProviderBase, IComputeProvider + { + private readonly HttpStatusCode[] _validServerActionResponseCode = new[] { HttpStatusCode.OK, HttpStatusCode.Accepted, HttpStatusCode.NonAuthoritativeInformation, HttpStatusCode.NoContent }; + + #region Constructors + + /// + /// Initializes a new instance of the class with + /// no default identity or region, and the default identity provider and REST + /// service implementation. + /// + public CloudServersProvider() + : this(null, null, null, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, no default region, and the default identity + /// provider and REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + public CloudServersProvider(CloudIdentity identity) + : this(identity, null, null, null) { } + + /// + /// Initializes a new instance of the class with + /// no default identity or region, the default identity provider, and the specified + /// REST service implementation. + /// + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudServersProvider(IRestService restService) + : this(null, null, null, restService) { } + + /// + /// Initializes a new instance of the class with + /// no default identity or region, the specified identity provider, and the default + /// REST service implementation. + /// + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created with no default identity. + public CloudServersProvider(IIdentityProvider identityProvider) + : this(null, null, identityProvider, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity and identity provider, no default region, and + /// the default REST service implementation. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + public CloudServersProvider(CloudIdentity identity, IIdentityProvider identityProvider) + : this(identity, null, identityProvider, null) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity and REST service implementation, no default region, + /// and the default identity provider. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + public CloudServersProvider(CloudIdentity identity, IRestService restService) + : this(identity, null, null, restService) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, no default region, and the specified identity + /// provider and REST service implementation. + /// + /// An instance of a object. If not provided, the user will be required to pass a object to each method individually. + /// An instance of an to override the default + /// An instance of an to override the default + public CloudServersProvider(CloudIdentity identity, IIdentityProvider identityProvider, IRestService restService) + : this(identity, null, identityProvider, restService) { } + + /// + /// Initializes a new instance of the class with + /// the specified default identity, default region, identity provider, and REST + /// service implementation. + /// + /// An instance of a object. If not provided, the user will be required to pass a object to each method individually. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// An instance of an to override the default + /// An instance of an to override the default + public CloudServersProvider(CloudIdentity identity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService) + : base(identity, defaultRegion, identityProvider, restService) { } + + #endregion + + #region Servers + + /// + public IEnumerable ListServers(string imageId = null, string flavorId = null, string name = null, ServerState status = null, string markerId = null, int? limit = null, DateTimeOffset? changesSince = null, string region = null, CloudIdentity identity = null) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers", GetServiceEndpoint(identity, region))); + + var parameters = BuildOptionalParameterList(new Dictionary + { + {"image", imageId}, + {"flavor", flavorId}, + {"name", name}, + {"status", status != null ? status.Name : null}, + {"marker", markerId}, + {"limit", !limit.HasValue ? null : limit.Value.ToString()}, + {"changes-since", !changesSince.HasValue ? null : changesSince.Value.ToString("yyyy-MM-ddThh:mm:ss")} + }); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, queryStringParameter: parameters); + + if (response == null || response.Data == null) + return null; + + return BuildCloudServersProviderAwareObject(response.Data.Servers, region, identity); + } + + /// + public IEnumerable ListServersWithDetails(string imageId = null, string flavorId = null, string name = null, ServerState status = null, string markerId = null, int? limit = null, DateTimeOffset? changesSince = null, string region = null, CloudIdentity identity = null) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/detail", GetServiceEndpoint(identity, region))); + + var parameters = BuildOptionalParameterList(new Dictionary + { + {"image", imageId}, + {"flavor", flavorId}, + {"name", name}, + {"status", status != null ? status.Name : null}, + {"marker", markerId}, + {"limit", !limit.HasValue ? null : limit.Value.ToString()}, + {"changes-since", !changesSince.HasValue ? null : changesSince.Value.ToString("yyyy-MM-ddThh:mm:ss")} + }); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, queryStringParameter: parameters); + + if (response == null || response.Data == null) + return null; + + return BuildCloudServersProviderAwareObject(response.Data.Servers, region, identity); + } + + /// + public NewServer CreateServer(string cloudServerName, string imageName, string flavor, DiskConfiguration diskConfig = null, Metadata metadata = null, Personality[] personality = null, bool attachToServiceNetwork = false, bool attachToPublicNetwork = false, IEnumerable networks = null, string region = null, CloudIdentity identity = null) + { + if (cloudServerName == null) + throw new ArgumentNullException("cloudServerName"); + if (imageName == null) + throw new ArgumentNullException("imageName"); + if (flavor == null) + throw new ArgumentNullException("flavor"); + if (string.IsNullOrEmpty(cloudServerName)) + throw new ArgumentException("cloudServerName cannot be empty"); + if (string.IsNullOrEmpty(imageName)) + throw new ArgumentException("imageName cannot be empty"); + if (string.IsNullOrEmpty(flavor)) + throw new ArgumentException("flavor cannot be empty"); + if (networks != null && networks.Any(string.IsNullOrEmpty)) + throw new ArgumentException("networks cannot contain any null or empty values"); + if (diskConfig != null && diskConfig != DiskConfiguration.Auto && diskConfig != DiskConfiguration.Manual) + throw new NotSupportedException("The specified disk configuration is not supported."); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers", GetServiceEndpoint(identity, region))); + + List networksToAttach = new List(); + if (attachToServiceNetwork || attachToPublicNetwork) + { + if(attachToPublicNetwork) + networksToAttach.Add("00000000-0000-0000-0000-000000000000"); + + if(attachToServiceNetwork) + networksToAttach.Add("11111111-1111-1111-1111-111111111111"); + } + + if (networks != null) + networksToAttach.AddRange(networks); + + const string accessIPv4 = null; + const string accessIPv6 = null; + var request = new CreateServerRequest(cloudServerName, imageName, flavor, diskConfig, metadata, accessIPv4, accessIPv6, networksToAttach, personality); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, request); + + if (response == null || response.Data == null || response.Data.Server == null) + return null; + + if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Accepted) + return null; // throw new ExternalServiceException(response.StatusCode, response.Status, response.RawBody); + + return BuildCloudServersProviderAwareObject(response.Data.Server, region, identity); + } + + /// + public Server GetDetails(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null || response.Data.Server == null) + return null; + + return BuildCloudServersProviderAwareObject(response.Data.Server, region, identity); + } + + /// + public bool UpdateServer(string serverId, string name = null, IPAddress accessIPv4 = null, IPAddress accessIPv6 = null, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (accessIPv4 != null && !IPAddress.None.Equals(accessIPv4) && accessIPv4.AddressFamily != AddressFamily.InterNetwork) + throw new ArgumentException("The specified value for accessIPv4 is not an IP v4 address.", "accessIPv4"); + if (accessIPv6 != null && !IPAddress.None.Equals(accessIPv6) && accessIPv6.AddressFamily != AddressFamily.InterNetworkV6) + throw new ArgumentException("The specified value for accessIPv6 is not an IP v6 address.", "accessIPv6"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}", GetServiceEndpoint(identity, region), serverId)); + + var requestJson = new UpdateServerRequest(name, accessIPv4, accessIPv6); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, requestJson); + + if (response == null || response.Data == null || response.Data.Server == null) + return false; + + if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Accepted) + return false; + + return true; + } + + /// + public bool DeleteServer(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}", GetServiceEndpoint(identity, region), serverId)); + + var defaultSettings = BuildDefaultRequestSettings(new [] {HttpStatusCode.NotFound}); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE, settings: defaultSettings); + + if (response == null || !_validServerActionResponseCode.Contains(response.StatusCode)) + return false; // throw new ExternalServiceException(response.StatusCode, response.Status, response.RawBody); + + return true; + } + + /// + public Server WaitForServerState(string serverId, ServerState expectedState, ServerState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (expectedState == null) + throw new ArgumentNullException("expectedState"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + return WaitForServerState(serverId, new[] { expectedState }, errorStates, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, region, identity); + } + + /// + public Server WaitForServerState(string serverId, ServerState[] expectedStates, ServerState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (expectedStates == null) + throw new ArgumentNullException("expectedStates"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (expectedStates.Length == 0) + throw new ArgumentException("expectedStates cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + var serverDetails = GetDetails(serverId, region, identity); + + /* + * The polling implementation uses triple-checked polling to work around a known bug in Cloud + * Servers status reporting. Occasionally, for a brief period of time during an asynchronous + * server operation, the service will return incorrect values in all of the status fields. + * Polling multiple times allows this SDK to provide reliable wait operations even when the + * server returns unreliable values. + */ + + Func exitCondition = () => serverDetails.TaskState == null && (expectedStates.Contains(serverDetails.Status) || errorStates.Contains(serverDetails.Status)); + int count = 0; + int currentProgress = -1; + int exitCount = exitCondition() ? 1 : 0; + while (exitCount < 3 && count < refreshCount) + { + if (progressUpdatedCallback != null) + { + if (serverDetails.Progress > currentProgress) + { + currentProgress = serverDetails.Progress; + progressUpdatedCallback(currentProgress); + } + } + + Thread.Sleep(refreshDelay ?? TimeSpan.FromMilliseconds(2400)); + serverDetails = GetDetails(serverId, region, identity); + count++; + if (exitCondition()) + exitCount++; + else + exitCount = 0; + } + + if (errorStates.Contains(serverDetails.Status)) + throw new ServerEnteredErrorStateException(serverDetails.Status); + + return BuildCloudServersProviderAwareObject(serverDetails, region, identity); + } + + /// + public Server WaitForServerActive(string serverId, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + return WaitForServerState(serverId, ServerState.Active, new[] { ServerState.Error, ServerState.Unknown, ServerState.Suspended }, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, region, identity); + } + + /// + public void WaitForServerDeleted(string serverId, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + try + { + WaitForServerState(serverId, ServerState.Deleted, + new[] {ServerState.Error, ServerState.Unknown, ServerState.Suspended}, + refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, region, identity); + } + catch (Core.Exceptions.Response.ItemNotFoundException){} // there is the possibility that the server can be ACTIVE for one pass and then + // by the next pass a 404 is returned. This is due to the VERY limited window in which + // the server goes into the DELETED state before it is removed from the system. + } + + #endregion + + #region Server Addresses + + /// + public ServerAddresses ListAddresses(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/ips", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Addresses; + } + + /// + public IEnumerable ListAddressesByNetwork(string serverId, string network, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (network == null) + throw new ArgumentNullException("network"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(network)) + throw new ArgumentException("network cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/ips/{2}", GetServiceEndpoint(identity, region), serverId, network)); + + try + { + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + if (response == null || response.Data == null) + return null; + + return response.Data[network]; + } + catch (ItemNotFoundException) + { + // if the specified server and network exist separately, then the 404 was only caused by server + // not being connected to the particular network + // https://github.com/openstacknetsdk/openstack.net/issues/176 + bool foundServer = false; + try + { + Server details = GetDetails(serverId); + foundServer = details != null; + } + catch (ResponseException) + { + } + + if (!foundServer) + throw; + + bool foundNetwork = false; + try + { + INetworksProvider networksProvider = new CloudNetworksProvider(DefaultIdentity, DefaultRegion, IdentityProvider, RestService); + IEnumerable networks = networksProvider.ListNetworks(region, identity); + if (networks != null && networks.Any(i => network.Equals(i.Label, StringComparison.OrdinalIgnoreCase))) + foundNetwork = true; + } + catch (ResponseException) + { + } + + if (!foundNetwork) + throw; + + return Enumerable.Empty(); + } + } + + #endregion + + #region Server Actions + + /// + public bool ChangeAdministratorPassword(string serverId, string password, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + CheckIdentity(identity); + + var request = new ChangeServerAdminPasswordRequest(password); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return resp; + } + + /// + public bool RebootServer(string serverId, RebootType rebootType, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (rebootType == null) + throw new ArgumentNullException("rebootType"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var request = new ServerRebootRequest(new ServerRebootDetails(rebootType)); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return resp; + } + + /// + public Server RebuildServer(string serverId, string serverName, string imageName, string flavor, string adminPassword, IPAddress accessIPv4 = null, IPAddress accessIPv6 = null, Metadata metadata = null, DiskConfiguration diskConfig = null, Personality personality = null, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (imageName == null) + throw new ArgumentNullException("imageName"); + if (flavor == null) + throw new ArgumentNullException("flavor"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(imageName)) + throw new ArgumentException("imageName cannot be empty"); + if (string.IsNullOrEmpty(flavor)) + throw new ArgumentException("flavor cannot be empty"); + if (accessIPv4 != null && !IPAddress.None.Equals(accessIPv4) && accessIPv4.AddressFamily != AddressFamily.InterNetwork) + throw new ArgumentException("The specified value for accessIPv4 is not an IP v4 address.", "accessIPv4"); + if (accessIPv6 != null && !IPAddress.None.Equals(accessIPv6) && accessIPv6.AddressFamily != AddressFamily.InterNetworkV6) + throw new ArgumentException("The specified value for accessIPv6 is not an IP v6 address.", "accessIPv6"); + if (diskConfig != null && diskConfig != DiskConfiguration.Auto && diskConfig != DiskConfiguration.Manual) + throw new NotSupportedException("The specified disk configuration is not supported."); + CheckIdentity(identity); + + var details = new ServerRebuildDetails(serverName, imageName, flavor, adminPassword, accessIPv4, accessIPv6, metadata, diskConfig, personality); + var request = new ServerRebuildRequest(details); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return BuildCloudServersProviderAwareObject(resp.Server, region, identity); + } + + /// + public bool ResizeServer(string serverId, string serverName, string flavor, DiskConfiguration diskConfig = null, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (serverName == null) + throw new ArgumentNullException("serverName"); + if (flavor == null) + throw new ArgumentNullException("flavor"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(serverName)) + throw new ArgumentException("serverName cannot be empty"); + if (string.IsNullOrEmpty(flavor)) + throw new ArgumentException("flavor cannot be empty"); + if (diskConfig != null && diskConfig != DiskConfiguration.Auto && diskConfig != DiskConfiguration.Manual) + throw new NotSupportedException("The specified disk configuration is not supported."); + CheckIdentity(identity); + + var details = new ServerResizeDetails(serverName, flavor, diskConfig); + var request = new ServerResizeRequest(details); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return resp; + } + + /// + public bool ConfirmServerResize(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var request = new ConfirmServerResizeRequest(); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return resp; + } + + /// + public bool RevertServerResize(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var request = new RevertServerResizeRequest(); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return resp; + } + + /// + public string RescueServer(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var request = new RescueServerRequest(); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return resp.AdminPassword; + } + + /// + public bool UnRescueServer(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var request = new UnrescueServerRequest(); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return resp; + } + + /// + public bool CreateImage(string serverId, string imageName, Metadata metadata = null, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (imageName == null) + throw new ArgumentNullException("imageName"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(imageName)) + throw new ArgumentException("imageName cannot be empty"); + CheckIdentity(identity); + + var request = new CreateServerImageRequest(new CreateServerImageDetails(imageName, metadata)); + var resp = ExecuteServerAction(serverId, request, region, identity); + + return resp; + } + + /// + /// Execute a Cloud Servers action which returns a strongly-typed value in the body of the response. + /// + /// + /// This method executes actions using a request to the URI + /// servers/{serverId}/action. + /// + /// The type modeling the JSON representation of the result of executing the action. + /// The server ID. This is obtained from . + /// The body of the action. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The result of the web request, as an object of type . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + protected T ExecuteServerAction(string serverId, object body, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (body == null) + throw new ArgumentNullException("body"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/action", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, body); + + if (response == null || response.Data == null || !_validServerActionResponseCode.Contains(response.StatusCode)) + return default(T); + + return response.Data; + } + + /// + /// Execute a Cloud Servers action which does not return a response. + /// + /// + /// This method executes actions using a request to the URI + /// servers/{serverId}/action. + /// + /// The server ID. This is obtained from . + /// The body of the action. + /// The region in which to execute this action. If not specified, the user's default region will be used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the request is executed successfully; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// -or- + /// If is and no default region is available for the provider. + /// + /// If the REST API request failed. + protected bool ExecuteServerAction(string serverId, object body, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (body == null) + throw new ArgumentNullException("body"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/action", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, body); + + if (response == null || !_validServerActionResponseCode.Contains(response.StatusCode)) + return false; + + return true; + } + + #endregion + + #region Volume Attachment Actions + + /// + public ServerVolume AttachServerVolume(string serverId, string volumeId, string storageDevice = null, string region = null, + CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/os-volume_attachments", GetServiceEndpoint(identity, region), serverId)); + + var request = new AttachServerVolumeRequest(storageDevice, volumeId); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, request); + + if (response == null || response.Data == null) + return null; + + return response.Data.ServerVolume; + } + + /// + public IEnumerable ListServerVolumes(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/os-volume_attachments", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.ServerVolumes; + } + + /// + public ServerVolume GetServerVolumeDetails(string serverId, string volumeId, string region = null, + CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/os-volume_attachments/{2}", GetServiceEndpoint(identity, region), serverId, volumeId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.ServerVolume; + } + + /// + public bool DetachServerVolume(string serverId, string volumeId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/os-volume_attachments/{2}", GetServiceEndpoint(identity, region), serverId, volumeId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE); + + if (response == null || !_validServerActionResponseCode.Contains(response.StatusCode)) + return false; + + return true; + } + + #endregion + + #region Virtual Interfaces + + /// + public IEnumerable ListVirtualInterfaces(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/os-virtual-interfacesv2", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.VirtualInterfaces; + } + + /// + public VirtualInterface CreateVirtualInterface(string serverId, string networkId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (networkId == null) + throw new ArgumentNullException("networkId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(networkId)) + throw new ArgumentException("networkId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/os-virtual-interfacesv2", GetServiceEndpoint(identity, region), serverId)); + + var request = new CreateVirtualInterfaceRequest(networkId); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, request); + + if (response == null || response.Data == null || response.Data.VirtualInterfaces == null) + return null; + + return response.Data.VirtualInterfaces.FirstOrDefault(); + } + + /// + public bool DeleteVirtualInterface(string serverId, string virtualInterfaceId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (virtualInterfaceId == null) + throw new ArgumentNullException("virtualInterfaceId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(virtualInterfaceId)) + throw new ArgumentException("virtualInterfaceId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/os-virtual-interfacesv2/{2}", GetServiceEndpoint(identity, region), serverId, virtualInterfaceId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE); + + if (response == null || !_validServerActionResponseCode.Contains(response.StatusCode)) + return false; + + return true; + } + #endregion + + #region Flavors + + /// + public IEnumerable ListFlavors(int? minDiskInGB = null, int? minRamInMB = null, string markerId = null, int? limit = null, string region = null, CloudIdentity identity = null) + { + if (minDiskInGB < 0) + throw new ArgumentOutOfRangeException("minDiskInGB"); + if (minRamInMB < 0) + throw new ArgumentOutOfRangeException("minRamInMB"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/flavors", GetServiceEndpoint(identity, region))); + + var queryStringParameters = BuildListFlavorsQueryStringParameters(minDiskInGB, minRamInMB, markerId, limit); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, queryStringParameter: queryStringParameters); + + if (response == null || response.Data == null) + return null; + + return response.Data.Flavors; + } + + /// + public IEnumerable ListFlavorsWithDetails(int? minDiskInGB = null, int? minRamInMB = null, string markerId = null, int? limit = null, string region = null, CloudIdentity identity = null) + { + if (minDiskInGB < 0) + throw new ArgumentOutOfRangeException("minDiskInGB"); + if (minRamInMB < 0) + throw new ArgumentOutOfRangeException("minRamInMB"); + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/flavors/detail", GetServiceEndpoint(identity, region))); + + var queryStringParameters = BuildListFlavorsQueryStringParameters(minDiskInGB, minRamInMB, markerId, limit); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, queryStringParameter: queryStringParameters); + + if (response == null || response.Data == null) + return null; + + return response.Data.Flavors; + } + + /// + public FlavorDetails GetFlavor(string id, string region = null, CloudIdentity identity = null) + { + if (id == null) + throw new ArgumentNullException("id"); + if (string.IsNullOrEmpty(id)) + throw new ArgumentException("id cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/flavors/{1}", GetServiceEndpoint(identity, region), id)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return response.Data.Flavor; + } + + #endregion + + #region Images + + /// + public IEnumerable ListImages(string server = null, string imageName = null, ImageState imageStatus = null, DateTimeOffset? changesSince = null, string markerId = null, int? limit = null, ImageType imageType = null, string region = null, CloudIdentity identity = null) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images", GetServiceEndpoint(identity, region))); + + var queryStringParameters = BuildListImagesQueryStringParameters(server, imageName, imageStatus, changesSince, markerId, limit, imageType); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, queryStringParameter: queryStringParameters); + + if (response == null || response.Data == null) + return null; + + return BuildCloudServersProviderAwareObject(response.Data.Images, region, identity); + } + + /// + public IEnumerable ListImagesWithDetails(string server = null, string imageName = null, ImageState imageStatus = null, DateTimeOffset? changesSince = null, string markerId = null, int? limit = null, ImageType imageType = null, string region = null, CloudIdentity identity = null) + { + if (limit < 0) + throw new ArgumentOutOfRangeException("limit"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/detail", GetServiceEndpoint(identity, region))); + + var queryStringParameters = BuildListImagesQueryStringParameters(server, imageName, imageStatus, changesSince, markerId, limit, imageType); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET, queryStringParameter: queryStringParameters); + + if (response == null || response.Data == null) + return null; + + return BuildCloudServersProviderAwareObject(response.Data.Images, region, identity); + } + + private Dictionary BuildListImagesQueryStringParameters(string serverId, string imageName, ImageState imageStatus, DateTimeOffset? changesSince, string markerId, int? limit, ImageType imageType) + { + var queryParameters = new Dictionary(); + + if(!string.IsNullOrEmpty(serverId)) + queryParameters.Add("server", serverId); + + if (!string.IsNullOrEmpty(imageName)) + queryParameters.Add("name", imageName); + + if (imageStatus != null && !string.IsNullOrEmpty(imageStatus.Name)) + queryParameters.Add("status", imageStatus.Name); + + if (changesSince != null) + queryParameters.Add("changes-since", changesSince.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")); + + if (!string.IsNullOrEmpty(markerId)) + queryParameters.Add("marker", markerId); + + if (limit > 0) + queryParameters.Add("limit", limit.ToString()); + + if(imageType != null) + queryParameters.Add("type", imageType.Name); + + return queryParameters; + } + + private Dictionary BuildListFlavorsQueryStringParameters(int? minDiskInGB, int? minRamInMB, string markerId, int? limit) + { + var queryParameters = new Dictionary(); + if (minDiskInGB != null) + queryParameters.Add("minDisk", minDiskInGB.ToString()); + if (minRamInMB != null) + queryParameters.Add("minRam", minRamInMB.ToString()); + if (!string.IsNullOrEmpty(markerId)) + queryParameters.Add("marker", markerId); + if (limit != null) + queryParameters.Add("limit", limit.ToString()); + + return queryParameters; + } + + /// + public ServerImage GetImage(string imageId, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/{1}", GetServiceEndpoint(identity, region), imageId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null) + return null; + + return BuildCloudServersProviderAwareObject(response.Data.Image, region, identity); + } + + /// + public bool DeleteImage(string imageId, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/{1}", GetServiceEndpoint(identity, region), imageId)); + + var defaultSettings = BuildDefaultRequestSettings(new[] { HttpStatusCode.NotFound }); + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE, settings: defaultSettings); + + if (response == null || !_validServerActionResponseCode.Contains(response.StatusCode)) + return false; // throw new ExternalServiceException(response.StatusCode, response.Status, response.RawBody); + + return true; + } + + /// + public ServerImage WaitForImageState(string imageId, ImageState[] expectedStates, ImageState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (expectedStates == null) + throw new ArgumentNullException("expectedStates"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (expectedStates.Length == 0) + throw new ArgumentException("expectedStates cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + var details = GetImage(imageId, region, identity); + + int count = 0; + int currentProgress = -1; + while (!expectedStates.Contains(details.Status) && !errorStates.Contains(details.Status) && count < refreshCount) + { + if (progressUpdatedCallback != null) + { + if (details.Progress > currentProgress) + { + currentProgress = details.Progress; + progressUpdatedCallback(currentProgress); + } + } + + Thread.Sleep(refreshDelay ?? TimeSpan.FromMilliseconds(2400)); + details = GetImage(imageId, region, identity); + count++; + } + + if (errorStates.Contains(details.Status)) + throw new ImageEnteredErrorStateException(details.Status); + + return BuildCloudServersProviderAwareObject(details, region, identity); + } + + /// + public ServerImage WaitForImageState(string imageId, ImageState expectedState, ImageState[] errorStates, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (expectedState == null) + throw new ArgumentNullException("expectedState"); + if (errorStates == null) + throw new ArgumentNullException("errorStates"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + return WaitForImageState(imageId, new[] { expectedState }, errorStates, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, region, identity); + } + + /// + public ServerImage WaitForImageActive(string imageId, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + return WaitForImageState(imageId, ImageState.Active, new[] { ImageState.Error, ImageState.Unknown }, refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, region, identity); + } + + /// + public void WaitForImageDeleted(string imageId, int refreshCount = 600, TimeSpan? refreshDelay = null, Action progressUpdatedCallback = null, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (refreshCount < 0) + throw new ArgumentOutOfRangeException("refreshCount"); + if (refreshDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("refreshDelay"); + CheckIdentity(identity); + + try + { + WaitForImageState(imageId, ImageState.Deleted, + new[] {ImageState.Error, ImageState.Unknown}, + refreshCount, refreshDelay ?? TimeSpan.FromMilliseconds(2400), progressUpdatedCallback, region, identity); + } + catch (net.openstack.Core.Exceptions.Response.ItemNotFoundException){} // there is the possibility that the image can be ACTIVE for one pass and then + // by the next pass a 404 is returned. This is due to the VERY limited window in which + // the image goes into the DELETED state before it is removed from the system. + } + + #endregion + + #region Server Metadata + + /// + public Metadata ListServerMetadata(string serverId, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/metadata", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null) + return null; + + return response.Data.Metadata; + } + + /// + public bool SetServerMetadata(string serverId, Metadata metadata, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (metadata.Any(i => string.IsNullOrEmpty(i.Key))) + throw new ArgumentException("metadata cannot contain any values with empty keys"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/metadata", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, new UpdateMetadataRequest(metadata)); + + if (response.StatusCode == HttpStatusCode.OK) + return true; + + return false; + } + + /// + public bool UpdateServerMetadata(string serverId, Metadata metadata, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (metadata.Any(i => string.IsNullOrEmpty(i.Key))) + throw new ArgumentException("metadata cannot contain any values with empty keys"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/metadata", GetServiceEndpoint(identity, region), serverId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, new UpdateMetadataRequest(metadata)); + + if (response.StatusCode == HttpStatusCode.OK) + return true; + + return false; + } + + /// + public string GetServerMetadataItem(string serverId, string key, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (key == null) + throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/metadata/{2}", GetServiceEndpoint(identity, region), serverId, key)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.NonAuthoritativeInformation) || response.Data == null || response.Data.Metadata == null || response.Data.Metadata.Count == 0) + return null; + + return response.Data.Metadata[key]; + } + + /// + public bool SetServerMetadataItem(string serverId, string key, string value, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (key == null) + throw new ArgumentNullException("key"); + if (value == null) + throw new ArgumentNullException("value"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/metadata/{2}", GetServiceEndpoint(identity, region), serverId, key)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, new UpdateMetadataItemRequest(key, value)); + + if (response.StatusCode == HttpStatusCode.OK) + return true; + + return false; + } + + /// + public bool DeleteServerMetadataItem(string serverId, string key, string region = null, CloudIdentity identity = null) + { + if (serverId == null) + throw new ArgumentNullException("serverId"); + if (key == null) + throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(serverId)) + throw new ArgumentException("serverId cannot be empty"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/servers/{1}/metadata/{2}", GetServiceEndpoint(identity, region), serverId, key)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE); + + if (response.StatusCode == HttpStatusCode.NoContent) + return true; + + return false; + } + + #endregion + + #region Image Metadata + + /// + public Metadata ListImageMetadata(string imageId, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/{1}/metadata", GetServiceEndpoint(identity, region), imageId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null) + return null; + + return response.Data.Metadata; + } + + /// + public bool SetImageMetadata(string imageId, Metadata metadata, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (metadata.Any(i => string.IsNullOrEmpty(i.Key))) + throw new ArgumentException("metadata cannot contain any values with empty keys"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/{1}/metadata", GetServiceEndpoint(identity, region), imageId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, new UpdateMetadataRequest(metadata)); + + if (response.StatusCode == HttpStatusCode.OK) + return true; + + return false; + } + + /// + public bool UpdateImageMetadata(string imageId, Metadata metadata, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (metadata.Any(i => string.IsNullOrEmpty(i.Key))) + throw new ArgumentException("metadata cannot contain any values with empty keys"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/{1}/metadata", GetServiceEndpoint(identity, region), imageId)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, new UpdateMetadataRequest(metadata)); + + if (response.StatusCode == HttpStatusCode.OK) + return true; + + return false; + } + + /// + public string GetImageMetadataItem(string imageId, string key, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (key == null) + throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/{1}/metadata/{2}", GetServiceEndpoint(identity, region), imageId, key)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.GET); + + if (response == null || response.Data == null || response.Data.Metadata == null || response.Data.Metadata.Count == 0) + return null; + + return response.Data.Metadata[key]; + } + + /// + public bool SetImageMetadataItem(string imageId, string key, string value, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (key == null) + throw new ArgumentNullException("key"); + if (value == null) + throw new ArgumentNullException("value"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/{1}/metadata/{2}", GetServiceEndpoint(identity, region), imageId, key)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, new UpdateMetadataItemRequest(key, value)); + + if (response.StatusCode == HttpStatusCode.OK) + return true; + + return false; + } + + /// + public bool DeleteImageMetadataItem(string imageId, string key, string region = null, CloudIdentity identity = null) + { + if (imageId == null) + throw new ArgumentNullException("imageId"); + if (key == null) + throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(imageId)) + throw new ArgumentException("imageId cannot be empty"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + CheckIdentity(identity); + + var urlPath = new Uri(string.Format("{0}/images/{1}/metadata/{2}", GetServiceEndpoint(identity, region), imageId, key)); + + var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.DELETE); + + if (response.StatusCode == HttpStatusCode.NoContent) + return true; + + return false; + } + + #endregion + + #region Protected methods + + /// + /// Gets the public service endpoint to use for Cloud Servers requests for the specified identity and region. + /// + /// + /// This method uses compute for the service type, and cloudServersOpenStack for the preferred service name. + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The preferred region for the service. If this value is , the user's default region will be used. + /// The public URL for the requested Cloud Servers endpoint. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If is and no default region is available for the identity or provider. + /// If no service catalog is available for the user. + /// If no endpoint is available for the requested service. + /// If the REST API request failed. + protected string GetServiceEndpoint(CloudIdentity identity, string region) + { + return base.GetPublicServiceEndpoint(identity, "compute", "cloudServersOpenStack", region); + } + + #endregion + } +} diff --git a/src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs b/src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs new file mode 100644 index 000000000..f8e610dad --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs @@ -0,0 +1,48 @@ +namespace net.openstack.Providers.Rackspace +{ + using net.openstack.Core; + + /// + /// Provides a default implementation of for + /// use with Rackspace services. This implementation encodes text using + /// with , + /// and decodes text with . + /// + /// + internal class EncodeDecodeProvider : IEncodeDecodeProvider + { + /// + /// A default instance of . + /// + private static readonly EncodeDecodeProvider _default = new EncodeDecodeProvider(); + + /// + /// Gets a default instance of . + /// + public static EncodeDecodeProvider Default + { + get + { + return _default; + } + } + + /// + public string UrlEncode(string stringToEncode) + { + if (stringToEncode == null) + return null; + + return UriUtility.UriEncode(stringToEncode, UriPart.AnyUrl); + } + + /// + public string UrlDecode(string stringToDecode) + { + if (stringToDecode == null) + return null; + + return UriUtility.UriDecode(stringToDecode); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Exceptions/BulkDeletionException.cs b/src/OpenStack/Providers/Rackspace/Exceptions/BulkDeletionException.cs new file mode 100644 index 000000000..b042a3ed1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Exceptions/BulkDeletionException.cs @@ -0,0 +1,74 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Providers.Rackspace.Objects; + +namespace net.openstack.Providers.Rackspace.Exceptions +{ + /// + /// Represents errors which occur during a bulk delete operation. + /// + /// + /// + [Serializable] + public class BulkDeletionException : Exception + { + [NonSerialized] + private ExceptionData _state; + + /// + /// Gets the detailed results of the bulk delete operation. + /// + public BulkDeletionResults Results + { + get + { + return _state.Results; + } + } + + /// + /// Initializes a new instance of the class + /// with the specified status and results. + /// + /// A description of the status of the operation. + /// The results of the bulk delete operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// + public BulkDeletionException(string status, BulkDeletionResults results) + : base(string.Format("The bulk deletion operation did not complete successfully. Status: {0}", status)) + { + if (status == null) + throw new ArgumentNullException("status"); + if (results == null) + throw new ArgumentNullException("results"); + if (string.IsNullOrEmpty(status)) + throw new ArgumentException("status cannot be empty"); + + _state.Results = results; +#if !NET35 + SerializeObjectState += (ex, args) => args.AddSerializedState(_state); +#endif + } + + [Serializable] + private struct ExceptionData : ISafeSerializationData + { + public BulkDeletionResults Results + { + get; + set; + } + + void ISafeSerializationData.CompleteDeserialization(object deserialized) + { + ((BulkDeletionException)deserialized)._state = this; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Exceptions/InvalidETagException.cs b/src/OpenStack/Providers/Rackspace/Exceptions/InvalidETagException.cs new file mode 100644 index 000000000..5d4aef017 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Exceptions/InvalidETagException.cs @@ -0,0 +1,32 @@ +using System; +using System.Runtime.Serialization; + +namespace net.openstack.Providers.Rackspace.Exceptions +{ + /// + /// Represents errors which occur while validating the ETag following an object transfer. + /// + /// + [Serializable] + public class InvalidETagException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public InvalidETagException() + { + } + + /// + /// Initializes a new instance of the class with + /// serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// If is . + protected InvalidETagException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Exceptions/InvalidVolumeSizeException.cs b/src/OpenStack/Providers/Rackspace/Exceptions/InvalidVolumeSizeException.cs new file mode 100644 index 000000000..c92e632a3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Exceptions/InvalidVolumeSizeException.cs @@ -0,0 +1,58 @@ +using System; +using System.Runtime.Serialization; +using net.openstack.Core.Validators; + +namespace net.openstack.Providers.Rackspace.Exceptions +{ + /// + /// Represents errors which occur during validation of a block storage volume size. + /// + /// + /// + [Serializable] + public class InvalidVolumeSizeException : Exception + { + [NonSerialized] + private ExceptionData _state; + + /// + /// Gets the requested volume size. + /// + public int Size + { + get + { + return _state.Size; + } + } + + /// + /// Initializes a new instance of the class + /// with the specified volume size. + /// + /// The invalid volume size which was requested. + public InvalidVolumeSizeException(int size) + : base(string.Format("The volume size value must be between 100 and 1000. The size requested was: {0}", size)) + { + _state.Size = size; +#if !NET35 + SerializeObjectState += (ex, args) => args.AddSerializedState(_state); +#endif + } + + [Serializable] + private struct ExceptionData : ISafeSerializationData + { + public int Size + { + get; + set; + } + + void ISafeSerializationData.CompleteDeserialization(object deserialized) + { + ((InvalidVolumeSizeException)deserialized)._state = this; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Exceptions/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Exceptions/NamespaceDoc.cs new file mode 100644 index 000000000..8cde92d46 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Exceptions/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Providers.Rackspace.Exceptions +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines + /// exception classes for errors which occur while using Rackspace-specific functionality. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/ExtendedJsonRestServices.cs b/src/OpenStack/Providers/Rackspace/ExtendedJsonRestServices.cs new file mode 100644 index 000000000..3f569b28b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/ExtendedJsonRestServices.cs @@ -0,0 +1,70 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net; + using JSIStudios.SimpleRESTServices.Client; + using JSIStudios.SimpleRESTServices.Client.Json; + + /// + /// This class extends to add support for handling response + /// codes other than in response to an + /// Expect: 100-Continue. + /// + /// + /// + public class ExtendedJsonRestServices : JsonRestServices + { + /// + /// + /// This method expands on the base implementation by avoiding writing to the request stream + /// if is , which prevents + /// the requirement that data be sent in the case where sending the Expect: 100-Continue + /// header resulted in an immediate error response with first send a + /// . + /// + public override Response Stream(Uri url, HttpMethod method, Func responseBuilderCallback, Stream content, int bufferSize, long maxReadLength, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings, Action progressUpdated) + { + if (url == null) + throw new ArgumentNullException("url"); + if (content == null) + throw new ArgumentNullException("content"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + if (maxReadLength < 0) + throw new ArgumentOutOfRangeException("maxReadLength"); + + return ExecuteRequest(url, method, responseBuilderCallback, headers, queryStringParameters, settings, (req) => + { + long bytesWritten = 0; + + if (settings.ChunkRequest || maxReadLength > 0) + { + req.SendChunked = settings.ChunkRequest; + req.AllowWriteStreamBuffering = false; + req.ContentLength = maxReadLength > 0 && content.Length > maxReadLength ? maxReadLength : content.Length; + } + + using (Stream stream = req.GetRequestStream()) + { + var buffer = new byte[bufferSize]; + int count; + while (!req.HaveResponse && (count = content.Read(buffer, 0, maxReadLength > 0 ? (int)Math.Min(bufferSize, maxReadLength - bytesWritten) : bufferSize)) > 0) + { + bytesWritten += count; + stream.Write(buffer, 0, count); + + if (progressUpdated != null) + progressUpdated(bytesWritten); + + if (maxReadLength > 0 && bytesWritten >= maxReadLength) + break; + } + } + + return "[STREAM CONTENT]"; + }); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/IAutoScaleService.cs b/src/OpenStack/Providers/Rackspace/IAutoScaleService.cs new file mode 100644 index 000000000..706e9d56c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/IAutoScaleService.cs @@ -0,0 +1,445 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using System.Threading; + using System.Threading.Tasks; + using net.openstack.Core.Collections; + using net.openstack.Providers.Rackspace.Objects.AutoScale; + + /// + /// Represents a provider for the Rackspace Cloud Auto Scale service. + /// + /// Rackspace Auto Scale Developer Guide - API v1.0 + /// + public interface IAutoScaleService + { + #region Groups + + /// + /// Gets a collection of scaling groups. + /// + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the current scaling groups. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List scaling groups (Rackspace Auto Scale Developer Guide - API v1.0) + Task> ListScalingGroupsAsync(ScalingGroupId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Create a new scaling group. + /// + /// A object describing the scaling group configuration. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the newly created scaling group. + /// + /// If is . + /// If the REST request does not return successfully. + /// Create Group (Rackspace Auto Scale Developer Guide - API v1.0) + Task CreateGroupAsync(ScalingGroupConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Get detailed information about a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the scaling group. + /// + /// If is . + /// If the REST request does not return successfully. + /// Show scaling group details (Rackspace Auto Scale Developer Guide - API v1.0) + Task GetGroupAsync(ScalingGroupId groupId, CancellationToken cancellationToken); + + /// + /// Remove and delete a scaling group. + /// + /// + /// If is , active servers in the group will be + /// immediately deleted, and pending servers will be deleted once they finish building and become + /// active. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// to delete the scaling group even if it has active or pending entities; otherwise, to only delete the group if it does not contain any entities. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Delete scaling group (Rackspace Auto Scale Developer Guide - API v1.0) + Task DeleteGroupAsync(ScalingGroupId groupId, bool? force, CancellationToken cancellationToken); + + /// + /// Get information about the current state of a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the current state of the scaling group. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get scaling group state (Rackspace Auto Scale Developer Guide - API v1.0) + Task GetGroupStateAsync(ScalingGroupId groupId, CancellationToken cancellationToken); + + /// + /// Suspend the execution of scaling policies for a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Pause group policy execution (Rackspace Auto Scale Developer Guide - API v1.0) + Task PauseGroupAsync(ScalingGroupId groupId, CancellationToken cancellationToken); + + /// + /// Resume the execution of scaling policies for a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Resume group policy execution (Rackspace Auto Scale Developer Guide - API v1.0) + Task ResumeGroupAsync(ScalingGroupId groupId, CancellationToken cancellationToken); + + #endregion Groups + + #region Configurations + + /// + /// Get the group configuration for a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the group configuration of the scaling group. + /// + /// If is . + /// If the REST request does not return successfully. + /// Show scaling group configuration (Rackspace Auto Scale Developer Guide - API v1.0) + Task GetGroupConfigurationAsync(ScalingGroupId groupId, CancellationToken cancellationToken); + + /// + /// Set the group configuration for a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The new group configuration for the scaling group. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update scaling group configuration (Rackspace Auto Scale Developer Guide - API v1.0) + Task SetGroupConfigurationAsync(ScalingGroupId groupId, GroupConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Get the launch configuration for a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the launch configuration of the scaling group. + /// + /// If is . + /// If the REST request does not return successfully. + /// Show launch configuration (Rackspace Auto Scale Developer Guide - API v1.0) + Task GetLaunchConfigurationAsync(ScalingGroupId groupId, CancellationToken cancellationToken); + + /// + /// Set the launch configuration for a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The new launch configuration for the scaling group. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update launch configuration (Rackspace Auto Scale Developer Guide - API v1.0) + Task SetLaunchConfigurationAsync(ScalingGroupId groupId, LaunchConfiguration configuration, CancellationToken cancellationToken); + + #endregion Configurations + + #region Policies + + /// + /// Gets a collection of scaling policies for a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the scaling policies for the scaling group. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List policies (Rackspace Auto Scale Developer Guide - API v1.0) + Task> ListPoliciesAsync(ScalingGroupId groupId, PolicyId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Create a new scaling policy for a scaling group. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// A object describing the scaling policy configuration. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the newly created scaling policy. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create policy (Rackspace Auto Scale Developer Guide - API v1.0) + Task CreatePolicyAsync(ScalingGroupId groupId, PolicyConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Get detailed information about a scaling policy. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the scaling policy. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Show policy details (Rackspace Auto Scale Developer Guide - API v1.0) + Task GetPolicyAsync(ScalingGroupId groupId, PolicyId policyId, CancellationToken cancellationToken); + + /// + /// Replace the configuration for a scaling policy. + /// + /// + /// This method can be used to replace the behavior associated with webhooks which + /// have already in use by applications. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// A object describing the new scaling policy configuration. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Replace policy (Rackspace Auto Scale Developer Guide - API v1.0) + Task SetPolicyAsync(ScalingGroupId groupId, PolicyId policyId, PolicyConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Remove and delete a scaling policy. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete policy (Rackspace Auto Scale Developer Guide - API v1.0) + Task DeletePolicyAsync(ScalingGroupId groupId, PolicyId policyId, CancellationToken cancellationToken); + + /// + /// Execute a scaling policy. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Execute policy (Rackspace Auto Scale Developer Guide - API v1.0) + Task ExecutePolicyAsync(ScalingGroupId groupId, PolicyId policyId, CancellationToken cancellationToken); + + #endregion Policies + + #region Webhooks + + /// + /// Gets a collection of webhooks which trigger the execution of a particular + /// scaling policy. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the webhooks for the scaling policy. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List webhooks for the policy (Rackspace Auto Scale Developer Guide - API v1.0) + Task> ListWebhooksAsync(ScalingGroupId groupId, PolicyId policyId, WebhookId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Create a webhook capable of anonymously executing a scaling policy. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// A object describing the webhook configuration. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the newly created webhook. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create a webhook (Rackspace Auto Scale Developer Guide - API v1.0) + Task CreateWebhookAsync(ScalingGroupId groupId, PolicyId policyId, NewWebhookConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Create a collection of webhooks capable of anonymously executing a scaling policy. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// A collection of objects describing the webhook configurations. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the newly created webhooks. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If contains any values. + /// If the REST request does not return successfully. + /// Create a webhook (Rackspace Auto Scale Developer Guide - API v1.0) + Task> CreateWebhookRangeAsync(ScalingGroupId groupId, PolicyId policyId, IEnumerable configurations, CancellationToken cancellationToken); + + /// + /// Get detailed information about a webhook associated with a scaling policy. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The ID of the webhook. This is obtained from Webhook.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the webhook. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Show webhook details (Rackspace Auto Scale Developer Guide - API v1.0) + Task GetWebhookAsync(ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId, CancellationToken cancellationToken); + + /// + /// Update the configuration for a webhook. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The ID of the webhook. This is obtained from Webhook.Id. + /// An object containing the updated configuration for the webhook. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update webhook (Rackspace Auto Scale Developer Guide - API v1.0) + Task UpdateWebhookAsync(ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId, UpdateWebhookConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Remove and delete a webhook associated with a scaling policy. + /// + /// The ID of the scaling group. This is obtained from ScalingGroup.Id. + /// The ID of the scaling policy. This is obtained from Policy.Id. + /// The ID of the webhook. This is obtained from Webhook.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete webhook (Rackspace Auto Scale Developer Guide - API v1.0) + Task DeleteWebhookAsync(ScalingGroupId groupId, PolicyId policyId, WebhookId webhookId, CancellationToken cancellationToken); + + #endregion Webhooks + } +} diff --git a/src/OpenStack/Providers/Rackspace/IDatabaseService.cs b/src/OpenStack/Providers/Rackspace/IDatabaseService.cs new file mode 100644 index 000000000..2f220b0bf --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/IDatabaseService.cs @@ -0,0 +1,554 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.ObjectModel; + using System.Threading.Tasks; + using net.openstack.Core; + using net.openstack.Core.Collections; + using net.openstack.Providers.Rackspace.Objects.Databases; + using CancellationToken = System.Threading.CancellationToken; + using WebException = System.Net.WebException; + + /// + /// Represents a provider for the Rackspace Cloud Databases service. + /// + /// Rackspace Cloud Databases Developer Guide - API v1.0 + /// + public interface IDatabaseService + { + #region Database instances + + /// + /// Create a new database instance. + /// + /// A object describing the configuration of the new database instance. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the new database instance. If is + /// , the task will not be considered complete until + /// the database instance transitions out of the state. + /// + /// If is . + /// If is not a valid . + /// If the REST request does not return successfully. + /// Create Database Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + Task CreateDatabaseInstanceAsync(DatabaseInstanceConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Gets a collection of all database instances. + /// + /// + /// + /// This is a paginated collection. + /// + /// + /// The database instance ID of the last in the previous page of results. This parameter is used for pagination. If the value is , the list starts at the beginning. + /// The maximum number of objects to return in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return an collection of + /// objects describing the database instances. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List All Database Instances (Rackspace Cloud Databases Developer Guide - API v1.0) + /// Pagination (Rackspace Cloud Databases Developer Guide - API v1.0) + Task> ListDatabaseInstancesAsync(DatabaseInstanceId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a database instance by ID. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the database instance. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Database Instance Status and Details (Rackspace Cloud Databases Developer Guide - API v1.0) + Task GetDatabaseInstanceAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken); + + /// + /// Removes and deletes a database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the database instance transitions out of the state. + /// + /// If is . + /// If is not a valid . + /// If the REST request does not return successfully. + /// Delete Database Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + Task RemoveDatabaseInstanceAsync(DatabaseInstanceId instanceId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Enables login from any host for the root user, and returns the root username and generated password. + /// + /// + /// + /// Changes you make as a root user may cause detrimental effects to the database instance and unpredictable + /// behavior for API operations. When you enable the root user, you accept the possibility that the provider + /// will not be able to support your database instance. While enabling root does not prevent the provider + /// from a "best effort" approach to helping you if something goes wrong with your instance, the provider + /// cannot ensure that they will be able to assist you if you change core MySQL settings. These changes can + /// be (but are not limited to) turning off binlogs, removing users that the provider uses to access your + /// instance, and so forth. + /// + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// containing the username and password of the root database user. + /// + /// If is . + /// If the REST request does not return successfully. + /// Enable Root User (Rackspace Cloud Databases Developer Guide - API v1.0) + Task EnableRootUserAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken); + + /// + /// Checks whether or not root access has been enabled for a database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return if root access is enabled for + /// the database instance; otherwise, . + /// + /// If is . + /// If the REST request does not return successfully. + /// List Root-Enabled Status (Rackspace Cloud Databases Developer Guide - API v1.0) + Task CheckRootEnabledStatusAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken); + + #endregion + + #region Database instance actions + + /// + /// Restarts the database service on the instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the database instance transitions out of the state. + /// + /// If is . + /// If is not a valid . + /// If the REST request does not return successfully. + /// Restart Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + Task RestartDatabaseInstanceAsync(DatabaseInstanceId instanceId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Resize the memory of the database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The new flavor to use for the database instance. This is obtained from DatabaseFlavor.Href. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the database instance transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If is not a valid . + /// If the REST request does not return successfully. + /// Resize the Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + Task ResizeDatabaseInstanceAsync(DatabaseInstanceId instanceId, FlavorRef flavorRef, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Resize the volume attached to the database instance. + /// + /// + /// The provider may limit database volume resize operations to increasing the volume size. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The new volume size for the database instance. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the database instance transitions out of the state. + /// + /// If is . + /// If is less than or equal to 0. + /// If is not a valid . + /// If the REST request does not return successfully. + /// Resize the Instance Volume (Rackspace Cloud Databases Developer Guide - API v1.0) + Task ResizeDatabaseInstanceVolumeAsync(DatabaseInstanceId instanceId, int volumeSize, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion + + #region Databases + + /// + /// Create a new database within a database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object describing the configuration of the new database. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create Database (Rackspace Cloud Databases Developer Guide - API v1.0) + Task CreateDatabaseAsync(DatabaseInstanceId instanceId, DatabaseConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Gets a collection of all databases within a database instance. + /// + /// + /// + /// This is a paginated collection. + /// + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The of the last in the previous page of results. This parameter is used for pagination. If the value is , the list starts at the beginning. + /// The maximum number of objects to return in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return an collection of + /// objects describing the databases. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Databases for Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + /// Pagination (Rackspace Cloud Databases Developer Guide - API v1.0) + Task> ListDatabasesAsync(DatabaseInstanceId instanceId, DatabaseName marker, int? limit, CancellationToken cancellationToken); + + /// + /// Removes and deletes a database from a database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The database name. This is obtained from Database.Name. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete Database (Rackspace Cloud Databases Developer Guide - API v1.0) + Task RemoveDatabaseAsync(DatabaseInstanceId instanceId, DatabaseName databaseName, CancellationToken cancellationToken); + + #endregion + + #region Users + + /// + /// Create a new user in a database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object describing the configuration of the new user. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create User (Rackspace Cloud Databases Developer Guide - API v1.0) + Task CreateUserAsync(DatabaseInstanceId instanceId, UserConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Gets a collection of all users within a database instance. + /// + /// + /// + /// This is a paginated collection. + /// + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The of the last user in the previous page of results. This parameter is used for pagination. If the value is , the list starts at the beginning. + /// The maximum number of objects to return in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return an collection of + /// objects describing the database instance users. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Users in Database Instance (Rackspace Cloud Databases Developer Guide - API v1.0) + /// Pagination (Rackspace Cloud Databases Developer Guide - API v1.0) + Task> ListDatabaseUsersAsync(DatabaseInstanceId instanceId, UserName marker, int? limit, CancellationToken cancellationToken); + + /// + /// Set the password for a database user. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// The new password for the user. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// If the REST request does not return successfully. + /// Change User(s) Password (Rackspace Cloud Databases Developer Guide - API v1.0) + Task SetUserPasswordAsync(DatabaseInstanceId instanceId, UserName userName, string password, CancellationToken cancellationToken); + + /// + /// Update properties of a database user. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// An object describing the updates to apply to the user. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Modify User Attributes (Rackspace Cloud Databases Developer Guide - API v1.0) + Task UpdateUserAsync(DatabaseInstanceId instanceId, UserName userName, UpdateUserConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Get a database user by ID. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a + /// object describing the user. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List User (Rackspace Cloud Databases Developer Guide - API v1.0) + Task GetUserAsync(DatabaseInstanceId instanceId, UserName userName, CancellationToken cancellationToken); + + /// + /// Remove and delete a user from a database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete User (Rackspace Cloud Databases Developer Guide - API v1.0) + Task RemoveUserAsync(DatabaseInstanceId instanceId, UserName userName, CancellationToken cancellationToken); + + /// + /// Gets a list of all databases a user has permission to access. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a collection of + /// objects identifying the databases the user can access. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List User Access (Rackspace Cloud Databases Developer Guide - API v1.0) + Task> ListUserAccessAsync(DatabaseInstanceId instanceId, UserName userName, CancellationToken cancellationToken); + + /// + /// Grant access to a database for a particular user. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The database name. This is obtained from Database.Name. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Grant User Access (Rackspace Cloud Databases Developer Guide - API v1.0) + Task GrantUserAccessAsync(DatabaseInstanceId instanceId, DatabaseName databaseName, UserName userName, CancellationToken cancellationToken); + + /// + /// Revoke access to a database for a particular user. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The database name. This is obtained from Database.Name. + /// A object identifying the database user. This is obtained from UserConfiguration.UserName. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Revoke User Access (Rackspace Cloud Databases Developer Guide - API v1.0) + Task RevokeUserAccessAsync(DatabaseInstanceId instanceId, DatabaseName databaseName, UserName userName, CancellationToken cancellationToken); + + #endregion + + #region Flavors + + /// + /// Get a collection of all database instance flavors available with the provider. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return an collection of + /// objects describing the database instance flavors. + /// + /// If the REST request does not return successfully. + /// List Flavors (Rackspace Cloud Databases Developer Guide - API v1.0) + Task> ListFlavorsAsync(CancellationToken cancellationToken); + + /// + /// Get a database instance flavor by ID. + /// + /// The flavor ID. This is obtained from DatabaseFlavor.Id + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the flavor. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Flavor By ID (Rackspace Cloud Databases Developer Guide - API v1.0) + Task GetFlavorAsync(FlavorId flavorId, CancellationToken cancellationToken); + + #endregion + + #region Backups + + /// + /// Create a backup of a database instance. + /// + /// A object containing the backup parameters. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the backup. If is + /// , the task will not be considered complete until + /// the database instance transitions out of the state. + /// + /// If is . + /// If is not a valid . + /// If the REST request does not return successfully. + /// Create Backup (Rackspace Cloud Databases Developer Guide - API v1.0) + Task CreateBackupAsync(BackupConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Get a collection of all backups for database instances in an account. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a collection of objects + /// describing the database instance backups. + /// + /// If the REST request does not return successfully. + /// List Backups (Rackspace Cloud Databases Developer Guide - API v1.0) + Task> ListBackupsAsync(CancellationToken cancellationToken); + + /// + /// Get information about a database instance backup by ID. + /// + /// The backup ID. This is obtained from Backup.Id + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the backup. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Backup by ID (Rackspace Cloud Databases Developer Guide - API v1.0) + Task GetBackupAsync(BackupId backupId, CancellationToken cancellationToken); + + /// + /// Remove and delete a database instance backup. + /// + /// The backup ID. This is obtained from Backup.Id + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Delete Backup (Rackspace Cloud Databases Developer Guide - API v1.0) + Task RemoveBackupAsync(BackupId backupId, CancellationToken cancellationToken); + + /// + /// Get a collection of all backups for a particular database instance. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a collection of objects + /// describing the backups for the database instance identified by . + /// + /// If is . + /// If the REST request does not return successfully. + /// List Backups (Rackspace Cloud Databases Developer Guide - API v1.0) + Task> ListBackupsForInstanceAsync(DatabaseInstanceId instanceId, CancellationToken cancellationToken); + + #endregion + } +} diff --git a/src/OpenStack/Providers/Rackspace/IDnsService.cs b/src/OpenStack/Providers/Rackspace/IDnsService.cs new file mode 100644 index 000000000..905fdb5c3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/IDnsService.cs @@ -0,0 +1,679 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using System.Threading; + using System.Threading.Tasks; + using net.openstack.Core; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using net.openstack.Providers.Rackspace.Objects.Dns; + using JsonSerializationException = Newtonsoft.Json.JsonSerializationException; + + /// + /// Represents a provider for the Rackspace Cloud DNS service. + /// + /// Rackspace Cloud DNS Developer Guide - API v1.0 + /// + public interface IDnsService + { + #region Limits + + /// + /// Get information about the provider-specific limits of this service. + /// + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a object containing detailed information about the limits for the service provider. + /// If the REST request does not return successfully. + /// List All Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + Task ListLimitsAsync(CancellationToken cancellationToken); + + /// + /// Get information about the types of provider-specific limits in place for this service. + /// + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a collection of objects containing the limit types supported by the service. + /// If the REST request does not return successfully. + /// List Limit Types (Rackspace Cloud DNS Developer Guide - API v1.0) + Task> ListLimitTypesAsync(CancellationToken cancellationToken); + + /// + /// Get information about the provider-specific limits of this service for a particular . + /// + /// The limit type. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a object containing detailed information about the limits of the specified for the service provider. + /// If is . + /// If the REST request does not return successfully. + /// List Specific Limit (Rackspace Cloud DNS Developer Guide - API v1.0) + Task ListLimitsAsync(LimitType type, CancellationToken cancellationToken); + + #endregion + + #region Jobs + + /// + /// Gets information about an asynchronous task being executed by the DNS service. + /// + /// The to query. + /// to include detailed information about the job; otherwise, . + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a object containing the updated job information. + /// If is . + /// If the REST request does not return successfully. + /// Synchronous and Asynchronous Responses (Rackspace Cloud DNS Developer Guide - API v1.0) + Task GetJobStatusAsync(DnsJob job, bool showDetails, CancellationToken cancellationToken); + + /// + /// Gets information about an asynchronous task with a strongly-typed result being executed by the DNS service. + /// + /// The class modeling the JSON result of the asynchronous operation. + /// The to query. + /// to include detailed information about the job; otherwise, . + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a object containing the updated job information. + /// If is . + /// If an error occurs while deserializing the response object. + /// If the REST request does not return successfully. + /// Synchronous and Asynchronous Responses (Rackspace Cloud DNS Developer Guide - API v1.0) + Task> GetJobStatusAsync(DnsJob job, bool showDetails, CancellationToken cancellationToken); + + #endregion + + #region Domains + + /// + /// Gets information about domains currently listed in the DNS service. + /// + /// If specified, the list will be filtered to only include the specified domain and its subdomains (if any exist). + /// The index of the last item in the previous page of results. If not specified, the list starts at the beginning. + /// The maximum number of domains to return in a single page. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a tuple of the resulting collection of + /// objects and the total number of domains in the list. If the total number of domains + /// in the list is not available, the second element of the tuple will be . + /// + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List Domains (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Search Domains with Filtering (Rackspace Cloud DNS Developer Guide - API v1.0) + Task, int?>> ListDomainsAsync(string domainName, int? offset, int? limit, CancellationToken cancellationToken); + + /// + /// Gets detailed information about a specific domain. + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// to populate the property of the result; otherwise, . + /// to populate the property of the result; otherwise, . + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a object containing the DNS information for the requested domain. + /// If is . + /// If the REST request does not return successfully. + /// List Domain Details (Rackspace Cloud DNS Developer Guide - API v1.0) + Task ListDomainDetailsAsync(DomainId domainId, bool showRecords, bool showSubdomains, CancellationToken cancellationToken); + + /// + /// Gets information about all changes made to a domain since a specified time. + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// The timestamp of the earliest changes to consider. If this is , a provider-specific default value is used. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a object describing the changes made to a domain registered in the DNS service. + /// If is . + /// If the REST request does not return successfully. + /// List Domain Changes (Rackspace Cloud DNS Developer Guide - API v1.0) + Task ListDomainChangesAsync(DomainId domainId, DateTimeOffset? since, CancellationToken cancellationToken); + + /// + /// Exports a domain registered in the DNS service. + /// + /// + /// The exported domain represents a single domain, and does not include subdomains. + /// + /// + /// The format does not support comments, so any + /// comments associated with a domain or its records will not be included in the exported + /// result. + /// + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// : In this case the + /// property contains an object containing the details of the exported domain. + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Export Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + Task> ExportDomainAsync(DomainId domainId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress); + + /// + /// Registers one or more new domains in the DNS service. + /// + /// A object describing the domains to register in the DNS service. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// : In this case the + /// property contains a object containing the details of the new domains. + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// If is . + /// If is not a valid . + /// If the REST request does not return successfully. + /// Create Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + Task> CreateDomainsAsync(DnsConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress); + + /// + /// Updates one or more domains in the DNS service. + /// + /// A object describing updates to apply to the domains. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// If is . + /// If is not a valid . + /// If the REST request does not return successfully. + /// Modify Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + Task UpdateDomainsAsync(DnsUpdateConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Clones a domain registered in the DNS service, optionally cloning its subdomains as well. + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// The name of the new (cloned) domain. + /// to recursively clone subdomains; otherwise, to only clone the top-level domain and its records. Cloned subdomain configurations are modified the same way that cloned top-level domain configurations are modified. If this is , a provider-specific default value is used. + /// to replace occurrences of the reference domain name with the new domain name in comments on the cloned (new) domain. If this is , a provider-specific default value is used. + /// to replace occurrences of the reference domain name with the new domain name in email addresses on the cloned (new) domain. If this is , a provider-specific default value is used. + /// true to replace occurrences of the reference domain name with the new domain name in data fields (of records) on the cloned (new) domain. Does not affect NS records. If this is , a provider-specific default value is used. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// : In this case the + /// property contains a object containing the details of the cloned (new) domains. + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Clone Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + Task> CloneDomainAsync(DomainId domainId, string cloneName, bool? cloneSubdomains, bool? modifyRecordData, bool? modifyEmailAddress, bool? modifyComment, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress); + + /// + /// Imports domains into the DNS service. + /// + /// A collection of objects containing the serialized domain information to import. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// : In this case the + /// property contains a object containing the details of the imported domains. + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// If is . + /// + /// If is contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Import Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + Task> ImportDomainAsync(IEnumerable serializedDomains, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress); + + /// + /// Removes one or more domains from the DNS service. + /// + /// A collection of IDs for the domains to remove. These are obtained from DnsDomain.Id. + /// to delete any subdomains associated with the specified domains; otherwise, to promote any subdomains to top-level domains. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// If is . + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + Task RemoveDomainsAsync(IEnumerable domainIds, bool deleteSubdomains, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion + + #region Subdomains + + /// + /// Gets information about subdomains currently associated with a domain in the DNS service. + /// + /// The top-level domain ID. This is obtained from DnsDomain.Id. + /// The index of the last item in the previous page of results. If not specified, the list starts at the beginning. + /// The maximum number of subdomains to return in a single page. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a tuple of the resulting collection of + /// objects and the total number of domains in the list. If the total number of + /// subdomains in the list is not available, the second element of the tuple will be . + /// + /// If is . + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List Subdomains (Rackspace Cloud DNS Developer Guide - API v1.0) + Task, int?>> ListSubdomainsAsync(DomainId domainId, int? offset, int? limit, CancellationToken cancellationToken); + + #endregion + + #region Records + + /// + /// Gets information about records currently associated with a domain in the DNS service, optionally filtering the results + /// to include only records of a specific type, name, and/or data. + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// The specific record type to consider, or to consider all record types. + /// The record name, which is matched to the property, or to consider all records. + /// The record data, which is matched to the property, or to consider all records. + /// The index of the last item in the previous page of results. If not specified, the list starts at the beginning. + /// The maximum number of records to return in a single page. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a tuple of the resulting collection of + /// objects and the total number of records in the list. If the total number of + /// records in the list is not available, the second element of the tuple will be . + /// + /// If is . + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List Records (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Search Records (Rackspace Cloud DNS Developer Guide - API v1.0) + Task, int?>> ListRecordsAsync(DomainId domainId, DnsRecordType recordType, string recordName, string recordData, int? offset, int? limit, CancellationToken cancellationToken); + + /// + /// Gets detailed information about a specific DNS record. + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// The record ID. This is obtained from DnsRecord.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a object containing the details of the specified DNS record. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Record Details (Rackspace Cloud DNS Developer Guide - API v1.0) + Task ListRecordDetailsAsync(DomainId domainId, RecordId recordId, CancellationToken cancellationToken); + + /// + /// Adds records to a domain in the DNS service. + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// A collection of objects describing the records to add. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// : In this case the + /// property contains a object containing the details of the added records. + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Add Records (Rackspace Cloud DNS Developer Guide - API v1.0) + Task> AddRecordsAsync(DomainId domainId, IEnumerable recordConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress); + + /// + /// Updates domain records in the DNS service. + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// A collection of objects describing the updates to apply to domain records. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Modify Records (Rackspace Cloud DNS Developer Guide - API v1.0) + Task UpdateRecordsAsync(DomainId domainId, IEnumerable recordConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Removes one or more domain records from the DNS service. + /// + /// The domain ID. This is obtained from DnsDomain.Id. + /// A collection of IDs for the records to remove. These are obtained from DnsRecord.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Records (Rackspace Cloud DNS Developer Guide - API v1.0) + Task RemoveRecordsAsync(DomainId domainId, IEnumerable recordIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion + + #region Reverse DNS + + /// + /// Gets information about reverse DNS records currently associated with a cloud resource in the DNS service. + /// + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// The index of the last item in the previous page of results. If not specified, the list starts at the beginning. + /// The maximum number of records to return in a single page. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a tuple of the resulting collection of + /// objects and the total number of domains in the list. If the total number of + /// subdomains in the list is not available, the second element of the tuple will be . + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List PTR Records (Rackspace Cloud DNS Developer Guide - API v1.0) + Task, int?>> ListPtrRecordsAsync(string serviceName, Uri deviceResourceUri, int? offset, int? limit, CancellationToken cancellationToken); + + /// + /// Gets detailed information about a reverse DNS record currently associated with a cloud resource in the DNS service. + /// + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// The record ID. This is obtained from DnsRecord.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. When the task completes successfully, the property will return a object containing the details of the specified reverse DNS record. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// If the REST request does not return successfully. + /// List PTR Record Details (Rackspace Cloud DNS Developer Guide - API v1.0) + Task ListPtrRecordDetailsAsync(string serviceName, Uri deviceResourceUri, RecordId recordId, CancellationToken cancellationToken); + + /// + /// Adds reverse DNS records to a cloud resource in the DNS service. + /// + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// A collection of objects describing the records to add. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// : In this case the + /// property contains a object containing the details of the added records. + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Add PTR Records (Rackspace Cloud DNS Developer Guide - API v1.0) + Task> AddPtrRecordsAsync(string serviceName, Uri deviceResourceUri, IEnumerable recordConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress> progress); + + /// + /// Update reverse DNS records for a cloud resource in the DNS service. + /// + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// A collection of objects describing the updates to apply to domain records. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Modify PTR Records (Rackspace Cloud DNS Developer Guide - API v1.0) + Task UpdatePtrRecordsAsync(string serviceName, Uri deviceResourceUri, IEnumerable recordConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Removes one or more reverse DNS records from the DNS service. + /// + /// The name of the service which owns the cloud resource. This is obtained from . + /// The absolute URI of the cloud resource. + /// The specific record to remove. If this is , all reverse DNS records associated with the specified device are removed. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the asynchronous server operation. If is + /// , the job will additionally be in one of the following + /// states. + /// + /// + /// + /// : In this case the property provides + /// additional information about the error which occurred during the asynchronous server operation. + /// + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove PTR Records (Rackspace Cloud DNS Developer Guide - API v1.0) + Task RemovePtrRecordsAsync(string serviceName, Uri deviceResourceUri, IPAddress ipAddress, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion + } +} diff --git a/src/OpenStack/Providers/Rackspace/IExtendedCloudIdentityProvider.cs b/src/OpenStack/Providers/Rackspace/IExtendedCloudIdentityProvider.cs new file mode 100644 index 000000000..840132dcf --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/IExtendedCloudIdentityProvider.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; +using net.openstack.Core; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Providers; + +namespace net.openstack.Providers.Rackspace +{ + /// + /// Represents an identity provider that implements Rackspace-specific extensions to the + /// OpenStack Identity API. + /// + /// Rackspace Cloud Identity Client Developer Guide - API v2.0 + public interface IExtendedCloudIdentityProvider : IIdentityProvider + { + /// + /// Lists all roles. + /// The behavior of this API method is not defined. Do not use. + /// + /// The "serviceId". + /// The index of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the requested roles. + /// If is less than 0. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method using the + /// implementation of . For more information about creating the provider, see + /// . + /// + /// + /// + /// + /// + /// List Roles (Rackspace OS-KSADM Extension - API v2.0) + IEnumerable ListRoles(string serviceId = null, int? marker = null, int? limit = null, CloudIdentity identity = null); + + /// + /// Lists all users for a given role. + /// + /// The role ID. This is obtained from Role.Id. + /// Allows you to filter enabled or un-enabled users. If the value is , a provider-specific default value is used. + /// The index of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A collection of objects describing the requested roles. + /// If is less than 0 or greater than 1000. + /// If the provider does not support the given type. + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + IEnumerable ListUsersByRole(string roleId, bool? enabled = null, int? marker = null, int? limit = null, CloudIdentity identity = null); + + /// + /// Create a new role. + /// + /// The name for the new role. + /// The description for the new role. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A containing the details of the added role. + /// If is . + /// If is empty. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Add Role (OpenStack Identity Service API v2.0 Reference) + Role AddRole(string name, string description, CloudIdentity identity = null); + + /// + /// Gets details about the specified role. + /// + /// The role ID. This is obtained from Role.Id. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A containing the details of the role. + /// If is . + /// If is empty. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Get Role by Name (OpenStack Identity Service API v2.0 Reference) + Role GetRole(string roleId, CloudIdentity identity = null); + + /// + /// Adds the specified global role to the user. + /// + /// The user ID. This is obtained from or . + /// The role ID. This is obtained from . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the role was removed from the user; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method using the + /// implementation of . For more information about creating the provider, see + /// . + /// + /// + /// + /// + /// + /// Add Global Role to User (OpenStack Identity Service API v2.0 Reference) + bool AddRoleToUser(string userId, string roleId, CloudIdentity identity = null); + + /// + /// Deletes the specified global role from the user. + /// + /// The user ID. This is obtained from or . + /// The role ID. This is obtained from . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the role was removed from the user; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// + /// The following example demonstrates the use of this method using the + /// implementation of . For more information about creating the provider, see + /// . + /// + /// + /// + /// + /// + /// Delete Global Role from User (OpenStack Identity Service API v2.0 Reference) + bool DeleteRoleFromUser(string userId, string roleId, CloudIdentity identity = null); + + /// + /// Updates the API key for the specified user. + /// + /// + /// This method is a Rackspace-specific usage scenario for the + /// Update User Credentials + /// method, where the credentials are always specified in the form of an API key. + /// + /// A object containing the updated user information. + /// The user ID. This is obtained from or . + /// The new API key. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + UserCredential UpdateUserCredentials(string userId, string apiKey, CloudIdentity identity = null); + + /// + /// Deletes API key credentials for the specified user. + /// + /// + /// This method is a Rackspace-specific usage scenario for the + /// Delete User Credentials + /// method, where the credentials are always specified in the form of an API key. + /// + /// The user ID. This is obtained from or . + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the credentials were removed from the user; otherwise, . + /// If is . + /// If is empty. + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Delete User Credentials + bool DeleteUserCredentials(string userId, CloudIdentity identity = null); + + /// + /// Sets the password for the specified user. + /// + /// The user ID. This is obtained from or . + /// The new password. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the operation succeeded; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + bool SetUserPassword(string userId, string password, CloudIdentity identity = null); + + /// + /// Updates the username and password for the specified user. + /// + /// The user. + /// The new password. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the operation succeeded; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If . is or empty. + /// -or- + /// If . is or empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + bool SetUserPassword(User user, string password, CloudIdentity identity = null); + + /// + /// Updates the username and password for the specified user. + /// + /// The user ID. This is obtained from or . + /// The new username. + /// The new password. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// if the operation succeeded; otherwise, . + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + bool SetUserPassword(string userId, string username, string password, CloudIdentity identity = null); + + /// + /// Updates the username and API key for the specified user. + /// + /// + /// This method is a Rackspace-specific usage scenario for the + /// Update User Credentials + /// method, where the credentials are always specified in the form of an API key. + /// + /// The user. + /// The API key. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the updated user information. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If . is or empty. + /// -or- + /// If . is or empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + UserCredential UpdateUserCredentials(User user, string apiKey, CloudIdentity identity = null); + + /// + /// Updates the username and API key for the specified user. + /// + /// + /// This method is a Rackspace-specific usage scenario for the + /// Update User Credentials + /// method, where the credentials are always specified in the form of an API key. + /// + /// The user ID. This is obtained from or . + /// The new username. + /// The new API key. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// A object containing the updated user information. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If the provider does not support the OS-KSADM Admin Extension. + /// -or- + /// If the provider does not support the given type. + /// + /// If is and no default identity is available for the provider. + /// If the REST API request failed. + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + UserCredential UpdateUserCredentials(string userId, string username, string apiKey, CloudIdentity identity = null); + } +} diff --git a/src/OpenStack/Providers/Rackspace/ILoadBalancerService.cs b/src/OpenStack/Providers/Rackspace/ILoadBalancerService.cs new file mode 100644 index 000000000..f0593924e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/ILoadBalancerService.cs @@ -0,0 +1,1417 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Net; + using System.Net.Sockets; + using System.Threading; + using System.Threading.Tasks; + using net.openstack.Core; + using net.openstack.Core.Collections; + using net.openstack.Providers.Rackspace.Objects.LoadBalancers; + + /// + /// Represents a provider for the Rackspace Cloud Load Balancers service. + /// + /// Rackspace Cloud Load Balancers Developer Guide - API v1.0 + /// + public interface ILoadBalancerService + { + #region Load Balancers + + /// + /// Gets a collection of current load balancers. + /// + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the current load balancers. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Load Balancers (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListLoadBalancersAsync(LoadBalancerId markerId, int? limit, CancellationToken cancellationToken); + + /// + /// Gets detailed information about a specific load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object containing detailed information about the specified load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Load Balancer Details (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetLoadBalancerAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Creates a new load balancer. + /// + /// The configuration for the new load balancer. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the task completes successfully, + /// the property will return a object + /// describing the new load balancer. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// If is not a valid . + /// If the REST request does not return successfully. + /// List Load Balancer Details (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task CreateLoadBalancerAsync(LoadBalancerConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Updates attributes for an existing load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The updated configuration for the load balancer. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Update Load Balancer Attributes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task UpdateLoadBalancerAsync(LoadBalancerId loadBalancerId, LoadBalancerUpdate configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Removes a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If + /// is , + /// the task will not be considered complete until the load balancer transitions + /// out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Load Balancer (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveLoadBalancerAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Removes one or more load balancers. + /// + /// The IDs of load balancers to remove. These is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If + /// is , + /// the task will not be considered complete until all of the load balancers + /// transition out of the state. + /// + /// If is . + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Load Balancer (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveLoadBalancerRangeAsync(IEnumerable loadBalancerIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion Load Balancers + + #region Error Page + + /// + /// Gets the HTML content of the page which is shown to an end user who is attempting to access a load balancer node that is offline or unavailable. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain the HTML content + /// of the error page which is shown to an end user who is attempting to access a load balancer + /// node that is offline or unavailable. + /// + /// If is . + /// If the REST request does not return successfully. + /// Error Page Operations (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetErrorPageAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Sets the HTML content of the custom error page which is shown to an end user who is attempting to access a load balancer node that is offline or unavailable. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The HTML content of the error page which is shown to an end user who is attempting to access a load balancer node that is offline or unavailable. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Error Page Operations (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task SetErrorPageAsync(LoadBalancerId loadBalancerId, string content, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Removes the custom error page which is shown to an end user who is attempting to access a load balancer node that is offline or unavailable. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Error Page Operations (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveErrorPageAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion Error Page + + #region Load Balancer Statistics + + /// + /// Get detailed statistics for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object containing the detailed statistics for the + /// load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Load Balancer Stats (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetStatisticsAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + #endregion Load Balancer Statistics + + #region Nodes + + /// + /// List the load balancer nodes associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the load balancer nodes associated with the specified + /// load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListNodesAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Get detailed information about a load balancer node. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the specified load balancer node. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetNodeAsync(LoadBalancerId loadBalancerId, NodeId nodeId, CancellationToken cancellationToken); + + /// + /// Add a node to a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A object describing the load balancer node to add. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the new load balancer node. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Add Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task AddNodeAsync(LoadBalancerId loadBalancerId, NodeConfiguration nodeConfiguration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Add one or more nodes to a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A collection of objects describing the load balancer nodes to add. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the new load balancer nodes. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Add Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> AddNodeRangeAsync(LoadBalancerId loadBalancerId, IEnumerable nodeConfigurations, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Update the configuration of a load balancer node. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node IDs. This is obtained from Node.Id. + /// The updated configuration for the load balancer node. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Modify Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task UpdateNodeAsync(LoadBalancerId loadBalancerId, NodeId nodeId, NodeUpdate configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Remove a nodes from a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node IDs. This is obtained from Node.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveNodeAsync(LoadBalancerId loadBalancerId, NodeId nodeId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Remove one or more nodes from a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node IDs of nodes to remove. These are obtained from Node.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveNodeRangeAsync(LoadBalancerId loadBalancerId, IEnumerable nodeIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// List the service events for a load balancer node. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The of the last item in the previous list. Used for pagination. If the value is , the list starts at the beginning. + /// Indicates the maximum number of items to return. Used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the service events for the load balancer node. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// View Node Service Events (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListNodeServiceEventsAsync(LoadBalancerId loadBalancerId, NodeServiceEventId markerId, int? limit, CancellationToken cancellationToken); + + #endregion Nodes + + #region Virtual IPs + + /// + /// Get a list of all virtual addresses associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the virtual addresses + /// associated with the load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Virtual IPs (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListVirtualAddressesAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Add a virtual address to a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The virtual address type. + /// The family of address to add. This should be or . + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the added virtual address. + /// If is , + /// the task will not be considered complete until the load balancer transitions out of the + /// state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If the specified is not supported by this provider. + /// + /// If the REST request does not return successfully. + /// Add Virtual IP Version 6 (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task AddVirtualAddressAsync(LoadBalancerId loadBalancerId, LoadBalancerVirtualAddressType type, AddressFamily addressFamily, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Remove a virtual address associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The virtual address ID. This is obtained from LoadBalancerVirtualAddress.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Virtual IP (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveVirtualAddressAsync(LoadBalancerId loadBalancerId, VirtualAddressId virtualAddressId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Remove a collection of virtual addresses associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The virtual address IDs. These are obtained from LoadBalancerVirtualAddress.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Remove Virtual IP (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveVirtualAddressRangeAsync(LoadBalancerId loadBalancerId, IEnumerable virtualAddressIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion Virtual IPs + + #region Allowed Domains + + /// + /// Gets the domain name restrictions in place for adding load balancer nodes. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// strings containing the allowed domain names used for adding load balancer nodes. + /// + /// If the REST request does not return successfully. + /// View Node Service Events (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListAllowedDomainsAsync(CancellationToken cancellationToken); + + #endregion Allowed Domains + + #region Usage Reports + + /// + /// List billable load balancers for a given date range. + /// + /// The start date to consider. The time component, if any, is ignored. If the value is , the result includes all usage prior to the specified . + /// The end date to consider. The time component, if any, is ignored. If the value is , the result includes all usage following the specified . + /// The index of the last item in the previous page of results. If the value is , the list starts at the beginning. + /// Gets the maximum number of load balancers to return in a single page of results. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the load balancers active in the specified + /// date range. + /// + /// If occurs before . + /// + /// If is less than 0. + /// -or- + /// If is less than or equal to 0. + /// + /// If the REST request does not return successfully. + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListBillableLoadBalancersAsync(DateTimeOffset? startTime, DateTimeOffset? endTime, int? offset, int? limit, CancellationToken cancellationToken); + + /// + /// List all usage for an account during a specified date range. + /// + /// The start date to consider. The time component, if any, is ignored. If the value is , the result includes all usage prior to the specified . + /// The end date to consider. The time component, if any, is ignored. If the value is , the result includes all usage following the specified . + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the load balancer usage for an account + /// in the specified date range. + /// + /// If occurs before . + /// If the REST request does not return successfully. + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListAccountLevelUsageAsync(DateTimeOffset? startTime, DateTimeOffset? endTime, CancellationToken cancellationToken); + + /// + /// List all usage for a specific load balancer during a specified date range. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The start date to consider. The time component, if any, is ignored. If the value is , the result includes all usage prior to the specified . + /// The end date to consider. The time component, if any, is ignored. If the value is , the result includes all usage following the specified . + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the usage for the load balancer in + /// the specified date range. + /// + /// If is . + /// + /// If occurs before . + /// + /// If the REST request does not return successfully. + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListHistoricalUsageAsync(LoadBalancerId loadBalancerId, DateTimeOffset? startTime, DateTimeOffset? endTime, CancellationToken cancellationToken); + + /// + /// List all usage for a specific load balancer during a preceding 24 hours. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the usage for the load balancer in + /// the preceding 24 hours. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListCurrentUsageAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + #endregion Usage Reports + + #region Access Lists + + /// + /// Gets the access list configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a collection of + /// objects describing the access list configuration for the load + /// balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListAccessListAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Add a network item to the access list for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A object describing the network item to add to the load balancer's access list. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. + /// If is , + /// the task will not be considered complete until the load balancer transitions out of the + /// state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task CreateAccessListAsync(LoadBalancerId loadBalancerId, NetworkItem networkItem, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Add a collection of network items to the access list for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A collection of objects describing the network items to add to the load balancer's access list. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task CreateAccessListAsync(LoadBalancerId loadBalancerId, IEnumerable networkItems, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Remove a network item from the access list of a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The network item ID. This is obtained from . + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveAccessListAsync(LoadBalancerId loadBalancerId, NetworkItemId networkItemId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Remove a collection of network items from the access list of a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The network item IDs. These are obtained from . + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveAccessListRangeAsync(LoadBalancerId loadBalancerId, IEnumerable networkItemIds, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Remove all network items from the access list of a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task ClearAccessListAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion Access Lists + + #region Monitors + + /// + /// Gets the health monitor currently configured for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the health monitor configured for the + /// load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// Monitor Health (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetHealthMonitorAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Sets the health monitor configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The updated health monitor configuration. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Monitor Health (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task SetHealthMonitorAsync(LoadBalancerId loadBalancerId, HealthMonitor monitor, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Remove the health monitor currently configured for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Monitor Health (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveHealthMonitorAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion Monitors + + #region Sessions + + /// + /// Gets the session persistence configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the session persistence configuration for the load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// Manage Session Persistence (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetSessionPersistenceAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Sets the session persistence configuration for a load balancer. + /// + /// + /// You can only set one of the session persistence modes on a load balancer, and it can only support one + /// protocol, so if you set mode for an HTTP load balancer, + /// then it will support session persistence for HTTP requests only. Likewise, if you set + /// mode for an HTTPS load balancer, then it will support + /// session persistence for HTTPS requests only. + /// + /// + /// If you want to support session persistence for both HTTP and HTTPS requests concurrently, then you have 2 choices: + /// + /// + /// + /// Use two load balancers, one configured for session persistence for HTTP requests and the other + /// configured for session persistence for HTTPS requests. That way, the load balancers together will support + /// session persistence for both HTTP and HTTPS requests concurrently, with each load balancer supporting one + /// of the protocols. + /// Use one load balancer, configure it for session persistence for HTTP requests, and then enable SSL + /// termination for that load balancer (refer to Section 4.17, "SSL Termination" for details). The load + /// balancer will then support session persistence for both HTTP and HTTPS requests concurrently. + /// + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The session persistence configuration. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Session Persistence (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task SetSessionPersistenceAsync(LoadBalancerId loadBalancerId, SessionPersistence sessionPersistence, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Removes the session persistence configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Manage Session Persistence (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveSessionPersistenceAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion Sessions + + #region Connections + + /// + /// Gets whether or not connection logging is enabled for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will be if content + /// caching is enabled for the load balancer; otherwise, . + /// + /// If is . + /// If the REST request does not return successfully. + /// Log Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetConnectionLoggingAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Enables or disables connection logging for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// to enable connection logging on the load balancer; otherwise, . + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Log Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task SetConnectionLoggingAsync(LoadBalancerId loadBalancerId, bool enabled, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Gets the connection throttling configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the connection throttling configuration in effect on the load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// Throttle Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task ListThrottlesAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Updates the connection throttling configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A object describing the throttling configuration to apply for the load balancer. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Throttle Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task UpdateThrottlesAsync(LoadBalancerId loadBalancerId, ConnectionThrottles throttleConfiguration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Removes the connection throttling configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Throttle Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveThrottlesAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion Connections + + #region Content Caching + + /// + /// Gets whether or not content caching is enabled for a load balancer. + /// + /// + /// When content caching is enabled, recently-accessed files are stored on the load balancer + /// for easy retrieval by web clients. Content caching improves the performance of high + /// traffic web sites by temporarily storing data that was recently accessed. While it's + /// cached, requests for that data will be served by the load balancer, which in turn reduces + /// load off the back end nodes. The result is improved response times for those requests and + /// less load on the web server. + /// + /// + /// For more information about content caching, refer to the following Knowledge Center + /// article: + /// Content Caching for Cloud Load Balancers. + /// + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will be if content + /// caching is enabled for the load balancer; otherwise, . + /// + /// If is . + /// If the REST request does not return successfully. + /// Content Caching (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetContentCachingAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Enables or disables content caching for a load balancer. + /// + /// + /// When content caching is enabled, recently-accessed files are stored on the load balancer + /// for easy retrieval by web clients. Content caching improves the performance of high + /// traffic web sites by temporarily storing data that was recently accessed. While it's + /// cached, requests for that data will be served by the load balancer, which in turn reduces + /// load off the back end nodes. The result is improved response times for those requests and + /// less load on the web server. + /// + /// + /// For more information about content caching, refer to the following Knowledge Center + /// article: + /// Content Caching for Cloud Load Balancers. + /// + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// to enable content caching on the load balancer; otherwise, . + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// Content Caching (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task SetContentCachingAsync(LoadBalancerId loadBalancerId, bool enabled, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion Content Caching + + #region Protocols + + /// + /// Gets a collection of supported load balancing protocols. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// a collection of objects describing the load balancing + /// protocols supported by this service. + /// + /// If the REST request does not return successfully. + /// List Load Balancing Protocols (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListProtocolsAsync(CancellationToken cancellationToken); + + #endregion Protocols + + #region Algorithms + + /// + /// Gets a collection of supported load balancing algorithms. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// a collection of objects describing the load balancing + /// algorithms supported by this service. + /// + /// If the REST request does not return successfully. + /// List Load Balancing Algorithms (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListAlgorithmsAsync(CancellationToken cancellationToken); + + #endregion Algorithms + + #region SSL Termination + + /// + /// Gets the SSL termination configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes, the property will contain a + /// object describing the SSL termination + /// configuration for the load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// SSL Termination (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetSslConfigurationAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Update the SSL termination configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The updated SSL termination configuration. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// SSL Termination (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task UpdateSslConfigurationAsync(LoadBalancerId loadBalancerId, LoadBalancerSslConfiguration configuration, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + /// + /// Update the SSL termination configuration for a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// Specifies when the representing the asynchronous server operation should be considered complete. + /// The that the task will observe. + /// An optional callback object to receive progress notifications, if is . If this is , no progress notifications are sent. + /// + /// A object representing the asynchronous operation. If is + /// , the task will not be considered complete until + /// the load balancer transitions out of the state. + /// + /// If is . + /// + /// If is not a valid . + /// + /// If the REST request does not return successfully. + /// SSL Termination (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveSslConfigurationAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress progress); + + #endregion SSL Termination + + #region Metadata + + /// + /// Gets the metadata associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// a collection of objects describing the metadata + /// associated with a load balancer. + /// + /// If is . + /// If the REST request does not return successfully. + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListLoadBalancerMetadataAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken); + + /// + /// Gets a specific metadata item associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The metadata item ID. This is obtained from LoadBalancerMetadataItem.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// a object describing the metadata item. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetLoadBalancerMetadataItemAsync(LoadBalancerId loadBalancerId, MetadataId metadataId, CancellationToken cancellationToken); + + /// + /// Gets the metadata associated with a load balancer node. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// a collection of objects describing the metadata + /// associated with the load balancer node. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> ListNodeMetadataAsync(LoadBalancerId loadBalancerId, NodeId nodeId, CancellationToken cancellationToken); + + /// + /// Gets a specific metadata item associated with a load balancer node. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The metadata item ID. This is obtained from LoadBalancerMetadataItem.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// a object describing the metadata item. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task GetNodeMetadataItemAsync(LoadBalancerId loadBalancerId, NodeId nodeId, MetadataId metadataId, CancellationToken cancellationToken); + + /// + /// Updates the metadata associated with a load balancer. + /// + /// + /// + /// The behavior is unspecified if contains a pair whose key matches the name of an existing metadata item associated with the load balancer. + /// + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// A collection of metadata items to associate with the load balancer. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// a collection of objects describing the updated + /// metadata associated with the load balancer. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a pair whose is or empty, or whose is is . + /// + /// If the REST request does not return successfully. + /// Add Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> AddLoadBalancerMetadataAsync(LoadBalancerId loadBalancerId, IEnumerable> metadata, CancellationToken cancellationToken); + + /// + /// Updates the metadata associated with a load balancer node. + /// + /// + /// + /// The behavior is unspecified if contains a pair whose key matches the name of an existing metadata item associated with the node. + /// + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// A collection of metadata items to associate with the node. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain a + /// a collection of objects describing the updated + /// metadata associated with the load balancer node. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains a pair whose is or empty, or whose is is . + /// + /// If the REST request does not return successfully. + /// Add Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task> AddNodeMetadataAsync(LoadBalancerId loadBalancerId, NodeId nodeId, IEnumerable> metadata, CancellationToken cancellationToken); + + /// + /// Sets the value for a metadata item associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The metadata item ID. This is obtained from LoadBalancerMetadataItem.Id. + /// The new value for the metadata item. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Modify Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task UpdateLoadBalancerMetadataItemAsync(LoadBalancerId loadBalancerId, MetadataId metadataId, string value, CancellationToken cancellationToken); + + /// + /// Sets the value for a metadata item associated with a load balancer node. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The metadata item ID. This is obtained from LoadBalancerMetadataItem.Id. + /// The new value for the metadata item. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Modify Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task UpdateNodeMetadataItemAsync(LoadBalancerId loadBalancerId, NodeId nodeId, MetadataId metadataId, string value, CancellationToken cancellationToken); + + /// + /// Removes one or more metadata items associated with a load balancer. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The metadata item IDs. These are obtained from LoadBalancerMetadataItem.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveLoadBalancerMetadataItemAsync(LoadBalancerId loadBalancerId, IEnumerable metadataIds, CancellationToken cancellationToken); + + /// + /// Removes one or more metadata items associated with a load balancer node. + /// + /// The load balancer ID. This is obtained from LoadBalancer.Id. + /// The load balancer node ID. This is obtained from Node.Id. + /// The metadata item IDs. These are obtained from LoadBalancerMetadataItem.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// + /// If the REST request does not return successfully. + /// Remove Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + Task RemoveNodeMetadataItemAsync(LoadBalancerId loadBalancerId, NodeId nodeId, IEnumerable metadataIds, CancellationToken cancellationToken); + + #endregion Metadata + } +} diff --git a/src/OpenStack/Providers/Rackspace/IMonitoringService.cs b/src/OpenStack/Providers/Rackspace/IMonitoringService.cs new file mode 100644 index 000000000..f51abb20c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/IMonitoringService.cs @@ -0,0 +1,1435 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Threading.Tasks; + using net.openstack.Providers.Rackspace.Objects.Monitoring; + using Newtonsoft.Json.Linq; + using CancellationToken = System.Threading.CancellationToken; + using WebException = System.Net.WebException; + + /// + /// Represents a provider for the Rackspace Cloud Monitoring service. + /// + /// Rackspace Cloud Monitoring Developer Guide - API v1.0 + /// + public interface IMonitoringService + { + #region Core + + #region Account + + /// + /// Gets information about a monitoring account. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object describing + /// the account. + /// + /// If the REST request does not return successfully. + /// Get Account (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetAccountAsync(CancellationToken cancellationToken); + + /// + /// Updates a monitoring account. + /// + /// The account ID. This is obtained from MonitoringAccount.Id. + /// An object describing the changes to apply to the account. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Account (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task UpdateAccountAsync(MonitoringAccountId accountId, AccountConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Gets the resource and rate limits enforced by the monitoring service. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object describing + /// the resource and rate limits of the monitoring service. + /// + /// If the REST request does not return successfully. + /// Get Limits (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetLimitsAsync(CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring audits. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , a provider-specific default value is used. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , the current time is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If occurs before . + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// List Audits (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Time Series Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAuditsAsync(AuditId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to, CancellationToken cancellationToken); + + #endregion Account + + #region Entities + + /// + /// Creates a new monitoring entity. + /// + /// A object describing the new entity. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain the identifying the new entity. + /// + /// If is . + /// If the REST request does not return successfully. + /// Create Entities (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task CreateEntityAsync(NewEntityConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring entities. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Entities (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListEntitiesAsync(EntityId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring entity by ID. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing the entity. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Entity (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetEntityAsync(EntityId entityId, CancellationToken cancellationToken); + + /// + /// Updates a monitoring entity. + /// + /// The entity ID. This is obtained from Entity.Id. + /// An object describing the changes to apply to the entity. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Entity (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task UpdateEntityAsync(EntityId entityId, UpdateEntityConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Remove and delete a monitoring entity by ID. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Delete Entity (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task RemoveEntityAsync(EntityId entityId, CancellationToken cancellationToken); + + #endregion Entities + + #region Checks + + /// + /// Creates a new check. + /// + /// The entity ID. This is obtained from Entity.Id. + /// A object describing the new check. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain the identifying the new check. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task CreateCheckAsync(EntityId entityId, NewCheckConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Test a monitoring check. + /// + /// The entity ID. This is obtained from Entity.Id. + /// A object describing the check to test. + /// to include debug information in the result; otherwise, . If the value is , a provider-specific default is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a collection objects describing + /// the test results. + /// + /// Test Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Test Check and Include Debug Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> TestCheckAsync(EntityId entityId, NewCheckConfiguration configuration, bool? debug, CancellationToken cancellationToken); + + /// + /// Test an existing check by ID. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a collection objects describing + /// the test results. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Test Existing Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> TestExistingCheckAsync(EntityId entityId, CheckId checkId, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring checks. + /// + /// The entity ID. This is obtained from Entity.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Checks (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListChecksAsync(EntityId entityId, CheckId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring check by ID. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing the check. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetCheckAsync(EntityId entityId, CheckId checkId, CancellationToken cancellationToken); + + /// + /// Updates a monitoring check. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// An object describing the changes to apply to the check. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task UpdateCheckAsync(EntityId entityId, CheckId checkId, UpdateCheckConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Remove and delete a monitoring check by ID. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Delete Check (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task RemoveCheckAsync(EntityId entityId, CheckId checkId, CancellationToken cancellationToken); + + #endregion Checks + + #region Check Types + + /// + /// Gets a collection of monitoring check types. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Check Types (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListCheckTypesAsync(CheckTypeId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring check type by ID. + /// + /// The check type ID. This is obtained from CheckType.Id, or from the predefined values in . + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing the + /// check type. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Check Type (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetCheckTypeAsync(CheckTypeId checkTypeId, CancellationToken cancellationToken); + + #endregion Check Types + + #region Metrics + + /// + /// Gets a collection of monitoring metrics. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Metrics (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListMetricsAsync(EntityId entityId, CheckId checkId, MetricName marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a collection of data points collected for a metric by the monitoring service. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The check ID. This is obtained from Check.Id. + /// The metric name. This is obtained from Metric.Name. + /// The number of data points to return. + /// The granularity of the returned data points. + /// A collection of objects identifying the statistics to compute for the data. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a collection of objects + /// describing the data points collected for the metric. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If both and are . + /// -or- + /// If occurs before . + /// + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// Fetch Data Points (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> GetDataPointsAsync(EntityId entityId, CheckId checkId, MetricName metricName, int? points, DataPointGranularity resolution, IEnumerable select, DateTimeOffset from, DateTimeOffset to, CancellationToken cancellationToken); + + #endregion Metrics + + #region Alarms + + /// + /// Creates a new alarm. + /// + /// The entity ID. This is obtained from Entity.Id. + /// A object describing the new alarm. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain the identifying the new alarm. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Create Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task CreateAlarmAsync(EntityId entityId, NewAlarmConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Test a monitoring alarm. + /// + /// The entity ID. This is obtained from Entity.Id. + /// A object describing the alarm test configuration. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a collection objects describing + /// the test results. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Test Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> TestAlarmAsync(EntityId entityId, TestAlarmConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring entities. + /// + /// The entity ID. This is obtained from Entity.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Alarms (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAlarmsAsync(EntityId entityId, AlarmId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring alarm by ID. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing the alarm. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetAlarmAsync(EntityId entityId, AlarmId alarmId, CancellationToken cancellationToken); + + /// + /// Updates a monitoring alarm. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// An object describing the changes to apply to the alarm. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task UpdateAlarmAsync(EntityId entityId, AlarmId alarmId, UpdateAlarmConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Remove and delete a monitoring alarm by ID. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Remove Alarm (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task RemoveAlarmAsync(EntityId entityId, AlarmId alarmId, CancellationToken cancellationToken); + + #endregion Alarms + + #region Notification Plans + + /// + /// Creates a new notification plan. + /// + /// A object describing the new notification plan. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain the identifying the + /// new notification plan. + /// + /// If is . + /// If the REST request does not return successfully. + /// Create Notification Plan (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task CreateNotificationPlanAsync(NewNotificationPlanConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring notification plans. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Notification Plans (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListNotificationPlansAsync(NotificationPlanId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring notification plan by ID. + /// + /// The notification plan ID. This is obtained from NotificationPlan.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object describing + /// the notification plan. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Notification Plan (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetNotificationPlanAsync(NotificationPlanId notificationPlanId, CancellationToken cancellationToken); + + /// + /// Updates a monitoring notification plan. + /// + /// The notification plan ID. This is obtained from NotificationPlan.Id. + /// An object describing the changes to apply to the notification plan. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Notification Plans (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task UpdateNotificationPlanAsync(NotificationPlanId notificationPlanId, UpdateNotificationPlanConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Remove and delete a monitoring notification plan by ID. + /// + /// The notification plan ID. This is obtained from NotificationPlan.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Delete Notification Plans (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task RemoveNotificationPlanAsync(NotificationPlanId notificationPlanId, CancellationToken cancellationToken); + + #endregion Notification Plans + + #region Monitoring Zones + + /// + /// Gets a collection of monitoring zones. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Monitoring Zones (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListMonitoringZonesAsync(MonitoringZoneId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring zone by ID. + /// + /// The monitoring zone ID. This is obtained from MonitoringZone.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object describing the + /// monitoring zone. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Monitoring Zone (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetMonitoringZoneAsync(MonitoringZoneId monitoringZoneId, CancellationToken cancellationToken); + + /// + /// Perform a traceroute operation from a monitoring zone to a particular target. + /// + /// The monitoring zone ID. This is obtained from MonitoringZone.Id. + /// A object containing the traceroute parameters. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object describing the + /// results of the traceroute operation. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Perform a "traceroute" from a Monitoring Zone (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task PerformTraceRouteFromMonitoringZoneAsync(MonitoringZoneId monitoringZoneId, TraceRouteConfiguration configuration, CancellationToken cancellationToken); + + #endregion Monitoring Zones + + #region Alarm Notification History + + /// + /// Gets a collection of objects identifying the particular checks + /// for which an alarm notification history is present for a particular entity/alarm + /// combination. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a collection of objects + /// identifying the checks for which an alarm notification history is present. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Discover Alarm Notification History (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> DiscoverAlarmNotificationHistoryAsync(EntityId entityId, AlarmId alarmId, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring alarm notification history items. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// The check ID. This is obtained from Check.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , a provider-specific default value is used. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , the current time is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If occurs before . + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// List Alarm Notification History (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Time Series Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAlarmNotificationHistoryAsync(EntityId entityId, AlarmId alarmId, CheckId checkId, AlarmNotificationHistoryItemId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to, CancellationToken cancellationToken); + + /// + /// Gets a monitoring alarm notification history item by ID. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The alarm ID. This is obtained from Alarm.Id. + /// The check ID. This is obtained from Check.Id. + /// The alarm notification history item ID. This is obtained from AlarmNotificationHistoryItem.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object + /// describing the alarm notification history item. + /// + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get Alarm Notification History (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetAlarmNotificationHistoryAsync(EntityId entityId, AlarmId alarmId, CheckId checkId, AlarmNotificationHistoryItemId alarmNotificationHistoryItemId, CancellationToken cancellationToken); + + #endregion Alarm Notification History + + #region Notifications + + /// + /// Creates a new notification. + /// + /// A object describing the new notification. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain the identifying the + /// new notification. + /// + /// If is . + /// If the REST request does not return successfully. + /// Create Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task CreateNotificationAsync(NewNotificationConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Test a monitoring notification. + /// + /// A object describing the notification to test. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object describing + /// the test results. + /// + /// If is . + /// If the REST request does not return successfully. + /// Test Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task TestNotificationAsync(NewNotificationConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Test an existing notification by ID. + /// + /// The notification ID. This is obtained from Notification.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object describing + /// the test results. + /// + /// If is . + /// If the REST request does not return successfully. + /// Test Existing Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task TestExistingNotificationAsync(NotificationId notificationId, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring notifications. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Notifications (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListNotificationsAsync(NotificationId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring notification by ID. + /// + /// The notification ID. This is obtained from Notification.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing the + /// notification. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetNotificationAsync(NotificationId notificationId, CancellationToken cancellationToken); + + /// + /// Updates a monitoring notification. + /// + /// The notification ID. This is obtained from Notification.Id. + /// An object describing the changes to apply to the notification. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task UpdateNotificationAsync(NotificationId notificationId, UpdateNotificationConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Remove and delete a monitoring notification by ID. + /// + /// The notification ID. This is obtained from Notification.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Delete Notification (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task RemoveNotificationAsync(NotificationId notificationId, CancellationToken cancellationToken); + + #endregion Notifications + + #region Notification Types + + /// + /// Gets a collection of monitoring notification types. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Notification Types (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListNotificationTypesAsync(NotificationTypeId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring notification type by ID. + /// + /// The notification type ID. This is obtained from NotificationType.Id, or from the predefined values in . + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing\ + /// the notification type. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Notification Type (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetNotificationTypeAsync(NotificationTypeId notificationTypeId, CancellationToken cancellationToken); + + #endregion Notification Types + + #region Changelogs + + /// + /// Gets a collection of monitoring alarm changelogs. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , a provider-specific default value is used. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , the current time is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If occurs before . + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// List Alarm Changelogs (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Time Series Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAlarmChangelogsAsync(AlarmChangelogId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring alarm changelogs. + /// + /// The entity ID to filter alarm changelogs. This is obtained from Entity.Id. If the value is , changelogs for all entities are returned. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The beginning timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , a provider-specific default value is used. + /// The ending timestamp of the items to include in the collection. This parameter is used for time series collections. If the value is , the current time is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If occurs before . + /// + /// If is less than or equal to 0. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// -or- + /// If represents a date before January 1, 1970 UTC. + /// + /// If the REST request does not return successfully. + /// List Alarm Changelogs (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Time Series Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAlarmChangelogsAsync(EntityId entityId, AlarmChangelogId marker, int? limit, DateTimeOffset? from, DateTimeOffset? to, CancellationToken cancellationToken); + + #endregion Changelogs + + #region Views + + /// + /// Gets a collection of monitoring entity overviews. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// Get Overview (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListEntityOverviewsAsync(EntityId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring entity overviews, filtered by entity ID. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// A collection of entity IDs for filter the results. If the value is , overviews for all entities are returned. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is non- and contains any values. + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// Get Overview (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListEntityOverviewsAsync(EntityId marker, int? limit, IEnumerable entityIdFilter, CancellationToken cancellationToken); + + #endregion Views + + #region Alarm Examples + + /// + /// Gets a collection of monitoring alarm examples. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Alarm Examples (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAlarmExamplesAsync(AlarmExampleId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring alarm example by ID. + /// + /// The alarm example ID. This is obtained from AlarmExample.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing the + /// alarm example. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Alarm Example (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetAlarmExampleAsync(AlarmExampleId alarmExampleId, CancellationToken cancellationToken); + + /// + /// Evaluate the template of a single alarm example. + /// + /// The alarm example ID. This is obtained from AlarmExample.Id. + /// A dictionary containing the values to insert in the alarm example. The dictionary should contain a key/value pair for each field described in for the alarm example. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a object containing + /// the evaluated alarm example. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If contains any empty keys. + /// If the REST request does not return successfully. + /// Evaluate Alarm Example (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task EvaluateAlarmExampleAsync(AlarmExampleId alarmExampleId, IDictionary exampleParameters, CancellationToken cancellationToken); + + #endregion Alarm Examples + + #endregion Core + + #region Agent + + #region Agents + + /// + /// Gets a collection of monitoring agents. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Agents (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAgentsAsync(AgentId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring agent by ID. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing the agent. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Agent (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetAgentAsync(AgentId agentId, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring agent connections. + /// + /// The agent ID. This is obtained from Agent.Id. + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is . + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Agent Connections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAgentConnectionsAsync(AgentId agentId, AgentConnectionId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring agent connection by ID. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The agent connection ID. This is obtained from AgentConnection.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing + /// the agent connection. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Get Agent Connection (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetAgentConnectionAsync(AgentId agentId, AgentConnectionId agentConnectionId, CancellationToken cancellationToken); + + #endregion Agents + + #region Agent Token + + /// + /// Creates a new agent token. + /// + /// An object describing the new agent token. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain the identifying the + /// new agent token. + /// + /// If is . + /// If the REST request does not return successfully. + /// Create Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task CreateAgentTokenAsync(AgentTokenConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Gets a collection of monitoring agent tokens. + /// + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Agent Tokens (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAgentTokensAsync(AgentTokenId marker, int? limit, CancellationToken cancellationToken); + + /// + /// Gets a monitoring agent token by ID. + /// + /// The agent token ID. This is obtained from AgentToken.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain an object describing the + /// agent token. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task GetAgentTokenAsync(AgentTokenId agentTokenId, CancellationToken cancellationToken); + + /// + /// Updates a monitoring agent token. + /// + /// The agent token ID. This is obtained from AgentToken.Id. + /// An object describing the changes to apply to the agent token. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Update Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task UpdateAgentTokenAsync(AgentTokenId agentTokenId, AgentTokenConfiguration configuration, CancellationToken cancellationToken); + + /// + /// Remove and delete a monitoring agent token by ID. + /// + /// The agent token ID. This is obtained from AgentToken.Id. + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// If the REST request does not return successfully. + /// Delete Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task RemoveAgentTokenAsync(AgentTokenId agentTokenId, CancellationToken cancellationToken); + + #endregion Agent Token + + #region Agent Host Information + + /// + /// Gets agent host information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The host information type. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If the REST request does not return successfully. + /// Agent Host Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> GetAgentHostInformationAsync(AgentId agentId, HostInformationType hostInformation, CancellationToken cancellationToken); + + /// + /// Gets CPU information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get CPUs Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task>> GetCpuInformationAsync(AgentId agentId, CancellationToken cancellationToken); + + /// + /// Gets disk information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Disks Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task>> GetDiskInformationAsync(AgentId agentId, CancellationToken cancellationToken); + + /// + /// Gets filesystem information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Filesystems Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task>> GetFilesystemInformationAsync(AgentId agentId, CancellationToken cancellationToken); + + /// + /// Gets memory information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Memory Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> GetMemoryInformationAsync(AgentId agentId, CancellationToken cancellationToken); + + /// + /// Gets network interface information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Network Interfaces Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task>> GetNetworkInterfaceInformationAsync(AgentId agentId, CancellationToken cancellationToken); + + /// + /// Gets process information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Processes Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task>> GetProcessInformationAsync(AgentId agentId, CancellationToken cancellationToken); + + /// + /// Gets system information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get System Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> GetSystemInformationAsync(AgentId agentId, CancellationToken cancellationToken); + + /// + /// Gets login information reported by a monitoring agent. + /// + /// The agent ID. This is obtained from Agent.Id. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the host information. + /// + /// If is . + /// If the REST request does not return successfully. + /// Get Logged-in User Information (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task>> GetLoginInformationAsync(AgentId agentId, CancellationToken cancellationToken); + + #endregion Agent Host Information + + #region Agent Targets + + /// + /// Gets a collection of monitoring agent check targets. + /// + /// The entity ID. This is obtained from Entity.Id. + /// The agent check type ID. This is obtained from CheckType.Id, or from the predefined values in . + /// A marker identifying the next page of results. This parameter is used for pagination, and is obtained from . If the value is , the list starts at the beginning. + /// The maximum number of items to include in a single page of results. This parameter is used for pagination. If the value is , a provider-specific default value is used. + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When + /// the task completes successfully, the + /// property will contain a + /// object containing the page of results and its associated pagination metadata. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// If is not an agent check type (i.e. the property is ). + /// If is less than or equal to 0. + /// If the REST request does not return successfully. + /// List Agent Check Targets (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// Paginated Collections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + Task> ListAgentCheckTargetsAsync(EntityId entityId, CheckTypeId agentCheckType, CheckTargetId marker, int? limit, CancellationToken cancellationToken); + + #endregion Agent Targets + + #endregion Agent + } +} diff --git a/src/OpenStack/Providers/Rackspace/IProviderFactory`2.cs b/src/OpenStack/Providers/Rackspace/IProviderFactory`2.cs new file mode 100644 index 000000000..bc54a0e42 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/IProviderFactory`2.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + + /// + /// Represents a factory for obtaining service providers for particular keys. + /// + /// The provider type. + /// The key type. + internal interface IProviderFactory + { + /// + /// Get a provider for the specified . + /// + /// The key. If this value is , a default provider will be returned if available. + /// The provider. + /// If is , and the factory does not support a default provider. + T Get(T2 key); + } +} diff --git a/src/OpenStack/Providers/Rackspace/IRackspaceProvider.cs b/src/OpenStack/Providers/Rackspace/IRackspaceProvider.cs new file mode 100644 index 000000000..18884a334 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/IRackspaceProvider.cs @@ -0,0 +1,18 @@ +using net.openstack.Core.Domain; +using net.openstack.Core.Providers; + +namespace net.openstack.Providers.Rackspace +{ + internal interface IRackspaceProvider + { + /// + /// The used by the provider. + /// + IIdentityProvider IdentityProvider { get; } + + /// + /// The default identify used by the provider. + /// + CloudIdentity DefaultIdentity { get; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Providers/Rackspace/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/NamespaceDoc.cs new file mode 100644 index 000000000..8966780dd --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace +{ + using System.Runtime.CompilerServices; + + /// + /// The namespaces provide an + /// implementation of the core OpenStack interfaces for accessing Rackspace + /// products and services, as well as additional Rackspace-specific functionality. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/ArchiveFormat.cs b/src/OpenStack/Providers/Rackspace/Objects/ArchiveFormat.cs new file mode 100644 index 000000000..183f1930c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/ArchiveFormat.cs @@ -0,0 +1,102 @@ +namespace net.openstack.Providers.Rackspace.Objects +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a archive format for the Cloud Files Extract Archive operation. + /// + /// + /// This class functions as a strongly-typed enumeration of known archive types, + /// with added support for unknown types returned or supported by a server extension. + /// + /// + /// + /// + /// + [JsonConverter(typeof(ArchiveFormat.Converter))] + public sealed class ArchiveFormat : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly ArchiveFormat _tar = FromName("tar"); + private static readonly ArchiveFormat _tarGz = FromName("tar.gz"); + private static readonly ArchiveFormat _tarBz2 = FromName("tar.bz2"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private ArchiveFormat(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static ArchiveFormat FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new ArchiveFormat(i)); + } + + /// + /// Gets an representing tar files. + /// + public static ArchiveFormat Tar + { + get + { + return _tar; + } + } + + /// + /// Gets an representing tar.gz files. + /// + public static ArchiveFormat TarGz + { + get + { + return _tarGz; + } + } + + /// + /// Gets an representing tar.bz2 files. + /// + public static ArchiveFormat TarBz2 + { + get + { + return _tarBz2; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ArchiveFormat FromName(string name) + { + return ArchiveFormat.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AuthDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/AuthDetails.cs new file mode 100644 index 000000000..1b0fcf595 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AuthDetails.cs @@ -0,0 +1,17 @@ +namespace net.openstack.Providers.Rackspace.Objects +{ + using Newtonsoft.Json; + + [JsonObject(MemberSerialization.OptIn)] + internal class AuthDetails + { + [JsonProperty("passwordCredentials", DefaultValueHandling = DefaultValueHandling.Include)] + public Credentials PasswordCredentials { get; set; } + + [JsonProperty("RAX-KSKEY:apiKeyCredentials", DefaultValueHandling = DefaultValueHandling.Include)] + public Credentials APIKeyCredentials { get; set; } + + [JsonProperty("RAX-AUTH:domain", DefaultValueHandling = DefaultValueHandling.Include)] + public Domain Domain { get; set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ActiveServer.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ActiveServer.cs new file mode 100644 index 000000000..51d0b814a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ActiveServer.cs @@ -0,0 +1,67 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + using Link = net.openstack.Core.Domain.Link; + using ServerBase = net.openstack.Core.Domain.ServerBase; + using ServerId = net.openstack.Core.Domain.ServerId; + + /// + /// Represents an active server which is part of a scaling group in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ActiveServer : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private ServerId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("links", DefaultValueHandling = DefaultValueHandling.Ignore)] + private Link[] _links; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ActiveServer() + { + } + + /// + /// Gets the ID of the active server which is part of the scaling group. + /// + /// + public ServerId Id + { + get + { + return _id; + } + } + + /// + /// Gets a collection of links to resources related to this active server resource. + /// + public ReadOnlyCollection Links + { + get + { + if (_links == null) + return null; + + return new ReadOnlyCollection(_links); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GenericLaunchConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GenericLaunchConfiguration.cs new file mode 100644 index 000000000..554ca3410 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GenericLaunchConfiguration.cs @@ -0,0 +1,39 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + + /// + /// This class extends the class + /// to model custom launch configurations that are not directly supported by this SDK. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class GenericLaunchConfiguration : LaunchConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GenericLaunchConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified launch type and arguments. + /// + /// The launch type. + /// An object modeling the JSON representation of the launch arguments. + /// If is . + public GenericLaunchConfiguration(LaunchType launchType, object arguments) + : base(launchType, JToken.FromObject(arguments)) + { + if (launchType == null) + throw new ArgumentNullException("launchType"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GroupConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GroupConfiguration.cs new file mode 100644 index 000000000..be56f0ec6 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GroupConfiguration.cs @@ -0,0 +1,168 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents the configuration for a scaling group in the . + /// + /// + /// The configuration options for the scaling group. The scaling group configuration specifies + /// the basic elements of the Auto Scale configuration. It manages how many servers can + /// participate in the scaling group. It specifies information related to load balancers. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class GroupConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("cooldown")] + private long? _cooldown; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("minEntities")] + private long? _minEntities; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("maxEntities", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _maxEntities; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private JObject _metadata; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GroupConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The name of the scaling group. + /// The cooldown period of the scaling group. + /// The minimum number of servers to include in the scaling group. + /// The maximum number of servers to include in the scaling group. + /// The metadata to associate with the scaling group. + /// If is . + /// + /// If is empty. + /// -or- + /// If is less than . + /// + /// + /// If is less than . + /// -or- + /// If is less than 0. + /// -or- + /// If is less than 0. + /// + public GroupConfiguration(string name, TimeSpan cooldown, int minEntities, int? maxEntities, JObject metadata) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (cooldown < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("cooldown"); + if (minEntities < 0) + throw new ArgumentOutOfRangeException("minEntities"); + if (maxEntities < 0) + throw new ArgumentOutOfRangeException("maxEntities"); + + _name = name; + _cooldown = (int)cooldown.TotalSeconds; + _minEntities = minEntities; + _maxEntities = maxEntities; + _metadata = metadata; + } + + /// + /// Gets the name of the scaling group. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the cooldown time of the scaling group, which specifies the time the group must wait + /// after a scaling policy is triggered before another request for scaling is accepted. + /// + /// + /// Applies mainly to event-based policies. + /// + public TimeSpan? Cooldown + { + get + { + if (_cooldown == null) + return null; + + return TimeSpan.FromSeconds(_cooldown.Value); + } + } + + /// + /// Gets the minimum amount of entities that are allowed in this group. You cannot scale down + /// below this value. Increasing this value can cause an immediate addition to the scaling + /// group. + /// + public long? MinEntities + { + get + { + return _minEntities; + } + } + + /// + /// Gets the maximum amount of entities that are allowed in this group. You cannot scale up + /// above this value. Decreasing this value can cause an immediate reduction of the scaling + /// group. + /// + public long? MaxEntities + { + get + { + return _maxEntities; + } + } + + /// + /// Gets the metadata associated with the scaling group resource. + /// + public JObject Metadata + { + get + { + return _metadata; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GroupState.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GroupState.cs new file mode 100644 index 000000000..a49889329 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/GroupState.cs @@ -0,0 +1,142 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + using ServerState = net.openstack.Core.Domain.ServerState; + + /// + /// This class represents the current state of a scaling group in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class GroupState : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("paused")] + private bool? _paused; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("activeCapacity")] + private long? _activeCapacity; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("desiredCapacity")] + private long? _desiredCapacity; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("pendingCapacity")] + private long? _pendingCapacity; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("active")] + private ActiveServer[] _active; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GroupState() + { + } + + /// + /// Gets the name of the Auto Scale group. + /// + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets a value indicating whether execution of the scaling policies in the Auto Scale + /// group is currently suspended. + /// + /// + /// If this value is , the group will not scale up or down. All + /// policy execution calls will be ignored while this value is set to . + /// + public bool? Paused + { + get + { + return _paused; + } + } + + /// + /// Gets the number of servers in the group which completed the build process + /// and are now considered active. + /// + public long? ActiveCapacity + { + get + { + return _activeCapacity; + } + } + + /// + /// Gets the desired number of resources in the scaling group. This property is + /// the sum of the and . + /// + public long? DesiredCapacity + { + get + { + return _desiredCapacity; + } + } + + /// + /// Gets the number of servers currently in the state. + /// + public long? PendingCapacity + { + get + { + return _pendingCapacity; + } + } + + /// + /// Gets a collection of objects describing the servers + /// in the scaling group. + /// + public ReadOnlyCollection Active + { + get + { + if (_active == null) + return null; + + return new ReadOnlyCollection(_active); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchConfiguration.cs new file mode 100644 index 000000000..fb24bf6bd --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchConfiguration.cs @@ -0,0 +1,56 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents the launch configuration for a scaling group in the . + /// + /// + /// A launch configuration defines what to do when a new server is created, including information + /// about the server image, the flavor of the server image, and the load balancer to which to + /// connect. Currently, the only supported is . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class LaunchConfiguration : ExtensibleJsonObject + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LaunchConfiguration() + { + } + + /// + /// Gets the launch type for the Auto Scale launch configuration. + /// + public abstract LaunchType LaunchType + { + get; + } + + /// + /// Deserializes a JSON object to a instance of the proper type. + /// + /// The JSON object representing the launch configuration. + /// A object corresponding to the JSON object. + /// If is . + public static LaunchConfiguration FromJObject(JObject jsonObject) + { + if (jsonObject == null) + throw new ArgumentNullException("jsonObject"); + + JToken launchType = jsonObject["type"]; + if (launchType == null || launchType.ToObject() == LaunchType.LaunchServer) + return jsonObject.ToObject(); + + return jsonObject.ToObject(); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchConfiguration`1.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchConfiguration`1.cs new file mode 100644 index 000000000..6272770f2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchConfiguration`1.cs @@ -0,0 +1,73 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using Newtonsoft.Json; + + /// + /// This class extends the class with + /// strongly-typed launch arguments. + /// + /// The type modeling the arguments for a launch configuration. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class LaunchConfiguration : LaunchConfiguration + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private LaunchType _launchType; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("args", DefaultValueHandling = DefaultValueHandling.Ignore)] + private TArguments _arguments; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LaunchConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified launch type and arguments. + /// + /// The server launch type. + /// The arguments for launching a server. + /// If is . + protected LaunchConfiguration(LaunchType launchType, TArguments arguments) + { + if (launchType == null) + throw new ArgumentNullException("launchType"); + + _launchType = launchType; + _arguments = arguments; + } + + /// + public override LaunchType LaunchType + { + get + { + return _launchType; + } + } + + /// + /// Gets the launch arguments. + /// + public TArguments Arguments + { + get + { + return _arguments; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchType.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchType.cs new file mode 100644 index 000000000..d592fefdc --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LaunchType.cs @@ -0,0 +1,76 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents an Auto Scale launch type. + /// + /// + /// This class functions as a strongly-typed enumeration of known launch types, + /// with added support for unknown types returned by a server extension. + /// + /// Update launch configuration (Rackspace Auto Scale Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(LaunchType.Converter))] + public sealed class LaunchType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly LaunchType _launchServer = FromName("launch_server"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private LaunchType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static LaunchType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new LaunchType(i)); + } + + /// + /// Gets a representing a launch configuration that launches new server resources. + /// + public static LaunchType LaunchServer + { + get + { + return _launchServer; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override LaunchType FromName(string name) + { + return LaunchType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LoadBalancerArgument.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LoadBalancerArgument.cs new file mode 100644 index 000000000..5c034a796 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/LoadBalancerArgument.cs @@ -0,0 +1,83 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + using LoadBalancer = net.openstack.Providers.Rackspace.Objects.LoadBalancers.LoadBalancer; + using LoadBalancerId = net.openstack.Providers.Rackspace.Objects.LoadBalancers.LoadBalancerId; + + /// + /// This class models the JSON representation of a load balancer to add new + /// servers created by a scaling group in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerArgument : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("loadBalancerId")] + private LoadBalancerId _loadBalancerId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("port")] + private int? _port; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerArgument() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified load balancer ID and port. + /// + /// The ID of the load balancer to add new servers to. See . + /// The port used for the load balancer protocol. See . + /// If is . + /// If is less than 0 or greater than 65535. + public LoadBalancerArgument(LoadBalancerId loadBalancerId, int port) + { + if (loadBalancerId == null) + throw new ArgumentNullException("loadBalancerId"); + if (port <= 0 || port > 65535) + throw new ArgumentOutOfRangeException("port"); + + _loadBalancerId = loadBalancerId; + _port = port; + } + + /// + /// Gets the ID of the load balancer to add new servers to. + /// + /// + public LoadBalancerId LoadBalancerId + { + get + { + return _loadBalancerId; + } + } + + /// + /// Gets the port on which new servers will receive traffic from the load balancer, often port 80. + /// + /// + public int? Port + { + get + { + return _port; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/NamespaceDoc.cs new file mode 100644 index 000000000..cb35c0b4d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines + /// the object model for communicating with Rackspace's Cloud Auto Scale service over REST APIs. + /// + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/NewWebhookConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/NewWebhookConfiguration.cs new file mode 100644 index 000000000..1fb01e0be --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/NewWebhookConfiguration.cs @@ -0,0 +1,55 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to create a new + /// resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewWebhookConfiguration : WebhookConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NewWebhookConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified name. + /// + /// The webhook name. + /// If is . + /// If is empty. + public NewWebhookConfiguration(string name) + : base(name, null) + { + if (name == null) + throw new ArgumentNullException("name"); + } + + /// + /// Initializes a new instance of the class + /// with the specified name and metadata. + /// + /// The webhook name. + /// The metadata to associate with the webhook. + /// If is . + /// If is empty. + public NewWebhookConfiguration(string name, IDictionary metadata) + : base(name, metadata) + { + if (name == null) + throw new ArgumentNullException("name"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/Policy.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/Policy.cs new file mode 100644 index 000000000..2f0bcb38c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/Policy.cs @@ -0,0 +1,63 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System.Collections.ObjectModel; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// Represents a scaling policy in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Policy : PolicyConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private PolicyId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("links")] + private Link[] _links; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Policy() + { + } + + /// + /// Gets the unique identifier of the scaling policy. + /// + public PolicyId Id + { + get + { + return _id; + } + } + + /// + /// Gets a collection of links to resources related to this scaling policy resource. + /// + public ReadOnlyCollection Links + { + get + { + if (_links == null) + return null; + + return new ReadOnlyCollection(_links); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyConfiguration.cs new file mode 100644 index 000000000..de2a8d297 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyConfiguration.cs @@ -0,0 +1,324 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the basic configuration of a scaling policy + /// in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class PolicyConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("desiredCapacity", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _desiredCapacity; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("cooldown")] + private long? _cooldown; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("change", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _change; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("changePercent", DefaultValueHandling = DefaultValueHandling.Ignore)] + private double? _changePercent; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("args", DefaultValueHandling = DefaultValueHandling.Ignore)] + private JObject _args; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private PolicyType _type; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected PolicyConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// + /// To create scaling policy for one of the predefined policy types, use + /// one of the following factory methods. + /// + /// + /// + /// + /// + /// + /// + /// The name of the scaling policy. + /// The scaling policy type. + /// The desired capacity of the scaling policy. + /// The cooldown of the scaling policy. + /// The incremental change for the scaling policy. + /// The percentage change for the scaling policy. + /// An object modeling the additional arguments to associate with the scaling policy. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is less than . + /// + protected PolicyConfiguration(string name, PolicyType type, long? desiredCapacity, TimeSpan? cooldown, long? change, double? changePercent, object arguments) + { + if (name == null) + throw new ArgumentNullException("name"); + if (type == null) + throw new ArgumentNullException("type"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (desiredCapacity < 0) + throw new ArgumentOutOfRangeException("desiredCapacity"); + if (cooldown < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("cooldown"); + + _name = name; + _type = type; + _desiredCapacity = desiredCapacity; + _cooldown = cooldown != null ? (long?)cooldown.Value.TotalSeconds : null; + _change = change; + _changePercent = changePercent; + _args = arguments != null ? JObject.FromObject(arguments) : null; + } + + /// + /// Gets the name of the scaling policy. + /// + /// + /// The must be unique for each scaling policy. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the desired capacity of the scaling policy. + /// + /// + /// Specifies the final capacity that is desired by the scale up event. Note that this value + /// is always rounded up. Use to specify a number of servers for the policy to implement - by + /// either adding or removing servers as needed. + /// + public long? DesiredCapacity + { + get + { + return _desiredCapacity; + } + } + + /// + /// Gets the cooldown period of the scaling policy. + /// + /// + /// The cooldown period prohibits the execution of this specific policy until the configured + /// cooldown time period has passed. Helps prevent an event triggering a policy and can help + /// to ensure that servers can be added quickly (short cooldown) and removed gradually (long + /// cooldown). + /// + public TimeSpan? Cooldown + { + get + { + if (_cooldown == null) + return null; + + return TimeSpan.FromSeconds(_cooldown.Value); + } + } + + /// + /// Gets the incremental change for the scaling policy. + /// + /// + /// Specifies the number of entities to add or remove, for example "1" implies that 1 server + /// needs to be added. Use to change the number of servers to a specific number. If a positive + /// number is used, servers are added; if a negative number is used, servers are removed. + /// + public long? Change + { + get + { + return _change; + } + } + + /// + /// Gets the percentage change for the scaling policy. + /// + /// + /// Use to change the percentage of servers relative to the current number of servers. If a positive + /// number is used, servers are added; if a negative number is used, servers are removed. The absolute + /// change in the number of servers is always rounded up. For example, if -X% of the current number + /// of servers translates to -0.5 or -0.25 or -0.75 servers, the actual number of servers that will + /// be shut down is 1. + /// + public double? ChangePercent + { + get + { + return _changePercent; + } + } + + /// + /// Gets the arguments for the scaling policy. + /// + public JObject Arguments + { + get + { + return _args; + } + } + + /// + /// Gets the scaling policy type. + /// + public PolicyType PolicyType + { + get + { + return _type; + } + } + + /// + /// Creates a new for a scaling policy that sets the + /// desired capacity of a scaling group to a specific value. + /// + /// The name of scaling policy. + /// The desired capacity for the scaling group. + /// The cooldown period for the scaling policy. + /// A representing the desired scaling policy configuration. + /// If is . + /// If is empty. + /// + /// If is less than 0. + /// -or- + /// If is less than . + /// + public static PolicyConfiguration Capacity(string name, int desiredCapacity, TimeSpan cooldown) + { + return new PolicyConfiguration(name, PolicyType.Webhook, desiredCapacity, cooldown, null, null, null); + } + + /// + /// Creates a new for a scaling policy that changes the + /// desired capacity of a scaling group by a fixed amount. + /// + /// The name of scaling policy. + /// The change to apply to the desired capacity for the scaling group. + /// The cooldown period for the scaling policy. + /// A representing the desired scaling policy configuration. + /// If is . + /// + /// If is empty. + /// -or- + /// If is 0. + /// + /// If is less than . + public static PolicyConfiguration IncrementalChange(string name, int change, TimeSpan cooldown) + { + if (change == 0) + throw new ArgumentException("change cannot be 0", "change"); + + return new PolicyConfiguration(name, PolicyType.Webhook, null, cooldown, change, null, null); + } + + /// + /// Creates a new for a scaling policy that changes the + /// desired capacity of a scaling group by a percentage amount. + /// + /// The name of scaling policy. + /// The percentage change to apply to the desired capacity for the scaling group. + /// The cooldown period for the scaling policy. + /// A representing the desired scaling policy configuration. + /// If is . + /// + /// If is empty. + /// -or- + /// If is 0. + /// + /// If is less than . + public static PolicyConfiguration PercentageChange(string name, double changePercentage, TimeSpan cooldown) + { + if (changePercentage == 0) + throw new ArgumentException("changePercentage cannot be 0", "changePercentage"); + + return new PolicyConfiguration(name, PolicyType.Webhook, null, cooldown, null, changePercentage, null); + } + + /// + /// Creates a new for a scaling policy that changes the + /// desired capacity of a scaling group by a percentage amount at the specified time. + /// + /// The name of scaling policy. + /// The percentage change to apply to the desired capacity for the scaling group. + /// The cooldown period for the scaling policy. + /// The time at which to apply the change. + /// A representing the desired scaling policy configuration. + /// If is . + /// + /// If is empty. + /// -or- + /// If is 0. + /// + /// If is less than . + public static PolicyConfiguration PercentageChangeAtTime(string name, double changePercentage, TimeSpan cooldown, DateTimeOffset time) + { + if (changePercentage == 0) + throw new ArgumentException("changePercentage cannot be 0", "changePercentage"); + + const string timeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"; + string serializedTime = time.ToUniversalTime().ToString(timeFormat); + + JObject arguments = new JObject( + new JProperty("at", JValue.CreateString(serializedTime))); + + return new PolicyConfiguration(name, PolicyType.Schedule, null, cooldown, null, changePercentage, arguments); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyId.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyId.cs new file mode 100644 index 000000000..7d823bbd2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a scaling policy in the . + /// + /// + /// + /// + [JsonConverter(typeof(PolicyId.Converter))] + public sealed class PolicyId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The scaling group identifier value. + /// If is . + /// If is empty. + public PolicyId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override PolicyId FromValue(string id) + { + return new PolicyId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyType.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyType.cs new file mode 100644 index 000000000..2f91a83b5 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/PolicyType.cs @@ -0,0 +1,100 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents an Auto Scale policy type. + /// + /// + /// This class functions as a strongly-typed enumeration of known policy types, + /// with added support for unknown types returned by a server extension. + /// + /// Create policy (Rackspace Auto Scale Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(PolicyType.Converter))] + public sealed class PolicyType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly PolicyType _webhook = FromName("webhook"); + private static readonly PolicyType _schedule = FromName("schedule"); + private static readonly PolicyType _cloudMonitoring = FromName("cloud_monitoring"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private PolicyType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static PolicyType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new PolicyType(i)); + } + + /// + /// Gets a representing a webhook scaling policy. + /// + public static PolicyType Webhook + { + get + { + return _webhook; + } + } + + /// + /// Gets a representing a scheduled scaling policy. + /// + public static PolicyType Schedule + { + get + { + return _schedule; + } + } + + /// + /// Gets a representing a scaling policy triggered by the Cloud Monitoring service. + /// + public static PolicyType CloudMonitoring + { + get + { + return _cloudMonitoring; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override PolicyType FromName(string name) + { + return PolicyType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroup.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroup.cs new file mode 100644 index 000000000..f785e82cf --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroup.cs @@ -0,0 +1,80 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System.Collections.ObjectModel; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// Represents a scaling group in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ScalingGroup : ScalingGroupConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private ScalingGroupId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("links")] + private Link[] _links; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state")] + private GroupState _state; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ScalingGroup() + { + } + + /// + /// Gets the unique identifier of the scaling group. + /// + public ScalingGroupId Id + { + get + { + return _id; + } + } + + /// + /// Gets a collection of links to resources related to this scaling group resource. + /// + public ReadOnlyCollection Links + { + get + { + if (_links == null) + return null; + + return new ReadOnlyCollection(_links); + } + } + + /// + /// Gets a object describing the current state of the scaling group. + /// + public GroupState State + { + get + { + return _state; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupConfiguration.cs new file mode 100644 index 000000000..5f9422e93 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupConfiguration.cs @@ -0,0 +1,37 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of the configuration for a new scaling group in the + /// . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ScalingGroupConfiguration : ScalingGroupConfiguration + { + /// + /// Initializes a new instance of the class with the specified + /// configurations. + /// + /// The group configuration for the scaling group. + /// The launch configuration for the scaling group. + /// A collection of scaling policies to initially create with the scaling group. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If contains any values. + public ScalingGroupConfiguration(GroupConfiguration groupConfiguration, LaunchConfiguration launchConfiguration, IEnumerable scalingPolicies) + : base(groupConfiguration, launchConfiguration, scalingPolicies) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupConfiguration`1.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupConfiguration`1.cs new file mode 100644 index 000000000..0d5c2ca9b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupConfiguration`1.cs @@ -0,0 +1,120 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the basic information related to the configuration of a + /// scaling group in the . + /// + /// The type modeling the JSON representation of a scaling policy. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class ScalingGroupConfiguration : ExtensibleJsonObject + where TPolicyConfiguration : PolicyConfiguration + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("groupConfiguration", DefaultValueHandling = DefaultValueHandling.Ignore)] + private GroupConfiguration _groupConfiguration; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("launchConfiguration", DefaultValueHandling = DefaultValueHandling.Ignore)] + private JObject _launchConfiguration; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("scalingPolicies", DefaultValueHandling = DefaultValueHandling.Ignore)] + private TPolicyConfiguration[] _scalingPolicies; + + /// + /// Initializes a new instance of the + /// class during JSON deserialization. + /// + [JsonConstructor] + protected ScalingGroupConfiguration() + { + } + + /// + /// Initializes a new instance of the + /// class with the specified configuration. + /// + /// The group configuration for the scaling group. + /// The launch configuration for the scaling group. + /// A collection of scaling policies to initially create with the scaling group. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If contains any values. + protected ScalingGroupConfiguration(GroupConfiguration groupConfiguration, LaunchConfiguration launchConfiguration, IEnumerable scalingPolicies) + { + if (groupConfiguration == null) + throw new ArgumentNullException("groupConfiguration"); + if (launchConfiguration == null) + throw new ArgumentNullException("launchConfiguration"); + if (scalingPolicies == null) + throw new ArgumentNullException("scalingPolicies"); + if (scalingPolicies.Contains(null)) + throw new ArgumentException("scalingPolicies cannot contain any null values", "scalingPolicies"); + + _groupConfiguration = groupConfiguration; + _launchConfiguration = JObject.FromObject(launchConfiguration); + _scalingPolicies = scalingPolicies.ToArray(); + } + + /// + /// Gets a object describing the group configuration for the scaling group. + /// + public GroupConfiguration GroupConfiguration + { + get + { + return _groupConfiguration; + } + } + + /// + /// Gets a object describing the launch configuration for the scaling group. + /// + public LaunchConfiguration LaunchConfiguration + { + get + { + if (_launchConfiguration == null) + return null; + + return LaunchConfiguration.FromJObject(_launchConfiguration); + } + } + + /// + /// Gets a collection of objects describing the + /// scaling policies of the scaling group. + /// + public ReadOnlyCollection ScalingPolicies + { + get + { + if (_scalingPolicies == null) + return null; + + return new ReadOnlyCollection(_scalingPolicies); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupId.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupId.cs new file mode 100644 index 000000000..d7a5d3019 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ScalingGroupId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a scaling group in the . + /// + /// + /// + /// + [JsonConverter(typeof(ScalingGroupId.Converter))] + public sealed class ScalingGroupId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The scaling group identifier value. + /// If is . + /// If is empty. + public ScalingGroupId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override ScalingGroupId FromValue(string id) + { + return new ScalingGroupId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerArgument.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerArgument.cs new file mode 100644 index 000000000..e2eac0583 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerArgument.cs @@ -0,0 +1,217 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using DiskConfiguration = net.openstack.Core.Domain.DiskConfiguration; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + using Flavor = net.openstack.Core.Domain.Flavor; + using FlavorId = net.openstack.Core.Domain.FlavorId; + using ImageId = net.openstack.Core.Domain.ImageId; + using Personality = net.openstack.Core.Domain.Personality; + using SimpleServerImage = net.openstack.Core.Domain.SimpleServerImage; + + /// + /// This class models the JSON representation of the arguments for creating new servers + /// as part of the launch configuration in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ServerArgument : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("flavorRef", DefaultValueHandling = DefaultValueHandling.Ignore)] + private FlavorId _flavorId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("imageRef", DefaultValueHandling = DefaultValueHandling.Ignore)] + private ImageId _imageId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("OS-DCF:diskConfig", DefaultValueHandling = DefaultValueHandling.Ignore)] + private DiskConfiguration _diskConfiguration; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private JObject _metadata; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("networks", DefaultValueHandling = DefaultValueHandling.Ignore)] + private ServerNetworkArgument[] _networks; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("personality", DefaultValueHandling = DefaultValueHandling.Ignore)] + private Personality[] _personality; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ServerArgument() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The ID of the flavor to use when creating new servers. See . + /// The ID of the image to use when creating new servers. See . + /// The prefix to use when assigning names to new servers. + /// The disk configuration to use for new servers. + /// The metadata to associate with the server argument. + /// A collection of objects describing the networks to initially connect newly created servers to. + /// A collection of objects describing the personality for new server instances. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values. + /// -or- + /// If contains any values. + /// + public ServerArgument(FlavorId flavorId, ImageId imageId, string name, DiskConfiguration diskConfiguration, JObject metadata, IEnumerable networks, IEnumerable personality) + { + if (flavorId == null) + throw new ArgumentNullException("flavorId"); + if (imageId == null) + throw new ArgumentNullException("imageId"); + + _flavorId = flavorId; + _imageId = imageId; + _name = name; + _diskConfiguration = diskConfiguration; + _metadata = metadata; + + if (networks != null) + { + _networks = networks.ToArray(); + if (_networks.Contains(null)) + throw new ArgumentException("networks cannot contain any null values", "networks"); + } + + if (personality != null) + { + _personality = personality.ToArray(); + if (_personality.Contains(null)) + throw new ArgumentException("personality cannot contain any null values", "personality"); + } + } + + /// + /// Gets the ID of the flavor to use when creating new servers. + /// + public FlavorId FlavorId + { + get + { + return _flavorId; + } + } + + /// + /// Gets the ID of the image to use when creating new servers. + /// + public ImageId ImageId + { + get + { + return _imageId; + } + } + + /// + /// Gets the prefix to use for the server name when creating new servers. + /// + /// + /// The final name assigned to servers created by the Auto Scale service will + /// be a combination of this value and a unique string generated by the Auto Scale + /// service. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the disk configuration, which specifies how new servers are partitioned. + /// + public DiskConfiguration DiskConfiguration + { + get + { + return _diskConfiguration; + } + } + + /// + /// Gets the metadata associated with the server argument resource. + /// + public JObject Metadata + { + get + { + return _metadata; + } + } + + /// + /// Gets a collection of objects describing the networks + /// to initially connect newly created servers to. + /// + public ReadOnlyCollection Networks + { + get + { + if (_networks == null) + return null; + + return new ReadOnlyCollection(_networks); + } + } + + /// + /// Gets a collection of objects describing the personality + /// for new server instances. + /// + public ReadOnlyCollection Personality + { + get + { + if (_personality == null) + return null; + + return new ReadOnlyCollection(_personality); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerLaunchArguments.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerLaunchArguments.cs new file mode 100644 index 000000000..395c8f9a8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerLaunchArguments.cs @@ -0,0 +1,104 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents the launch arguments for a in + /// the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ServerLaunchArguments : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("loadBalancers", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerArgument[] _loadBalancers; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("server", DefaultValueHandling = DefaultValueHandling.Ignore)] + private ServerArgument _server; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ServerLaunchArguments() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified server argument. + /// + /// A object containing the detailed arguments for launching a server. + public ServerLaunchArguments(ServerArgument server) + : this(server, null) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified server argument and collection of load balancers to initially + /// add created servers to. + /// + /// A object containing the detailed arguments for launching a server. + /// A collection of objects describing the load balancers to initially add created servers to. + /// If is . + /// If contains any values. + public ServerLaunchArguments(ServerArgument server, IEnumerable loadBalancers) + { + if (server == null) + throw new ArgumentNullException("server"); + + _server = server; + if (loadBalancers != null) + { + _loadBalancers = loadBalancers.ToArray(); + if (_loadBalancers.Contains(null)) + throw new ArgumentException("loadBalancers cannot contain any null values", "loadBalancers"); + } + } + + /// + /// Gets a object describing the launch arguments for the server. + /// + public ServerArgument Server + { + get + { + return _server; + } + } + + /// + /// Gets a collection of objects describing the load balancers to + /// initially add the created server to. + /// + /// + /// All servers are added to these load balancers with the IP addresses of their ServiceNet network. + /// All servers are enabled and equally weighted. Any new servers that are not connected to the + /// ServiceNet network are not added to any load balancers. + /// + public ReadOnlyCollection LoadBalancers + { + get + { + if (_loadBalancers == null) + return null; + + return new ReadOnlyCollection(_loadBalancers); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerLaunchConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerLaunchConfiguration.cs new file mode 100644 index 000000000..1676f92e3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerLaunchConfiguration.cs @@ -0,0 +1,37 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using Newtonsoft.Json; + + /// + /// This class describes the launch configuration for the + /// launch type. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ServerLaunchConfiguration : LaunchConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ServerLaunchConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified arguments. + /// + /// A object describing the launch arguments. + /// If is . + public ServerLaunchConfiguration(ServerLaunchArguments arguments) + : base(LaunchType.LaunchServer, arguments) + { + if (arguments == null) + throw new ArgumentNullException("arguments"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerNetworkArgument.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerNetworkArgument.cs new file mode 100644 index 000000000..5546ea745 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/ServerNetworkArgument.cs @@ -0,0 +1,60 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using Newtonsoft.Json; + using CloudNetwork = net.openstack.Core.Domain.CloudNetwork; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + using NetworkId = net.openstack.Core.Domain.NetworkId; + + /// + /// This class models the JSON representation of a network to initially connect to new + /// servers created by a scaling group in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ServerNetworkArgument : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("uuid")] + private NetworkId _uuid; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ServerNetworkArgument() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified network ID. + /// + /// The network ID. + /// If is . + public ServerNetworkArgument(NetworkId networkId) + { + if (networkId == null) + throw new ArgumentNullException("networkId"); + + _uuid = networkId; + } + + /// + /// Gets the ID of the network to initially connect servers to. + /// + /// + public NetworkId NetworkId + { + get + { + return _uuid; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/UpdateWebhookConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/UpdateWebhookConfiguration.cs new file mode 100644 index 000000000..33375787a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/UpdateWebhookConfiguration.cs @@ -0,0 +1,79 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to update the properties + /// of a resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UpdateWebhookConfiguration : WebhookConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected UpdateWebhookConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified name. + /// + /// The name of the webhook. + /// If is . + /// If is empty. + public UpdateWebhookConfiguration(string name) + : base(name, null) + { + if (name == null) + throw new ArgumentNullException("name"); + } + + /// + /// Initializes a new instance of the class + /// with the specified metadata. + /// + /// A collection of metadata to associate with the webhook resource. + /// If is . + /// If contains any empty keys. + public UpdateWebhookConfiguration(IDictionary metadata) + : base(null, metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + } + + /// + /// Initializes a new instance of the class + /// with the specified name and metadata. + /// + /// The name of the webhook. + /// A collection of metadata to associate with the webhook resource. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any empty keys. + /// + public UpdateWebhookConfiguration(string name, IDictionary metadata) + : base(name, metadata) + { + if (name == null) + throw new ArgumentNullException("name"); + if (metadata == null) + throw new ArgumentNullException("metadata"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/Webhook.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/Webhook.cs new file mode 100644 index 000000000..c60581bec --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/Webhook.cs @@ -0,0 +1,63 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System.Collections.ObjectModel; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// Represents a webhook resource in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Webhook : WebhookConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private WebhookId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("links")] + private Link[] _links; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Webhook() + { + } + + /// + /// Gets the unique identifier of the webhook. + /// + public WebhookId Id + { + get + { + return _id; + } + } + + /// + /// Gets a collection of links to resources related to the webhook resource. + /// + public ReadOnlyCollection Links + { + get + { + if (_links == null) + return null; + + return new ReadOnlyCollection(_links); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/WebhookConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/WebhookConfiguration.cs new file mode 100644 index 000000000..d9e69816a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/WebhookConfiguration.cs @@ -0,0 +1,83 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the base configuration information of a webhook resource + /// in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class WebhookConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private Dictionary _metadata; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected WebhookConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified name and metadata. + /// + /// The webhook name. + /// The metadata to associate with the webhook. + /// If is empty. + protected WebhookConfiguration(string name, IDictionary metadata) + { + if (name == string.Empty) + throw new ArgumentException("name cannot be empty"); + + _name = name; + if (metadata != null) + _metadata = new Dictionary(metadata); + } + + /// + /// Gets the name of the webhook. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets a collection of metadata associated with the webhook. + /// + public ReadOnlyDictionary Metadata + { + get + { + if (_metadata == null) + return null; + + return new ReadOnlyDictionary(_metadata); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/AutoScale/WebhookId.cs b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/WebhookId.cs new file mode 100644 index 000000000..cb8ce05fd --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/AutoScale/WebhookId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.AutoScale +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a webhook in the . + /// + /// + /// + /// + [JsonConverter(typeof(WebhookId.Converter))] + public sealed class WebhookId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The scaling group identifier value. + /// If is . + /// If is empty. + public WebhookId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override WebhookId FromValue(string id) + { + return new WebhookId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/BulkDeletionFailedObject.cs b/src/OpenStack/Providers/Rackspace/Objects/BulkDeletionFailedObject.cs new file mode 100644 index 000000000..11d60fb36 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/BulkDeletionFailedObject.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using net.openstack.Core.Domain; + +namespace net.openstack.Providers.Rackspace.Objects +{ + /// + /// Describes an object which could not be deleted by a bulk deletion operation, + /// along with a status providing the reason why the deletion failed. + /// + /// + [Serializable] + public class BulkDeletionFailedObject + { + /// + /// Gets a object describing the reason the object + /// could not be deleted. + /// + public Status Status { get; private set; } + + /// + /// Gets the name of the object which could not be deleted. + /// + public string Object { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified object name and status. + /// + /// The name of the object which could not be deleted. + /// A object describing the reason the object could not be deleted. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public BulkDeletionFailedObject(string obj, Status status) + { + if (obj == null) + throw new ArgumentNullException("obj"); + if (status == null) + throw new ArgumentNullException("status"); + if (string.IsNullOrEmpty(obj)) + throw new ArgumentException("obj cannot be empty"); + + Object = obj; + Status = status; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/BulkDeletionResults.cs b/src/OpenStack/Providers/Rackspace/Objects/BulkDeletionResults.cs new file mode 100644 index 000000000..113ed4911 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/BulkDeletionResults.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using net.openstack.Core.Domain; + +namespace net.openstack.Providers.Rackspace.Objects +{ + /// + /// Represents the detailed results of a bulk deletion operation. + /// + /// + [Serializable] + public class BulkDeletionResults + { + /// + /// Gets a collection objects which were successfully deleted. + /// + public IEnumerable SuccessfulObjects { get; private set; } + + /// + /// Gets a collection of objects providing + /// the name and status of objects which could not be deleted during the bulk + /// deletion operation. + /// + public IEnumerable FailedObjects { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified collections of successful and failed objects. + /// + /// The objects which were successfully deleted. + /// The objects which could not be deleted. + public BulkDeletionResults(IEnumerable successfulObjects, IEnumerable failedObjects) + { + if (successfulObjects == null) + throw new ArgumentNullException("successfulObjects"); + if (failedObjects == null) + throw new ArgumentNullException("failedObjects"); + + SuccessfulObjects = successfulObjects; + FailedObjects = failedObjects; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Credentials.cs b/src/OpenStack/Providers/Rackspace/Objects/Credentials.cs new file mode 100644 index 000000000..142dbb1d8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Credentials.cs @@ -0,0 +1,61 @@ +namespace net.openstack.Providers.Rackspace.Objects +{ + using System; + using Newtonsoft.Json; + + /// + /// Represents the credentials data for an Authenticate request to the Rackspace + /// Identity Service. + /// + /// Authenticate (Rackspace Cloud Identity Client Developer Guide - API v2.0) + /// Sample Authentication Request and Response (Rackspace Cloud Identity Client Developer Guide - API v2.0) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class Credentials + { + /// + /// Gets or sets the username to use for authentication. + /// + [JsonProperty("username", DefaultValueHandling = DefaultValueHandling.Include)] + public string Username { get; private set; } + + /// + /// Gets or sets the password to use for authentication. + /// + [JsonProperty("password", DefaultValueHandling = DefaultValueHandling.Include)] + public string Password { get; private set; } + + /// + /// Gets or sets the API key to use for authentication. + /// + [JsonProperty("apiKey", DefaultValueHandling = DefaultValueHandling.Include)] + public string APIKey { get; private set; } + + /// + /// Initializes a new instance of the class using the specified + /// username, password, and API key. + /// + /// The username to use for authentication. + /// The password to use for authentication. + /// The API key to use for authentication. + /// If is . + /// + /// If is empty. + /// -or- + /// If and are both or empty. + /// + public Credentials(string username, string password, string apiKey) + { + if (username == null) + throw new ArgumentNullException("username"); + if (string.IsNullOrEmpty(username)) + throw new ArgumentException("username cannot be empty"); + if (string.IsNullOrEmpty(password) && string.IsNullOrEmpty(apiKey)) + throw new ArgumentException("password and apiKey cannot both be null or empty"); + + Username = username; + Password = password; + APIKey = apiKey; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/Backup.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/Backup.cs new file mode 100644 index 000000000..1e6a9ca04 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/Backup.cs @@ -0,0 +1,165 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a database instance backup in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Backup : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private BackupId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("instance_id")] + private DatabaseInstanceId _instanceId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("locationRef")] + private string _locationRef; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("description")] + private string _description; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private BackupStatus _status; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created")] + private DateTimeOffset? _created; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated")] + private DateTimeOffset? _updated; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Backup() + { + } + + /// + /// Gets the unique identifier for this database backup. + /// + public BackupId Id + { + get + { + return _id; + } + } + + /// + /// Gets the unique identifier of the database instance associated with this backup. + /// + public DatabaseInstanceId InstanceId + { + get + { + return _instanceId; + } + } + + /// + /// Gets the name of this database backup. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the description associated with this database backup. + /// + public string Description + { + get + { + return _description; + } + } + + /// + /// Gets the location of this database backup. + /// + public Uri LocationRef + { + get + { + if (_locationRef == null) + return null; + + return new Uri(_locationRef); + } + } + + /// + /// Gets the status of this database backup. + /// + public BackupStatus Status + { + get + { + return _status; + } + } + + /// + /// Gets a timestamp indicating when this backup was first created. + /// + public DateTimeOffset? Created + { + get + { + return _created; + } + } + + /// + /// Gets a timestamp indicating when this backup was last modified. + /// + public DateTimeOffset? Updated + { + get + { + return _updated; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupConfiguration.cs new file mode 100644 index 000000000..99334fac3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupConfiguration.cs @@ -0,0 +1,103 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a database instance backup configuration in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class BackupConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("instance")] + private DatabaseInstanceId _instanceId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("description", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _description; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected BackupConfiguration() + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The database instance ID. This is obtained from DatabaseInstance.Id. + /// The name of the backup. + /// The optional description of the backup. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public BackupConfiguration(DatabaseInstanceId instanceId, string name, string description) + { + if (instanceId == null) + throw new ArgumentNullException("instanceId"); + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + _instanceId = instanceId; + _name = name; + _description = description; + } + + /// + /// Gets the identifier of the database instance which should be backed up. + /// + public DatabaseInstanceId InstanceId + { + get + { + return _instanceId; + } + } + + /// + /// Gets the name of this backup. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the description of this backup. + /// + public string Description + { + get + { + return _description; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupId.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupId.cs new file mode 100644 index 000000000..02536104f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a backup in the . + /// + /// + /// + /// + [JsonConverter(typeof(BackupId.Converter))] + public sealed class BackupId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The backup identifier value. + /// If is . + /// If is empty. + public BackupId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override BackupId FromValue(string id) + { + return new BackupId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupStatus.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupStatus.cs new file mode 100644 index 000000000..d9a7abdbc --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/BackupStatus.cs @@ -0,0 +1,126 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the status of a database backup. + /// + /// + /// This class functions as a strongly-typed enumeration of known statuses, + /// with added support for unknown statuses returned by a server extension. + /// + /// + /// Backups (Rackspace Cloud Databases Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(BackupStatus.Converter))] + public sealed class BackupStatus : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly BackupStatus _new = FromName("NEW"); + private static readonly BackupStatus _building = FromName("BUILDING"); + private static readonly BackupStatus _completed = FromName("COMPLETED"); + private static readonly BackupStatus _failed = FromName("FAILED"); + private static readonly BackupStatus _deleteFailed = FromName("DELETE_FAILED"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private BackupStatus(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static BackupStatus FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new BackupStatus(i)); + } + + /// + /// Gets a representing a backup task that is created but not yet running. + /// + public static BackupStatus New + { + get + { + return _new; + } + } + + /// + /// Gets a representing a backup task that is currently running. + /// + public static BackupStatus Building + { + get + { + return _building; + } + } + + /// + /// Gets a representing a backup task which completed successfully. + /// + public static BackupStatus Completed + { + get + { + return _completed; + } + } + + /// + /// Gets a representing a backup task which failed to complete successfully. + /// + public static BackupStatus Failed + { + get + { + return _failed; + } + } + + /// + /// Gets a representing a backup task which failed to delete Cloud Files objects. + /// + public static BackupStatus DeleteFailed + { + get + { + return _deleteFailed; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override BackupStatus FromName(string name) + { + return BackupStatus.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/Database.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/Database.cs new file mode 100644 index 000000000..dcdae4d75 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/Database.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a database resource in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Database : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private DatabaseName _name; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Database() + { + } + + /// + /// Gets the name of the database. + /// + public DatabaseName Name + { + get + { + return _name; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseConfiguration.cs new file mode 100644 index 000000000..bbc5b7add --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseConfiguration.cs @@ -0,0 +1,105 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents the configuration for a new database in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DatabaseConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private DatabaseName _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("character_set", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _characterSet; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("collate", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _collate; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DatabaseConfiguration() + { + } + + /// + /// Initializes a new instance of the class with + /// the specified name and the default MySQL character set and collation configuration. + /// + /// The name of the database. + /// If is . + public DatabaseConfiguration(DatabaseName name) + : this(name, null, null) + { + } + + /// + /// Initializes a new instance of the class with + /// the specified name, character set, and collation configuration. + /// + /// The name of the database. + /// The MySQL character set. If the value is , a provider-specific default value is used. + /// The MySQL collation configuration. If the value is , a provider-specific default value is used. + /// If is . + public DatabaseConfiguration(DatabaseName name, string characterSet, string collate) + { + if (name == null) + throw new ArgumentNullException("name"); + + _name = name; + _characterSet = characterSet; + _collate = collate; + } + + /// + /// Gets the name of the database. + /// + public DatabaseName Name + { + get + { + return _name; + } + } + + /// + /// Gets the MySQL character set used by the database. + /// + public string CharacterSet + { + get + { + return _characterSet; + } + } + + /// + /// Gets the MySQL collation configuration used by the database. + /// + public string Collate + { + get + { + return _collate; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseFlavor.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseFlavor.cs new file mode 100644 index 000000000..3c4d1873b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseFlavor.cs @@ -0,0 +1,125 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using System.Collections.ObjectModel; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a database instance flavor in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DatabaseFlavor : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private FlavorId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("links")] + private Link[] _links; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ram")] + private int? _ram; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DatabaseFlavor() + { + } + + /// + /// Gets the unique identifier for the flavor. + /// + public FlavorId Id + { + get + { + return _id; + } + } + + /// + /// Gets a reference to the flavor in URI form. + /// + /// + /// The "flavorRef" is obtained from the property via the link + /// with the property set to self. + /// + public FlavorRef Href + { + get + { + if (_links == null) + return null; + + foreach (Link link in _links) + { + if (string.Equals(link.Rel, "self", StringComparison.OrdinalIgnoreCase)) + return new FlavorRef(link.Href); + } + + return null; + } + } + + /// + /// Gets a collection of objects describing resources associated + /// with this flavor resource. + /// + public ReadOnlyCollection Links + { + get + { + if (_links == null) + return null; + + return new ReadOnlyCollection(_links); + } + } + + /// + /// Gets the name of the flavor. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the amount of memory allocated to this flavor, in GB. + /// + public int? Memory + { + get + { + return _ram; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstance.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstance.cs new file mode 100644 index 000000000..4c20bc470 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstance.cs @@ -0,0 +1,184 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using System.Collections.ObjectModel; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a database instance within the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DatabaseInstance : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private DatabaseInstanceId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private DatabaseInstanceStatus _status; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("volume")] + private DatabaseVolumeConfiguration _volumeStatistics; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("hostname")] + private string _hostName; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("flavor")] + private DatabaseFlavor _flavor; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created")] + private DateTimeOffset? _created; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated")] + private DateTimeOffset? _updated; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("links")] + private Link[] _links; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DatabaseInstance() + { + } + + /// + /// Gets the unique identifier for the database instance. + /// + public DatabaseInstanceId Id + { + get + { + return _id; + } + } + + /// + /// Gets the name of the database instance. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the current status of the database instance. + /// + public DatabaseInstanceStatus Status + { + get + { + return _status; + } + } + + /// + /// Gets the volume configuration for the database instance. + /// + public DatabaseVolumeConfiguration VolumeConfiguration + { + get + { + return _volumeStatistics; + } + } + + /// + /// Gets the host name for the database instance. + /// + public string HostName + { + get + { + return _hostName; + } + } + + /// + /// Gets the flavor for the database instance. + /// + public DatabaseFlavor Flavor + { + get + { + return _flavor; + } + } + + /// + /// Gets a timestamp indicating when this database instance was created. + /// + public DateTimeOffset? Created + { + get + { + return _created; + } + } + + /// + /// Gets a timestamp indicating when this database instance was last updated. + /// + public DateTimeOffset? Updated + { + get + { + return _updated; + } + } + + /// + /// Gets a collection of links describing resources related to this database instance. + /// + public ReadOnlyCollection Links + { + get + { + if (_links == null) + return null; + + return new ReadOnlyCollection(_links); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceConfiguration.cs new file mode 100644 index 000000000..5eea87bc1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceConfiguration.cs @@ -0,0 +1,139 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON object used to describe a new database instance in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DatabaseInstanceConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("flavorRef", DefaultValueHandling = DefaultValueHandling.Include)] + private FlavorRef _flavorRef; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("volume", DefaultValueHandling = DefaultValueHandling.Include)] + private DatabaseVolumeConfiguration _volume; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("restorePoint", DefaultValueHandling = DefaultValueHandling.Ignore)] + private RestorePoint _restorePoint; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DatabaseInstanceConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// A object describing the flavor of the database instance. + /// A object containing additional information about + /// the database instance storage volume. + /// The name of the database instance, or if the database instance is not named. + /// + /// If is . + /// -or- + /// If is . + /// + public DatabaseInstanceConfiguration(FlavorRef flavorRef, DatabaseVolumeConfiguration volumeConfiguration, string name) + : this(flavorRef, volumeConfiguration, name, null) + { + } + + /// + /// Initializes a new instance of the class + /// with a restore point for restoring a database instance from a backup. + /// + /// A object describing the flavor of the database instance. + /// A object containing additional information about + /// the database instance storage volume. + /// The name of the database instance, or if the database instance is not named. + /// A object describing the backup from which this database instance was restored, or null if the restore point is not available. + /// + /// If is . + /// -or- + /// If is . + /// + public DatabaseInstanceConfiguration(FlavorRef flavorRef, DatabaseVolumeConfiguration volumeConfiguration, string name, RestorePoint restorePoint) + { + if (flavorRef == null) + throw new ArgumentNullException("flavorRef"); + if (volumeConfiguration == null) + throw new ArgumentNullException("volumeConfiguration"); + + _flavorRef = flavorRef; + _volume = volumeConfiguration; + _name = name; + _restorePoint = restorePoint; + } + + /// + /// Gets a object describing the flavor of the database instance. + /// + public FlavorRef FlavorRef + { + get + { + return _flavorRef; + } + } + + /// + /// Gets a object containing additional information about + /// the database instance storage volume. + /// + public DatabaseVolumeConfiguration Volume + { + get + { + return _volume; + } + } + + /// + /// Gets the name of the database instance. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets a object describing the backup from which this database instance was restored. + /// + public RestorePoint RestorePoint + { + get + { + return _restorePoint; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceId.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceId.cs new file mode 100644 index 000000000..bcf3f31ef --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a database instance in the . + /// + /// + /// + /// + [JsonConverter(typeof(DatabaseInstanceId.Converter))] + public sealed class DatabaseInstanceId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The database instance identifier value. + /// If is . + /// If is empty. + public DatabaseInstanceId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DatabaseInstanceId FromValue(string id) + { + return new DatabaseInstanceId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceStatus.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceStatus.cs new file mode 100644 index 000000000..1ce337629 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseInstanceStatus.cs @@ -0,0 +1,162 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the status of a database instance. + /// + /// + /// This class functions as a strongly-typed enumeration of known statuses, + /// with added support for unknown statuses returned by a server extension. + /// + /// + /// + /// + [JsonConverter(typeof(DatabaseInstanceStatus.Converter))] + public sealed class DatabaseInstanceStatus : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly DatabaseInstanceStatus _build = FromName("BUILD"); + private static readonly DatabaseInstanceStatus _reboot = FromName("REBOOT"); + private static readonly DatabaseInstanceStatus _active = FromName("ACTIVE"); + private static readonly DatabaseInstanceStatus _backup = FromName("BACKUP"); + private static readonly DatabaseInstanceStatus _blocked = FromName("BLOCKED"); + private static readonly DatabaseInstanceStatus _resize = FromName("RESIZE"); + private static readonly DatabaseInstanceStatus _shutdown = FromName("SHUTDOWN"); + private static readonly DatabaseInstanceStatus _error = FromName("ERROR"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private DatabaseInstanceStatus(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static DatabaseInstanceStatus FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new DatabaseInstanceStatus(i)); + } + + /// + /// Gets a representing a database instance which is being provisioned. + /// + public static DatabaseInstanceStatus Build + { + get + { + return _build; + } + } + + /// + /// Gets a representing a database instance which is rebooting. + /// + public static DatabaseInstanceStatus Reboot + { + get + { + return _reboot; + } + } + + /// + /// Gets a representing a database instance which is online and available to take requests. + /// + public static DatabaseInstanceStatus Active + { + get + { + return _active; + } + } + + /// + /// Gets a representing a database instance which is currently running a backup process. + /// + public static DatabaseInstanceStatus Backup + { + get + { + return _backup; + } + } + + /// + /// Gets a representing a database instance which is currently unresponsive. + /// + public static DatabaseInstanceStatus Blocked + { + get + { + return _blocked; + } + } + + /// + /// Gets a representing a database instance which is being resized. + /// + public static DatabaseInstanceStatus Resize + { + get + { + return _resize; + } + } + + /// + /// Gets a representing a database instance which is terminating services, + /// or the MySQL instance is shut down but not the actual server. + /// + public static DatabaseInstanceStatus Shutdown + { + get + { + return _shutdown; + } + } + + /// + /// Gets a representing a database instance where the last operation failed due to an error. + /// + public static DatabaseInstanceStatus Error + { + get + { + return _error; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DatabaseInstanceStatus FromName(string name) + { + return DatabaseInstanceStatus.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseName.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseName.cs new file mode 100644 index 000000000..41d7677db --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseName.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique name of a database in the . + /// + /// + /// + /// + [JsonConverter(typeof(DatabaseName.Converter))] + public sealed class DatabaseName : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified name. + /// + /// The database name. + /// If is . + /// If is empty. + public DatabaseName(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DatabaseName FromValue(string id) + { + return new DatabaseName(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseUser.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseUser.cs new file mode 100644 index 000000000..4da266d95 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseUser.cs @@ -0,0 +1,24 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a database user in the . + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DatabaseUser : UserConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DatabaseUser() + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseVolumeConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseVolumeConfiguration.cs new file mode 100644 index 000000000..619cd0474 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/DatabaseVolumeConfiguration.cs @@ -0,0 +1,83 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents the volume configuration for a database instance. For + /// running instances, the volume configuration also reports the approximate + /// fraction of volume space currently in use by the database instance. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DatabaseVolumeConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("size", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _size; + +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("used", DefaultValueHandling = DefaultValueHandling.Ignore)] + private double? _used; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DatabaseVolumeConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified size. + /// + /// The size of the database volume in GB + /// If is less than or equal to 0. + public DatabaseVolumeConfiguration(int size) + { + if (size <= 0) + throw new ArgumentOutOfRangeException("size"); + + _size = size; + } + + /// + /// Gets the size of the database instance volume in GB. + /// + /// + /// The size of the database instance volume in GB, or if the size is not available. + /// + public int? Size + { + get + { + return _size; + } + } + + /// + /// Gets an approximation of the amount of space currently in use. + /// + /// + /// A value between 0 and 1 indicating the approximate fraction of disk space currently + /// in use on the database volume, or if the current usage is not available. + /// + public double? Used + { + get + { + return _used; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/FlavorId.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/FlavorId.cs new file mode 100644 index 000000000..e17381f07 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/FlavorId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a flavor in the . + /// + /// + /// + /// + [JsonConverter(typeof(FlavorId.Converter))] + public sealed class FlavorId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The flavor identifier value. + /// If is . + /// If is empty. + public FlavorId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override FlavorId FromValue(string id) + { + return new FlavorId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/FlavorRef.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/FlavorRef.cs new file mode 100644 index 000000000..0d9090e88 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/FlavorRef.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique URI reference to a flavor in the . + /// + /// + /// + /// + [JsonConverter(typeof(FlavorRef.Converter))] + public sealed class FlavorRef : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The URI reference for the flavor. + /// If is . + /// If is empty. + public FlavorRef(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override FlavorRef FromValue(string id) + { + return new FlavorRef(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/NamespaceDoc.cs new file mode 100644 index 000000000..24e89bafb --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines + /// the object model for communicating with Rackspace's Cloud Databases service over REST APIs. + /// + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/RestorePoint.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/RestorePoint.cs new file mode 100644 index 000000000..4ddc745b3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/RestorePoint.cs @@ -0,0 +1,54 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a restore point, used to restore + /// a database instance from a backup during a call to + /// . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class RestorePoint : ExtensibleJsonObject + { + [JsonProperty("backupRef", DefaultValueHandling = DefaultValueHandling.Ignore)] + private BackupId _backupId; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected RestorePoint() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified backup ID. + /// + /// The backup ID. This is obtained from Backup.Id. + /// If is . + public RestorePoint(BackupId backupId) + { + if (backupId == null) + throw new ArgumentNullException("backupId"); + + _backupId = backupId; + } + + /// + /// Gets the unique identifier for this backup. + /// + public BackupId BackupId + { + get + { + return _backupId; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/RootUser.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/RootUser.cs new file mode 100644 index 000000000..bea6d902e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/RootUser.cs @@ -0,0 +1,60 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a root user for a database instance. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class RootUser : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("password")] + private string _password; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected RootUser() + { + } + + /// + /// Gets the username of the database instance root user. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the password for the database instance root user. + /// + public string Password + { + get + { + return _password; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/UpdateUserConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/UpdateUserConfiguration.cs new file mode 100644 index 000000000..5a4ec5d10 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/UpdateUserConfiguration.cs @@ -0,0 +1,96 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of an operation to update properties + /// of a in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UpdateUserConfiguration : ExtensibleJsonObject + { + /// + /// This is one of the backing fields for the property. + /// + [JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("password", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _password; + + /// + /// This is one of the backing fields for the property. + /// + [JsonProperty("host", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _host; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected UpdateUserConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// A object providing the new name and host for the user. If this value is , the name and host address for the database user is not changed. + /// The new password for the user. If this value is , the existing password for the database user is not changed. + public UpdateUserConfiguration(UserName name, string password) + { + if (name != null) + { + _name = name.Name; + _host = name.Host; + } + + _password = password; + } + + /// + /// Gets a object containing the updated username and host address for the database user. + /// + /// + /// A object containing the new username and host address for the existing database user, or if the username and password for the existing database user should not be changed. + /// + public UserName UserName + { + get + { + if (_host == null) + { + if (_name == null) + return null; + + return new UserName(_name); + } + + return new UserName(_name, _host); + } + } + + /// + /// Gets the updated password for the database user. + /// + /// + /// The new password for the database user, or if the password for the user should not be changed. + /// + public string Password + { + get + { + return _password; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/UserConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/UserConfiguration.cs new file mode 100644 index 000000000..291013e6b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/UserConfiguration.cs @@ -0,0 +1,207 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class describes the configuration for a new database user in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UserConfiguration : ExtensibleJsonObject + { + /// + /// This is one of the backing fields for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("password")] + private string _password; + + /// + /// This is one of the backing fields for the property. + /// + [JsonProperty("host", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _host; + + /// + /// This is one of the backing fields for the property. + /// + [JsonProperty("database", DefaultValueHandling = DefaultValueHandling.Ignore)] + private DatabaseName _database; + + /// + /// This is one of the backing fields for the property. + /// + [JsonProperty("databases", DefaultValueHandling = DefaultValueHandling.Ignore)] + private WrappedDatabaseName[] _databases; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected UserConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified user name, password, and databases to initially grant + /// access to. + /// + /// A object describing the name and host of the user to add. + /// The password for the new user. + /// A collection of objects identifying the databases to initially grant access to for the new user. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// + public UserConfiguration(UserName name, string password, IEnumerable databases) + : this(name, password, databases != null ? databases.ToArray() : null) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified user name, password, and databases to initially grant + /// access to. + /// + /// A object describing the name and host of the user to add. + /// The password for the new user. + /// A collection of objects identifying the databases to initially grant access to for the new user. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// + public UserConfiguration(UserName name, string password, params DatabaseName[] databases) + { + if (name == null) + throw new ArgumentNullException("name"); + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + if (databases != null && databases.Contains(null)) + throw new ArgumentException("databases cannot contain any null values", "databases"); + + _name = name.Name; + _password = password; + _host = name.Host; + if (databases != null && databases.Length > 0) + { + if (databases.Length == 1) + _database = databases[0]; + else + _databases = Array.ConvertAll(databases, i => new WrappedDatabaseName(i)); + } + } + + /// + /// Gets a object describing the username and host of the user. + /// + public UserName UserName + { + get + { + if (_host == null) + return new UserName(_name); + + return new UserName(_name, _host); + } + } + + /// + /// Gets the password for the user. + /// + public string Password + { + get + { + return _password; + } + } + + /// + /// Gets a collection of objects identifying the databases to + /// initially grant access to. + /// + public ReadOnlyCollection Databases + { + get + { + if (_databases != null) + { + return new ReadOnlyCollection(Array.ConvertAll(_databases, i => i.Name)); + } + else if (_database != null) + { + return new ReadOnlyCollection(new[] { _database }); + } + + return new ReadOnlyCollection(new DatabaseName[0]); + } + } + + /// + /// This class models the JSON representation of a database name in the Create User API call. + /// + /// Create User (Rackspace Cloud Databases Developer Guide - API v1.0) + [JsonObject(MemberSerialization.OptIn)] + protected class WrappedDatabaseName : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private DatabaseName _name; + + /// + /// Initializes a new instance of the class + /// with the specified name. + /// + /// The database name. + /// If is . + public WrappedDatabaseName(DatabaseName name) + { + if (name == null) + throw new ArgumentNullException("name"); + + _name = name; + } + + /// + /// Gets the name of the database. + /// + public DatabaseName Name + { + get + { + return _name; + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Databases/UserName.cs b/src/OpenStack/Providers/Rackspace/Objects/Databases/UserName.cs new file mode 100644 index 000000000..c862edba1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Databases/UserName.cs @@ -0,0 +1,126 @@ +namespace net.openstack.Providers.Rackspace.Objects.Databases +{ + using System; + using System.Net; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique name of a user in the . + /// + /// + /// + /// + [JsonConverter(typeof(UserName.Converter))] + public sealed class UserName : ResourceIdentifier + { + private readonly string _name; + + private readonly string _host; + + /// + /// Initializes a new instance of the class + /// with the specified name. + /// + /// The database name. + /// If is . + /// If is empty. + public UserName(string id) + : base(id) + { + int lastAt = id.LastIndexOf('@'); + if (lastAt >= 0) + { + _name = id.Substring(0, lastAt); + _host = id.Substring(lastAt + 1); + } + else + { + _name = id; + _host = "%"; + } + } + + /// + /// Initializes a new instance of the class + /// with the specified name and host address. + /// + /// The database name. + /// The host address which the user must connect from, or to allow this user to connect from any host. + /// If is . + /// If is empty. + public UserName(string id, IPAddress hostAddress) + : base(string.Format("{0}@{1}", id, hostAddress != null ? hostAddress.ToString() : "%")) + { + if (id == null) + throw new ArgumentNullException("id"); + if (string.IsNullOrEmpty(id)) + throw new ArgumentException("id cannot be empty"); + + _name = id; + _host = hostAddress != null ? hostAddress.ToString() : "%"; + } + + /// + /// Initializes a new instance of the class + /// with the specified name and host. + /// + /// The database user name. + /// The name of the host from which this user can connect, or to allow this user to connect from any host. + /// If is . + /// + /// If is empty. + /// -or- + /// If is empty. + /// + public UserName(string id, string host) + : base(string.Format("{0}@{1}", id, host ?? "%")) + { + if (id == null) + throw new ArgumentNullException("id"); + if (string.IsNullOrEmpty(id)) + throw new ArgumentException("id cannot be empty"); + if (host == string.Empty) + throw new ArgumentException("host cannot be empty", "host"); + + _name = id; + _host = host ?? "%"; + } + + /// + /// Gets the username portion of this MySQL user name. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the host portion of this MySQL user name. + /// + public string Host + { + get + { + return _host; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override UserName FromValue(string id) + { + return new UserName(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsChange.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsChange.cs new file mode 100644 index 000000000..43a885bc1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsChange.cs @@ -0,0 +1,91 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents a change made to a DNS record. + /// + /// + /// + /// List Domain Changes (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsChange : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("field")] + private string _field; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("originalValue")] + private string _originalValue; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("newValue")] + private string _newValue; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected DnsChange() + { + } + + /// + /// Gets the name of the field which changed. + /// + /// + /// The name of the field which changed, or if the JSON response from the + /// server did not include this property. + /// + public string Field + { + get + { + return _field; + } + } + + /// + /// Gets the value of the field before the change was made. + /// + /// + /// The original value of the field which changed, or if the JSON response + /// from the server did not include this property. + /// + public string OriginalValue + { + get + { + return _originalValue; + } + } + + /// + /// Gets the value of the field after the change was made. + /// + /// + /// The new value of the field which changed, or if the JSON response + /// from the server did not include this property. + /// + public string NewValue + { + get + { + return _newValue; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsConfiguration.cs new file mode 100644 index 000000000..844440011 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsConfiguration.cs @@ -0,0 +1,74 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents the configuration of a collection of domains being added to the DNS service. + /// + /// + /// + /// This class can be extended if a server extension requires additional information (beyond + /// the domains property which is already supported) be sent in the body of a + /// Create Domain API call. + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("domains")] + private readonly DnsDomainConfiguration[] _domainConfiguration; + + /// + /// Initializes a new instance of the class for the + /// specified domains. + /// + /// A collection of objects describing the domains. + /// If is . + /// If contains a value. + public DnsConfiguration(params DnsDomainConfiguration[] domainConfigurations) + : this(domainConfigurations.AsEnumerable()) + { + } + + /// + /// Initializes a new instance of the class for the + /// specified domains. + /// + /// A collection of objects describing the domains. + /// If is . + /// If contains a value. + public DnsConfiguration(IEnumerable domainConfigurations) + { + if (domainConfigurations == null) + throw new ArgumentNullException("domainConfigurations"); + + _domainConfiguration = domainConfigurations.ToArray(); + + if (_domainConfiguration.Contains(null)) + throw new ArgumentException("domainConfigurations cannot contain any null values.", "domainConfigurations"); + } + + /// + /// Gets a collection of the objects describing + /// domains in this configuration. + /// + public ReadOnlyCollection DomainConfigurations + { + get + { + return new ReadOnlyCollection(_domainConfiguration); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomain.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomain.cs new file mode 100644 index 000000000..753c0a04a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomain.cs @@ -0,0 +1,274 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.ObjectModel; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a domain within the DNS service. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsDomain : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("emailAddress")] + private string _emailAddress; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated")] + private DateTimeOffset? _updated; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created")] + private DateTimeOffset? _created; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("accountId")] + private ProjectId _accountId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private DomainId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("comment")] + private string _comment; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("nameservers")] + private DnsNameserver[] _nameservers; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ttl")] + private int? _timeToLive; + + /// + /// This is an intermediate representation for the property, + /// which is necessary for correctly modeling the JSON response from the server. + /// + [JsonProperty("recordsList")] + private DnsRecordsList _recordsList; + + /// + /// This is an intermediate representation for the property, + /// which is necessary for correctly modeling the JSON response from the server. + /// + [JsonProperty("subdomains")] + private DnsSubdomainsList _subdomains; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected DnsDomain() + { + } + + /// + /// Gets the domain name. + /// + /// + /// The name of the domain, or if the JSON response from the server + /// did not include this property. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the unique ID representing this domain within the DNS service. + /// + /// + /// The unique ID for the domain, or if the JSON response from the server + /// did not include this property. + /// + public DomainId Id + { + get + { + return _id; + } + } + + /// + /// Gets the comment associated with this domain. + /// + /// + /// The comment for the domain, or if the JSON response from the server + /// did not include this property. + /// + public string Comment + { + get + { + return _comment; + } + } + + /// + /// Gets the account ID associated with this domain. The account ID within the DNS service + /// is equivalent to the Tenant.Id referenced by other services. + /// + /// + /// The account ID for the domain, or if the JSON response from the server + /// did not include this property. + /// + public ProjectId AccountId + { + get + { + return _accountId; + } + } + + /// + /// Gets the email address associated with this domain. + /// + /// + /// The email address for the domain, or if the JSON response from the server + /// did not include this property. + /// + public string EmailAddress + { + get + { + return _emailAddress; + } + } + + /// + /// Gets the timestamp when this domain was first added to the DNS service. + /// + /// + /// The creation timestamp for the domain, or if the JSON response from the server + /// did not include this property. + /// + public DateTimeOffset? Created + { + get + { + return _created; + } + } + + /// + /// Gets the timestamp when this domain was last updated within the DNS service. + /// + /// + /// The last-updated timestamp for the domain, or if the JSON response from the server + /// did not include this property. + /// + public DateTimeOffset? Updated + { + get + { + return _updated; + } + } + + /// + /// Gets a collection of objects describing the DNS records for the domain. + /// + /// + /// A collection of objects, or if the JSON response from the + /// server did not include the associated property. + /// + public ReadOnlyCollection Records + { + get + { + if (_recordsList == null) + return null; + + return _recordsList.Records; + } + } + + /// + /// Gets a collection of objects describing the DNS subdomains for the domain. + /// + /// + /// A collection of objects, or if the JSON response from the + /// server did not include the associated property. + /// + public ReadOnlyCollection Subdomains + { + get + { + if (_subdomains == null) + return null; + + return _subdomains.Subdomains; + } + } + + /// + /// Gets a collection of objects describing the DNS nameservers for the domain. + /// + /// + /// A collection of objects, or if the JSON response from the + /// server did not include the associated property. + /// + public ReadOnlyCollection Nameservers + { + get + { + if (_nameservers == null) + return null; + + return new ReadOnlyCollection(_nameservers); + } + } + + /// + /// Gets the time-to-live for the domain. + /// + /// + /// A object containing the time-to-live for the domain, or if the + /// JSON response from the server did not include the associated property. + /// + public TimeSpan? TimeToLive + { + get + { + if (_timeToLive == null) + return null; + + return TimeSpan.FromSeconds(_timeToLive.Value); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainChange.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainChange.cs new file mode 100644 index 000000000..904cb2b17 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainChange.cs @@ -0,0 +1,161 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + using ProjectId = net.openstack.Core.Domain.ProjectId; + using Tenant = net.openstack.Core.Domain.Tenant; + + /// + /// This object represents changes made to a specific resource in the DNS service as the + /// result of a single logical action. + /// + /// + /// List Domain Changes (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsDomainChange : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This the backing field for the property. + /// + [JsonProperty("action")] + private string _action; + + /// + /// This the backing field for the property. + /// + [JsonProperty("targetType")] + private string _targetType; + + /// + /// This the backing field for the property. + /// + [JsonProperty("targetId")] + private string _targetId; + + /// + /// This the backing field for the property. + /// + [JsonProperty("changeDetails")] + private DnsChange[] _details; + + /// + /// This the backing field for the property. + /// + [JsonProperty("accountId")] + private ProjectId _accountId; + + /// + /// This the backing field for the property. + /// + [JsonProperty("domain")] + private string _domainName; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsDomainChange() + { + } + + /// + /// Gets the name of the action which made this change. + /// + /// + /// The name of the action which made this change, or if the JSON response from the + /// server did not include this property. + /// + public string Action + { + get + { + return _action; + } + } + + /// + /// Gets the resource type which was changed. + /// + /// + /// The type of resource which was changed, or if the JSON response from the + /// server did not include this property. + /// + public string TargetType + { + get + { + return _targetType; + } + } + + /// + /// Gets the unique identifier of the resource which was changed. + /// + /// + /// The unique identifier of the resource which was changed, or if the JSON + /// response from the server did not include this property. + /// + public string TargetId + { + get + { + return _targetId; + } + } + + /// + /// Gets a collection of specific changes made to the target resource. + /// + /// + /// A collection of objects describing the changes made to the resource, + /// or if the JSON response from the server did not include this property. + /// + public ReadOnlyCollection Details + { + get + { + if (_details == null) + return null; + + return new ReadOnlyCollection(_details); + } + } + + /// + /// Gets the account ID under which this change was made. The account ID within the DNS service + /// is equivalent to the Tenant.Id referenced by other services. + /// + /// + /// The account ID under which this change was made, or if the JSON response from the server + /// did not include this property. + /// + public ProjectId AccountId + { + get + { + return _accountId; + } + } + + /// + /// Gets the name of the domain this resource belongs to. + /// + /// + /// The name of the domain the changed resource belongs to, or if the JSON response from + /// the server did not include this property. + /// + public string DomainName + { + get + { + return _domainName; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainChanges.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainChanges.cs new file mode 100644 index 000000000..66f4e9fa8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainChanges.cs @@ -0,0 +1,125 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents the changes made to various DNS resources as a result of + /// logical actions made during a particular interval of time. + /// + /// + /// List Domain Changes (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsDomainChanges : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("totalEntries")] + private int? _totalEntries; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("from")] + private DateTimeOffset? _from; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("to")] + private DateTimeOffset? _to; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("changes")] + private DnsDomainChange[] _changes; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsDomainChanges() + { + } + + /// + /// Gets the total number of objects in the time interval + /// described by and . + /// + /// + /// This value may exceed the number of items in the collection returned by the + /// property since the + /// method returns a subset of the complete paginated collection. + /// + /// + /// The total number of changes in this time interval, or if the JSON response + /// from the server did not include this property. + /// + public int? TotalEntries + { + get + { + return _totalEntries; + } + } + + /// + /// Gets the starting timestamp of this collection of changes to DNS resources. + /// + /// + /// The starting timestamp of this collection of changes to DNS resources, or + /// if the JSON response from the server did not include this property. + /// + public DateTimeOffset? From + { + get + { + return _from; + } + } + + /// + /// Gets the ending timestamp of this collection of changes to DNS resources. + /// + /// + /// The ending timestamp of this collection of changes to DNS resources, or + /// if the JSON response from the server did not include this property. + /// + public DateTimeOffset? To + { + get + { + return _to; + } + } + + /// + /// Gets a collection of objects describing changes made + /// to DNS resources as a result of logical actions performed during the time interval. + /// + /// + /// A collection of objects describing changes made to + /// DNS resources, or if the JSON response from the server did not include + /// this property. + /// + public ReadOnlyCollection Changes + { + get + { + if (_changes == null) + return null; + + return new ReadOnlyCollection(_changes); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainConfiguration.cs new file mode 100644 index 000000000..3bdd4b524 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainConfiguration.cs @@ -0,0 +1,326 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a domain configuration for calls to . + /// + /// + /// Create Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsDomainConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("recordsList")] + private RecordsList _recordsList; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("subdomains")] + private SubdomainsList _subdomains; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("emailAddress")] + private string _emailAddress; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ttl")] + private int? _timeToLive; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("comment")] + private string _comment; + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The fully-qualified domain name. + /// The time-to-live for the domain. + /// The email address associated with the domain. + /// An optional comment associated with the domain. + /// A collection of objects describing the initial DNS records to associate with the domain. + /// A collection of objects containing the initial subdomains to create with the domain. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// + /// If is negative or . + public DnsDomainConfiguration(string name, TimeSpan? timeToLive, string emailAddress, string comment, IEnumerable records, IEnumerable subdomains) + : this(name, timeToLive, emailAddress, comment, new RecordsList(records), new SubdomainsList(subdomains)) + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// + /// + /// Derived types may use this constructor to create a configuration with class derived from + /// or should a server change or extension + /// require additional information be passed in the body of the request. + /// + /// + /// The fully-qualified domain name. + /// The time-to-live for the domain. + /// The email address associated with the domain. + /// An optional comment associated with the domain. + /// A object containing the initial DNS records to associate with the domain. + /// A object containing the initial subdomains to create with the domain. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// If is negative or . + protected DnsDomainConfiguration(string name, TimeSpan? timeToLive, string emailAddress, string comment, RecordsList records, SubdomainsList subdomains) + { + if (name == null) + throw new ArgumentNullException("name"); + if (emailAddress == null) + throw new ArgumentNullException("emailAddress"); + if (records == null) + throw new ArgumentNullException("records"); + if (subdomains == null) + throw new ArgumentNullException("subdomains"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (string.IsNullOrEmpty(emailAddress)) + throw new ArgumentException("emailAddress cannot be empty"); + if (timeToLive <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeToLive cannot be negative or zero"); + + _name = name; + _emailAddress = emailAddress; + _comment = comment; + if (timeToLive.HasValue) + _timeToLive = (int)timeToLive.Value.TotalSeconds; + + _recordsList = records; + _subdomains = subdomains; + } + + /// + /// Gets the fully-qualified domain name. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the email address associated with the domain. + /// + public string EmailAddress + { + get + { + return _emailAddress; + } + } + + /// + /// Gets the optional comment associated with the domain. + /// + /// + /// The comment to associate with the domain, or if no comment should be + /// associated with the domain. + /// + public string Comment + { + get + { + return _comment; + } + } + + /// + /// Gets the time-to-live for the domain. + /// + /// + /// The time-to-live for the domain, or if the time-to-live should be automatically + /// assigned by the server when the domain is created. + /// + public TimeSpan? TimeToLive + { + get + { + if (_timeToLive == null) + return null; + + return TimeSpan.FromSeconds(_timeToLive.Value); + } + } + + /// + /// Gets a collection of objects describing the + /// initial DNS records to create with this domain. + /// + public ReadOnlyCollection Records + { + get + { + return _recordsList.Records; + } + } + + /// + /// Gets a collection of objects describing the + /// initial DNS subdomains to create with this domain. + /// + public ReadOnlyCollection Subdomains + { + get + { + return _subdomains.Subdomains; + } + } + + /// + /// This class models the value of the recordsList property in the JSON + /// request body sent to the Create Domain(s) API. + /// + /// + /// + /// Derived types may extend this class to customize the JSON request should a server change + /// or extension require additional information be passed in the body of the request. + /// + /// + /// + /// Create Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + protected class RecordsList : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("records")] + private DnsDomainRecordConfiguration[] _records; + + /// + /// Initializes a new instance of the class with the + /// specified DNS record configurations. + /// + /// A collection of objects describing the DNS records to associate with a domain. + /// If is . + /// If contains any values. + protected internal RecordsList(IEnumerable records) + { + if (records == null) + throw new ArgumentNullException("records"); + + _records = records.ToArray(); + if (_records.Contains(null)) + throw new ArgumentException("records cannot contain any null values."); + } + + /// + /// Gets a collection of objects describing the DNS records to associate with a domain. + /// + public ReadOnlyCollection Records + { + get + { + return new ReadOnlyCollection(_records); + } + } + } + + /// + /// This class models the value of the subdomains property in the JSON + /// request body sent to the Create Domain(s) API. + /// + /// + /// + /// Derived types may extend this class to customize the JSON request should a server change + /// or extension require additional information be passed in the body of the request. + /// + /// + /// + /// Create Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + protected class SubdomainsList : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("domains")] + private DnsSubdomainConfiguration[] _subdomains; + + /// + /// Initializes a new instance of the class with the + /// specified subdomain configurations. + /// + /// A collection of objects describing the subdomains to associate with a domain. + /// If is . + /// If contains any values. + protected internal SubdomainsList(IEnumerable subdomains) + { + if (subdomains == null) + throw new ArgumentNullException("subdomains"); + + _subdomains = subdomains.ToArray(); + if (_subdomains.Contains(null)) + throw new ArgumentException("subdomains cannot contain any null values."); + } + + /// + /// Gets a collection of objects describing the subdomains to associate with a domain. + /// + public ReadOnlyCollection Subdomains + { + get + { + return new ReadOnlyCollection(_subdomains); + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainRecordConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainRecordConfiguration.cs new file mode 100644 index 000000000..4b6c86317 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainRecordConfiguration.cs @@ -0,0 +1,195 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This models a DNS record for the + /// and calls. + /// + /// Supported Record Types (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Add Records (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsDomainRecordConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private DnsRecordType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("data")] + private string _data; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ttl", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _timeToLive; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("comment", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _comment; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("priority", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _priority; + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The DNS record type. + /// The DNS record name. + /// The data to associate with the DNS record. + /// The time-to-live for the DNS record. If not specified, a provider-specific default value will be used. + /// An optional comment to associate with the DNS record. + /// The priority of the DNS record. This is only specified for and records. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is specified and is not or . + /// -or- + /// If is not specified and is or . + /// + /// + /// If is negative. + /// -or- + /// If is less than 0. + /// + public DnsDomainRecordConfiguration(DnsRecordType type, string name, string data, TimeSpan? timeToLive, string comment, int? priority) + { + if (type == null) + throw new ArgumentNullException("type"); + if (name == null) + throw new ArgumentNullException("name"); + if (data == null) + throw new ArgumentNullException("data"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (string.IsNullOrEmpty(data)) + throw new ArgumentException("data cannot be empty"); + if (timeToLive <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeToLive cannot be negative or zero"); + if (priority < 0) + throw new ArgumentOutOfRangeException("priority"); + + if (type == DnsRecordType.Mx || type == DnsRecordType.Srv) + { + if (!priority.HasValue) + throw new ArgumentException("A priority must be specified for MX and SRV records."); + } + else + { + if (priority.HasValue) + throw new ArgumentException(string.Format("A priority cannot be specified for {0} records.", type)); + } + + _name = name; + _type = type; + _data = data; + _comment = comment; + _priority = priority; + if (timeToLive != null) + _timeToLive = (int)timeToLive.Value.TotalSeconds; + } + + /// + /// Gets the DNS record type. + /// + public DnsRecordType Type + { + get + { + return _type; + } + } + + /// + /// Gets the name of the DNS record. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the data for this DNS record. + /// + public string Data + { + get + { + return _data; + } + } + + /// + /// Gets the time-to-live for the DNS record. + /// + public TimeSpan? TimeToLive + { + get + { + if (!_timeToLive.HasValue) + return null; + + return TimeSpan.FromSeconds(_timeToLive.Value); + } + } + + /// + /// Gets the optional comment associated with the DNS record. + /// + public string Comment + { + get + { + return _comment; + } + } + + /// + /// Gets the priority associated with the DNS record. + /// + /// + /// The priority only applies to and + /// records. For other record types, this property is . + /// + public int? Priority + { + get + { + return _priority; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainRecordUpdateConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainRecordUpdateConfiguration.cs new file mode 100644 index 000000000..2613e55c7 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainRecordUpdateConfiguration.cs @@ -0,0 +1,186 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This models a DNS record configuration update for the call. + /// + /// Supported Record Types (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Modify Records (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsDomainRecordUpdateConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private RecordId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("data", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _data; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ttl", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _timeToLive; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("comment", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _comment; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("priority", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _priority; + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The DNS record to update. + /// The DNS record name. + /// The data to associate with the DNS record. If this value is , the existing value for the record is not changed. + /// The time-to-live for the DNS record. If this value is , the existing value for the record is not changed. + /// An optional comment to associate with the DNS record. If this value is , the existing value for the record is not changed. + /// The priority of the DNS record. This is only specified for and records. If this value is , the existing value for the record is not changed. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is specified and the type of is not or . + /// + /// + /// If is negative. + /// -or- + /// If is less than 0. + /// + public DnsDomainRecordUpdateConfiguration(DnsRecord record, string name, string data = null, TimeSpan? timeToLive = null, string comment = null, int? priority = null) + { + if (record == null) + throw new ArgumentNullException("record"); + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (data == string.Empty) + throw new ArgumentException("data cannot be empty"); + if (timeToLive <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeToLive cannot be negative or zero"); + if (priority < 0) + throw new ArgumentOutOfRangeException("priority"); + + if (record.Type != DnsRecordType.Mx && record.Type != DnsRecordType.Srv) + { + if (priority.HasValue) + throw new ArgumentException(string.Format("A priority cannot be specified for {0} records.", record.Type)); + } + + _id = record.Id; + _name = name; + _data = data; + _comment = comment; + _priority = priority; + if (timeToLive != null) + _timeToLive = (int)timeToLive.Value.TotalSeconds; + } + + /// + /// Gets the unique ID of the record to update within the DNS service. + /// + /// + /// The unique ID for the record. + /// + public RecordId Id + { + get + { + return _id; + } + } + + /// + /// Gets the name of the DNS record. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the data for this DNS record. + /// + public string Data + { + get + { + return _data; + } + } + + /// + /// Gets the time-to-live for the DNS record. + /// + public TimeSpan? TimeToLive + { + get + { + if (!_timeToLive.HasValue) + return null; + + return TimeSpan.FromSeconds(_timeToLive.Value); + } + } + + /// + /// Gets the optional comment associated with the DNS record. + /// + public string Comment + { + get + { + return _comment; + } + } + + /// + /// Gets the priority associated with the DNS record. + /// + /// + /// The priority only applies to and + /// records. For other record types, this property is . + /// + public int? Priority + { + get + { + return _priority; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainUpdateConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainUpdateConfiguration.cs new file mode 100644 index 000000000..4000eb5ea --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomainUpdateConfiguration.cs @@ -0,0 +1,130 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a domain within the DNS service. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsDomainUpdateConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("emailAddress")] + private string _emailAddress; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private DomainId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("comment")] + private string _comment; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ttl", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _timeToLive; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsDomainUpdateConfiguration() + { + } + + /// + /// Initializes a new instance of the class with + /// the specified values. + /// + /// The domain to update. + /// The time-to-live for the domain. If this value is , the existing value for the domain is not updated. + /// The email address associated with the domain. If this value is , the existing value for the domain is not updated. + /// An optional comment associated with the domain. If this value is , the existing value for the domain is not updated. + /// If is . + public DnsDomainUpdateConfiguration(DnsDomain domain, string emailAddress = null, string comment = null, TimeSpan? timeToLive = null) + { + if (domain == null) + throw new ArgumentNullException("domain"); + + _id = domain.Id; + _emailAddress = emailAddress; + _comment = comment; + _timeToLive = timeToLive.HasValue ? (int?)timeToLive.Value.TotalSeconds : null; + } + + /// + /// Gets the unique ID representing this domain within the DNS service. + /// + /// + /// The unique ID for the domain. + /// + public DomainId Id + { + get + { + return _id; + } + } + + /// + /// Gets the comment associated with this domain. + /// + /// + /// The comment for the domain, or if + /// the current comment for the domain should not be changed. + /// + public string Comment + { + get + { + return _comment; + } + } + + /// + /// Gets the email address associated with this domain. + /// + /// + /// The email address for the domain, or if the current email address for the + /// domain should not be changed. + /// + public string EmailAddress + { + get + { + return _emailAddress; + } + } + + /// + /// Gets the time-to-live for the domain. + /// + /// + /// A object containing the time-to-live for the domain, or if + /// the current time-to-live for the domain should not be changed. + /// + public TimeSpan? TimeToLive + { + get + { + if (_timeToLive == null) + return null; + + return TimeSpan.FromSeconds(_timeToLive.Value); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomains.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomains.cs new file mode 100644 index 000000000..c632e224d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsDomains.cs @@ -0,0 +1,57 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a collection of DNS domains returned from a call to create, clone, or + /// import domains in the DNS service. + /// + /// + /// + /// + /// Create Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Clone Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Import Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsDomains : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("domains")] + private DnsDomain[] _domains; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsDomains() + { + } + + /// + /// Gets a collection of objects describing domains in the DNS service. + /// + /// + /// A collection of objects describing domains in the DNS service, or + /// if the JSON response from the server did not include this property. + /// + public ReadOnlyCollection Domains + { + get + { + if (_domains == null) + return null; + + return new ReadOnlyCollection(_domains); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJob.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJob.cs new file mode 100644 index 000000000..7ae85f0d4 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJob.cs @@ -0,0 +1,193 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using JSIStudios.SimpleRESTServices.Client; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents the job resource associated with a server-side asynchronous + /// operation being performed by the DNS service. + /// + /// + /// Synchronous and Asynchronous Responses (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsJob : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("request")] + private string _request; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private DnsJobStatus _status; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("verb")] + [JsonConverter(typeof(StringEnumConverter))] + private HttpMethod? _verb; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("jobId")] + private JobId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("callbackUrl")] + private string _callbackUrl; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("requestUrl")] + private string _requestUrl; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("error")] + private JObject _error; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsJob() + { + } + + /// + /// Gets the unique ID for this job. + /// + /// + /// The unique ID for the job, or if the JSON response from the server + /// did not include this property. + /// + public JobId Id + { + get + { + return _id; + } + } + + /// + /// Gets the status for this job. + /// + /// + /// The current status of the job, or if the JSON response from the server + /// did not include this property. + /// + public DnsJobStatus Status + { + get + { + return _status; + } + } + + /// + /// Gets the representing the job resource itself. + /// + /// + /// The URI for the current job resource, or if the JSON response + /// from the server did not include this property. + /// + public Uri CallbackUri + { + get + { + if (_callbackUrl == null) + return null; + + return new Uri(_callbackUrl); + } + } + + /// + /// Gets the original for which this job resource was + /// created. + /// + /// + /// The URI for for which this job resource was created, or + /// if the JSON response from the server did not include this property. + /// + public Uri RequestUri + { + get + { + if (_requestUrl == null) + return null; + + return new Uri(_requestUrl); + } + } + + /// + /// Gets the HTTP method used for the API call that created this job resource. + /// + /// + /// The HTTP method used for the API call for which this job resource was + /// created, or if the JSON response from the server did not + /// include this property. + /// + public HttpMethod? Verb + { + get + { + return _verb; + } + } + + /// + /// Gets the body of the original HTTP request for which this job resource + /// was created. + /// + /// + /// The body of the original HTTP request for which this job resource was + /// created, or if the JSON response from the server did not + /// include this property. + /// + public string Request + { + get + { + return _request; + } + } + + /// + /// Gets a containing information about the specific + /// error which occurred during the execution of this job. This property + /// is only set when the job is . + /// + /// + /// A object representing the JSON-formatted information + /// about the error that occurred while this task was running, or + /// if the JSON response from the server did not include this property. + /// + public JObject Error + { + get + { + return _error; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJobStatus.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJobStatus.cs new file mode 100644 index 000000000..52bb078af --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJobStatus.cs @@ -0,0 +1,113 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the status of a DNS job. + /// + /// + /// This class functions as a strongly-typed enumeration of known statuses, + /// with added support for unknown statuses returned by a server extension. + /// + /// + /// + /// + [JsonConverter(typeof(DnsJobStatus.Converter))] + public sealed class DnsJobStatus : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly DnsJobStatus _initialized = FromName("INITIALIZED"); + private static readonly DnsJobStatus _running = FromName("RUNNING"); + private static readonly DnsJobStatus _completed = FromName("COMPLETED"); + private static readonly DnsJobStatus _error = FromName("ERROR"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private DnsJobStatus(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static DnsJobStatus FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new DnsJobStatus(i)); + } + + /// + /// Gets a representing a job which has been accepted by the DNS service but has not yet started. + /// + public static DnsJobStatus Initialized + { + get + { + return _initialized; + } + } + + /// + /// Gets a representing a job which is currently running. + /// + public static DnsJobStatus Running + { + get + { + return _running; + } + } + + /// + /// Gets a representing a job which completed successfully. + /// + public static DnsJobStatus Completed + { + get + { + return _completed; + } + } + + /// + /// Gets a representing a job which terminated with an error. + /// + public static DnsJobStatus Error + { + get + { + return _error; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DnsJobStatus FromName(string name) + { + return DnsJobStatus.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJob`1.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJob`1.cs new file mode 100644 index 000000000..e45a276a2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsJob`1.cs @@ -0,0 +1,50 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using Newtonsoft.Json; + + /// + /// Represents an asynchronous job which provides a strongly-typed response + /// once the job reaches . + /// + /// The class modeling the JSON result of the asynchronous operation. + /// + /// Synchronous and Asynchronous Responses (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsJob : DnsJob + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("response")] + private TResponse _response; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsJob() + { + } + + /// + /// Gets the strongly-typed response from this job. + /// + /// + /// A object representing the JSON-formatted + /// response from the asynchronous operation, or if the JSON + /// response from the server did not include this property. + /// + public TResponse Response + { + get + { + return _response; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsNameserver.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsNameserver.cs new file mode 100644 index 000000000..eb05e6f85 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsNameserver.cs @@ -0,0 +1,49 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a nameserver associated with a domain + /// in the DNS service. + /// + /// + /// List Domain Details (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsNameserver : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsNameserver() + { + } + + /// + /// Gets the fully-qualified domain name of the nameserver. + /// + /// + /// The fully-qualified domain name of the nameserver, or if the JSON + /// response from the server did not include this property. + /// + public string Name + { + get + { + return _name; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimit.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimit.cs new file mode 100644 index 000000000..b75a53b10 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimit.cs @@ -0,0 +1,139 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using JSIStudios.SimpleRESTServices.Client; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + using CancellationToken = System.Threading.CancellationToken; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the detailed parameters of a specific single rate limit within + /// the DNS service. + /// + /// + /// List All Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsRateLimit : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("verb")] + [JsonConverter(typeof(StringEnumConverter))] + private HttpMethod? _verb; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("unit")] + private DnsRateLimitUnit _unit; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("value")] + private long? _value; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("remaining")] + private long? _remaining; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("next-available")] + private DateTimeOffset? _nextAvailable; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsRateLimit() + { + } + + /// + /// Gets the HTTP method associated with the rate limit. + /// + /// + /// The specific HTTP method which is rate limited, or if the JSON + /// response from the server did not include this property. + /// + public HttpMethod? Verb + { + get + { + return _verb; + } + } + + /// + /// Gets the time unit this rate limit is measured in. + /// + /// + /// The time unit used for measuring this rate limit, or if the JSON + /// response from the server did not include this property. + /// + public DnsRateLimitUnit Unit + { + get + { + return _unit; + } + } + + /// + /// Gets the rate limit, in number of times an API call can be made using the + /// HTTP method in the measuring time . + /// + /// + /// The rate limit value, or if the JSON response from the server + /// did not include this property. + /// + public long? Value + { + get + { + return _value; + } + } + + /// + /// Gets the number of calls remaining in the current time unit. + /// + /// + /// The number of calls remaining within the current rate limit time unit, or + /// if the JSON response from the server did not include this property. + /// + public long? Remaining + { + get + { + return _remaining; + } + } + + /// + /// Gets a timestamp indicating when the rate limit next resets. + /// + /// + /// The timestamp for when the rate limit next resets, or if the + /// JSON response from the server did not include this property. + /// + public DateTimeOffset? NextAvailable + { + get + { + return _nextAvailable; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimitPattern.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimitPattern.cs new file mode 100644 index 000000000..b796008a2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimitPattern.cs @@ -0,0 +1,97 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using CancellationToken = System.Threading.CancellationToken; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class describes the rate limits in effect for resource URIs matching + /// a specific pattern. + /// + /// + /// List All Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsRateLimitPattern : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("uri")] + private string _uri; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("regex")] + private string _regex; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("limit")] + private DnsRateLimit[] _limit; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsRateLimitPattern() + { + } + + /// + /// Gets a display representation of the URIs which are limited by this pattern. + /// + /// + /// A display representation of the URIs which are limited by this pattern, or + /// if the JSON response from the server did not include this property. + /// + public string Uri + { + get + { + return _uri; + } + } + + /// + /// Gets a regular expression pattern intended to match the URIs which are limited by this pattern. + /// + /// + /// A regular expression pattern intended to match the URIs which are limited by this pattern, or + /// if the JSON response from the server did not include this property. + /// + public string RegularExpression + { + get + { + return _regex; + } + } + + /// + /// Gets a collection of objects describing the specific limits in + /// effect for the resources at URIs described by this pattern. + /// + /// + /// A collection of objects describing the specific limits, or + /// if the JSON response from the server did not include this property. + /// + public ReadOnlyCollection Limit + { + get + { + if (_limit == null) + return null; + + return new ReadOnlyCollection(_limit); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimitUnit.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimitUnit.cs new file mode 100644 index 000000000..a0b5797c8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimitUnit.cs @@ -0,0 +1,88 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the time unit used for measuring a rate limit in the DNS service. + /// + /// + /// This class functions as a strongly-typed enumeration of known time units, + /// with added support for unknown formats returned by a server extension. + /// + /// + /// + [JsonConverter(typeof(DnsRateLimitUnit.Converter))] + public sealed class DnsRateLimitUnit : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly DnsRateLimitUnit _second = FromName("SECOND"); + private static readonly DnsRateLimitUnit _minute = FromName("MINUTE"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private DnsRateLimitUnit(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static DnsRateLimitUnit FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new DnsRateLimitUnit(i)); + } + + /// + /// Gets a representing a rate limit measured in seconds. + /// + public static DnsRateLimitUnit Second + { + get + { + return _second; + } + } + + /// + /// Gets a representing a rate limit measured in minutes. + /// + public static DnsRateLimitUnit Minute + { + get + { + return _minute; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DnsRateLimitUnit FromName(string name) + { + return DnsRateLimitUnit.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimits.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimits.cs new file mode 100644 index 000000000..1d895e513 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRateLimits.cs @@ -0,0 +1,55 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using CancellationToken = System.Threading.CancellationToken; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the rate limits in effect for the DNS service. + /// + /// + /// List All Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsRateLimits : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("rate")] + private DnsRateLimitPattern[] _rate; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsRateLimits() + { + } + + /// + /// Gets a collection of objects describing the + /// rate limits in effect for various DNS resources. + /// + /// + /// A collection of objects describing DNS rate + /// limits, or if the JSON response from the server did not include + /// this property. + /// + public ReadOnlyCollection Rate + { + get + { + if (_rate == null) + return null; + + return new ReadOnlyCollection(_rate); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecord.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecord.cs new file mode 100644 index 000000000..f824e9948 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecord.cs @@ -0,0 +1,220 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class describes a single record associated with a domain in the DNS service. + /// + /// + /// List Record Details (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsRecord : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("ttl")] + private int? _timeToLive; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private RecordId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private DnsRecordType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("comment")] + private string _comment; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("data")] + private string _data; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("priority")] + private int? _priority; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created")] + private DateTimeOffset? _created; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated")] + private DateTimeOffset? _updated; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsRecord() + { + } + + /// + /// Gets the unique ID representing this record within the DNS service. + /// + /// + /// The unique ID for the record, or if the JSON response from the server + /// did not include this property. + /// + public RecordId Id + { + get + { + return _id; + } + } + + /// + /// Gets the DNS record type. + /// + /// + /// The DNS record type, or if the JSON response from the server + /// did not include this property. + /// + public DnsRecordType Type + { + get + { + return _type; + } + } + + /// + /// Gets the name of the DNS record. + /// + /// + /// The DNS record name, or if the JSON response from the server + /// did not include this property. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the data associated with the DNS record. + /// + /// + /// The DNS record data, or if the JSON response from the server + /// did not include this property. + /// + public string Data + { + get + { + return _data; + } + } + + /// + /// Gets the time-to-live for the DNS record. + /// + /// + /// The time-to-live of the DNS record, or if the JSON response from the server + /// did not include this property. + /// + public TimeSpan? TimeToLive + { + get + { + if (_timeToLive == null) + return null; + + return TimeSpan.FromSeconds(_timeToLive.Value); + } + } + + /// + /// Gets the timestamp when this DNS record was initially created. + /// + /// + /// The creation timestamp of the DNS record, or if the JSON response from the server + /// did not include this property. + /// + public DateTimeOffset? Created + { + get + { + return _created; + } + } + + /// + /// Gets the timestamp when this DNS record was last updated. + /// + /// + /// The last-updated timestamp of the DNS record, or if the JSON response from the server + /// did not include this property. + /// + public DateTimeOffset? Updated + { + get + { + return _updated; + } + } + + /// + /// Gets the priority of this DNS record. + /// + /// + /// The priority of the DNS record, or if the JSON response from the server + /// did not include this property. + /// + public int? Priority + { + get + { + return _priority; + } + } + + /// + /// Gets the optional comment associated with the DNS record. + /// + /// + /// The comment associated with the DNS record, or if the JSON response from the server + /// did not include this property or if the record does not have an associated comment. + /// + public string Comment + { + get + { + return _comment; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecordType.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecordType.cs new file mode 100644 index 000000000..8d927adf0 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecordType.cs @@ -0,0 +1,161 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a DNS record type. + /// + /// + /// This class functions as a strongly-typed enumeration of known record types, + /// with added support for unknown types returned by a server extension. + /// + /// Supported Record Types (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(DnsRecordType.Converter))] + public sealed class DnsRecordType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly DnsRecordType _a = FromName("A"); + private static readonly DnsRecordType _aaaa = FromName("AAAA"); + private static readonly DnsRecordType _cname = FromName("CNAME"); + private static readonly DnsRecordType _mx = FromName("MX"); + private static readonly DnsRecordType _ns = FromName("NS"); + private static readonly DnsRecordType _ptr = FromName("PTR"); + private static readonly DnsRecordType _srv = FromName("SRV"); + private static readonly DnsRecordType _txt = FromName("TXT"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private DnsRecordType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static DnsRecordType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new DnsRecordType(i)); + } + + /// + /// Gets a representing an address record. + /// + public static DnsRecordType A + { + get + { + return _a; + } + } + + /// + /// Gets a representing an IPv6 address record. + /// + public static DnsRecordType Aaaa + { + get + { + return _aaaa; + } + } + + /// + /// Gets a representing a canonical name record. + /// + public static DnsRecordType Cname + { + get + { + return _cname; + } + } + + /// + /// Gets a representing mail exchange record. + /// + public static DnsRecordType Mx + { + get + { + return _mx; + } + } + + /// + /// Gets a representing a name server record. + /// + public static DnsRecordType Ns + { + get + { + return _ns; + } + } + + /// + /// Gets a representing a pointer record. + /// + public static DnsRecordType Ptr + { + get + { + return _ptr; + } + } + + /// + /// Gets a representing a service locator. + /// + public static DnsRecordType Srv + { + get + { + return _srv; + } + } + + /// + /// Gets a representing a text record. + /// + public static DnsRecordType Txt + { + get + { + return _txt; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DnsRecordType FromName(string name) + { + return DnsRecordType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecordsList.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecordsList.cs new file mode 100644 index 000000000..e611bed77 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsRecordsList.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the object associated with the "recordsList" property in + /// the JSON model for a DNS domain. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsRecordsList : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("records")] + private DnsRecord[] _records; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsRecordsList() + { + } + + /// + /// Gets a collection of objects describing the DNS records + /// associated with a . + /// + /// + /// A collection of objects, or if the JSON response + /// from the server did not include the associated property. + /// + public ReadOnlyCollection Records + { + get + { + if (_records == null) + return null; + + return new ReadOnlyCollection(_records); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsServiceLimits.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsServiceLimits.cs new file mode 100644 index 000000000..7d8c88b72 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsServiceLimits.cs @@ -0,0 +1,74 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System.Collections.Generic; + using System.Collections.ObjectModel; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using CancellationToken = System.Threading.CancellationToken; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the rate and absolute limits in effect for the DNS service. + /// + /// + /// List All Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsServiceLimits : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("rate")] + private DnsRateLimitPattern[] _rate; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("absolute")] + private Dictionary _absolute; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsServiceLimits() + { + } + + /// + /// Gets a collection of objects describing the rate limits + /// associated with resources in the DNS service. + /// + public ReadOnlyCollection RateLimits + { + get + { + if (_rate == null) + return null; + + return new ReadOnlyCollection(_rate); + } + } + + /// + /// Gets a map of absolute limits in effect for the DNS service. The keys of the map are + /// canonical names describing the limited DNS resource, and the values are the actual limits + /// in effect for the service. + /// + public ReadOnlyDictionary AbsoluteLimits + { + get + { + if (_absolute == null) + return null; + + return new ReadOnlyDictionary(_absolute); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomain.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomain.cs new file mode 100644 index 000000000..908d0a9e9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomain.cs @@ -0,0 +1,154 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class describes a single subdomain associated with a domain in the DNS service. + /// + /// + /// List Subdomains (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsSubdomain : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("emailAddress")] + private string _emailAddress; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private DomainId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("comment")] + private string _comment; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created")] + private DateTimeOffset? _created; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated")] + private DateTimeOffset? _updated; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsSubdomain() + { + } + + /// + /// Gets the unique ID representing this subdomain within the DNS service. + /// + /// + /// The unique ID for the subdomain, or if the JSON response from the server + /// did not include the associated property. + /// + public DomainId Id + { + get + { + return _id; + } + } + + /// + /// Gets the fully-qualified DNS subdomain name. + /// + /// + /// The fully-qualified subdomain name, or if the JSON response from the server + /// did not include the associated property. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the email address associated with this subdomain. + /// + /// + /// The email address for the subdomain, or if the JSON response from the server + /// did not include the associated property. + /// + public string EmailAddress + { + get + { + return _emailAddress; + } + } + + /// + /// Gets the optional comment associated with the subdomain. + /// + /// + /// The comment associated with the subdomain, or if the JSON response from the server + /// did not include this property or if the subdomain does not have an associated comment. + /// + public string Comment + { + get + { + return _comment; + } + } + + /// + /// Gets the timestamp when this subdomain was initially created. + /// + /// + /// The creation timestamp of the subdomain, or if the JSON response from the server + /// did not include the associated property. + /// + public DateTimeOffset? Created + { + get + { + return _created; + } + } + + /// + /// Gets the timestamp when this subdomain was last updated. + /// + /// + /// The last-updated timestamp of the subdomain, or if the JSON response from the server + /// did not include the associated property. + /// + public DateTimeOffset? Updated + { + get + { + return _updated; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomainConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomainConfiguration.cs new file mode 100644 index 000000000..fc9efc67b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomainConfiguration.cs @@ -0,0 +1,109 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This models a DNS subdomain for calls to the . + /// + /// Create Domain(s) (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsSubdomainConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("emailAddress")] + private string _emailAddress; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("comment")] + private string _comment; + + /// + /// Initializes a new instance of the class + /// with the specified name, email address, and optional comment to associate with + /// the subdomain. + /// + /// The email address associated with the subdomain. + /// + /// The name of the subdomain. This is the fully-qualified name of the subdomain, e.g. + /// if the primary domain is example.com, then + /// the subdomain name could be www.example.com + /// but not just www. + /// An optional comment to associate with the subdomain. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + public DnsSubdomainConfiguration(string emailAddress, string name, string comment) + { + if (name == null) + throw new ArgumentNullException("name"); + if (emailAddress == null) + throw new ArgumentNullException("emailAddress"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (string.IsNullOrEmpty(emailAddress)) + throw new ArgumentException("emailAddress cannot be empty"); + + _emailAddress = emailAddress; + _name = name; + _comment = comment; + } + + /// + /// Gets the fully-qualified name of this subdomain. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the email address associated with the subdomain. + /// + public string EmailAddress + { + get + { + return _emailAddress; + } + } + + /// + /// Gets the comment associated with the subdomain. + /// + /// + /// The comment associated with the subdomain, or if no comment + /// was provided for this subdomain. + /// + public string Comment + { + get + { + return _comment; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomainsList.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomainsList.cs new file mode 100644 index 000000000..67ec640f3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsSubdomainsList.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the object associated with the "subdomains" property in + /// the JSON model for a DNS domain. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsSubdomainsList : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("domains")] + private DnsSubdomain[] _subdomains; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsSubdomainsList() + { + } + + /// + /// Gets a collection of objects describing the subdomains + /// associated with a . + /// + /// + /// A collection of objects, or if the JSON response + /// from the server did not include the associated property. + /// + public ReadOnlyCollection Subdomains + { + get + { + if (_subdomains == null) + return null; + + return new ReadOnlyCollection(_subdomains); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsUpdateConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsUpdateConfiguration.cs new file mode 100644 index 000000000..e4eae2b1b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DnsUpdateConfiguration.cs @@ -0,0 +1,74 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents the updates to apply to a collection of domains in the DNS service. + /// + /// + /// + /// This class can be extended if a server extension requires additional information (beyond + /// the domains property which is already supported) be sent in the body of a + /// Modify Domain(s) API call. + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsUpdateConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("domains")] + private readonly DnsDomainUpdateConfiguration[] _domainConfiguration; + + /// + /// Initializes a new instance of the class for the + /// specified domains. + /// + /// A collection of objects describing the domains. + /// If is . + /// If contains a value. + public DnsUpdateConfiguration(params DnsDomainUpdateConfiguration[] domainConfigurations) + : this(domainConfigurations.AsEnumerable()) + { + } + + /// + /// Initializes a new instance of the class for the + /// specified domains. + /// + /// A collection of objects describing the domains. + /// If is . + /// If contains a value. + public DnsUpdateConfiguration(IEnumerable domainConfigurations) + { + if (domainConfigurations == null) + throw new ArgumentNullException("domainConfigurations"); + + _domainConfiguration = domainConfigurations.ToArray(); + + if (_domainConfiguration.Contains(null)) + throw new ArgumentException("domainConfigurations cannot contain any null values.", "domainConfigurations"); + } + + /// + /// Gets a collection of the objects describing + /// domains in this configuration. + /// + public ReadOnlyCollection DomainConfigurations + { + get + { + return new ReadOnlyCollection(_domainConfiguration); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/DomainId.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/DomainId.cs new file mode 100644 index 000000000..e865db944 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/DomainId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a domain in the . + /// + /// + /// + /// + [JsonConverter(typeof(DomainId.Converter))] + public sealed class DomainId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The domain identifier value. + /// If is . + /// If is empty. + public DomainId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DomainId FromValue(string id) + { + return new DomainId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/ExportedDomain.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/ExportedDomain.cs new file mode 100644 index 000000000..dc4a7028d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/ExportedDomain.cs @@ -0,0 +1,72 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using Newtonsoft.Json; + using ProjectId = net.openstack.Core.Domain.ProjectId; + using Tenant = net.openstack.Core.Domain.Tenant; + + /// + /// Extends the object to expose additional information + /// provided by the method. + /// + /// Export Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ExportedDomain : SerializedDomain + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("accountId")] + private ProjectId _accountId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private DomainId _id; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ExportedDomain() + { + } + + /// + /// Gets the ID of the exported domain. + /// + /// + /// The ID for the exported domain, or if the JSON response from the server + /// did not include this property. + /// + /// + public DomainId Id + { + get + { + return _id; + } + } + + /// + /// Gets the account ID associated with this domain. The account ID within the DNS service + /// is equivalent to the Tenant.Id referenced by other services. + /// + /// + /// The account ID for the domain, or if the JSON response from the server + /// did not include this property. + /// + public ProjectId AccountId + { + get + { + return _accountId; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/JobId.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/JobId.cs new file mode 100644 index 000000000..e45aa52df --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/JobId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a job in the . + /// + /// + /// + /// + [JsonConverter(typeof(JobId.Converter))] + public sealed class JobId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The job identifier value. + /// If is . + /// If is empty. + public JobId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override JobId FromValue(string id) + { + return new JobId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/LimitType.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/LimitType.cs new file mode 100644 index 000000000..d34060e39 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/LimitType.cs @@ -0,0 +1,103 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a category of limits which apply to the DNS service. + /// + /// + /// This class functions as a strongly-typed enumeration of known limit types, + /// with added support for unknown types returned by a server extension. + /// + /// Rate Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Domain Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Record Limits (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(LimitType.Converter))] + public sealed class LimitType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly LimitType _rate = FromName("RATE_LIMIT"); + private static readonly LimitType _domain = FromName("DOMAIN_LIMIT"); + private static readonly LimitType _domainRecord = FromName("DOMAIN_RECORD_LIMIT"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private LimitType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static LimitType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new LimitType(i)); + } + + /// + /// Gets a representing rate limits in effect for the DNS service. + /// + public static LimitType Rate + { + get + { + return _rate; + } + } + + /// + /// Gets a representing absolute limits in place for domains in the DNS service. + /// + public static LimitType Domain + { + get + { + return _domain; + } + } + + /// + /// Gets a representing absolute limits in place for records in the DNS service. + /// + public static LimitType DomainRecord + { + get + { + return _domainRecord; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override LimitType FromName(string name) + { + return LimitType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/NamespaceDoc.cs new file mode 100644 index 000000000..ed6c1a76c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System.Runtime.CompilerServices; + + /// + /// The namespaces define + /// the object model for communicating with Rackspace's Cloud DNS service over REST APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/RecordId.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/RecordId.cs new file mode 100644 index 000000000..fcbf012b4 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/RecordId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a domain record in the . + /// + /// + /// + /// + [JsonConverter(typeof(RecordId.Converter))] + public sealed class RecordId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The domain record identifier value. + /// If is . + /// If is empty. + public RecordId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override RecordId FromValue(string id) + { + return new RecordId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/SerializedDomain.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/SerializedDomain.cs new file mode 100644 index 000000000..42b2414fd --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/SerializedDomain.cs @@ -0,0 +1,88 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This models the JSON representation of a serialized domain for calls to + /// . + /// + /// + /// + /// Export Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + /// Import Domain (Rackspace Cloud DNS Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class SerializedDomain : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("contents")] + private string _contents; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("contentType")] + private SerializedDomainFormat _contentType; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected SerializedDomain() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified contents and content type. + /// + /// The contents of the serialized domain. + /// The content type of the serialized domain. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public SerializedDomain(string contents, SerializedDomainFormat contentType) + { + if (contents == null) + throw new ArgumentNullException("contents"); + if (contentType == null) + throw new ArgumentNullException("contentType"); + if (string.IsNullOrEmpty(contents)) + throw new ArgumentException("contents cannot be empty"); + + _contents = contents; + _contentType = contentType; + } + + /// + /// Gets the contents of the serialized domain. + /// + public string Contents + { + get + { + return _contents; + } + } + + /// + /// Gets the content type of the serialized domain. + /// + public SerializedDomainFormat ContentType + { + get + { + return _contentType; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Dns/SerializedDomainFormat.cs b/src/OpenStack/Providers/Rackspace/Objects/Dns/SerializedDomainFormat.cs new file mode 100644 index 000000000..2bd25cb18 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Dns/SerializedDomainFormat.cs @@ -0,0 +1,75 @@ +namespace net.openstack.Providers.Rackspace.Objects.Dns +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a format for domains exported by the DNS service. + /// + /// + /// This class functions as a strongly-typed enumeration of known serialization + /// formats, with added support for unknown formats returned by a server extension. + /// + /// + /// + [JsonConverter(typeof(SerializedDomainFormat.Converter))] + public sealed class SerializedDomainFormat : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly SerializedDomainFormat _bind9 = FromName("BIND_9"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private SerializedDomainFormat(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static SerializedDomainFormat FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new SerializedDomainFormat(i)); + } + + /// + /// Gets a representing a BIND 9 serialized domain. + /// + public static SerializedDomainFormat Bind9 + { + get + { + return _bind9; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override SerializedDomainFormat FromName(string name) + { + return SerializedDomainFormat.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Domain.cs b/src/OpenStack/Providers/Rackspace/Objects/Domain.cs new file mode 100644 index 000000000..17aeaf4d0 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Domain.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents the domain for a user account. + /// + /// + /// + /// This property is an undocumented Rackspace-specific extension to the OpenStack Identity Service. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Domain : ExtensibleJsonObject + { + /// + /// Gets the "name" property for the domain. + /// The value of this property is not defined. Do not use. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Initializes a new instance of the class with the specified domain. + /// + /// The domain name. + /// If is . + /// If is empty. + public Domain(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + Name = name; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/AccessType.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/AccessType.cs new file mode 100644 index 000000000..8b45859ea --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/AccessType.cs @@ -0,0 +1,90 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents an network access type in the load balancers service. + /// + /// + /// This class functions as a strongly-typed enumeration of known access types, + /// with added support for unknown types returned by a server extension. + /// + /// Manage Access Lists (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(AccessType.Converter))] + public sealed class AccessType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly AccessType _allow = FromName("ALLOW"); + private static readonly AccessType _deny = FromName("DENY"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private AccessType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static AccessType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new AccessType(i)); + } + + /// + /// Gets an representing an item to which traffic should be allowed. + /// The access type takes priority over the access type. + /// + public static AccessType Allow + { + get + { + return _allow; + } + } + + /// + /// Gets an representing an item to which traffic can be denied. + /// + public static AccessType Deny + { + get + { + return _deny; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AccessType FromName(string name) + { + return AccessType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/ConnectionHealthMonitor.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/ConnectionHealthMonitor.cs new file mode 100644 index 000000000..fcbdec731 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/ConnectionHealthMonitor.cs @@ -0,0 +1,43 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + + /// + /// This class models the JSON object used to represent a for + /// simple connection monitoring. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ConnectionHealthMonitor : HealthMonitor + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ConnectionHealthMonitor() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The number of permissible monitor failures before removing a node from rotation. + /// The maximum number of seconds to wait for a connection to be established before timing out. + /// The minimum time to wait before executing the health monitor. + /// + /// If is less than or equal to 0. + /// -or- + /// If is negative or . + /// -or- + /// If is negative or . + /// + public ConnectionHealthMonitor(int attemptsBeforeDeactivation, TimeSpan timeout, TimeSpan delay) + : base(HealthMonitorType.Connect, attemptsBeforeDeactivation, timeout, delay) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/ConnectionThrottles.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/ConnectionThrottles.cs new file mode 100644 index 000000000..48284c256 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/ConnectionThrottles.cs @@ -0,0 +1,146 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a connection throttling configuration for a load + /// balancer in the load balancer service. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ConnectionThrottles : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("maxConnectionRate", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _maxConnectionRate; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("maxConnections", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _maxConnections; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("minConnections", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _minConnections; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rateInterval", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _rateInterval; + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected ConnectionThrottles() + { + } + + /// + /// Initializes a new instance of the class with + /// the specified configuration. + /// + /// The maximum number of connections per rate interval to allow from a single IP address, or 0 to not limit the connection rate. If this value is , the value for this throttle will not be changed during a call to . + /// The maximum number of connections to allow from a single IP address, or 0 to not limit the number connections. If this value is , the value for this throttle will not be changed during a call to . + /// The minimum number of connections to allow from an IP address before applying throttling restrictions. If this value is , the value for this throttle will not be changed during a call to . + /// The time period for which the connection rate limit is evaluated. If this value is , the value for this throttle will not be changed during a call to . + /// + /// If is less than 0. + /// -or- + /// If is less than 0. + /// -or- + /// If is less than 0. + /// -or- + /// If is negative or . + /// + public ConnectionThrottles(int? maxConnectionRate, int? maxConnections, int? minConnections, TimeSpan? rateInterval) + { + if (maxConnectionRate < 0) + throw new ArgumentOutOfRangeException("maxConnectionRate"); + if (maxConnections < 0) + throw new ArgumentOutOfRangeException("maxConnections"); + if (minConnections < 0) + throw new ArgumentOutOfRangeException("minConnections"); + if (rateInterval <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("rateInterval"); + + _maxConnectionRate = maxConnectionRate; + _maxConnections = maxConnections; + _minConnections = minConnections; + _rateInterval = rateInterval != null ? (int?)rateInterval.Value.TotalSeconds : default(int?); + } + + /// + /// Gets the maximum number of connections allowed from a single IP address in the defined . + /// A value of 0 indicates an unlimited connection rate. A value of indicates this connection limit is + /// not configured. + /// + /// + /// The maximum number of connections allowed from a single IP address in the defined , + /// or one of the following values: + /// + /// + /// 0, if the connection rate is configured but unlimited. + /// , if the connection rate limit is not configured. + /// + /// + public int? MaxConnectionRate + { + get + { + return _maxConnectionRate; + } + } + + /// + /// Gets the maximum number of connections allowed for a single IP address. A value of 0 indicates + /// an unlimited number of connections. A value of indicates this connection limit is + /// not configured. + /// + public int? MaxConnections + { + get + { + return _maxConnections; + } + } + + /// + /// Gets the minimum number of connections to allow from an IP address before applying throttling restrictions. + /// A value of indicates this connection limit is not configured. + /// + public int? MinConnections + { + get + { + return _minConnections; + } + } + + /// + /// Gets the time period for which is evaluated. For example, a + /// of 30 with a of 60 seconds would allow a maximum of 30 connections per minute from a single IP + /// address. A value of indicates this connection limit is not configured. + /// + public TimeSpan? RateInterval + { + get + { + if (_rateInterval == null) + return null; + + return TimeSpan.FromSeconds(_rateInterval.Value); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/CustomHealthMonitor.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/CustomHealthMonitor.cs new file mode 100644 index 000000000..a9a41df7e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/CustomHealthMonitor.cs @@ -0,0 +1,22 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using Newtonsoft.Json; + + /// + /// This class models the JSON object used to represent a custom . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CustomHealthMonitor : HealthMonitor + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected CustomHealthMonitor() + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/HealthMonitor.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/HealthMonitor.cs new file mode 100644 index 000000000..039693452 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/HealthMonitor.cs @@ -0,0 +1,160 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This is the base class for load balancer health monitoring configurations. + /// + /// + /// + /// + /// Monitor Health (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class HealthMonitor : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private HealthMonitorType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timeout")] + private int? _timeout; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("delay")] + private int? _delay; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("attemptsBeforeDeactivation")] + private int? _attemptsBeforeDeactivation; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected HealthMonitor() + { + } + + /// + /// Initializes a new instance of the class + /// using the specified values. + /// + /// The type of health monitor. + /// The number of permissible monitor failures before removing a node from rotation. + /// The maximum number of seconds to wait for a connection to be established before timing out. + /// The minimum time to wait before executing the health monitor. + /// If is . + /// + /// If is less than or equal to 0. + /// -or- + /// If is negative or . + /// -or- + /// If is negative or . + /// + protected HealthMonitor(HealthMonitorType type, int attemptsBeforeDeactivation, TimeSpan timeout, TimeSpan delay) + { + if (type == null) + throw new ArgumentNullException("type"); + if (attemptsBeforeDeactivation <= 0) + throw new ArgumentOutOfRangeException("attemptsBeforeDeactivation"); + if (timeout <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeout"); + if (delay <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("delay"); + + _type = type; + _attemptsBeforeDeactivation = attemptsBeforeDeactivation; + _timeout = (int)timeout.TotalSeconds; + _delay = (int)delay.TotalSeconds; + } + + /// + /// Gets the type of health monitor. + /// + public HealthMonitorType Type + { + get + { + return _type; + } + } + + /// + /// Gets the maximum number of seconds to wait for a connection to be established before timing out. + /// + public TimeSpan? Timeout + { + get + { + if (_timeout == null) + return null; + + return TimeSpan.FromSeconds(_timeout.Value); + } + } + + /// + /// Gets the minimum time to wait before executing the health monitor. + /// + public TimeSpan? Delay + { + get + { + if (_delay == null) + return null; + + return TimeSpan.FromSeconds(_delay.Value); + } + } + + /// + /// Gets the number of permissible monitor failures before removing a node from rotation. + /// + public int? AttemptsBeforeDeactivation + { + get + { + return _attemptsBeforeDeactivation; + } + } + + /// + /// Deserializes a JSON object to a instance of the proper type. + /// + /// The JSON object representing the health monitor. + /// A object corresponding to the JSON object. + /// If is . + public static HealthMonitor FromJObject(JObject jsonObject) + { + if (jsonObject == null) + throw new ArgumentNullException("jsonObject"); + + JValue typeValue = jsonObject["type"] as JValue; + if (typeValue == null) + return null; + + HealthMonitorType type = typeValue.ToObject(); + if (type == HealthMonitorType.Connect) + return jsonObject.ToObject(); + else if (type == HealthMonitorType.Http || type == HealthMonitorType.Https) + return jsonObject.ToObject(); + else + return jsonObject.ToObject(); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/HealthMonitorType.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/HealthMonitorType.cs new file mode 100644 index 000000000..637adbfbc --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/HealthMonitorType.cs @@ -0,0 +1,101 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents load balancer health monitor type. + /// + /// + /// This class functions as a strongly-typed enumeration of known monitor types, + /// with added support for unknown types returned by a server extension. + /// + /// Monitors (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(HealthMonitorType.Converter))] + public sealed class HealthMonitorType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly HealthMonitorType _connect = FromName("CONNECT"); + private static readonly HealthMonitorType _http = FromName("HTTP"); + private static readonly HealthMonitorType _https = FromName("HTTPS"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private HealthMonitorType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static HealthMonitorType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new HealthMonitorType(i)); + } + + /// + /// Gets a representing a connect monitor. + /// + public static HealthMonitorType Connect + { + get + { + return _connect; + } + } + + /// + /// Gets a representing an HTTP monitor. + /// + public static HealthMonitorType Http + { + get + { + return _http; + } + } + + /// + /// Gets a representing an HTTPS monitor. + /// + public static HealthMonitorType Https + { + get + { + return _https; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override HealthMonitorType FromName(string name) + { + return HealthMonitorType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancer.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancer.cs new file mode 100644 index 000000000..55e06aa5c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancer.cs @@ -0,0 +1,194 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + + /// + /// Represents a load balancer in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancer : LoadBalancerConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("nodeCount", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _nodeCount; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("cluster", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerCluster _cluster; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerStatus _status; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerTimestamp _created; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerTimestamp _updated; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("sourceAddresses", DefaultValueHandling = DefaultValueHandling.Ignore)] + private Dictionary _sourceAddresses; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancer() + { + } + + /// + /// Gets unique ID representing this load balancer within the load balancers service. + /// + /// + /// The unique ID for the load balancer, or if the JSON response from the server + /// did not include this property. + /// + public LoadBalancerId Id + { + get + { + return _id; + } + } + + /// + /// Gets the total number of nodes in the load balancer. + /// + /// + /// This property is typically populated by calls that do not provide the complete + /// set of nodes in the + /// property. + /// + /// + /// The total number of nodes in the load balancer, or if the JSON response + /// from the server did not include this property. + /// + public int? NodeCount + { + get + { + return _nodeCount; + } + } + + /// + /// Gets the status of the load balancer. + /// + /// + /// The status of the load balancer, or if the JSON response from the server + /// did not include this property. + /// + public LoadBalancerStatus Status + { + get + { + return _status; + } + } + + /// + /// Gets the cluster the load balancer is located within. + /// + /// + /// A object describing the cluster where the load balancer + /// is located, or if the JSON response from the server did not include this + /// property. + /// + public LoadBalancerCluster Cluster + { + get + { + return _cluster; + } + } + + /// + /// Gets the timestamp when the load balancer was created. + /// + /// + /// The creation timestamp of the load balancer, or if the JSON response from the server + /// did not include this property. + /// + public DateTimeOffset? Created + { + get + { + if (_created == null) + return null; + + return _created.Time; + } + } + + /// + /// Gets the timestamp when the load balancer was last updated. + /// + /// + /// The last-updated timestamp of the load balancer, or if the JSON response from the server + /// did not include this property. + /// + public DateTimeOffset? Updated + { + get + { + if (_updated == null) + return null; + + return _updated.Time; + } + } + + /// + /// Gets the source addresses for the load balancer. The keys of this dictionary + /// are the names of the source network, and the values are an IP address or + /// IP address range (in CIDR notation) of the addresses available to the load + /// balancer on that network. + /// + /// + /// A dictionary mapping network names to source addresses for the load balancer, + /// or if the JSON response from the server did not include this property. + /// + public ReadOnlyDictionary SourceAddresses + { + get + { + if (_sourceAddresses == null) + return null; + + return new ReadOnlyDictionary(_sourceAddresses); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerCluster.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerCluster.cs new file mode 100644 index 000000000..42f719f15 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerCluster.cs @@ -0,0 +1,43 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a load balancer cluster to support the + /// property. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerCluster : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerCluster() + { + } + + /// + /// Gets the name of the cluster a load balancer is located within. + /// + public string Name + { + get + { + return _name; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration.cs new file mode 100644 index 000000000..b16af6688 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration.cs @@ -0,0 +1,73 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class represents the configuration for a new load balancer. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerConfiguration : LoadBalancerConfiguration + { + /// + /// Initializes a new instance of the class. + /// + /// + /// This constructor is used during JSON deserialization of derived types. + /// + [JsonConstructor] + protected LoadBalancerConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The name of the load balancer. + /// The load balancing protocol to use for this load balancer. + /// A collection of objects describing the virtual addresses to assign to the load balancer. + /// A collection of objects describing the nodes in the load balancer. If this value is , the load balancer will be created without any nodes. + /// to enable half-closed support for the load balancer; otherwise, . Half-Closed support provides the ability for one end of the connection to terminate its output, while still receiving data from the other end. Only applies to TCP/TCP_CLIENT_FIRST protocols. + /// A collection of objects describing the access list for the load balancer. If this value is , the load balancer will be created without an access list configured. + /// The load balancing algorithm that defines how traffic should be directed between back-end nodes. If this value is , a provider-specific default algorithm will be used. + /// to enable connection logging; otherwise, . If this value is , a provider-specific default value will be used. + /// to enable content caching; otherwise, . If this value is , a provider-specific default value will be used. + /// A object defining the connection throttling configuration for the load balancer. If this value is , a provider-specific default value will be used. + /// A object defining the health monitor to configure for the load balancer. If this value is , the load balancer will be created with no health monitor configured. + /// A collection of objects defining the initial metadata for the load balancer. If this value is , the load balancer will be created without any initial custom metadata. + /// The timeout value for the load balancer and communications with its nodes. If this value is , a provider-specific default value will be used. + /// A object defining the session persistence configuration for the load balancer. If this value is , the load balancer will be created with session persistence disabled. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// + /// + /// If is negative or . + /// + public LoadBalancerConfiguration(string name, LoadBalancingProtocol protocol, IEnumerable virtualAddresses, IEnumerable nodes = null, bool? halfClosed = null, IEnumerable accessList = null, LoadBalancingAlgorithm algorithm = null, bool? connectionLogging = null, bool? contentCaching = null, ConnectionThrottles connectionThrottle = null, HealthMonitor healthMonitor = null, IEnumerable metadata = null, TimeSpan? timeout = null, SessionPersistence sessionPersistence = null) + : base(name, protocol, virtualAddresses, nodes, halfClosed, accessList, algorithm, connectionLogging, contentCaching, connectionThrottle, healthMonitor, metadata, timeout, sessionPersistence) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration`1.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration`1.cs new file mode 100644 index 000000000..8dbb6b1dc --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration`1.cs @@ -0,0 +1,403 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents a load balancer configuration. + /// + /// + /// The extends this class for use in calls to + /// , and the + /// class extends this class to represent a load balancer + /// that already exists as a resource in the . + /// + /// The class used to represent a load balancer node configuration. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerConfiguration : ExtensibleJsonObject + where TNodeConfiguration : NodeConfiguration + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("nodes", DefaultValueHandling = DefaultValueHandling.Ignore)] + private TNodeConfiguration[] _nodes; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("protocol", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _protocolName; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("halfClosed", DefaultValueHandling = DefaultValueHandling.Ignore)] + private bool? _halfClosed; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("virtualIps", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerVirtualAddress[] _virtualIps; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("accessList", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NetworkItem[] _accessList; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("algorithm", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancingAlgorithm _algorithm; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("connectionLogging", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerEnabledFlag _connectionLogging; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("contentCaching", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerEnabledFlag _contentCaching; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("connectionThrottle", DefaultValueHandling = DefaultValueHandling.Ignore)] + private ConnectionThrottles _connectionThrottle; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("healthMonitor", DefaultValueHandling = DefaultValueHandling.Ignore)] + private JObject _healthMonitor; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerMetadataItem[] _metadata; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("port", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _port; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timeout", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _timeout; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("sessionPersistence", DefaultValueHandling = DefaultValueHandling.Ignore)] + private SessionPersistence _sessionPersistence; + + /// + /// Initializes a new instance of the class. + /// + /// + /// This constructor is used during JSON deserialization of derived types. + /// + [JsonConstructor] + protected LoadBalancerConfiguration() + { + } + + /// + /// Initializes a new instance of the + /// class with the specified values. + /// + /// The name of the load balancer. + /// The load balancing protocol to use for this load balancer. + /// A collection of objects describing the virtual addresses to assign to the load balancer. + /// A collection of objects describing the nodes in the load balancer. If this value is , the load balancer will be created without any nodes. + /// to enable half-closed support for the load balancer; otherwise, . Half-Closed support provides the ability for one end of the connection to terminate its output, while still receiving data from the other end. Only applies to TCP/TCP_CLIENT_FIRST protocols. + /// A collection of objects describing the access list for the load balancer. If this value is , the load balancer will be created without an access list configured. + /// The load balancing algorithm that defines how traffic should be directed between back-end nodes. If this value is , a provider-specific default algorithm will be used. + /// to enable connection logging; otherwise, . If this value is , a provider-specific default value will be used. + /// to enable content caching; otherwise, . If this value is , a provider-specific default value will be used. + /// A object defining the connection throttling configuration for the load balancer. If this value is , a provider-specific default value will be used. + /// A object defining the health monitor to configure for the load balancer. If this value is , the load balancer will be created with no health monitor configured. + /// A collection of objects defining the initial metadata for the load balancer. If this value is , the load balancer will be created without any initial custom metadata. + /// The timeout value for the load balancer and communications with its nodes. If this value is , a provider-specific default value will be used. + /// A object defining the session persistence configuration for the load balancer. If this value is , the load balancer will be created with session persistence disabled. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// + /// + /// If is negative or . + /// + public LoadBalancerConfiguration(string name, LoadBalancingProtocol protocol, IEnumerable virtualAddresses, IEnumerable nodes = null, bool? halfClosed = null, IEnumerable accessList = null, LoadBalancingAlgorithm algorithm = null, bool? connectionLogging = null, bool? contentCaching = null, ConnectionThrottles connectionThrottle = null, HealthMonitor healthMonitor = null, IEnumerable metadata = null, TimeSpan? timeout = null, SessionPersistence sessionPersistence = null) + { + if (name == null) + throw new ArgumentNullException("name"); + if (protocol == null) + throw new ArgumentNullException("protocol"); + if (virtualAddresses == null) + throw new ArgumentNullException("virtualAddresses"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (timeout <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeout"); + + _name = name; + _nodes = nodes != null ? nodes.ToArray() : null; + _protocolName = protocol != null ? protocol.Name : null; + _port = protocol != null ? (int?)protocol.Port : null; + _halfClosed = halfClosed; + _virtualIps = virtualAddresses.ToArray(); + _accessList = accessList != null ? accessList.ToArray() : null; + _algorithm = algorithm; + if (connectionLogging.HasValue) + _connectionLogging = connectionLogging.Value ? LoadBalancerEnabledFlag.True : LoadBalancerEnabledFlag.False; + if (contentCaching.HasValue) + _contentCaching = contentCaching.Value ? LoadBalancerEnabledFlag.True : LoadBalancerEnabledFlag.False; + _connectionThrottle = connectionThrottle; + _healthMonitor = healthMonitor != null ? JObject.FromObject(healthMonitor) : null; + _metadata = metadata != null ? metadata.ToArray() : null; + _timeout = timeout != null ? (int?)timeout.Value.TotalSeconds : null; + _sessionPersistence = sessionPersistence; + + if (_nodes != null && _nodes.Contains(null)) + throw new ArgumentException("nodes cannot contain any null values", "nodes"); + if (_virtualIps.Contains(null)) + throw new ArgumentException("virtualAddresses cannot contain any null values", "virtualAddresses"); + if (_accessList != null && _accessList.Contains(null)) + throw new ArgumentException("accessList cannot contain any null values", "accessList"); + if (_metadata != null && _metadata.Contains(null)) + throw new ArgumentException("metadata cannot contain any null values", "metadata"); + } + + /// + /// Gets the name of the load balancer. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets a collection of objects describing the + /// nodes associated with the load balancer. + /// + public ReadOnlyCollection Nodes + { + get + { + if (_nodes == null) + return null; + + return new ReadOnlyCollection(_nodes); + } + } + + /// + /// Gets the name of the load balanced protocol. + /// + public string ProtocolName + { + get + { + return _protocolName; + } + } + + /// + /// Gets a value indicating whether or not half-closed support is enabled for the load balancer. + /// + public bool? HalfClosed + { + get + { + return _halfClosed; + } + } + + /// + /// Gets a collection of objects describing + /// the virtual addresses associated with the load balancer. + /// + public ReadOnlyCollection VirtualAddresses + { + get + { + if (_virtualIps == null) + return null; + + return new ReadOnlyCollection(_virtualIps); + } + } + + /// + /// Gets a collection of objects describing the access + /// list for the load balancer. + /// + public ReadOnlyCollection AccessList + { + get + { + if (_accessList == null) + return null; + + return new ReadOnlyCollection(_accessList); + } + } + + /// + /// Gets the load balancing algorithm used for distributing data between back-end nodes. + /// + public LoadBalancingAlgorithm Algorithm + { + get + { + return _algorithm; + } + } + + /// + /// Gets a value indicating whether or not connection logging is enabled for the load balancer. + /// + public bool? ConnectionLogging + { + get + { + if (_connectionLogging == null) + return null; + + return _connectionLogging.Enabled; + } + } + + /// + /// Gets a value indicating whether or not content caching is enabled for the load balancer. + /// + public bool? ContentCaching + { + get + { + if (_contentCaching == null) + return null; + + return _contentCaching.Enabled; + } + } + + /// + /// Gets the connection throttling configuration for the load balancer. + /// + public ConnectionThrottles ConnectionThrottles + { + get + { + return _connectionThrottle; + } + } + + /// + /// Gets the health monitor configured for the load balancer. + /// + public HealthMonitor HealthMonitor + { + get + { + if (_healthMonitor == null) + return null; + + return HealthMonitor.FromJObject(_healthMonitor); + } + } + + /// + /// Gets a collection of objects describing + /// the metadata associated with the load balancer. + /// + public ReadOnlyCollection Metadata + { + get + { + if (_metadata == null) + return null; + + return new ReadOnlyCollection(_metadata); + } + } + + /// + /// Gets the port number the load balancer will listen for connections on. + /// + public int? Port + { + get + { + return _port; + } + } + + /// + /// Gets the timeout value for the load balancer and communications with its nodes. + /// + public TimeSpan? Timeout + { + get + { + if (_timeout == null) + return null; + + return TimeSpan.FromSeconds(_timeout.Value); + } + } + + /// + /// Gets the session persistence configuration for the load balancer. + /// + public SessionPersistence SessionPersistence + { + get + { + return _sessionPersistence; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerEnabledFlag.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerEnabledFlag.cs new file mode 100644 index 000000000..234f3b261 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerEnabledFlag.cs @@ -0,0 +1,86 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON object used to represent an enabled/disabled + /// flag for a configuration option. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerEnabledFlag : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + private static readonly LoadBalancerEnabledFlag _true = new LoadBalancerEnabledFlag(true); + + /// + /// This is the backing field for the property. + /// + private static readonly LoadBalancerEnabledFlag _false = new LoadBalancerEnabledFlag(false); + + /// + /// This is the backing field for the property. + /// + [JsonProperty("enabled")] + private bool _enabled; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerEnabledFlag() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified value. + /// + /// if the option is enabled; otherwise, . + public LoadBalancerEnabledFlag(bool enabled) + { + _enabled = enabled; + } + + /// + /// Gets a instance representing an enabled option. + /// + public static LoadBalancerEnabledFlag True + { + get + { + return _true; + } + } + + /// + /// Gets a instance representing a disabled option. + /// + public static LoadBalancerEnabledFlag False + { + get + { + return _false; + } + } + + /// + /// Gets a value indicating whether or not the option is enabled. + /// + /// + /// if the option is enabled; otherwise, . + /// + public bool Enabled + { + get + { + return _enabled; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerId.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerId.cs new file mode 100644 index 000000000..c9157bd7a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a load balancer in the . + /// + /// + /// + /// + [JsonConverter(typeof(LoadBalancerId.Converter))] + public sealed class LoadBalancerId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The load balancer identifier value. + /// If is . + /// If is empty. + public LoadBalancerId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override LoadBalancerId FromValue(string id) + { + return new LoadBalancerId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerMetadataItem.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerMetadataItem.cs new file mode 100644 index 000000000..fef6278bd --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerMetadataItem.cs @@ -0,0 +1,106 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a metadata item associated with a resource in the load balancer service. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerMetadataItem : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private MetadataId _id; +#pragma warning restore 649 + + /// + /// This is the backing field for the property. + /// + [JsonProperty("key", DefaultValueHandling = DefaultValueHandling.Include)] + private string _key; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("value", DefaultValueHandling = DefaultValueHandling.Include)] + private string _value; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerMetadataItem() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified key and value. + /// + /// The metadata key. + /// The metadata value. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public LoadBalancerMetadataItem(string key, string value) + { + if (key == null) + throw new ArgumentNullException("key"); + if (value == null) + throw new ArgumentNullException("value"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + + _key = key; + _value = value; + } + + /// + /// Gets the unique ID for the metadata item. + /// + /// + /// Metadata IDs in the load balancer service are only guaranteed to be unique within the + /// context of the item they are associated with. + /// + public MetadataId Id + { + get + { + return _id; + } + } + + /// + /// Gets the key for this metadata item. + /// + public string Key + { + get + { + return _key; + } + } + + /// + /// Gets the value for this metadata item. + /// + public string Value + { + get + { + return _value; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerSslConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerSslConfiguration.cs new file mode 100644 index 000000000..221d5834f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerSslConfiguration.cs @@ -0,0 +1,198 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of an SSL termination configuration in the + /// load balancer service. + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerSslConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("enabled", DefaultValueHandling = DefaultValueHandling.Ignore)] + private bool? _enabled; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("secureTrafficOnly", DefaultValueHandling = DefaultValueHandling.Ignore)] + private bool? _secureTrafficOnly; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("securePort", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _securePort; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("privatekey", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _privateKey; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("certificate", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _certificate; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("intermediateCertificate", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _intermediateCertificate; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerSslConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// using the specified configuration. + /// + /// + /// Configurations created with this constructor will not overwrite the private key or + /// certificates stored on the server during a call to + /// . + /// + /// to enable SSL termination on the load balancer; otherwise, . If this value is , the current configuration for the value is not changed by a call to . + /// to require encryption for all traffic through the load balancer; otherwise, . If this value is , the current configuration for the value is not changed by a call to . + /// The port on which the SSL termination load balancer will listen for secure traffic. If this value is , the current configuration for the value is not changed by a call to . + /// + /// If is less than 0 or greater than 65535. + /// + public LoadBalancerSslConfiguration(bool? enabled, bool? secureTrafficOnly, int? securePort) + { + if (securePort < 0 || securePort > 65535) + throw new ArgumentOutOfRangeException("securePort"); + + _enabled = enabled; + _secureTrafficOnly = secureTrafficOnly; + _securePort = securePort; + } + + /// + /// Initializes a new instance of the class + /// using the specified configuration and certificates. + /// + /// to enable SSL termination on the load balancer; otherwise, . If this value is , the current configuration for the value is not changed by a call to . + /// to require encryption for all traffic through the load balancer; otherwise, . If this value is , the current configuration for the value is not changed by a call to . + /// The port on which the SSL termination load balancer will listen for secure traffic. If this value is , the current configuration for the value is not changed by a call to . + /// The private key for the SSL certificate. + /// The certificate used for SSL termination. + /// The user's intermediate certificate used for SSL termination. + /// + /// If is and either or is not . + /// -or- + /// If is and is not . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If is less than 0 or greater than 65535. + /// + public LoadBalancerSslConfiguration(bool? enabled, bool? secureTrafficOnly, int securePort, string privateKey, string certificate, string intermediateCertificate) + : this(enabled, secureTrafficOnly, securePort) + { + if (privateKey == null && (certificate != null || intermediateCertificate != null)) + throw new ArgumentNullException("privateKey"); + if (certificate == null && privateKey != null) + throw new ArgumentNullException("certificate"); + if (privateKey == string.Empty) + throw new ArgumentException("privateKey cannot be empty"); + if (certificate == string.Empty) + throw new ArgumentException("certificate cannot be empty"); + if (intermediateCertificate == string.Empty) + throw new ArgumentException("intermediateCertificate cannot be empty"); + + _privateKey = privateKey; + _certificate = certificate; + _intermediateCertificate = intermediateCertificate; + } + + /// + /// Gets a value indicating whether or not SSL termination is enabled on the load balancer. + /// + public bool? Enabled + { + get + { + return _enabled; + } + } + + /// + /// Gets a value indicating whether or not the load balancer should only accept secure traffic. + /// + public bool? SecureTrafficOnly + { + get + { + return _secureTrafficOnly; + } + } + + /// + /// Gets a value indicating which port the load balancer should listen for secure traffic on. + /// + public int? SecurePort + { + get + { + return _securePort; + } + } + + /// + /// Gets the private key for the certificate used for SSL termination on the load balancer. + /// + public string PrivateKey + { + get + { + return _privateKey; + } + } + + /// + /// Gets the certificate used for SSL termination on the load balancer. + /// + public string Certificate + { + get + { + return _certificate; + } + } + + /// + /// Gets the intermediate certificate used for SSL termination on the load balancer. + /// + public string IntermediateCertificate + { + get + { + return _intermediateCertificate; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerStatistics.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerStatistics.cs new file mode 100644 index 000000000..08bc3a3cc --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerStatistics.cs @@ -0,0 +1,111 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents the load balancer statistics returned from a + /// call to . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerStatistics : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + [JsonProperty("connectTimeOut", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _connectTimeOut; + + [JsonProperty("connectError", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _connectError; + + [JsonProperty("connectFailure", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _connectFailure; + + [JsonProperty("dataTimedOut", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _dataTimedOut; + + [JsonProperty("keepAliveTimedOut", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _keepAliveTimedOut; + + [JsonProperty("maxConn", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _maxConn; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerStatistics() + { + } + + /// + /// Gets the number of connections closed by the load balancer because the connect_timeout interval was exceeded. + /// + public long? ConnectionTimedOut + { + get + { + return _connectTimeOut; + } + } + + /// + /// Gets the number of transaction or protocol errors in the load balancer. + /// + public long? ConnectionError + { + get + { + return _connectError; + } + } + + /// + /// Gets the number of connection failures in the load balancer. + /// + public long? ConnectionFailure + { + get + { + return _connectFailure; + } + } + + /// + /// Gets the number of connections closed by this load balancer because the timeout interval was exceeded. + /// + public long? DataTimedOut + { + get + { + return _dataTimedOut; + } + } + + /// + /// Gets the number of connections closed by this load balancer because the keepalive_timeout interval was exceeded. + /// + public long? KeepAliveTimedOut + { + get + { + return _keepAliveTimedOut; + } + } + + /// + /// Gets the maximum number of simultaneous TCP connections this load balancer has processed at any one time. + /// + public long? MaxConnections + { + get + { + return _maxConn; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerStatus.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerStatus.cs new file mode 100644 index 000000000..d70b01e7b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerStatus.cs @@ -0,0 +1,160 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the current status of a load balancer. + /// + /// + /// This class functions as a strongly-typed enumeration of known load balancer + /// statuses, with added support for unknown statuses returned by a server extension. + /// + /// + /// Update Load Balancer Attributes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(LoadBalancerStatus.Converter))] + public sealed class LoadBalancerStatus : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly LoadBalancerStatus _active = FromName("ACTIVE"); + private static readonly LoadBalancerStatus _build = FromName("BUILD"); + private static readonly LoadBalancerStatus _pendingUpdate = FromName("PENDING_UPDATE"); + private static readonly LoadBalancerStatus _pendingDelete = FromName("PENDING_DELETE"); + private static readonly LoadBalancerStatus _suspended = FromName("SUSPENDED"); + private static readonly LoadBalancerStatus _error = FromName("ERROR"); + private static readonly LoadBalancerStatus _deleted = FromName("DELETED"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private LoadBalancerStatus(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static LoadBalancerStatus FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new LoadBalancerStatus(i)); + } + + /// + /// Gets a representing a load balancer that is configured + /// properly and ready to serve traffic to incoming requests via the configured virtual IPs. + /// + public static LoadBalancerStatus Active + { + get + { + return _active; + } + } + + /// + /// Gets a representing a load balancer that is being + /// provisioned for the first time and configuration is being applied to bring the service + /// online. The service will not yet be ready to serve incoming requests. + /// + public static LoadBalancerStatus Build + { + get + { + return _build; + } + } + + /// + /// Gets a representing a load balancer that is online + /// but configuration changes are being applied to update the service based on a previous + /// request. + /// + public static LoadBalancerStatus PendingUpdate + { + get + { + return _pendingUpdate; + } + } + + /// + /// Gets a representing a load balancer that is online + /// but configuration changes are being applied to begin deletion of the service based + /// on a previous request. + /// + public static LoadBalancerStatus PendingDelete + { + get + { + return _pendingDelete; + } + } + + /// + /// Gets a representing a load balancer that has been + /// taken offline and disabled. + /// + public static LoadBalancerStatus Suspended + { + get + { + return _suspended; + } + } + + /// + /// Gets a indicating the system encountered an error + /// when attempting to configure the load balancer. + /// + public static LoadBalancerStatus Error + { + get + { + return _error; + } + } + + /// + /// Gets a representing a load balancer that has been + /// deleted. + /// + public static LoadBalancerStatus Deleted + { + get + { + return _deleted; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override LoadBalancerStatus FromName(string name) + { + return LoadBalancerStatus.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerTimestamp.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerTimestamp.cs new file mode 100644 index 000000000..efd42ac2a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerTimestamp.cs @@ -0,0 +1,44 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a timestamp object + /// in the load balancers service. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerTimestamp : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("time")] + private DateTimeOffset? _time; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerTimestamp() + { + } + + /// + /// Gets the time represented by the object. + /// + public DateTimeOffset? Time + { + get + { + return _time; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUpdate.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUpdate.cs new file mode 100644 index 000000000..85ca9fc7c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUpdate.cs @@ -0,0 +1,158 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This object models the JSON representation of a configuration update to apply + /// to an existing load balancer. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerUpdate : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("protocol", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _protocolName; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("halfClosed", DefaultValueHandling = DefaultValueHandling.Ignore)] + private bool? _halfClosed; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("algorithm", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancingAlgorithm _algorithm; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("port", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _port; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timeout", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _timeout; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerUpdate() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The name of the load balancer. If this value is , the existing value for the load balancer is not changed. + /// The load balancing protocol to use for this load balancer. If this value is , the existing value for the load balancer is not changed. + /// to enable half-closed support for the load balancer; otherwise, . Half-Closed support provides the ability for one end of the connection to terminate its output, while still receiving data from the other end. Only applies to TCP/TCP_CLIENT_FIRST protocols. If this value is , the existing value for the load balancer is not changed. + /// The load balancing algorithm that defines how traffic should be directed between back-end nodes. If this value is , the existing value for the load balancer is not changed. + /// The timeout value for the load balancer and communications with its nodes. If this value is , the existing value for the load balancer is not changed. + /// If is empty. + /// + /// If is negative or . + /// + public LoadBalancerUpdate(string name = null, LoadBalancingProtocol protocol = null, bool? halfClosed = null, LoadBalancingAlgorithm algorithm = null, TimeSpan? timeout = null) + { + if (name == string.Empty) + throw new ArgumentException("name cannot be empty"); + if (timeout <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeout"); + + _name = name; + _protocolName = protocol != null ? protocol.Name : null; + _port = protocol != null ? (int?)protocol.Port : null; + _halfClosed = halfClosed; + _algorithm = algorithm; + _timeout = timeout != null ? (int?)timeout.Value.TotalSeconds : null; + } + + /// + /// Gets the name of the load balancer. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the name of the load balanced protocol. + /// + public string ProtocolName + { + get + { + return _protocolName; + } + } + + /// + /// Gets a value indicating whether or not half-closed support is enabled for the load balancer. + /// + public bool? HalfClosed + { + get + { + return _halfClosed; + } + } + + /// + /// Gets the load balancing algorithm used for distributing data between back-end nodes. + /// + public LoadBalancingAlgorithm Algorithm + { + get + { + return _algorithm; + } + } + + /// + /// Gets the port number the load balancer will listen for connections on. + /// + public int? Port + { + get + { + return _port; + } + } + + /// + /// Gets the timeout value for the load balancer and communications with its nodes. + /// + public TimeSpan? Timeout + { + get + { + if (_timeout == null) + return null; + + return TimeSpan.FromSeconds(_timeout.Value); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUsage.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUsage.cs new file mode 100644 index 000000000..73e9560c4 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUsage.cs @@ -0,0 +1,268 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class provides information about load balancer usage during a span of time. + /// + /// + /// + /// + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerUsage : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private LoadBalancerUsageId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("averageNumConnections")] + private double? _averageConnections; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("incomingTransfer")] + private long? _incomingTransfer; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("outgoingTransfer")] + private long? _outgoingTransfer; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("averageNumConnectionsSsl")] + private double? _averageConnectionsSsl; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("incomingTransferSsl")] + private long? _incomingTransferSsl; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("outgoingTransferSsl")] + private long? _outgoingTransferSsl; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("numVips")] + private int? _virtualAddressCount; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("numPolls")] + private int? _pollCount; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("startTime")] + private DateTimeOffset? _startTime; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("endTime")] + private DateTimeOffset? _endTime; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("vipType")] + private LoadBalancerVirtualAddressType _virtualAddressType; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("sslMode")] + private string _sslMode; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("eventType")] + private string _eventType; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerUsage() + { + } + + /// + /// Gets the unique ID for this usage record. + /// + public LoadBalancerUsageId Id + { + get + { + return _id; + } + } + + /// + /// Gets the average number of connections open to the load balancer between and . + /// + public double? AverageConnections + { + get + { + return _averageConnections; + } + } + + /// + /// Gets the number of incoming bytes transferred. + /// + public long? IncomingTransfer + { + get + { + return _incomingTransfer; + } + } + + /// + /// Gets the number of outgoing bytes transferred. + /// + public long? OutgoingTransfer + { + get + { + return _outgoingTransfer; + } + } + + /// + /// Gets the average number of secure connections open to the load balancer between and . + /// + public double? AverageConnectionsSsl + { + get + { + return _averageConnectionsSsl; + } + } + + /// + /// Gets the number of incoming bytes transferred over secure connections. + /// + public long? IncomingTransferSsl + { + get + { + return _incomingTransferSsl; + } + } + + /// + /// Gets the number of outgoing bytes transferred over secure connections. + /// + public long? OutgoingTransferSsl + { + get + { + return _outgoingTransferSsl; + } + } + + /// + /// Gets the number of virtual addresses assigned to the load balancer between and . + /// + public int? VirtualAddressCount + { + get + { + return _virtualAddressCount; + } + } + + /// + /// Gets what? + /// + public int? PollCount + { + get + { + return _pollCount; + } + } + + /// + /// Gets the starting timestamp for this load balancer usage record. + /// + public DateTimeOffset? StartTime + { + get + { + return _startTime; + } + } + + /// + /// Gets the ending timestamp for this load balancer usage record. + /// + public DateTimeOffset? EndTime + { + get + { + return _endTime; + } + } + + /// + /// Gets the virtual address type for the load balancer between and . + /// + public LoadBalancerVirtualAddressType VirtualAddressType + { + get + { + return _virtualAddressType; + } + } + + /// + /// Gets the SSL mode for the load balancer between and . + /// + public string SslMode + { + get + { + return _sslMode; + } + } + + /// + /// Gets what? + /// + public string EventType + { + get + { + return _eventType; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUsageId.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUsageId.cs new file mode 100644 index 000000000..f0c14ab3a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerUsageId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a load balancer usage record in the . + /// + /// + /// + /// + [JsonConverter(typeof(LoadBalancerUsageId.Converter))] + public sealed class LoadBalancerUsageId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The load balancer usage record identifier value. + /// If is . + /// If is empty. + public LoadBalancerUsageId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override LoadBalancerUsageId FromValue(string id) + { + return new LoadBalancerUsageId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerVirtualAddress.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerVirtualAddress.cs new file mode 100644 index 000000000..22d7c88cc --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerVirtualAddress.cs @@ -0,0 +1,171 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Net; + using System.Net.Sockets; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a virtual address which is assigned to a load balancer, + /// or a virtual address configuration for instructing the load balancer service + /// to assign a particular type of virtual address to a load balancer. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancerVirtualAddress : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("address", DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonConverter(typeof(IPAddressSimpleConverter))] + private IPAddress _address; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private VirtualAddressId _id; +#pragma warning restore 649 + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore)] + private LoadBalancerVirtualAddressType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ipVersion", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _ipVersion; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancerVirtualAddress() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified virtual address type. + /// + /// The virtual address type. + /// If is . + public LoadBalancerVirtualAddress(LoadBalancerVirtualAddressType type) + : this(type, null) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified virtual address type and family. + /// + /// The virtual address type. + /// The address family for this virtual address, or to not specify the address family. + /// If is . + /// If is not or . + public LoadBalancerVirtualAddress(LoadBalancerVirtualAddressType type, AddressFamily? version) + { + if (type == null) + throw new ArgumentNullException("type"); + + _type = type; + if (version.HasValue) + { + switch (version) + { + case AddressFamily.InterNetwork: + _ipVersion = "IPV4"; + break; + + case AddressFamily.InterNetworkV6: + _ipVersion = "IPV6"; + break; + + default: + throw new NotSupportedException("The specified address family is not supported by this service."); + } + } + } + + /// + /// Gets the unique ID representing this virtual address within the load balancers service. + /// + /// + /// The unique ID for the virtual address, or if the virtual address has not been + /// created or the JSON response from the server did not include this property. + /// + public VirtualAddressId Id + { + get + { + return _id; + } + } + + /// + /// Gets the IP address for this virtual address within the load balancers service. + /// + /// + /// The IP address for the virtual address, or if the virtual address has not been + /// created or the JSON response from the server did not include this property. + /// + public IPAddress Address + { + get + { + return _address; + } + } + + /// + /// Gets the virtual address type. + /// + /// + /// A object describing the virtual address type, + /// or if the JSON response from the server did not include this property. + /// + public LoadBalancerVirtualAddressType Type + { + get + { + return _type; + } + } + + /// + /// Gets the address family for this virtual address. + /// + /// + /// An describing the address family for this virtual address, + /// or if the JSON response from the server did not include this property or + /// the value was unrecognized. + /// + public AddressFamily? IPVersion + { + get + { + if (_ipVersion == null) + return null; + + switch (_ipVersion.ToLowerInvariant()) + { + case "ipv4": + return AddressFamily.InterNetwork; + case "ipv6": + return AddressFamily.InterNetworkV6; + default: + return null; + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerVirtualAddressType.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerVirtualAddressType.cs new file mode 100644 index 000000000..8043a55ad --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerVirtualAddressType.cs @@ -0,0 +1,101 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a virtual address type in the load balancer service. + /// + /// + /// This class functions as a strongly-typed enumeration of known virtual address types, + /// with added support for unknown types returned by a server extension. + /// + /// + /// + [JsonConverter(typeof(LoadBalancerVirtualAddressType.Converter))] + public sealed class LoadBalancerVirtualAddressType : ExtensibleEnum + { + /// + /// This dictionary maintains a list of all objects + /// which have already been created, to preserve reference equality semantics for objects of + /// this class. + /// + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// This is the backing field for the property. + /// + private static readonly LoadBalancerVirtualAddressType _public = FromName("PUBLIC"); + + /// + /// This is the backing field for the property. + /// + private static readonly LoadBalancerVirtualAddressType _servicenet = FromName("SERVICENET"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private LoadBalancerVirtualAddressType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static LoadBalancerVirtualAddressType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new LoadBalancerVirtualAddressType(i)); + } + + /// + /// Gets a representing placeholder. + /// + public static LoadBalancerVirtualAddressType Public + { + get + { + return _public; + } + } + + /// + /// Gets a representing placeholder. + /// + public static LoadBalancerVirtualAddressType ServiceNet + { + get + { + return _servicenet; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override LoadBalancerVirtualAddressType FromName(string name) + { + return LoadBalancerVirtualAddressType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancingAlgorithm.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancingAlgorithm.cs new file mode 100644 index 000000000..38be92644 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancingAlgorithm.cs @@ -0,0 +1,132 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + + /// + /// Represents a load balancing algorithm. + /// + /// + /// This class functions as a strongly-typed enumeration of known load balancing + /// algorithms, with added support for unknown algorithms returned by a server + /// extension. + /// + /// List Load Balancing Algorithms (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(LoadBalancingAlgorithm.Converter))] + public sealed class LoadBalancingAlgorithm : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly LoadBalancingAlgorithm _leastConnections = FromName("LEAST_CONNECTIONS"); + private static readonly LoadBalancingAlgorithm _random = FromName("RANDOM"); + private static readonly LoadBalancingAlgorithm _roundRobin = FromName("ROUND_ROBIN"); + private static readonly LoadBalancingAlgorithm _weightedLeastConnections = FromName("WEIGHTED_LEAST_CONNECTIONS"); + private static readonly LoadBalancingAlgorithm _weightedRoundRobin = FromName("WEIGHTED_ROUND_ROBIN"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private LoadBalancingAlgorithm(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static LoadBalancingAlgorithm FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new LoadBalancingAlgorithm(i)); + } + + /// + /// Gets a where the node with the lowest number + /// of connections will receive requests. + /// + public static LoadBalancingAlgorithm LeastConnections + { + get + { + return _leastConnections; + } + } + + /// + /// Gets a where back-end servers are selected + /// at random. + /// + public static LoadBalancingAlgorithm Random + { + get + { + return _random; + } + } + + /// + /// Gets a where connections are routed to each + /// of the back-end servers in turn. + /// + public static LoadBalancingAlgorithm RoundRobin + { + get + { + return _roundRobin; + } + } + + /// + /// Gets a where each request will be assigned + /// to a node based on the number of concurrent connections to the node and its weight. + /// + public static LoadBalancingAlgorithm WeightedLeastConnections + { + get + { + return _weightedLeastConnections; + } + } + + /// + /// Gets a similar to , + /// but with different proportions of traffic being directed to the back-end nodes. + /// Weights must be defined as part of the load balancer's node configuration. + /// + public static LoadBalancingAlgorithm WeightedRoundRobin + { + get + { + return _weightedRoundRobin; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override LoadBalancingAlgorithm FromName(string name) + { + return LoadBalancingAlgorithm.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancingProtocol.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancingProtocol.cs new file mode 100644 index 000000000..5cc8acdb6 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/LoadBalancingProtocol.cs @@ -0,0 +1,87 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This models the JSON object representing a load balancing protocol. + /// + /// + /// List Load Balancing Protocols (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadBalancingProtocol : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("port")] + private int? _port; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoadBalancingProtocol() + { + } + + /// + /// Initializes a new instance of the class + /// using the specified name and port number. + /// + /// The protocol name. + /// The default port number for the protocol, or 0 if no default port is defined for the protocol. + /// If is . + /// If is empty. + /// If is less than 0 or greated than 65535. + public LoadBalancingProtocol(string name, int port) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + if (port < 0 || port > 65535) + throw new ArgumentOutOfRangeException("port"); + + _name = name; + _port = port; + } + + /// + /// Gets the name of the load balancing protocol. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the port for the load balancing protocol. + /// + /// + /// The default port number used for the protocol, or if the JSON response from + /// the server did not include the underlying property. If the value is 0, no default port + /// is defined for the protocol. + /// + public int? Port + { + get + { + return _port; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/MetadataId.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/MetadataId.cs new file mode 100644 index 000000000..857704f1f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/MetadataId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a metadata item in the . + /// + /// + /// + /// + [JsonConverter(typeof(MetadataId.Converter))] + public sealed class MetadataId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The metadata item identifier value. + /// If is . + /// If is empty. + public MetadataId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override MetadataId FromValue(string id) + { + return new MetadataId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NamespaceDoc.cs new file mode 100644 index 000000000..abae9b21c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System.Runtime.CompilerServices; + + /// + /// The namespaces define + /// the object model for communicating with Rackspace's Cloud Load Balancers service over REST APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NetworkItem.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NetworkItem.cs new file mode 100644 index 000000000..1b649de9b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NetworkItem.cs @@ -0,0 +1,125 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Net; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a single entry in a load balancer access list. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NetworkItem : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + private NetworkItemId _id; +#pragma warning restore 649 + + /// + /// This is the backing field for the property. + /// + [JsonProperty("address")] + private string _address; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private AccessType _type; + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected NetworkItem() + { + } + + /// + /// Initializes a new instance of the class with the + /// specified IP address and access type. + /// + /// The IP address to which this network item applies. + /// The access type for this network item. + /// + /// If is . + /// -or- + /// If is . + /// + public NetworkItem(IPAddress address, AccessType accessType) + { + if (address == null) + throw new ArgumentNullException("address"); + if (accessType == null) + throw new ArgumentNullException("accessType"); + + _address = address.ToString(); + _type = accessType; + } + + /// + /// Initializes a new instance of the class with the + /// specified IP address and access type. + /// + /// The IP address, or address range in CIDR notation, to which this network item applies. + /// The access type for this network item. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public NetworkItem(string address, AccessType accessType) + { + if (address == null) + throw new ArgumentNullException("address"); + if (accessType == null) + throw new ArgumentNullException("accessType"); + if (string.IsNullOrEmpty(address)) + throw new ArgumentException("address cannot be empty"); + + _address = address; + _type = accessType; + } + + /// + /// Gets the unique ID associated with this network item resource in the load balancer service. + /// + public NetworkItemId Id + { + get + { + return _id; + } + } + + /// + /// Gets the IP address, or address range in CIDR notation, to which this network item applies. + /// + public string Address + { + get + { + return _address; + } + } + + /// + /// The access type for this network item. + /// + public AccessType AccessType + { + get + { + return _type; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NetworkItemId.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NetworkItemId.cs new file mode 100644 index 000000000..725ce69db --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NetworkItemId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an access control network item in the . + /// + /// + /// + /// + [JsonConverter(typeof(NetworkItemId.Converter))] + public sealed class NetworkItemId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The network item identifier value. + /// If is . + /// If is empty. + public NetworkItemId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NetworkItemId FromValue(string id) + { + return new NetworkItemId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Node.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Node.cs new file mode 100644 index 000000000..7c93bc10b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Node.cs @@ -0,0 +1,66 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using Newtonsoft.Json; + + /// + /// Represents a load balancer node in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Node : NodeConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private NodeId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private NodeStatus _status; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected Node() + { + } + + /// + /// Gets unique ID representing this node within the load balancers service. + /// + /// + /// The unique ID for the load balancer node, or if the JSON response + /// from the server did not include this property. + /// + public NodeId Id + { + get + { + return _id; + } + } + + /// + /// Gets the status of the load balancer node. + /// + /// + /// The status of the load balancer node, or if the JSON response + /// from the server did not include this property. + /// + public NodeStatus Status + { + get + { + return _status; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeCondition.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeCondition.cs new file mode 100644 index 000000000..3d659c818 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeCondition.cs @@ -0,0 +1,107 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + + /// + /// Represents the role of a node within a load balancer. + /// + /// + /// This class functions as a strongly-typed enumeration of known node conditions, + /// with added support for unknown conditions returned by a server extension. + /// + /// + /// Modify Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(NodeCondition.Converter))] + public sealed class NodeCondition : ExtensibleEnum + { + private static readonly ConcurrentDictionary _states = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly NodeCondition _enabled = FromName("ENABLED"); + private static readonly NodeCondition _disabled = FromName("DISABLED"); + private static readonly NodeCondition _draining = FromName("DRAINING"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private NodeCondition(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static NodeCondition FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _states.GetOrAdd(name, i => new NodeCondition(i)); + } + + /// + /// Gets a instance representing a node which is permitted + /// to accept new connections. + /// + public static NodeCondition Enabled + { + get + { + return _enabled; + } + } + + /// + /// Gets a instance representing a node which is not permitted + /// to accept any new connections regardless of the session persistence configuration. + /// Existing connections are forcibly terminated. + /// + public static NodeCondition Disabled + { + get + { + return _disabled; + } + } + + /// + /// Gets a instance representing a node which is allowed to + /// service existing established connections and connections that are being directed to + /// it as a result of the session persistence configuration. + /// + public static NodeCondition Draining + { + get + { + return _draining; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NodeCondition FromName(string name) + { + return NodeCondition.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeConfiguration.cs new file mode 100644 index 000000000..d414ab20e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeConfiguration.cs @@ -0,0 +1,195 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Net; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents a load balancer node configuration. + /// + /// + /// This class is used in calls to + /// or , and the + /// class extends this class to represent a load balancer + /// node that already exists as a resource in the . + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NodeConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("address")] + private string _address; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("port")] + private int? _port; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("condition")] + private NodeCondition _condition; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NodeType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("weight", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _weight; + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected NodeConfiguration() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The IP address of the node. + /// The port number for the load balanced service. + /// The condition for the node, which determines its role within the load balancer. + /// The node type. If this value is , a provider-specific default value will be used. + /// The weight of the node. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is less than 0 or greater than 65535. + /// -or- + /// If is less than or equal to 0. + /// + public NodeConfiguration(IPAddress address, int port, NodeCondition condition, NodeType type, int? weight) + { + if (address == null) + throw new ArgumentNullException("address"); + if (condition == null) + throw new ArgumentNullException("condition"); + if (port < 0 || port > 65535) + throw new ArgumentOutOfRangeException("port"); + if (weight <= 0) + throw new ArgumentOutOfRangeException("weight"); + + _address = address.ToString(); + _port = port; + _condition = condition; + _type = type; + _weight = weight; + } + + /// + /// Initializes a new instance of the class. + /// + /// The domain name of the node. + /// The port number for the load balanced service. + /// The condition for the node, which determines its role within the load balancer. + /// The node type. If this value is , a provider-specific default value will be used. + /// The weight of the node. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + /// + /// If is less than 0 or greater than 65535. + /// -or- + /// If is less than or equal to 0. + /// + public NodeConfiguration(string hostDomain, int port, NodeCondition condition, NodeType type, int? weight) + { + if (hostDomain == null) + throw new ArgumentNullException("hostDomain"); + if (condition == null) + throw new ArgumentNullException("condition"); + if (string.IsNullOrEmpty(hostDomain)) + throw new ArgumentException("hostDomain cannot be empty"); + if (port < 0 || port > 65535) + throw new ArgumentOutOfRangeException("port"); + if (weight <= 0) + throw new ArgumentOutOfRangeException("weight"); + + _address = hostDomain; + _port = port; + _condition = condition; + _type = type; + _weight = weight; + } + + /// + /// Gets the IP address or domain name for the node. + /// + public string Address + { + get + { + return _address; + } + } + + /// + /// Gets the condition for the node, which determines its role within the load balancer. + /// + public NodeCondition Condition + { + get + { + return _condition; + } + } + + /// + /// Gets the port number of the load balanced service. + /// + public int? Port + { + get + { + return _port; + } + } + + /// + /// Gets the load balancer node type. + /// + public NodeType Type + { + get + { + return _type; + } + } + + /// + /// Gets the weight of the load balancer node. + /// + /// + /// This property is only used by load balancers with a weighted algorithm, such as + /// . + /// + public int? Weight + { + get + { + return _weight; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeId.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeId.cs new file mode 100644 index 000000000..4f5197a5b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a load balancer node in the . + /// + /// + /// + /// + [JsonConverter(typeof(NodeId.Converter))] + public sealed class NodeId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The load balancer node identifier value. + /// If is . + /// If is empty. + public NodeId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NodeId FromValue(string id) + { + return new NodeId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEvent.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEvent.cs new file mode 100644 index 000000000..f37cd81a9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEvent.cs @@ -0,0 +1,260 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a node service event in the load balancer service. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NodeServiceEvent : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private NodeServiceEventId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("loadBalancerId")] + private LoadBalancerId _loadBalancerId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("nodeId")] + private NodeId _nodeId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("detailedMessage")] + private string _detailedMessage; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private NodeServiceEventType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("category")] + private NodeServiceEventCategory _category; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("severity")] + private NodeServiceEventSeverity _severity; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("description")] + private string _description; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("relativeUri")] + private string _relativeUri; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("accountId")] + private ProjectId _accountId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("title")] + private string _title; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("author")] + private string _author; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created")] + private DateTimeOffset? _created; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NodeServiceEvent() + { + } + + /// + /// Gets the unique ID for this node service event record. + /// + public NodeServiceEventId Id + { + get + { + return _id; + } + } + + /// + /// Gets the load balancer ID. + /// + /// + public LoadBalancerId LoadBalancerId + { + get + { + return _loadBalancerId; + } + } + + /// + /// Gets the load balancer node ID. + /// + /// + public NodeId NodeId + { + get + { + return _nodeId; + } + } + + /// + /// Gets the detailed message describing the service event. + /// + public string DetailedMessage + { + get + { + return _detailedMessage; + } + } + + /// + /// Gets the service event type. + /// + public NodeServiceEventType Type + { + get + { + return _type; + } + } + + /// + /// Gets the service event category. + /// + public NodeServiceEventCategory Category + { + get + { + return _category; + } + } + + /// + /// Gets the service event severity. + /// + public NodeServiceEventSeverity Severity + { + get + { + return _severity; + } + } + + /// + /// Gets a description of the service event. + /// + public string Description + { + get + { + return _description; + } + } + + /// + /// Gets what? + /// + public Uri RelativeUri + { + get + { + if (_relativeUri == null) + return null; + + return new Uri(_relativeUri); + } + } + + /// + /// Gets the account ID associated with this service event. The account ID within + /// the load balancer service is equivalent to the Tenant.Id + /// referenced by other services. + /// + /// + /// The account ID for the node service event, or if the JSON response from the server + /// did not include this property. + /// + public ProjectId AccountId + { + get + { + return _accountId; + } + } + + /// + /// Gets the title of the service event. + /// + public string Title + { + get + { + return _title; + } + } + + /// + /// Gets the author responsible for this service event. + /// + public string Author + { + get + { + return _author; + } + } + + /// + /// Gets a timestamp indicating when this service event was created. + /// + public DateTimeOffset? Created + { + get + { + return _created; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventCategory.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventCategory.cs new file mode 100644 index 000000000..c464611c5 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventCategory.cs @@ -0,0 +1,66 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a node service event category. + /// + /// + /// This class functions as a strongly-typed enumeration of known categories, + /// with added support for unknown categories returned by a server extension. + /// + /// + /// View Node Service Events (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(NodeServiceEventCategory.Converter))] + public sealed class NodeServiceEventCategory : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private NodeServiceEventCategory(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static NodeServiceEventCategory FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new NodeServiceEventCategory(i)); + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NodeServiceEventCategory FromName(string name) + { + return NodeServiceEventCategory.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventId.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventId.cs new file mode 100644 index 000000000..ca1d67622 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a node service event in the . + /// + /// + /// + /// + [JsonConverter(typeof(NodeServiceEventId.Converter))] + public sealed class NodeServiceEventId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The node service event identifier value. + /// If is . + /// If is empty. + public NodeServiceEventId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NodeServiceEventId FromValue(string id) + { + return new NodeServiceEventId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventSeverity.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventSeverity.cs new file mode 100644 index 000000000..ed37a36a4 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventSeverity.cs @@ -0,0 +1,66 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a node service event severity. + /// + /// + /// This class functions as a strongly-typed enumeration of known severities, + /// with added support for unknown severities returned by a server extension. + /// + /// + /// View Node Service Events (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(NodeServiceEventSeverity.Converter))] + public sealed class NodeServiceEventSeverity : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private NodeServiceEventSeverity(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static NodeServiceEventSeverity FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new NodeServiceEventSeverity(i)); + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NodeServiceEventSeverity FromName(string name) + { + return NodeServiceEventSeverity.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventType.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventType.cs new file mode 100644 index 000000000..bfc4ff0ef --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeServiceEventType.cs @@ -0,0 +1,66 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a node service event type. + /// + /// + /// This class functions as a strongly-typed enumeration of known event types, + /// with added support for unknown types returned by a server extension. + /// + /// + /// View Node Service Events (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(NodeServiceEventType.Converter))] + public sealed class NodeServiceEventType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private NodeServiceEventType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static NodeServiceEventType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new NodeServiceEventType(i)); + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NodeServiceEventType FromName(string name) + { + return NodeServiceEventType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeStatus.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeStatus.cs new file mode 100644 index 000000000..04332b008 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeStatus.cs @@ -0,0 +1,77 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents load balancer node status. + /// + /// + /// This class functions as a strongly-typed enumeration of known node statuses, + /// with added support for unknown statuses returned by a server extension. + /// + /// List Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(NodeStatus.Converter))] + public sealed class NodeStatus : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly NodeStatus _online = FromName("ONLINE"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private NodeStatus(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static NodeStatus FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new NodeStatus(i)); + } + + /// + /// Gets a representing placeholder. + /// + public static NodeStatus Online + { + get + { + return _online; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NodeStatus FromName(string name) + { + return NodeStatus.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeType.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeType.cs new file mode 100644 index 000000000..4d143297f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeType.cs @@ -0,0 +1,89 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents load balancer node type. + /// + /// + /// This class functions as a strongly-typed enumeration of known node types, + /// with added support for unknown types returned by a server extension. + /// + /// Add Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonConverter(typeof(NodeType.Converter))] + public sealed class NodeType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly NodeType _primary = FromName("PRIMARY"); + private static readonly NodeType _secondary = FromName("SECONDARY"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private NodeType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static NodeType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new NodeType(i)); + } + + /// + /// Gets a representing a node in the normal rotation to receive traffic from the load balancer. + /// + public static NodeType Primary + { + get + { + return _primary; + } + } + + /// + /// Gets a representing a node only in the rotation to receive traffic from the load balancer when all the nodes fail. + /// + public static NodeType Secondary + { + get + { + return _secondary; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NodeType FromName(string name) + { + return NodeType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeUpdate.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeUpdate.cs new file mode 100644 index 000000000..85942689e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/NodeUpdate.cs @@ -0,0 +1,97 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This object models the JSON representation of a configuration update to apply + /// to an existing load balancer node. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NodeUpdate : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("condition", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NodeCondition _condition; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NodeType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("weight", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _weight; + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected NodeUpdate() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The condition for the node, which determines its role within the load balancer. If this value is , the existing value for the node is not changed. + /// The node type. If this value is , a provider-specific default value will be used. If this value is , the existing value for the node is not changed. + /// The weight of the node. If this value is , the existing value for the node is not changed. + /// If is less than or equal to 0. + public NodeUpdate(NodeCondition condition = null, NodeType type = null, int? weight = null) + { + if (weight <= 0) + throw new ArgumentOutOfRangeException("weight"); + + _condition = condition; + _type = type; + _weight = weight; + } + + /// + /// Gets the condition for the node, which determines its role within the load balancer. + /// + public NodeCondition Condition + { + get + { + return _condition; + } + } + + /// + /// Gets the load balancer node type. + /// + public NodeType Type + { + get + { + return _type; + } + } + + /// + /// Gets the weight of the load balancer node. + /// + /// + /// This property is only used by load balancers with a weighted algorithm, such as + /// . + /// + public int? Weight + { + get + { + return _weight; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/AddLoadBalancerMetadataRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/AddLoadBalancerMetadataRequest.cs new file mode 100644 index 000000000..74ba9cd59 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/AddLoadBalancerMetadataRequest.cs @@ -0,0 +1,31 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class AddLoadBalancerMetadataRequest + { + [JsonProperty("metadata")] + private LoadBalancerMetadataItem[] _metadata; + + /// + /// Initializes a new instance of the class + /// with the specified metadata. + /// + /// The metadata to add. + /// If is . + /// If contains a pair whose key is or empty, or whose value is . + public AddLoadBalancerMetadataRequest(IEnumerable> metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + + _metadata = metadata.Select(i => new LoadBalancerMetadataItem(i.Key, i.Value)).ToArray(); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/AddNodesRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/AddNodesRequest.cs new file mode 100644 index 000000000..377693081 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/AddNodesRequest.cs @@ -0,0 +1,24 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class AddNodesRequest + { + [JsonProperty("nodes")] + private NodeConfiguration[] _nodes; + + public AddNodesRequest(IEnumerable nodes) + { + if (nodes == null) + throw new ArgumentNullException("nodes"); + + _nodes = nodes.ToArray(); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/CreateAccessListRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/CreateAccessListRequest.cs new file mode 100644 index 000000000..8c4ef9cb6 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/CreateAccessListRequest.cs @@ -0,0 +1,24 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateAccessListRequest + { + [JsonProperty("accessList")] + private NetworkItem[] _accessList; + + public CreateAccessListRequest(IEnumerable accessList) + { + if (accessList == null) + throw new ArgumentNullException("accessList"); + + _accessList = accessList.ToArray(); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/CreateLoadBalancerRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/CreateLoadBalancerRequest.cs new file mode 100644 index 000000000..e34640581 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/CreateLoadBalancerRequest.cs @@ -0,0 +1,22 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateLoadBalancerRequest + { + [JsonProperty("loadBalancer")] + private LoadBalancerConfiguration _configuration; + + public CreateLoadBalancerRequest(LoadBalancerConfiguration configuration) + { + if (configuration == null) + throw new ArgumentNullException("configuration"); + + _configuration = configuration; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/NamespaceDoc.cs new file mode 100644 index 000000000..a84dd66dd --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace + /// contains the object models for JSON request bodies sent in calls to Rackspace's + /// Cloud Load Balancers API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerConnectionLoggingRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerConnectionLoggingRequest.cs new file mode 100644 index 000000000..709026a6d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerConnectionLoggingRequest.cs @@ -0,0 +1,16 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class SetLoadBalancerConnectionLoggingRequest : GetLoadBalancerConnectionLoggingResponse + { + public SetLoadBalancerConnectionLoggingRequest(bool enabled) + : base(enabled) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerContentCachingRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerContentCachingRequest.cs new file mode 100644 index 000000000..468ecbf81 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerContentCachingRequest.cs @@ -0,0 +1,16 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class SetLoadBalancerContentCachingRequest : GetLoadBalancerContentCachingResponse + { + public SetLoadBalancerContentCachingRequest(bool enabled) + : base(enabled) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerErrorPageRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerErrorPageRequest.cs new file mode 100644 index 000000000..51b15c89b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/SetLoadBalancerErrorPageRequest.cs @@ -0,0 +1,16 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class SetLoadBalancerErrorPageRequest : GetLoadBalancerErrorPageResponse + { + public SetLoadBalancerErrorPageRequest(string content) + : base(content) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerMetadataItemRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerMetadataItemRequest.cs new file mode 100644 index 000000000..100ada90c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerMetadataItemRequest.cs @@ -0,0 +1,49 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UpdateLoadBalancerMetadataItemRequest + { + [JsonProperty("meta")] + private UpdateMetadataItemRequestBody _body; + + /// + /// Initializes a new instance of the class + /// with the specified metadata value. + /// + /// The updated metadata value. + /// If is . + public UpdateLoadBalancerMetadataItemRequest(string value) + { + if (value == null) + throw new ArgumentNullException("value"); + + _body = new UpdateMetadataItemRequestBody(value); + } + + [JsonObject(MemberSerialization.OptIn)] + protected class UpdateMetadataItemRequestBody + { + [JsonProperty("value")] + private string _value; + + /// + /// Initializes a new instance of the class + /// with the specified metadata value. + /// + /// The updated metadata value. + /// If is . + public UpdateMetadataItemRequestBody(string value) + { + if (value == null) + throw new ArgumentNullException("value"); + + _value = value; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerNodeRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerNodeRequest.cs new file mode 100644 index 000000000..a211e4d45 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerNodeRequest.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UpdateLoadBalancerNodeRequest + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("node")] + private NodeUpdate _nodeUpdate; + + /// + /// Initializes a new instance of the class + /// with the specified configuration. + /// + /// The updated configuration for the load balancer node. + /// If is . + public UpdateLoadBalancerNodeRequest(NodeUpdate nodeUpdate) + { + if (nodeUpdate == null) + throw new ArgumentNullException("nodeUpdate"); + + _nodeUpdate = nodeUpdate; + } + + /// + /// Gets the updated configuration for the load balancer node. + /// + public NodeUpdate NodeUpdate + { + get + { + return _nodeUpdate; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerRequest.cs new file mode 100644 index 000000000..411371158 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Request/UpdateLoadBalancerRequest.cs @@ -0,0 +1,18 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request +{ + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UpdateLoadBalancerRequest + { + [JsonProperty("loadBalancer")] + private LoadBalancerUpdate _loadBalancerUpdate; + + public UpdateLoadBalancerRequest(LoadBalancerUpdate update) + { + _loadBalancerUpdate = update; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetAccessListResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetAccessListResponse.cs new file mode 100644 index 000000000..b990c0031 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetAccessListResponse.cs @@ -0,0 +1,36 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetAccessListResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + [JsonProperty("accessList")] + private NetworkItem[] _accessList; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetAccessListResponse() + { + } + + public ReadOnlyCollection AccessList + { + get + { + if (_accessList == null) + return null; + + return new ReadOnlyCollection(_accessList); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerConnectionLoggingResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerConnectionLoggingResponse.cs new file mode 100644 index 000000000..1c43a84e0 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerConnectionLoggingResponse.cs @@ -0,0 +1,38 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetLoadBalancerConnectionLoggingResponse + { + [JsonProperty("connectionLogging")] + private LoadBalancerEnabledFlag _body; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetLoadBalancerConnectionLoggingResponse() + { + } + + protected GetLoadBalancerConnectionLoggingResponse(bool enabled) + { + _body = enabled ? LoadBalancerEnabledFlag.True : LoadBalancerEnabledFlag.False; + } + + public bool? Enabled + { + get + { + if (_body == null) + return null; + + return _body.Enabled; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerContentCachingResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerContentCachingResponse.cs new file mode 100644 index 000000000..3f46c2d08 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerContentCachingResponse.cs @@ -0,0 +1,38 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetLoadBalancerContentCachingResponse + { + [JsonProperty("contentCaching")] + private LoadBalancerEnabledFlag _body; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetLoadBalancerContentCachingResponse() + { + } + + protected GetLoadBalancerContentCachingResponse(bool enabled) + { + _body = enabled ? LoadBalancerEnabledFlag.True : LoadBalancerEnabledFlag.False; + } + + public bool? Enabled + { + get + { + if (_body == null) + return null; + + return _body.Enabled; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerErrorPageResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerErrorPageResponse.cs new file mode 100644 index 000000000..dcfe2d482 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerErrorPageResponse.cs @@ -0,0 +1,74 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetLoadBalancerErrorPageResponse + { + [JsonProperty("errorpage")] + private ErrorPageBody _body; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetLoadBalancerErrorPageResponse() + { + } + + public GetLoadBalancerErrorPageResponse(string content) + { + if (content == null) + throw new ArgumentNullException("content"); + if (string.IsNullOrEmpty(content)) + throw new ArgumentException("content cannot be empty"); + + _body = new ErrorPageBody(content); + } + + public string Content + { + get + { + if (_body == null) + return null; + + return _body.Content; + } + } + + [JsonObject(MemberSerialization.OptIn)] + protected class ErrorPageBody + { + [JsonProperty("content")] + private string _content; + + [JsonConstructor] + protected ErrorPageBody() + { + } + + public ErrorPageBody(string content) + { + if (content == null) + throw new ArgumentNullException("content"); + if (string.IsNullOrEmpty(content)) + throw new ArgumentException("content cannot be empty"); + + _content = content; + } + + public string Content + { + get + { + return _content; + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerMetadataItemResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerMetadataItemResponse.cs new file mode 100644 index 000000000..053dc3be5 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerMetadataItemResponse.cs @@ -0,0 +1,35 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetLoadBalancerMetadataItemResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("meta")] + private LoadBalancerMetadataItem _metadataItem; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetLoadBalancerMetadataItemResponse() + { + } + + public LoadBalancerMetadataItem MetadataItem + { + get + { + return _metadataItem; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerNodeResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerNodeResponse.cs new file mode 100644 index 000000000..8dec4f11d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerNodeResponse.cs @@ -0,0 +1,32 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetLoadBalancerNodeResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + [JsonProperty("node")] + private Node _node; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetLoadBalancerNodeResponse() + { + } + + public Node Node + { + get + { + return _node; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerResponse.cs new file mode 100644 index 000000000..8db8d4ba0 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerResponse.cs @@ -0,0 +1,32 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetLoadBalancerResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + [JsonProperty("loadBalancer")] + private LoadBalancer _loadBalancer; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetLoadBalancerResponse() + { + } + + public LoadBalancer LoadBalancer + { + get + { + return _loadBalancer; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerSslConfigurationResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerSslConfigurationResponse.cs new file mode 100644 index 000000000..b21582fc8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/GetLoadBalancerSslConfigurationResponse.cs @@ -0,0 +1,32 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetLoadBalancerSslConfigurationResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + [JsonProperty("sslTermination")] + private LoadBalancerSslConfiguration _sslConfiguration; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetLoadBalancerSslConfigurationResponse() + { + } + + public LoadBalancerSslConfiguration SslConfiguration + { + get + { + return _sslConfiguration; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListAllowedDomainsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListAllowedDomainsResponse.cs new file mode 100644 index 000000000..7a0ae0af6 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListAllowedDomainsResponse.cs @@ -0,0 +1,92 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListAllowedDomainsResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + [JsonProperty("allowedDomains")] + private AllowedDomain[] _allowedDomains; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListAllowedDomainsResponse() + { + } + + public IEnumerable AllowedDomains + { + get + { + if (_allowedDomains == null) + return null; + + return _allowedDomains.Select(i => i.Name); + } + } + + [JsonObject(MemberSerialization.OptIn)] + protected class AllowedDomain + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + [JsonProperty("allowedDomain")] + private AllowedDomainDescriptor _allowedDomain; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AllowedDomain() + { + } + + public string Name + { + get + { + if (_allowedDomain == null) + return null; + + return _allowedDomain.Name; + } + } + + [JsonObject(MemberSerialization.OptIn)] + protected class AllowedDomainDescriptor + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + [JsonProperty("name")] + private string _name; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AllowedDomainDescriptor() + { + } + + public string Name + { + get + { + return _name; + } + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerMetadataResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerMetadataResponse.cs new file mode 100644 index 000000000..da219c362 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerMetadataResponse.cs @@ -0,0 +1,48 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Metadata and Add Metadata requests. + /// + /// List Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// Add Metadata (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListLoadBalancerMetadataResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata")] + private LoadBalancerMetadataItem[] _metadata; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListLoadBalancerMetadataResponse() + { + } + + /// + /// Gets a collection of objects describing the + /// metadata associated with a resource in the load balancer service. + /// + public ReadOnlyCollection Metadata + { + get + { + if (_metadata == null) + return null; + + return new ReadOnlyCollection(_metadata); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerNodesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerNodesResponse.cs new file mode 100644 index 000000000..88535f305 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerNodesResponse.cs @@ -0,0 +1,48 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Nodes and Add Nodes requests. + /// + /// List Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// Add Nodes (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListLoadBalancerNodesResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("nodes")] + private Node[] _nodes; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListLoadBalancerNodesResponse() + { + } + + /// + /// Gets a collection of objects describing the load balancer + /// node resources available for a load balancer in the load balancer service. + /// + public ReadOnlyCollection Nodes + { + get + { + if (_nodes == null) + return null; + + return new ReadOnlyCollection(_nodes); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerThrottlesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerThrottlesResponse.cs new file mode 100644 index 000000000..307ceb70d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerThrottlesResponse.cs @@ -0,0 +1,43 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Throttle Connections request. + /// + /// Throttle Connections (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListLoadBalancerThrottlesResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("connectionThrottle")] + private ConnectionThrottles _throttles; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListLoadBalancerThrottlesResponse() + { + } + + /// + /// Gets a object describing the connection throttling + /// configuration for a load balancer. + /// + public ConnectionThrottles Throttles + { + get + { + return _throttles; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerUsageResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerUsageResponse.cs new file mode 100644 index 000000000..52a28d508 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancerUsageResponse.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Usage request. + /// + /// List Usage (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListLoadBalancerUsageResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("loadBalancerUsageRecords")] + private LoadBalancerUsage[] _loadBalancerUsage; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListLoadBalancerUsageResponse() + { + } + + /// + /// Gets a collection of objects describing the load + /// balancer usage resources in a load balancer service provider. + /// + public ReadOnlyCollection UsageRecords + { + get + { + if (_loadBalancerUsage == null) + return null; + + return new ReadOnlyCollection(_loadBalancerUsage); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancersResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancersResponse.cs new file mode 100644 index 000000000..b9537ef76 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancersResponse.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Load Balancers request. + /// + /// List Load Balancers (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListLoadBalancersResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("loadBalancers")] + private LoadBalancer[] _loadBalancers; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListLoadBalancersResponse() + { + } + + /// + /// Gets a collection of objects describing the load + /// balancer resources in a load balancer service provider. + /// + public ReadOnlyCollection LoadBalancers + { + get + { + if (_loadBalancers == null) + return null; + + return new ReadOnlyCollection(_loadBalancers); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancingAlgorithmsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancingAlgorithmsResponse.cs new file mode 100644 index 000000000..1cfbd1c56 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancingAlgorithmsResponse.cs @@ -0,0 +1,72 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Load Balancing Algorithms request. + /// + /// List Load Balancing Algorithms (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListLoadBalancingAlgorithmsResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("algorithms")] + private SerializedLoadBalancingAlgorithm[] _algorithms; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the + /// class during JSON deserialization. + /// + [JsonConstructor] + protected ListLoadBalancingAlgorithmsResponse() + { + } + + /// + /// Gets a collection of objects + /// describing the load balancing algorithms supported by a load balancer + /// service provider. + /// + public IEnumerable Algorithms + { + get + { + return _algorithms.Select(i => i.Algorithm); + } + } + + /// + /// This models the intermediate JSON representation of a named object. + /// + [JsonObject(MemberSerialization.OptIn)] + private class SerializedLoadBalancingAlgorithm + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private LoadBalancingAlgorithm _name; +#pragma warning restore 649 + + /// + /// Gets the load balancing algorithm. + /// + public LoadBalancingAlgorithm Algorithm + { + get + { + return _name; + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancingProtocolsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancingProtocolsResponse.cs new file mode 100644 index 000000000..e19815e50 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListLoadBalancingProtocolsResponse.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Load Balancing Protocols request. + /// + /// List Load Balancing Protocols (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListLoadBalancingProtocolsResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("protocols")] + private LoadBalancingProtocol[] _protocols; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the + /// class during JSON deserialization. + /// + [JsonConstructor] + protected ListLoadBalancingProtocolsResponse() + { + } + + /// + /// Gets a collection of objects describing the + /// protocols supported by the a load balancing service provider. + /// + public ReadOnlyCollection Protocols + { + get + { + if (_protocols == null) + return null; + + return new ReadOnlyCollection(_protocols); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListNodeServiceEventsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListNodeServiceEventsResponse.cs new file mode 100644 index 000000000..dd610ff68 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListNodeServiceEventsResponse.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the View Node Service Events request. + /// + /// View Node Service Events (Rackspace Cloud Load Balancers Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListNodeServiceEventsResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value + /// + /// This is the backing field for the property. + /// + [JsonProperty("nodeServiceEvents")] + private NodeServiceEvent[] _nodeServiceEvents; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListNodeServiceEventsResponse() + { + } + + /// + /// Gets a collection of objects describing the node service + /// events for a load balancer. + /// + public ReadOnlyCollection NodeServiceEvents + { + get + { + if (_nodeServiceEvents == null) + return null; + + return new ReadOnlyCollection(_nodeServiceEvents); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListVirtualAddressesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListVirtualAddressesResponse.cs new file mode 100644 index 000000000..59bf0eec1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/ListVirtualAddressesResponse.cs @@ -0,0 +1,36 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListVirtualAddressesResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + [JsonProperty("virtualIps")] + private LoadBalancerVirtualAddress[] _virtualAddresses; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListVirtualAddressesResponse() + { + } + + public ReadOnlyCollection VirtualAddresses + { + get + { + if (_virtualAddresses == null) + return null; + + return new ReadOnlyCollection(_virtualAddresses); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/NamespaceDoc.cs new file mode 100644 index 000000000..807bc1f3f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/Response/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace + /// contains the object models for JSON responses returned by calls to Rackspace's + /// Cloud Load Balancers API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/SessionPersistence.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/SessionPersistence.cs new file mode 100644 index 000000000..79d28534c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/SessionPersistence.cs @@ -0,0 +1,107 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a session persistence configuration in the load balancer service. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class SessionPersistence : ExtensibleJsonObject + { + /// + /// This intermediate field is required for modeling the JSON representation of a + /// session persistence configuration. + /// + [JsonProperty("sessionPersistence")] + private SessionPersistenceBody _body; + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected SessionPersistence() + { + } + + /// + /// Initializes a new instance of the class using + /// the specified persistence type. + /// + /// The session persistence mode to use. + /// If is . + public SessionPersistence(SessionPersistenceType persistenceType) + { + if (persistenceType == null) + throw new ArgumentNullException("persistenceType"); + + _body = new SessionPersistenceBody(persistenceType); + } + + /// + /// Gets the session persistence type. + /// + public SessionPersistenceType PersistenceType + { + get + { + if (_body == null) + return null; + + return _body.PersistenceType; + } + } + + /// + /// This class models the JSON representation used for the body of a session persistence + /// configuration. + /// + [JsonObject(MemberSerialization.OptIn)] + protected class SessionPersistenceBody : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("persistenceType")] + private SessionPersistenceType _persistenceType; + + /// + /// Initializes a new instance of the class during + /// JSON deserialization. + /// + [JsonConstructor] + protected SessionPersistenceBody() + { + } + + /// + /// Initializes a new instance of the class + /// using the specified persistence type. + /// + /// The session persistence mode to use. + /// If is . + protected internal SessionPersistenceBody(SessionPersistenceType persistenceType) + { + if (persistenceType == null) + throw new ArgumentNullException("persistenceType"); + + _persistenceType = persistenceType; + } + + /// + /// Gets the session persistence type. + /// + public SessionPersistenceType PersistenceType + { + get + { + return _persistenceType; + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/SessionPersistenceType.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/SessionPersistenceType.cs new file mode 100644 index 000000000..772a17dc8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/SessionPersistenceType.cs @@ -0,0 +1,92 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a type of session persistence in the load balancers service. + /// + /// + /// This class functions as a strongly-typed enumeration of known session persistence types, + /// with added support for unknown types returned by a server extension. + /// + /// + /// + [JsonConverter(typeof(SessionPersistenceType.Converter))] + public sealed class SessionPersistenceType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly SessionPersistenceType _httpCookie = FromName("HTTP_COOKIE"); + private static readonly SessionPersistenceType _sourceAddress = FromName("SOURCE_IP"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private SessionPersistenceType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static SessionPersistenceType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new SessionPersistenceType(i)); + } + + /// + /// Gets a representing a session persistence mechanism that + /// inserts an HTTP cookie and is used to determine the destination back-end node. This is supported + /// for HTTP load balancing only. + /// + public static SessionPersistenceType HttpCookie + { + get + { + return _httpCookie; + } + } + + /// + /// Gets a representing a session persistence mechanism that + /// will keep track of the source IP address that is mapped and is able to determine the destination + /// back-end node. This is supported for HTTPS pass-through and non-HTTP load balancing only. + /// + public static SessionPersistenceType SourceAddress + { + get + { + return _sourceAddress; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override SessionPersistenceType FromName(string name) + { + return SessionPersistenceType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/VirtualAddressId.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/VirtualAddressId.cs new file mode 100644 index 000000000..8cd81474a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/VirtualAddressId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a virtual address in the . + /// + /// + /// + /// + [JsonConverter(typeof(VirtualAddressId.Converter))] + public sealed class VirtualAddressId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The virtual address identifier value. + /// If is . + /// If is empty. + public VirtualAddressId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override VirtualAddressId FromValue(string id) + { + return new VirtualAddressId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/WebServerHealthMonitor.cs b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/WebServerHealthMonitor.cs new file mode 100644 index 000000000..ca03bbb4f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/LoadBalancers/WebServerHealthMonitor.cs @@ -0,0 +1,184 @@ +namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers +{ + using System; + using Newtonsoft.Json; + + /// + /// This class models the JSON object used to represent a for + /// HTTP or HTTPS connections. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class WebServerHealthMonitor : HealthMonitor + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("bodyRegex")] + private string _bodyRegex; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("path")] + private string _path; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("statusRegex")] + private string _statusRegex; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("hostHeader", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _hostHeader; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected WebServerHealthMonitor() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// to monitor HTTPS connections; otherwise, to monitor HTTP connections. + /// The number of permissible monitor failures before removing a node from rotation. + /// The maximum number of seconds to wait for a connection to be established before timing out. + /// The minimum time to wait before executing the health monitor. + /// A regular expression that will be used to evaluate the contents of the body of the response. + /// The HTTP path that will be used in the sample request. + /// A regular expression that will be used to evaluate the HTTP status code returned in the response. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If is less than or equal to 0. + /// -or- + /// If is negative or . + /// -or- + /// If is negative or . + /// + public WebServerHealthMonitor(bool https, int attemptsBeforeDeactivation, TimeSpan timeout, TimeSpan delay, string bodyRegex, string path, string statusRegex) + : this(https, attemptsBeforeDeactivation, timeout, delay, bodyRegex, path, statusRegex, null) + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// to monitor HTTPS connections; otherwise, to monitor HTTP connections. + /// The number of permissible monitor failures before removing a node from rotation. + /// The maximum number of seconds to wait for a connection to be established before timing out. + /// The minimum time to wait before executing the health monitor. + /// A regular expression that will be used to evaluate the contents of the body of the response. + /// The HTTP path that will be used in the sample request. + /// A regular expression that will be used to evaluate the HTTP status code returned in the response. + /// The name of a host for which the health monitors will check, or when?. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// + /// + /// If is less than or equal to 0. + /// -or- + /// If is negative or . + /// -or- + /// If is negative or . + /// + public WebServerHealthMonitor(bool https, int attemptsBeforeDeactivation, TimeSpan timeout, TimeSpan delay, string bodyRegex, string path, string statusRegex, string hostHeader) + : base(https ? HealthMonitorType.Https : HealthMonitorType.Http, attemptsBeforeDeactivation, timeout, delay) + { + if (bodyRegex == null) + throw new ArgumentNullException("bodyRegex"); + if (path == null) + throw new ArgumentNullException("path"); + if (statusRegex == null) + throw new ArgumentNullException("statusRegex"); + if (string.IsNullOrEmpty(bodyRegex)) + throw new ArgumentException("bodyRegex cannot be empty"); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("path cannot be empty"); + if (string.IsNullOrEmpty(statusRegex)) + throw new ArgumentException("statusRegex cannot be empty"); + + _bodyRegex = bodyRegex; + _path = path; + _statusRegex = statusRegex; + _hostHeader = hostHeader; + } + + /// + /// Gets a regular expression that will be used to evaluate the contents of the body of the response. + /// + public string BodyRegex + { + get + { + return _bodyRegex; + } + } + + /// + /// Gets the HTTP path that will be used in the sample request. + /// + public string Path + { + get + { + return _path; + } + } + + /// + /// Gets a regular expression that will be used to evaluate the HTTP status code returned in the response. + /// + public string StatusRegex + { + get + { + return _statusRegex; + } + } + + /// + /// Gets the optional name of a host for which the health monitors will check. + /// + public string HostHeader + { + get + { + return _hostHeader; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Mapping/BulkDeletionResultMapper.cs b/src/OpenStack/Providers/Rackspace/Objects/Mapping/BulkDeletionResultMapper.cs new file mode 100644 index 000000000..8debac3fd --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Mapping/BulkDeletionResultMapper.cs @@ -0,0 +1,60 @@ +using System; +using System.Linq; +using net.openstack.Core; +using net.openstack.Core.Domain; +using net.openstack.Core.Domain.Mapping; +using net.openstack.Providers.Rackspace.Objects.Response; + +namespace net.openstack.Providers.Rackspace.Objects.Mapping +{ + internal class BulkDeletionResultMapper : IObjectMapper + { + private readonly IStatusParser _statusParser; + + public BulkDeletionResultMapper(IStatusParser statusParser) + { + _statusParser = statusParser; + } + + /// + public BulkDeletionResults Map(BulkDeleteResponse from) + { + var successfulObjects = from.AllItems.Where(i => !from.IsItemError(i)); + var failedObjects = from.Errors.Select(e => + { + var eParts = e.ToArray(); + Status errorStatus; + string errorItem; + + if (eParts.Length != 2) + { + errorStatus = new Status(0, "Unknown"); + errorItem = string.Format("The error array has an unexpected length. Array: {0}", string.Join("||", eParts)); + } + else + { + errorItem = eParts[1]; + if (!_statusParser.TryParse(eParts[0], out errorStatus)) + { + errorItem = eParts[0]; + if (!_statusParser.TryParse(eParts[1], out errorStatus)) + { + errorStatus = new Status(0, "Unknown"); + errorItem = string.Format("The error array is in an unknown format. Array: {0}", string.Join("||", eParts)); + } + } + } + + return new BulkDeletionFailedObject(errorItem, errorStatus); + }); + + return new BulkDeletionResults(successfulObjects, failedObjects); + } + + /// + public BulkDeleteResponse Map(BulkDeletionResults to) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Mapping/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Mapping/NamespaceDoc.cs new file mode 100644 index 000000000..51211ce63 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Mapping/NamespaceDoc.cs @@ -0,0 +1,15 @@ +namespace net.openstack.Providers.Rackspace.Objects.Mapping +{ + using System.Runtime.CompilerServices; + using net.openstack.Core.Domain.Mapping; + + /// + /// The namespace provides + /// implementations of used in Rackspace-specific + /// features. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AccountConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AccountConfiguration.cs new file mode 100644 index 000000000..926414743 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AccountConfiguration.cs @@ -0,0 +1,115 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the configurable properties of a monitoring account. + /// + /// + /// Account (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AccountConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private Dictionary _metadata; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("webhook_token", DefaultValueHandling = DefaultValueHandling.Ignore)] + private WebhookToken _webhookToken; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AccountConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified metadata. + /// + /// The metadata to associate with the monitoring account. + /// If is . + /// If contains any empty keys. + public AccountConfiguration(IDictionary metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + if (metadata.ContainsKey(string.Empty)) + throw new ArgumentException("metadata cannot contain any empty keys", "metadata"); + + _metadata = new Dictionary(metadata); + } + + /// + /// Initializes a new instance of the class + /// with the specified webhook token. + /// + /// The webhook token to associate with the account. + /// If is . + public AccountConfiguration(WebhookToken webhookToken) + { + if (webhookToken == null) + throw new ArgumentNullException("webhookToken"); + + _webhookToken = webhookToken; + } + + /// + /// Initializes a new instance of the class + /// with the specified metadata and webhook token. + /// + /// The metadata to associate with the monitoring account. If this value is , the metadata associated with the account is not changed. + /// The webhook token to associate with the account. If this value is , the webhook token associated with the account is not changed. + /// If contains any empty keys. + public AccountConfiguration(IDictionary metadata, WebhookToken webhookToken) + { + if (metadata != null) + { + if (metadata.ContainsKey(string.Empty)) + throw new ArgumentException("metadata cannot contain any empty keys", "metadata"); + + _metadata = new Dictionary(metadata); + } + + _webhookToken = webhookToken; + } + + /// + /// Gets the collection of metadata associated with the monitoring account. + /// + public ReadOnlyDictionary Metadata + { + get + { + return new ReadOnlyDictionary(_metadata); + } + } + + /// + /// Gets the webhook token associated with the monitoring account. + /// + public WebhookToken WebhookToken + { + get + { + return _webhookToken; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Agent.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Agent.cs new file mode 100644 index 000000000..5fa906c1f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Agent.cs @@ -0,0 +1,61 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a monitoring agent. + /// + /// Agents (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Agent : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private AgentId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("last_connected", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _lastConnected; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Agent() + { + } + + /// + /// Gets the unique identifier of the agent. + /// + public AgentId Id + { + get + { + return _id; + } + } + + /// + /// Gets the time when the agent last connected to the account. + /// + public DateTimeOffset? LastConnected + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_lastConnected); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentConnection.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentConnection.cs new file mode 100644 index 000000000..fff0db016 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentConnection.cs @@ -0,0 +1,155 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Net; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a monitoring agent connection. + /// + /// Get Agent Connection (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// List Agent Connections (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + public class AgentConnection : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private AgentConnectionId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("guid")] + private string _guid; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("agent_id")] + private AgentId _agentId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("endpoint")] + private string _endpoint; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("process_version")] + private string _processVersion; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("bundle_version")] + private string _bundleVersion; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("agent_ip")] + [JsonConverter(typeof(IPAddressSimpleConverter))] + private IPAddress _agentIp; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AgentConnection() + { + } + + /// + /// Gets the unique identifier of the agent connection resource. + /// + public AgentConnectionId Id + { + get + { + return _id; + } + } + + /// + /// Gets the string generated by the agent to identify the session. + /// + /// + /// + /// The generated ID is simply a string, and does not necessarily conform + /// to the standard format. + /// + /// + public string Guid + { + get + { + return _guid; + } + } + + /// + /// Gets the unique identifier of the for the connection. + /// + public AgentId AgentId + { + get + { + return _agentId; + } + } + + /// + /// Gets the datacenter endpoint of the connection. + /// + public string Endpoint + { + get + { + return _endpoint; + } + } + + /// + /// Gets the process version of the agent. + /// + public string ProcessVersion + { + get + { + return _processVersion; + } + } + + /// + /// Gets the bundle version of the agent. + /// + public string BundleVersion + { + get + { + return _bundleVersion; + } + } + + /// + /// Gets the Internet address where the agent is reporting from. + /// + public IPAddress AgentAddress + { + get + { + return _agentIp; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentConnectionId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentConnectionId.cs new file mode 100644 index 000000000..20b12f231 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentConnectionId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an agent connection in the . + /// + /// + /// + /// + [JsonConverter(typeof(AgentConnectionId.Converter))] + public sealed class AgentConnectionId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The agent connection identifier value. + /// If is . + /// If is empty. + public AgentConnectionId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AgentConnectionId FromValue(string id) + { + return new AgentConnectionId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentId.cs new file mode 100644 index 000000000..079f85f0b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an agent in the . + /// + /// + /// + /// + [JsonConverter(typeof(AgentId.Converter))] + public sealed class AgentId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The agent identifier value. + /// If is . + /// If is empty. + public AgentId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AgentId FromValue(string id) + { + return new AgentId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentToken.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentToken.cs new file mode 100644 index 000000000..c48d8fcb7 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentToken.cs @@ -0,0 +1,60 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + + /// + /// Agent tokens are used to authenticate monitoring agents to the monitoring + /// service. Multiple agents can share a single token. + /// + /// Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AgentToken : AgentTokenConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private AgentTokenId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("token")] + private string _token; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AgentToken() + { + } + + /// + /// Gets the unique identifier of the agent token. + /// + public AgentTokenId Id + { + get + { + return _id; + } + } + + /// + /// Gets the value of the agent token. + /// + public string Token + { + get + { + return _token; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentTokenConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentTokenConfiguration.cs new file mode 100644 index 000000000..5bd18f2a5 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentTokenConfiguration.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the basic properties of an Agent Token resource + /// in the . + /// + /// Agent Token (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AgentTokenConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("label")] + private string _label; + + /// + /// Initializes a new instance of the class + /// with no label. + /// + [JsonConstructor] + public AgentTokenConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified label. + /// + /// The token label. + public AgentTokenConfiguration(string label) + { + _label = label; + } + + /// + /// Gets the label for the agent token. + /// + public string Label + { + get + { + return _label; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentTokenId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentTokenId.cs new file mode 100644 index 000000000..2210694aa --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AgentTokenId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an agent token in the . + /// + /// + /// + /// + [JsonConverter(typeof(AgentTokenId.Converter))] + public sealed class AgentTokenId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The agent token identifier value. + /// If is . + /// If is empty. + public AgentTokenId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AgentTokenId FromValue(string id) + { + return new AgentTokenId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Alarm.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Alarm.cs new file mode 100644 index 000000000..0c3ffeec1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Alarm.cs @@ -0,0 +1,77 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of an Alarm resource in the . + /// + /// Alarms (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Alarm : AlarmConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private AlarmId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created_at")] + private long? _createdAt; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated_at")] + private long? _updatedAt; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Alarm() + { + } + + /// + /// Gets the unique identifier for this alarm. + /// + public AlarmId Id + { + get + { + return _id; + } + } + + /// + /// Gets a timestamp indicating when the alarm was first created. + /// + public DateTimeOffset? Created + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_createdAt); + } + } + + /// + /// Gets a timestamp indicating when the alarm was last modified. + /// + public DateTimeOffset? LastModified + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_updatedAt); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmChangelog.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmChangelog.cs new file mode 100644 index 000000000..369ddad54 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmChangelog.cs @@ -0,0 +1,129 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a Changelog resource in the . + /// + /// Changelogs (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AlarmChangelog : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private AlarmChangelogId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timestamp", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _timestamp; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("entity_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private EntityId _entityId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("alarm_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private AlarmId _alarmId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("check_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private CheckId _checkId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("analyzed_by_monitoring_zone_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private MonitoringZoneId _analyzedByMonitoringZoneId; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AlarmChangelog() + { + } + + /// + /// Gets the unique identifier associated with the alarm changelog resource. + /// + public AlarmChangelogId Id + { + get + { + return _id; + } + } + + /// + /// Gets a timestamp indicating when the alarm was triggered. + /// + public DateTimeOffset? Timestamp + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timestamp); + } + } + + /// + /// Gets the ID of the entity associated with the alarm. + /// + public EntityId EntityId + { + get + { + return _entityId; + } + } + + /// + /// Gets the ID of the alarm which was triggered. + /// + public AlarmId AlarmId + { + get + { + return _alarmId; + } + } + + /// + /// Gets the ID of the check which triggered the alarm. + /// + public CheckId CheckId + { + get + { + return _checkId; + } + } + + /// + /// Gets the ID of the monitoring zone which analyzed the check and triggered the alarm. + /// + public MonitoringZoneId AnalyzedByMonitoringZoneId + { + get + { + return _analyzedByMonitoringZoneId; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmChangelogId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmChangelogId.cs new file mode 100644 index 000000000..744a0c832 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmChangelogId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an alarm changelog in the . + /// + /// + /// + /// + [JsonConverter(typeof(AlarmChangelogId.Converter))] + public sealed class AlarmChangelogId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The changelog identifier value. + /// If is . + /// If is empty. + public AlarmChangelogId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AlarmChangelogId FromValue(string id) + { + return new AlarmChangelogId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmConfiguration.cs new file mode 100644 index 000000000..fe32dad9d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmConfiguration.cs @@ -0,0 +1,166 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the basic properties of an Alarm resource + /// in the . + /// + /// + /// + /// + /// Alarms (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class AlarmConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("check_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private CheckId _checkId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("notification_plan_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NotificationPlanId _notificationPlanId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("criteria", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _criteria; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("disabled", DefaultValueHandling = DefaultValueHandling.Ignore)] + private bool? _disabled; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("label", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _label; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private IDictionary _metadata; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AlarmConfiguration() + { + } + + /// + /// Initializes a new instance of the class with the specified + /// values. + /// + /// The ID of the check to alert on. This is obtained from Check.Id. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The ID of the notification plan to execute when the state changes. This is obtained from NotificationPlan.Id. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The alarm DSL for describing alerting conditions and their output states. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// to enable processing and alerts on this alarm; otherwise, . If this value is , the underlying property will be omitted from the JSON representation of the object. + /// A friendly label for the alarm. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// A collection of metadata to associate with the alarm. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// + /// If contains any values with empty keys. + /// + protected AlarmConfiguration(CheckId checkId, NotificationPlanId notificationPlanId, string criteria, bool? enabled, string label, IDictionary metadata) + { + if (metadata != null && metadata.ContainsKey(string.Empty)) + throw new ArgumentException("metadata cannot contain any empty keys", "metadata"); + + _checkId = checkId; + _notificationPlanId = notificationPlanId; + _criteria = criteria; + _disabled = !enabled; + _label = label; + _metadata = metadata; + } + + /// + /// Gets the ID of the check to alert on. + /// + /// + public CheckId CheckId + { + get + { + return _checkId; + } + } + + /// + /// Gets the ID of the notification plan to execute when the state changes. + /// + /// + public NotificationPlanId NotificationPlanId + { + get + { + return _notificationPlanId; + } + } + + /// + /// Gets the alarm DSL for describing alerting conditions and their output states. + /// + public string Criteria + { + get + { + return _criteria; + } + } + + /// + /// Gets a value indicating whether processing and alerts are enabled on the alarm. + /// + public bool? Enabled + { + get + { + return !_disabled; + } + } + + /// + /// Gets the friendly label for the alarm. + /// + public string Label + { + get + { + return _label; + } + } + + /// + /// Gets a collection of metadata associated with the alarm. + /// + public ReadOnlyDictionary Metadata + { + get + { + if (_metadata == null) + return null; + + return new ReadOnlyDictionary(_metadata); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmData.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmData.cs new file mode 100644 index 000000000..a6e3672ed --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmData.cs @@ -0,0 +1,78 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the data produced by testing a monitoring alarm. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AlarmData : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("timestamp")] + private long? _timestamp; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state")] + private AlarmState _state; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private string _status; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AlarmData() + { + } + + /// + /// Gets a timestamp indicating when this alarm data occurred. + /// + public DateTimeOffset? Timestamp + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timestamp); + } + } + + /// + /// Gets the state of the alarm. + /// + public AlarmState State + { + get + { + return _state; + } + } + + /// + /// Gets the status of the alarm. + /// + public string Status + { + get + { + return _status; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExample.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExample.cs new file mode 100644 index 000000000..97fdbbdfc --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExample.cs @@ -0,0 +1,136 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of an Alarm Example resource in the . + /// + /// + /// View provides examples alarms for the various checks in the system. They are presented as a template with parameters. Each of the parameters is documented with a type, name and description. There are quite a few different examples in the system. + /// + /// Alarm Examples (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AlarmExample : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private AlarmExampleId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("label")] + private string _label; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("description")] + private string _description; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("check_type")] + private CheckTypeId _checkTypeId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("criteria")] + private string _criteria; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("fields")] + private AlarmExampleField[] _fields; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AlarmExample() + { + } + + /// + /// Gets the unique identifier of the alarm example resource. + /// + public AlarmExampleId Id + { + get + { + return _id; + } + } + + /// + /// Gets the name of the alarm example. + /// + public string Label + { + get + { + return _label; + } + } + + /// + /// Gets a description of the alarm example. + /// + public string Description + { + get + { + return _description; + } + } + + /// + /// Gets the type of check this alarm example applies to. + /// + public CheckTypeId CheckTypeId + { + get + { + return _checkTypeId; + } + } + + /// + /// Gets the example criteria as a template. + /// + public string Criteria + { + get + { + return _criteria; + } + } + + /// + /// Gets a collection of objects describing the replaceable + /// template parameters in the example string. + /// + public ReadOnlyCollection Fields + { + get + { + if (_fields == null) + return null; + + return new ReadOnlyCollection(_fields); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExampleField.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExampleField.cs new file mode 100644 index 000000000..cb7ebcf97 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExampleField.cs @@ -0,0 +1,77 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a field in an Alarm Example template. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AlarmExampleField : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("description")] + private string _description; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private string _type; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AlarmExampleField() + { + } + + /// + /// Gets the field name. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets a description of the field. + /// + public string Description + { + get + { + return _description; + } + } + + /// + /// Gets the type of data stored in the field. + /// + public string Type + { + get + { + return _type; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExampleId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExampleId.cs new file mode 100644 index 000000000..818e03e31 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmExampleId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an Alarm Example resource in the . + /// + /// + /// + /// + [JsonConverter(typeof(AlarmExampleId.Converter))] + public sealed class AlarmExampleId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The alarm example identifier value. + /// If is . + /// If is empty. + public AlarmExampleId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AlarmExampleId FromValue(string id) + { + return new AlarmExampleId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmId.cs new file mode 100644 index 000000000..038f81bd1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an Alarm resource in the . + /// + /// + /// + /// + [JsonConverter(typeof(AlarmId.Converter))] + public sealed class AlarmId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The alarm identifier value. + /// If is . + /// If is empty. + public AlarmId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AlarmId FromValue(string id) + { + return new AlarmId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmNotificationHistoryItem.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmNotificationHistoryItem.cs new file mode 100644 index 000000000..6a0082e4b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmNotificationHistoryItem.cs @@ -0,0 +1,176 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of an alarm notification history resource in the . + /// + /// + /// The monitoring service keeps a record of notifications sent for each alarm. + /// This history is further subdivided by the check on which the notification + /// occurred. Every attempt to send a notification is recorded, making this + /// history a valuable tool in diagnosing issues with unreceived notifications, + /// in addition to offering a means of viewing the history of an alarm's + /// statuses. + /// + /// Alarm Notification History (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AlarmNotificationHistoryItem : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private AlarmNotificationHistoryItemId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timestamp")] + private long? _timestamp; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("notification_plan_id")] + private NotificationPlanId _notificationPlanId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("transaction_id")] + private TransactionId _transactionId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private string _status; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state")] + private AlarmState _state; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("previous_state")] + private AlarmState _previousState; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("notification_results")] + private NotificationResult[] _results; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AlarmNotificationHistoryItem() + { + } + + /// + /// Gets the unique identifier of the alarm notification history item. + /// + public AlarmNotificationHistoryItemId Id + { + get + { + return _id; + } + } + + /// + /// Gets the timestamp associated with this history item. + /// + public DateTimeOffset? Timestamp + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timestamp); + } + } + + /// + /// Gets the ID of the notification plan associated with the alarm. + /// + public NotificationPlanId NotificationPlanId + { + get + { + return _notificationPlanId; + } + } + + /// + /// Gets the transaction ID for the history item. + /// + public TransactionId TransactionId + { + get + { + return _transactionId; + } + } + + /// + /// Gets the status of the history item. + /// + public string Status + { + get + { + return _status; + } + } + + /// + /// Gets the state of the alarm after this history item. + /// + public AlarmState State + { + get + { + return _state; + } + } + + /// + /// Gets the state of the alarm before this history item. + /// + public AlarmState PreviousState + { + get + { + return _previousState; + } + } + + /// + /// Gets a collection of objects describing + /// the notifications sent by this history item. + /// + public ReadOnlyCollection Results + { + get + { + if (_results == null) + return null; + + return new ReadOnlyCollection(_results); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmNotificationHistoryItemId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmNotificationHistoryItemId.cs new file mode 100644 index 000000000..465148ab4 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmNotificationHistoryItemId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an alarm notification history item in the . + /// + /// + /// + /// + [JsonConverter(typeof(AlarmNotificationHistoryItemId.Converter))] + public sealed class AlarmNotificationHistoryItemId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The alarm notification history item identifier value. + /// If is . + /// If is empty. + public AlarmNotificationHistoryItemId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AlarmNotificationHistoryItemId FromValue(string id) + { + return new AlarmNotificationHistoryItemId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmState.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmState.cs new file mode 100644 index 000000000..dac3257a3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmState.cs @@ -0,0 +1,100 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents an alarm state in the monitoring service. + /// + /// + /// This class functions as a strongly-typed enumeration of known alarm states, + /// with added support for unknown states returned by a server extension. + /// + /// + /// + [JsonConverter(typeof(AlarmState.Converter))] + public sealed class AlarmState : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly AlarmState _ok = FromName("OK"); + private static readonly AlarmState _warning = FromName("WARNING"); + private static readonly AlarmState _critical = FromName("CRITICAL"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private AlarmState(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static AlarmState FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new AlarmState(i)); + } + + /// + /// Gets a representing the OK alarm state. + /// + public static AlarmState OK + { + get + { + return _ok; + } + } + + /// + /// Gets a representing the WARNING alarm state. + /// + public static AlarmState Warning + { + get + { + return _warning; + } + } + + /// + /// Gets a representing the CRITICAL alarm state. + /// + public static AlarmState Critical + { + get + { + return _critical; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AlarmState FromName(string name) + { + return AlarmState.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmStateHistory.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmStateHistory.cs new file mode 100644 index 000000000..e5beb57da --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AlarmStateHistory.cs @@ -0,0 +1,164 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation the record of an alarm state change + /// in the entity overview. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AlarmStateHistory : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("timestamp", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _timestamp; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("entity_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private EntityId _entityId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("alarm_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private AlarmId _alarmId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("check_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private CheckId _checkId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private string _status; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state")] + private AlarmState _state; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("previous_state")] + private AlarmState _previousState; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("analyzed_by_monitoring_zone_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private MonitoringZoneId _analyzedByMonitoringZoneId; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AlarmStateHistory() + { + } + + /// + /// Gets a timestamp indicating when the alarm state changed. + /// + public DateTimeOffset? Timestamp + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timestamp); + } + } + + /// + /// Gets the ID of the entity associated with the alarm. + /// + public EntityId EntityId + { + get + { + return _entityId; + } + } + + /// + /// Gets the ID of the alarm which changed state. + /// + public AlarmId AlarmId + { + get + { + return _alarmId; + } + } + + /// + /// Gets the ID of the check which triggered the alarm state change. + /// + public CheckId CheckId + { + get + { + return _checkId; + } + } + + /// + /// Gets the status of the history item. + /// + public string Status + { + get + { + return _status; + } + } + + /// + /// Gets the state of the alarm after this history item. + /// + public AlarmState State + { + get + { + return _state; + } + } + + /// + /// Gets the state of the alarm before this history item. + /// + public AlarmState PreviousState + { + get + { + return _previousState; + } + } + + /// + /// Gets the ID of the monitoring zone which analyzed the check that changed the alarm state. + /// + public MonitoringZoneId AnalyzedByMonitoringZoneId + { + get + { + return _analyzedByMonitoringZoneId; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Audit.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Audit.cs new file mode 100644 index 000000000..adf639c82 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Audit.cs @@ -0,0 +1,287 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using System.Net; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + using HttpMethod = JSIStudios.SimpleRESTServices.Client.HttpMethod; + + /// + /// This class models the JSON representation of an Audit resource in the . + /// + /// + /// Every write operation performed against the API (PUT, POST or DELETE) generates an + /// audit record that is stored for 30 days. Audits record a variety of information + /// about the request including the method, URL, headers, query string, transaction ID, + /// the request body and the response code. They also store information about the action + /// performed including a JSON list of the previous state of any modified objects. For + /// example, if you perform an update on an entity, this will record the state of the + /// entity before modification. + /// + /// Audits (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Audit : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private AuditId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timestamp")] + private long? _timestamp; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("headers")] + private Dictionary _headers; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("url")] + private string _url; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("app")] + private string _app; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("query")] + private Dictionary _query; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("txnId")] + private TransactionId _transactionId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("payload")] + private string _payload; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("method")] + [JsonConverter(typeof(StringEnumConverter))] + private HttpMethod _method; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("account_id")] + private ProjectId _accountId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("who")] + private string _who; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("why")] + private string _why; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("statusCode")] + private int _statusCode; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Audit() + { + } + + /// + /// Gets the unique identifier of the audit resource. + /// + public AuditId Id + { + get + { + return _id; + } + } + + /// + /// Gets a timestamp indicating when this audit record was created. + /// + public DateTimeOffset? Timestamp + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timestamp); + } + } + + /// + /// Gets a collection of custom HTTP headers which were sent with the request that created this audit record. + /// + public ReadOnlyDictionary Headers + { + get + { + if (_headers == null) + return null; + + return new ReadOnlyDictionary(_headers); + } + } + + /// + /// Gets the target URI of the HTTP request represented by the audit record. + /// + public Uri Url + { + get + { + if (_url == null) + return null; + + return new Uri(_url, UriKind.RelativeOrAbsolute); + } + } + + /// + /// Gets the name of the monitoring service module that processed the request. + /// + public string App + { + get + { + return _app; + } + } + + /// + /// Gets a collection of query string parameters decoded from . + /// + public ReadOnlyDictionary Query + { + get + { + if (_query == null) + return null; + + return new ReadOnlyDictionary(_query); + } + } + + /// + /// Gets the ID of the transaction that created this audit record. + /// + public TransactionId TransactionId + { + get + { + return _transactionId; + } + } + + /// + /// Gets the body of the HTTP request that created this audit record. + /// + public string Payload + { + get + { + return _payload; + } + } + + /// + /// Gets the HTTP method used for the request represented by the audit record. + /// + public HttpMethod Method + { + get + { + return _method; + } + } + + /// + /// Gets the account ID associated with the audit record. The account ID within + /// the monitoring service is equivalent to the Tenant.Id + /// referenced by other services. + /// + /// + /// The account ID for the audit record, or if the JSON response from + /// the server did not include the underlying property. + /// + public ProjectId AccountId + { + get + { + return _accountId; + } + } + + /// + /// Gets a value indicating who made this change to the monitoring account. + /// + /// + /// This is the value of the optional _who query parameter for HTTP requests. + /// + public string Who + { + get + { + return _who; + } + } + + /// + /// Gets a value indicating why this change was made to the monitoring account. + /// + /// + /// This is the value of the optional _why query parameter for HTTP requests. + /// + public string Why + { + get + { + return _why; + } + } + + /// + /// Gets the HTTP status code returned by the HTTP request represented by the audit record. + /// + public HttpStatusCode StatusCode + { + get + { + return (HttpStatusCode)_statusCode; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AuditId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AuditId.cs new file mode 100644 index 000000000..96dc9f907 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/AuditId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an audit in the . + /// + /// + /// + /// + [JsonConverter(typeof(AuditId.Converter))] + public sealed class AuditId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The audit identifier value. + /// If is . + /// If is empty. + public AuditId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override AuditId FromValue(string id) + { + return new AuditId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/BoundAlarmExample.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/BoundAlarmExample.cs new file mode 100644 index 000000000..cc179ce51 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/BoundAlarmExample.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of an evaluated alarm example in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class BoundAlarmExample : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("bound_criteria")] + private string _boundCriteria; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected BoundAlarmExample() + { + } + + /// + /// Gets the evaluated alarm example criteria. + /// + /// + /// The evaluated alarm example criteria, or if the JSON + /// response from the server did not include the underlying property. + /// + public string BoundCriteria + { + get + { + return _boundCriteria; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Check.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Check.cs new file mode 100644 index 000000000..deb593bc3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Check.cs @@ -0,0 +1,98 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents an check in the . + /// + /// + /// A check is one of the foundational building blocks of the monitoring system. The + /// check determines the parts or pieces of the entity that you want to monitor, the + /// monitoring frequency, how many monitoring zones are originating the check, and so + /// on. When you create a new check in the monitoring system, you specify the following + /// information: + /// + /// + /// A name for the check + /// The check's parent entity + /// The type of check you're creating + /// Details of the check + /// The monitoring zones that will launch the check + /// + /// + /// The check, as created, will not trigger alert messages until you create an + /// alarm to generate notifications, to enable the creation of a single alarm that + /// acts upon multiple checks (e.g. alert if any of ten different servers stops + /// responding) or multiple alarms off of a single check. (e.g. ensure both that a + /// HTTPS server is responding and that it has a valid certificate). + /// + /// Checks (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Check : CheckConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private CheckId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created_at")] + private long? _createdAt; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated_at")] + private long? _updatedAt; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Check() + { + } + + /// + /// Gets the unique identifier for the check. + /// + public CheckId Id + { + get + { + return _id; + } + } + + /// + /// Gets a timestamp indicating when the check was first created. + /// + public DateTimeOffset? Created + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_createdAt); + } + } + + /// + /// Gets a timestamp indicating when the check was last modified. + /// + public DateTimeOffset? LastModified + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_updatedAt); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckConfiguration.cs new file mode 100644 index 000000000..ee0439134 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckConfiguration.cs @@ -0,0 +1,303 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the configurable properties of the JSON representation of + /// a Check resource in the . + /// + /// + /// + /// + /// + /// Checks (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class CheckConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("label", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _label; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore)] + private CheckTypeId _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("details", DefaultValueHandling = DefaultValueHandling.Ignore)] + private JObject _details; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("monitoring_zones_poll", DefaultValueHandling = DefaultValueHandling.Ignore)] + private MonitoringZoneId[] _monitoringZonesPoll; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timeout", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _timeout; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("period", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _period; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("target_alias", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _targetAlias; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("target_hostname", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _targetHostname; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("target_resolver", DefaultValueHandling = DefaultValueHandling.Ignore)] + private TargetResolverType _resolverType; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private IDictionary _metadata; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected CheckConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The friendly name of the check. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The check type ID. This is obtained from CheckType.Id, or from the predefined values in . If this value is , the underlying property will be omitted from the JSON representation of the object. + /// A object containing detailed configuration information for the specific check type. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// A collection of objects identifying the monitoring zones to poll from. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The timeout of a check operation. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The period between check operations. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The alias of the target for this check in the associated entity's map. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The hostname this check should target. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The type of resolver to use for converting to an IP address. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// A collection of metadata to associate with the check. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// + /// If is non- but empty. + /// -or- + /// If the specified object does support checks of type . + /// -or- + /// If contains any values. + /// -or- + /// If is less than or equal to . + /// -or- + /// If is non- but empty. + /// -or- + /// If is non- but empty. + /// -or- + /// If contains any empty keys. + /// + /// + /// If is less than or equal to . + /// -or- + /// If is less than or equal to . + /// + /// + /// If and are both non-. + /// + protected CheckConfiguration(string label, CheckTypeId checkTypeId, CheckDetails details, IEnumerable monitoringZonesPoll, TimeSpan? timeout, TimeSpan? period, string targetAlias, string targetHostname, TargetResolverType resolverType, IDictionary metadata) + { + if (label == string.Empty) + throw new ArgumentException("label cannot be empty"); + if (targetAlias == string.Empty) + throw new ArgumentException("targetAlias cannot be empty"); + if (targetHostname == string.Empty) + throw new ArgumentException("targetHostname cannot be empty"); + if (details != null && !details.SupportsCheckType(checkTypeId)) + throw new ArgumentException(string.Format("The check details object does not support '{0}' checks.", checkTypeId), "details"); + if (timeout <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeout"); + if (period <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException("period"); + if (period <= timeout) + throw new ArgumentException("period cannot be less than or equal to timeout", "period"); + if (targetAlias != null && targetHostname != null) + throw new InvalidOperationException("targetAlias and targetHostname cannot both be specified"); + if (metadata != null && metadata.ContainsKey(string.Empty)) + throw new ArgumentException("metadata cannot contain any empty keys", "metadata"); + + _label = label; + _type = checkTypeId; + _details = details != null ? JObject.FromObject(details) : null; + _monitoringZonesPoll = monitoringZonesPoll != null ? monitoringZonesPoll.ToArray() : null; + _timeout = timeout.HasValue ? (int?)timeout.Value.TotalSeconds : null; + _period = period.HasValue ? (int?)period.Value.TotalSeconds : null; + _targetAlias = targetAlias; + _targetHostname = targetHostname; + _resolverType = resolverType; + _metadata = metadata; + + // this check is at the end of the constructor so monitoringZonesPoll is only enumerated once + if (_monitoringZonesPoll != null && _monitoringZonesPoll.Contains(null)) + throw new ArgumentException("monitoringZonesPoll cannot contain any null values", "monitoringZonesPoll"); + } + + /// + /// Gets the friendly name of the check. + /// + public string Label + { + get + { + return _label; + } + } + + /// + /// Gets the ID of the check type. + /// + public CheckTypeId CheckTypeId + { + get + { + return _type; + } + } + + /// + /// Gets a object describing the detailed properties specific + /// to this type of check. + /// + /// + /// The exact type returned by this property depends on the + /// for the current check. For additional information about the predefined check types, + /// see . + /// + public CheckDetails Details + { + get + { + if (_details == null) + return null; + + return CheckDetails.FromJObject(CheckTypeId, _details); + } + } + + /// + /// Gets a collection of objects identifying the monitoring + /// zones to poll from. + /// + public ReadOnlyCollection MonitoringZonesPoll + { + get + { + if (_monitoringZonesPoll == null) + return null; + + return new ReadOnlyCollection(_monitoringZonesPoll); + } + } + + /// + /// Gets the timeout for the check. + /// + public TimeSpan? Timeout + { + get + { + if (_timeout == null) + return null; + + return TimeSpan.FromSeconds(_timeout.Value); + } + } + + /// + /// Gets the delay between check operations. + /// + public TimeSpan? Period + { + get + { + if (_period == null) + return null; + + return TimeSpan.FromSeconds(_period.Value); + } + } + + /// + /// Gets the key for looking up the target for this check in the associated + /// entity's map. + /// + public string TargetAlias + { + get + { + return _targetAlias; + } + } + + /// + /// Gets the target hostname this check should target. + /// + public string TargetHostname + { + get + { + return _targetHostname; + } + } + + /// + /// Gets the type of resolver that should be used to convert the + /// to an IP address. + /// + public TargetResolverType ResolverType + { + get + { + return _resolverType; + } + } + + /// + /// Gets a collection of custom metadata associated with the check. + /// + public ReadOnlyDictionary Metadata + { + get + { + if (_metadata == null) + return null; + + return new ReadOnlyDictionary(_metadata); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckData.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckData.cs new file mode 100644 index 000000000..1b9a6a41f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckData.cs @@ -0,0 +1,257 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the data produced by testing a monitoring check. + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CheckData : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("timestamp")] + private long? _timestamp; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("monitoring_zone_id")] + private MonitoringZoneId _monitoringZoneId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("available")] + private bool? _available; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private string _status; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metrics")] + private Dictionary _metrics; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("debug_info")] + private DebugInformation _debugInfo; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected CheckData() + { + } + + /// + /// Gets a timestamp indicating when the check was evaluated. + /// + public DateTimeOffset? Timestamp + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timestamp); + } + } + + /// + /// Gets the ID of the monitoring zone which evaluated the check. + /// + public MonitoringZoneId MonitoringZoneId + { + get + { + return _monitoringZoneId; + } + } + + /// + /// Gets a value indicating whether or not the target of the check was available. + /// + public bool? Available + { + get + { + return _available; + } + } + + /// + /// Gets the a description of the status of the check. + /// + public string Status + { + get + { + return _status; + } + } + + /// + /// Gets a collection of named metrics collected by the check. The keys of the collection + /// are the names of metrics which are accessible in alarm criteria, and the values + /// contain the actual metric information collected by the evaluation of the check. + /// + public ReadOnlyDictionary Metrics + { + get + { + if (_metrics == null) + return null; + + return new ReadOnlyDictionary(_metrics); + } + } + + /// + /// Gets additional debug information about the evaluation of the check. + /// + public DebugInformation DebugInfo + { + get + { + return _debugInfo; + } + } + + /// + /// This class models the JSON representation of metric information collected by a + /// test evaluation of a monitoring check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CheckMetric : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private CheckMetricType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("data")] + private string _data; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("unit")] + private string _unit; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected CheckMetric() + { + } + + /// + /// Gets the type of data collected for this metric. + /// + public CheckMetricType Type + { + get + { + return _type; + } + } + + /// + /// Gets the actual data collected for this metric. + /// + public string Data + { + get + { + return _data; + } + } + + /// + /// Gets the name of the units for the collected data. + /// + public string Unit + { + get + { + return _unit; + } + } + } + + /// + /// This class models the JSON representation of additional check-type-specific + /// debugging information collected during the test evaluation of a monitoring + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DebugInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonExtensionData] + private IDictionary _data; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DebugInformation() + { + } + + /// + /// Gets a collection of additional check-type-specific debug information collected + /// during the test evaluation of a monitoring check. + /// + public ReadOnlyDictionary Data + { + get + { + if (_data == null) + return null; + + return new ReadOnlyDictionary(_data); + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckDetails.cs new file mode 100644 index 000000000..e25387f11 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckDetails.cs @@ -0,0 +1,86 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This is the base class for classes modeling the detailed configuration parameters + /// of various types of checks. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class CheckDetails : ExtensibleJsonObject + { + /// + /// Provides factory methods for deserializing a instance from + /// a according to the of the associated + /// check. + /// + private static readonly Dictionary> DetailsFactories = + new Dictionary> + { + // remote checks + { CheckTypeId.RemoteDns, obj => obj.ToObject() }, + { CheckTypeId.RemoteFtpBanner, obj => obj.ToObject() }, + { CheckTypeId.RemoteHttp, obj => obj.ToObject() }, + { CheckTypeId.RemoteImapBanner, obj => obj.ToObject() }, + { CheckTypeId.RemoteMssqlBanner, obj => obj.ToObject() }, + { CheckTypeId.RemoteMysqlBanner, obj => obj.ToObject() }, + { CheckTypeId.RemotePing, obj => obj.ToObject() }, + { CheckTypeId.RemotePop3Banner, obj => obj.ToObject() }, + { CheckTypeId.RemotePostgresqlBanner, obj => obj.ToObject() }, + { CheckTypeId.RemoteSmtpBanner, obj => obj.ToObject() }, + { CheckTypeId.RemoteSmtp, obj => obj.ToObject() }, + { CheckTypeId.RemoteSsh, obj => obj.ToObject() }, + { CheckTypeId.RemoteTcp, obj => obj.ToObject() }, + { CheckTypeId.RemoteTelnetBanner, obj => obj.ToObject() }, + + // agent checks + { CheckTypeId.AgentFilesystem, obj => obj.ToObject() }, + { CheckTypeId.AgentMemory, obj => obj.ToObject() }, + { CheckTypeId.AgentLoadAverage, obj => obj.ToObject() }, + { CheckTypeId.AgentCpu, obj => obj.ToObject() }, + { CheckTypeId.AgentDisk, obj => obj.ToObject() }, + { CheckTypeId.AgentNetwork, obj => obj.ToObject() }, + { CheckTypeId.AgentPlugin, obj => obj.ToObject() }, + }; + + /// + /// Deserializes a JSON object to a instance of the proper type. + /// + /// The check type ID. + /// The JSON object representing the check details. + /// A object corresponding to the JSON object. + /// + /// If is . + /// -or- + /// If is . + /// + public static CheckDetails FromJObject(CheckTypeId checkTypeId, JObject obj) + { + if (checkTypeId == null) + throw new ArgumentNullException("checkTypeId"); + if (obj == null) + throw new ArgumentNullException("obj"); + + Func factory; + if (DetailsFactories.TryGetValue(checkTypeId, out factory)) + return factory(obj); + + return obj.ToObject(); + } + + /// + /// Determines whether the current object is compatible + /// with checks of a particular type. + /// + /// The check type ID. + /// if the current object is compatible with ; otherwise, . + /// If is . + protected internal abstract bool SupportsCheckType(CheckTypeId checkTypeId); + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckId.cs new file mode 100644 index 000000000..f359f5ac1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a check in the . + /// + /// + /// + /// + [JsonConverter(typeof(CheckId.Converter))] + public sealed class CheckId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The check identifier value. + /// If is . + /// If is empty. + public CheckId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override CheckId FromValue(string id) + { + return new CheckId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckMetricType.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckMetricType.cs new file mode 100644 index 000000000..72bd99a21 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckMetricType.cs @@ -0,0 +1,100 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a metric type in the monitoring service. + /// + /// + /// This class functions as a strongly-typed enumeration of known metric types, + /// with added support for unknown types returned by a server extension. + /// + /// + /// + [JsonConverter(typeof(CheckMetricType.Converter))] + public sealed class CheckMetricType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly CheckMetricType _int32 = FromName("i"); + private static readonly CheckMetricType _int64 = FromName("l"); + private static readonly CheckMetricType _string = FromName("s"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private CheckMetricType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static CheckMetricType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new CheckMetricType(i)); + } + + /// + /// Gets a representing a 32-bit integer. + /// + public static CheckMetricType Int32 + { + get + { + return _int32; + } + } + + /// + /// Gets a representing a 64-bit integer. + /// + public static CheckMetricType Int64 + { + get + { + return _int64; + } + } + + /// + /// Gets a representing a string. + /// + public static CheckMetricType String + { + get + { + return _string; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override CheckMetricType FromName(string name) + { + return CheckMetricType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTarget.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTarget.cs new file mode 100644 index 000000000..1dd291cf2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTarget.cs @@ -0,0 +1,67 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of an agent check target in the . + /// + /// + /// Each agent check type gathers data for a related set of target devices on the server + /// where the agent is installed. For example, + /// gathers data for network devices. The actual list of target devices is specific to + /// the configuration of the host server. By focusing on specific targets, you can + /// efficiently narrow the metric data that the agent gathers. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CheckTarget : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private CheckTargetId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("label")] + private string _label; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected CheckTarget() + { + } + + /// + /// Gets the unique identifier for the agent check target. + /// + public CheckTargetId Id + { + get + { + return _id; + } + } + + /// + /// Gets the label for the agent check target. + /// + public string Label + { + get + { + return _label; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTargetId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTargetId.cs new file mode 100644 index 000000000..9f3b578fb --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTargetId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a check target in the . + /// + /// + /// + /// + [JsonConverter(typeof(CheckTargetId.Converter))] + public sealed class CheckTargetId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The check target identifier value. + /// If is . + /// If is empty. + public CheckTargetId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override CheckTargetId FromValue(string id) + { + return new CheckTargetId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckType.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckType.cs new file mode 100644 index 000000000..9668c6622 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckType.cs @@ -0,0 +1,82 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// Represents the type of a check in the monitoring service. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CheckType : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private CheckTypeId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private CheckTypeType _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("fields")] + private NotificationTypeField[] _fields; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected CheckType() + { + } + + /// + /// Gets the unique identifier of the check type. + /// + public CheckTypeId Id + { + get + { + return _id; + } + } + + /// + /// Gets the type of check type. + /// + public CheckTypeType Type + { + get + { + return _type; + } + } + + /// + /// Gets a collection of objects describing the + /// configurable properties of checks of this type. + /// + public ReadOnlyCollection Fields + { + get + { + if (_fields == null) + return null; + + return new ReadOnlyCollection(_fields); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTypeId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTypeId.cs new file mode 100644 index 000000000..c051b41c3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTypeId.cs @@ -0,0 +1,345 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a item placeholder in the . + /// + /// + /// + /// + [JsonConverter(typeof(CheckTypeId.Converter))] + public sealed class CheckTypeId : ResourceIdentifier + { + private static readonly CheckTypeId _remoteDns = new CheckTypeId("remote.dns"); + private static readonly CheckTypeId _remoteFtpBanner = new CheckTypeId("remote.ftp-banner"); + private static readonly CheckTypeId _remoteHttp = new CheckTypeId("remote.http"); + private static readonly CheckTypeId _remoteImapBanner = new CheckTypeId("remote.imap-banner"); + private static readonly CheckTypeId _remoteMssqlBanner = new CheckTypeId("remote.mssql-banner"); + private static readonly CheckTypeId _remoteMysqlBanner = new CheckTypeId("remote.mysql-banner"); + private static readonly CheckTypeId _remotePing = new CheckTypeId("remote.ping"); + private static readonly CheckTypeId _remotePop3Banner = new CheckTypeId("remote.pop3-banner"); + private static readonly CheckTypeId _remotePostgresqlBanner = new CheckTypeId("remote.postgresql-banner"); + private static readonly CheckTypeId _remoteSmtpBanner = new CheckTypeId("remote.smtp-banner"); + private static readonly CheckTypeId _remoteSmtp = new CheckTypeId("remote.smtp"); + private static readonly CheckTypeId _remoteSsh = new CheckTypeId("remote.ssh"); + private static readonly CheckTypeId _remoteTcp = new CheckTypeId("remote.tcp"); + private static readonly CheckTypeId _remoteTelnetBanner = new CheckTypeId("remote.telnet-banner"); + + private static readonly CheckTypeId _agentFilesystem = new CheckTypeId("agent.filesystem"); + private static readonly CheckTypeId _agentMemory = new CheckTypeId("agent.memory"); + private static readonly CheckTypeId _agentLoadAverage = new CheckTypeId("agent.load_average"); + private static readonly CheckTypeId _agentCpu = new CheckTypeId("agent.cpu"); + private static readonly CheckTypeId _agentDisk = new CheckTypeId("agent.disk"); + private static readonly CheckTypeId _agentNetwork = new CheckTypeId("agent.network"); + private static readonly CheckTypeId _agentPlugin = new CheckTypeId("agent.plugin"); + + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The identifier value. + /// If is . + /// If is empty. + public CheckTypeId(string id) + : base(id) + { + } + + /// + /// Gets a representing a remote DNS check. + /// + /// + public static CheckTypeId RemoteDns + { + get + { + return _remoteDns; + } + } + + /// + /// Gets a representing a remote FTP banner check. + /// + /// + public static CheckTypeId RemoteFtpBanner + { + get + { + return _remoteFtpBanner; + } + } + + /// + /// Gets a representing a remote HTTP check. + /// + /// + public static CheckTypeId RemoteHttp + { + get + { + return _remoteHttp; + } + } + + /// + /// Gets a representing a remote IMAP check. + /// + /// + public static CheckTypeId RemoteImapBanner + { + get + { + return _remoteImapBanner; + } + } + + /// + /// Gets a representing a remote SQL Server check. + /// + /// + public static CheckTypeId RemoteMssqlBanner + { + get + { + return _remoteMssqlBanner; + } + } + + /// + /// Gets a representing a remote MySQL check. + /// + /// + public static CheckTypeId RemoteMysqlBanner + { + get + { + return _remoteMysqlBanner; + } + } + + /// + /// Gets a representing a remote PING check. + /// + /// + public static CheckTypeId RemotePing + { + get + { + return _remotePing; + } + } + + /// + /// Gets a representing a remote POP3 check. + /// + /// + public static CheckTypeId RemotePop3Banner + { + get + { + return _remotePop3Banner; + } + } + + /// + /// Gets a representing a remote PostgreSQL check. + /// + /// + public static CheckTypeId RemotePostgresqlBanner + { + get + { + return _remotePostgresqlBanner; + } + } + + /// + /// Gets a representing a remote SMTP banner check. + /// + /// + public static CheckTypeId RemoteSmtpBanner + { + get + { + return _remoteSmtpBanner; + } + } + + /// + /// Gets a representing a remote SMTP check. + /// + /// + public static CheckTypeId RemoteSmtp + { + get + { + return _remoteSmtp; + } + } + + /// + /// Gets a representing a remote SSH check. + /// + /// + public static CheckTypeId RemoteSsh + { + get + { + return _remoteSsh; + } + } + + /// + /// Gets a representing a remote TCP check. + /// + /// + public static CheckTypeId RemoteTcp + { + get + { + return _remoteTcp; + } + } + + /// + /// Gets a representing a remote telnet banner check. + /// + /// + public static CheckTypeId RemoteTelnetBanner + { + get + { + return _remoteTelnetBanner; + } + } + + /// + /// Gets a representing an agent filesystem check. + /// + /// + public static CheckTypeId AgentFilesystem + { + get + { + return _agentFilesystem; + } + } + + /// + /// Gets a representing an agent memory check. + /// + /// + public static CheckTypeId AgentMemory + { + get + { + return _agentMemory; + } + } + + /// + /// Gets a representing an agent load average check. + /// + /// + public static CheckTypeId AgentLoadAverage + { + get + { + return _agentLoadAverage; + } + } + + /// + /// Gets a representing an agent CPU check. + /// + /// + public static CheckTypeId AgentCpu + { + get + { + return _agentCpu; + } + } + + /// + /// Gets a representing an agent disk check. + /// + /// + public static CheckTypeId AgentDisk + { + get + { + return _agentDisk; + } + } + + /// + /// Gets a representing an agent network check. + /// + /// + public static CheckTypeId AgentNetwork + { + get + { + return _agentNetwork; + } + } + + /// + /// Gets a representing an agent plug-in check. + /// + /// + public static CheckTypeId AgentPlugin + { + get + { + return _agentPlugin; + } + } + + /// + /// Gets a value indicating whether this check type identifies an agent check. + /// + /// + /// if this check type identifies an agent check type; otherwise, . + /// + public bool IsAgent + { + get + { + return Value.StartsWith("agent.", StringComparison.OrdinalIgnoreCase); + } + } + + /// + /// Gets a value indicating whether this check type identifies a remote check. + /// + /// + /// if this check type identifies a remote check type; otherwise, . + /// + public bool IsRemote + { + get + { + return Value.StartsWith("remote.", StringComparison.OrdinalIgnoreCase); + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override CheckTypeId FromValue(string id) + { + return new CheckTypeId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTypeType.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTypeType.cs new file mode 100644 index 000000000..fbf3e3023 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CheckTypeType.cs @@ -0,0 +1,88 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the type of a check type in the monitoring service. + /// + /// + /// This class functions as a strongly-typed enumeration of known check type types, + /// with added support for unknown types returned by a server extension. + /// + /// + /// + [JsonConverter(typeof(CheckTypeType.Converter))] + public sealed class CheckTypeType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly CheckTypeType _remote = FromName("remote"); + private static readonly CheckTypeType _agent = FromName("agent"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private CheckTypeType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static CheckTypeType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new CheckTypeType(i)); + } + + /// + /// Gets a representing a remote check type. + /// + public static CheckTypeType Remote + { + get + { + return _remote; + } + } + + /// + /// Gets a representing an agent check type. + /// + public static CheckTypeType Agent + { + get + { + return _agent; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override CheckTypeType FromName(string name) + { + return CheckTypeType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ConnectionCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ConnectionCheckDetails.cs new file mode 100644 index 000000000..654abfe0a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ConnectionCheckDetails.cs @@ -0,0 +1,55 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class provides a base class for configuring checks that connect to a + /// service on a configurable port. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class ConnectionCheckDetails : CheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("port", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _port; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ConnectionCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port. + /// + /// The port to use for connecting to the remote service. If this value is , the default port for the associated service should be used. + /// If is less than or equal to 0, or if is greater than 65535. + protected ConnectionCheckDetails(int? port) + { + if (port <= 0 || port > 65535) + throw new ArgumentOutOfRangeException("port"); + + _port = port; + } + + /// + /// Gets the port to use for remote monitoring connections. + /// + public int? Port + { + get + { + return _port; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CpuCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CpuCheckDetails.cs new file mode 100644 index 000000000..9c2265d64 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CpuCheckDetails.cs @@ -0,0 +1,31 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CpuCheckDetails : CheckDetails + { + /// + /// Initializes a new instance of the class. + /// + public CpuCheckDetails() + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.AgentCpu; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CpuInformation.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CpuInformation.cs new file mode 100644 index 000000000..9133233c7 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/CpuInformation.cs @@ -0,0 +1,290 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the CPU data reported agents for + /// the information type. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CpuInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("vendor")] + private string _vendor; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("model")] + private string _model; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("mhz")] + private int? _mhz; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("idle")] + private long? _idle; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("irq")] + private long? _irq; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("soft_irq")] + private long? _softIrq; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("nice")] + private long? _nice; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("sys")] + private long? _sys; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("user")] + private long? _user; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("wait")] + private long? _wait; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("total")] + private long? _total; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("total_cores")] + private int? _totalCores; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("total_sockets")] + private int? _totalSockets; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected CpuInformation() + { + } + + /// + /// Gets the CPU name. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the CPU vendor name. + /// + public string Vendor + { + get + { + return _vendor; + } + } + + /// + /// Gets the CPU vendor model string. + /// + public string Model + { + get + { + return _model; + } + } + + /// + /// Gets the CPU clock speed in MHz. + /// + public int? Frequency + { + get + { + return _mhz; + } + } + + /// + /// Gets the CPU time spent idle. + /// + public TimeSpan? IdleTime + { + get + { + if (_idle == null) + return null; + + return TimeSpan.FromMilliseconds(_idle.Value); + } + } + + /// + /// Gets the CPU time spent servicing/handling hardware interrupts. + /// + public TimeSpan? InterruptTime + { + get + { + if (_irq == null) + return null; + + return TimeSpan.FromMilliseconds(_irq.Value); + } + } + + /// + /// Gets the CPU time spent servicing/handling software interrupts. + /// + public TimeSpan? SoftInterruptTime + { + get + { + if (_softIrq == null) + return null; + + return TimeSpan.FromMilliseconds(_softIrq.Value); + } + } + + /// + /// Gets the CPU time spent on low-priority processes. + /// + public TimeSpan? LowPriorityTime + { + get + { + if (_nice == null) + return null; + + return TimeSpan.FromMilliseconds(_nice.Value); + } + } + + /// + /// Gets the CPU time spent in kernel space. + /// + public TimeSpan? KernelTime + { + get + { + if (_sys == null) + return null; + + return TimeSpan.FromMilliseconds(_sys.Value); + } + } + + /// + /// Gets the CPU time spent in user space. + /// + public TimeSpan? UserTime + { + get + { + if (_user == null) + return null; + + return TimeSpan.FromMilliseconds(_user.Value); + } + } + + /// + /// Gets the CPU time spent waiting on I/O operations to complete. + /// + public TimeSpan? WaitTime + { + get + { + if (_wait == null) + return null; + + return TimeSpan.FromMilliseconds(_wait.Value); + } + } + + /// + /// Gets the total CPU time. + /// + public TimeSpan? TotalTime + { + get + { + if (_total == null) + return null; + + return TimeSpan.FromMilliseconds(_total.Value); + } + } + + /// + /// Gets the total number of processor cores on all sockets. + /// + public int? ProcessorCount + { + get + { + return _totalCores; + } + } + + /// + /// Gets the total number of CPU sockets. + /// + public int? SocketCount + { + get + { + return _totalSockets; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPoint.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPoint.cs new file mode 100644 index 000000000..3f5d0f159 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPoint.cs @@ -0,0 +1,135 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a raw or rolled-up data point + /// reported by . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DataPoint : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("numPoints")] + private long? _numPoints; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("average")] + private double? _average; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("variance")] + private double? _variance; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("min")] + private double? _min; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("max")] + private double? _max; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timestamp")] + private long? _timestamp; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DataPoint() + { + } + + /// + /// Gets the number of raw data points represented by this instance. + /// + /// + public long? NumPoints + { + get + { + return _numPoints; + } + } + + /// + /// Gets the average value of the data points represented by this instance. + /// + /// + public double? Average + { + get + { + return _average; + } + } + + /// + /// Gets the variance of the data points represented by this instance. + /// + /// + public double? Variance + { + get + { + return _variance; + } + } + + /// + /// Gets the minimum value of the data points represented by this instance. + /// + /// + public double? Min + { + get + { + return _min; + } + } + + /// + /// Gets the maximum value of the data points represented by this instance. + /// + /// + public double? Max + { + get + { + return _max; + } + } + + /// + /// Gets a timestamp indicating when the data represented by this instance was recorded. + /// + public DateTimeOffset? Timestamp + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timestamp); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPointGranularity.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPointGranularity.cs new file mode 100644 index 000000000..139d05933 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPointGranularity.cs @@ -0,0 +1,136 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a data granularity in the monitoring service. + /// + /// + /// This class functions as a strongly-typed enumeration of known granularities, + /// with added support for unknown values supported by a server extension. + /// + /// + /// + [JsonConverter(typeof(DataPointGranularity.Converter))] + public sealed class DataPointGranularity : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly DataPointGranularity _full = FromName("FULL"); + private static readonly DataPointGranularity _min5 = FromName("MIN5"); + private static readonly DataPointGranularity _min20 = FromName("MIN20"); + private static readonly DataPointGranularity _min60 = FromName("MIN60"); + private static readonly DataPointGranularity _min240 = FromName("MIN240"); + private static readonly DataPointGranularity _min1440 = FromName("MIN1440"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private DataPointGranularity(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static DataPointGranularity FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new DataPointGranularity(i)); + } + + /// + /// Gets a representing full resolution data. + /// + public static DataPointGranularity Full + { + get + { + return _full; + } + } + + /// + /// Gets a representing data roll-ups computed at 5-minute intervals. + /// + public static DataPointGranularity Min5 + { + get + { + return _min5; + } + } + + /// + /// Gets a representing data roll-ups computed at 20-minute intervals. + /// + public static DataPointGranularity Min20 + { + get + { + return _min20; + } + } + + /// + /// Gets a representing data roll-ups computed at 60-minute intervals. + /// + public static DataPointGranularity Min60 + { + get + { + return _min60; + } + } + + /// + /// Gets a representing data roll-ups computed at 240-minute intervals. + /// + public static DataPointGranularity Min240 + { + get + { + return _min240; + } + } + + /// + /// Gets a representing data roll-ups computed at 1440-minute intervals. + /// + public static DataPointGranularity Min1440 + { + get + { + return _min1440; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DataPointGranularity FromName(string name) + { + return DataPointGranularity.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPointStatistic.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPointStatistic.cs new file mode 100644 index 000000000..23749a48a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DataPointStatistic.cs @@ -0,0 +1,124 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a statistic type in the monitoring service. + /// + /// + /// This class functions as a strongly-typed enumeration of known statistic types, + /// with added support for unknown types supported by a server extension. + /// + /// + /// + [JsonConverter(typeof(DataPointStatistic.Converter))] + public sealed class DataPointStatistic : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly DataPointStatistic _numPoints = FromName("numPoints"); + private static readonly DataPointStatistic _average = FromName("average"); + private static readonly DataPointStatistic _variance = FromName("variance"); + private static readonly DataPointStatistic _min = FromName("min"); + private static readonly DataPointStatistic _max = FromName("max"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private DataPointStatistic(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static DataPointStatistic FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new DataPointStatistic(i)); + } + + /// + /// Gets a representing the size of a set of data points. + /// + public static DataPointStatistic NumPoints + { + get + { + return _numPoints; + } + } + + /// + /// Gets a representing the average of a set of data points. + /// + public static DataPointStatistic Average + { + get + { + return _average; + } + } + + /// + /// Gets a representing the variance of a set of data points. + /// + public static DataPointStatistic Variance + { + get + { + return _variance; + } + } + + /// + /// Gets a representing the minimum of a set of data points. + /// + public static DataPointStatistic Min + { + get + { + return _min; + } + } + + /// + /// Gets a representing the maximum of a set of data points. + /// + public static DataPointStatistic Max + { + get + { + return _max; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override DataPointStatistic FromName(string name) + { + return DataPointStatistic.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DateTimeOffsetExtensions.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DateTimeOffsetExtensions.cs new file mode 100644 index 000000000..5477af6d7 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DateTimeOffsetExtensions.cs @@ -0,0 +1,74 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + + /// + /// This class provides utility methods for converting between Unix timestamps and + /// objects. + /// + /// + /// + internal static class DateTimeOffsetExtensions + { + /// + /// The Epoch used as a reference for Unix timestamps and file times. + /// + internal static readonly DateTimeOffset Epoch = new DateTimeOffset(new DateTime(1970, 1, 1), TimeSpan.Zero); + + /// + /// Converts a Unix timestamp (number of milliseconds since the ) to a . + /// + /// The Unix timestamp. + /// A representation of the timestamp. + /// If is less than 0. + public static DateTimeOffset ToDateTimeOffset(long timestamp) + { + if (timestamp < 0) + throw new ArgumentOutOfRangeException("timestamp"); + + return Epoch.AddMilliseconds(timestamp); + } + + /// + /// Converts a value to a Unix-style timestamp (number of milliseconds since the ). + /// + /// The to convert. + /// The number of milliseconds since the until the time indicated by . + /// If occurs before . + public static long ToTimestamp(this DateTimeOffset dateTimeOffset) + { + if (dateTimeOffset < Epoch) + throw new ArgumentOutOfRangeException("Cannot convert a time before the epoch (January 1, 1970, 00:00 UTC) to a timestamp.", "dateTimeOffset"); + + return (long)(dateTimeOffset - Epoch).TotalMilliseconds; + } + + /// + /// Converts a Unix timestamp (number of milliseconds since the ) to a . + /// + /// The Unix timestamp, or . + /// A representation of the timestamp, or if is . + /// If is less than 0. + public static DateTimeOffset? ToDateTimeOffset(long? timestamp) + { + if (timestamp == null) + return null; + + return ToDateTimeOffset(timestamp.Value); + } + + /// + /// Converts a value to a Unix-style timestamp (number of milliseconds since the ). + /// + /// The to convert, or . + /// The number of milliseconds since the until the time indicated by , or if is . + /// If occurs before . + public static long? ToTimestamp(this DateTimeOffset? dateTimeOffset) + { + if (dateTimeOffset == null) + return null; + + return ToTimestamp(dateTimeOffset.Value); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DiskCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DiskCheckDetails.cs new file mode 100644 index 000000000..def919da9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DiskCheckDetails.cs @@ -0,0 +1,68 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DiskCheckDetails : CheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("target")] + private string _target; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DiskCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified target. + /// + /// The disk to check. + /// If is . + /// If is empty. + public DiskCheckDetails(string target) + { + if (target == null) + throw new ArgumentNullException("target"); + if (string.IsNullOrEmpty(target)) + throw new ArgumentException("target cannot be empty"); + + _target = target; + } + + /// + /// Gets the disk to check. + /// + public string Target + { + get + { + return _target; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.AgentDisk; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DiskInformation.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DiskInformation.cs new file mode 100644 index 000000000..c0e1fbde3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DiskInformation.cs @@ -0,0 +1,173 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the disk data reported agents for + /// the information type. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DiskInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("read_bytes")] + private long? _readBytes; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("reads")] + private long? _readCount; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rtime")] + private long? _readTime; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("write_bytes")] + private long? _writeBytes; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("writes")] + private long? _writeCount; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("wtime")] + private long? _writeTime; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("time")] + private long? _time; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DiskInformation() + { + } + + /// + /// Gets the total number of bytes read from disk. + /// + public long? ReadBytes + { + get + { + return _readBytes; + } + } + + /// + /// Gets the total number of completed read requests. + /// + public long? ReadCount + { + get + { + return _readCount; + } + } + + /// + /// Gets the total time spent reading from disk. + /// + public TimeSpan? ReadTime + { + get + { + if (_readTime == null) + return null; + + return TimeSpan.FromMilliseconds(_readTime.Value); + } + } + + /// + /// Gets the total number of bytes written to disk. + /// + public long? WriteBytes + { + get + { + return _writeBytes; + } + } + + /// + /// Gets the total number of completed write requests. + /// + public long? WriteCount + { + get + { + return _writeCount; + } + } + + /// + /// Gets the total time spent writing to disk. + /// + public TimeSpan? WriteTime + { + get + { + if (_writeTime == null) + return null; + + return TimeSpan.FromMilliseconds(_writeTime.Value); + } + } + + /// + /// Gets the total time spent on disk I/O operations. + /// + public TimeSpan? IOTime + { + get + { + if (_time == null) + return null; + + return TimeSpan.FromMilliseconds(_time.Value); + } + } + + /// + /// Gets the device name. + /// + public string Name + { + get + { + return _name; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DnsCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DnsCheckDetails.cs new file mode 100644 index 000000000..a3f414593 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/DnsCheckDetails.cs @@ -0,0 +1,96 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using DnsRecordType = net.openstack.Providers.Rackspace.Objects.Dns.DnsRecordType; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class DnsCheckDetails : ConnectionCheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("query")] + private string _query; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("record_type")] + private DnsRecordType _recordType; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected DnsCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The DNS query. + /// The DNS record type. + /// The port number of the DNS service. If this value is , the default value (53) for the service is used. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is less than or equal to 0, or if is greater than 65535. + public DnsCheckDetails(string query, DnsRecordType recordType, int? port = null) + : base(port) + { + if (query == null) + throw new ArgumentNullException("query"); + if (string.IsNullOrEmpty(query)) + throw new ArgumentException("query cannot be empty"); + if (recordType == null) + throw new ArgumentNullException("recordType"); + + _query = query; + _recordType = recordType; + } + + /// + /// Gets the DNS query. + /// + public string Query + { + get + { + return _query; + } + } + + /// + /// Gets the DNS record type. + /// + public DnsRecordType RecordType + { + get + { + return _recordType; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteDns; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EmailNotificationDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EmailNotificationDetails.cs new file mode 100644 index 000000000..7619c12de --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EmailNotificationDetails.cs @@ -0,0 +1,67 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class extends with properties specific to + /// notifications. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class EmailNotificationDetails : NotificationDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("address")] + private string _address; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected EmailNotificationDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified email address. + /// + /// The email address that should be notified. + /// If is . + /// If is empty. + public EmailNotificationDetails(string address) + { + if (address == null) + throw new ArgumentNullException("address"); + if (string.IsNullOrEmpty(address)) + throw new ArgumentException("address cannot be empty"); + + _address = address; + } + + /// + /// Gets the email address notifications will be sent to. + /// + public string Address + { + get + { + return _address; + } + } + + /// + /// + /// This class only supports notifications. + /// + protected internal override bool SupportsNotificationType(NotificationTypeId notificationTypeId) + { + return notificationTypeId == NotificationTypeId.Email; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Entity.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Entity.cs new file mode 100644 index 000000000..8c5673a44 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Entity.cs @@ -0,0 +1,72 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + + /// + /// This class represents an entity in the . + /// + /// + /// An entity is the target of what you are monitoring. For example, you can create an entity + /// to monitor your website, a particular web service, or your Rackspace server or server + /// instance. Note that an entity represents only one item in the monitoring system. For + /// example, if you wanted to monitor each server in a cluster, you would create an entity + /// for each of the servers. You would not create a single entity to represent the entire + /// cluster. + /// + /// + /// An entity can have multiple checks associated with it. This allows you to check multiple + /// services on the same host by creating multiple checks on the same entity, instead of + /// multiple entities each with a single check. + /// + /// + /// + /// When you create a new entity in the monitoring system, you specify the following + /// parameters: + /// + /// + /// + /// A meaningful name for the entity + /// The IP address(es) for the entity (optional) + /// The metadata that the monitoring system uses if an alarm is triggered (optional) + /// + /// + /// Entities (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Entity : EntityConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private EntityId _id; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Entity() + { + } + + /// + /// Gets the unique identifier of this entity. + /// + /// + /// An object containing the unique identifier of the entity, + /// or if the JSON response from the server did not contain the underlying + /// property. + /// + public EntityId Id + { + get + { + return _id; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityConfiguration.cs new file mode 100644 index 000000000..892d6ca18 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityConfiguration.cs @@ -0,0 +1,147 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using System.Net; + using net.openstack.Core.Collections; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the configurable properties of the JSON representation of + /// an Entity resource in the . + /// + /// + /// + /// + /// + /// Entities (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class EntityConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("agent_id", DefaultValueHandling = DefaultValueHandling.Ignore)] + private AgentId _agentId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("label", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _label; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ip_addresses", ItemConverterType = typeof(IPAddressSimpleConverter), DefaultValueHandling = DefaultValueHandling.Ignore)] + private IDictionary _ipAddresses; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private IDictionary _metadata; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected EntityConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The name for the entity. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The agent which this entity is bound to. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The IP addresses which can be referenced by checks on this entity. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// A collection of metadata to associate with the entity. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// + /// If is empty. + /// -or- + /// If contains any empty keys. + /// -or- + /// If contains any empty keys. + /// + protected EntityConfiguration(string label, AgentId agentId, IDictionary ipAddresses, IDictionary metadata) + { + if (label == string.Empty) + throw new ArgumentException("label cannot be empty"); + + _label = label; + _agentId = agentId; + _ipAddresses = ipAddresses; + if (_ipAddresses != null) + { + if (_ipAddresses.ContainsKey(string.Empty)) + throw new ArgumentException("ipAddresses cannot contain any empty keys", "ipAddresses"); + } + + _metadata = metadata; + if (_metadata != null) + { + if (_metadata.ContainsKey(string.Empty)) + throw new ArgumentException("metadata cannot contain any empty keys", "metadata"); + } + } + + /// + /// Gets the ID of the agent which reports information from this entity. + /// + public AgentId AgentId + { + get + { + return _agentId; + } + } + + /// + /// Gets the name of the entity. + /// + public string Label + { + get + { + return _label; + } + } + + /// + /// Gets a dictionary which maps target aliases to IP addresses associated with the entity. + /// + public ReadOnlyDictionary IPAddresses + { + get + { + if (_ipAddresses == null) + return null; + + return new ReadOnlyDictionary(_ipAddresses); + } + } + + /// + /// Gets a collection of custom metadata associated with the entity. + /// + public ReadOnlyDictionary Metadata + { + get + { + if (_metadata == null) + return null; + + return new ReadOnlyDictionary(_metadata); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityId.cs new file mode 100644 index 000000000..32e93fc7f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of an entity in the . + /// + /// + /// + /// + [JsonConverter(typeof(EntityId.Converter))] + public sealed class EntityId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The entity identifier value. + /// If is . + /// If is empty. + public EntityId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override EntityId FromValue(string id) + { + return new EntityId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityOverview.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityOverview.cs new file mode 100644 index 000000000..5e99576bd --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/EntityOverview.cs @@ -0,0 +1,107 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a monitoring entity overview. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class EntityOverview : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("entity")] + private Entity _entity; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("checks")] + private Check[] _checks; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("alarms")] + private Alarm[] _alarms; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("latest_alarm_states")] + private AlarmStateHistory[] _latestAlarmStates; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected EntityOverview() + { + } + + /// + /// Gets an object describing the monitoring entity. + /// + public Entity Entity + { + get + { + return _entity; + } + } + + /// + /// Gets a collection of objects describing the checks associated + /// with the entity. + /// + public ReadOnlyCollection Checks + { + get + { + if (_checks == null) + return null; + + return new ReadOnlyCollection(_checks); + } + } + + /// + /// Gets a collection of objects describing the alarms associated + /// with the entity. + /// + public ReadOnlyCollection Alarms + { + get + { + if (_alarms == null) + return null; + + return new ReadOnlyCollection(_alarms); + } + } + + /// + /// Gets a collection of objects describing recent + /// changes to the state of alarms associated with the entity. + /// + public ReadOnlyCollection LatestAlarmStates + { + get + { + if (_latestAlarmStates == null) + return null; + + return new ReadOnlyCollection(_latestAlarmStates); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FilesystemCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FilesystemCheckDetails.cs new file mode 100644 index 000000000..ad452a981 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FilesystemCheckDetails.cs @@ -0,0 +1,68 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class FilesystemCheckDetails : CheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("target")] + private string _target; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected FilesystemCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified target. + /// + /// The mount point to check. + /// If is . + /// If is empty. + public FilesystemCheckDetails(string target) + { + if (target == null) + throw new ArgumentNullException("target"); + if (string.IsNullOrEmpty(target)) + throw new ArgumentException("target cannot be empty"); + + _target = target; + } + + /// + /// Gets the mount point to check. + /// + public string Target + { + get + { + return _target; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.AgentFilesystem; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FilesystemInformation.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FilesystemInformation.cs new file mode 100644 index 000000000..96d265a50 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FilesystemInformation.cs @@ -0,0 +1,197 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the filesystem data reported agents for + /// the information type. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class FilesystemInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("dir_name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _dirName; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("options", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _options; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("dev_name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _devName; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("sys_type_name", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _sysTypeName; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("used", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _used; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("avail", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _available; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("free", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _free; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("total", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _total; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("files", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _files; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("free_files", DefaultValueHandling = DefaultValueHandling.Ignore)] + private long? _freeFiles; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected FilesystemInformation() + { + } + + /// + /// Gets the name of the directory where the filesystem is mounted. + /// + public string DirectoryName + { + get + { + return _dirName; + } + } + + /// + /// Gets the filesystem mount options. + /// + public string Options + { + get + { + return _options; + } + } + + /// + /// Gets the name of the device from which this filesystem is mounted. + /// + public string DeviceName + { + get + { + return _devName; + } + } + + /// + /// Gets the name of the filesystem. + /// + public string Name + { + get + { + return _sysTypeName; + } + } + + /// + /// Gets the used space on the filesystem. + /// + public long? BytesUsed + { + get + { + return _used * 1024; + } + } + + /// + /// Gets the available space on the filesystem. + /// + public long? BytesAvailable + { + get + { + return _available * 1024; + } + } + + /// + /// Gets the free space available on the filesystem. + /// + public long? BytesFree + { + get + { + return _free * 1024; + } + } + + /// + /// Gets the total space on the filesystem. + /// + public long? BytesTotal + { + get + { + return _total * 1024; + } + } + + /// + /// Gets the number of file nodes on the filesystem. + /// + public long? FileNodes + { + get + { + return _files; + } + } + + /// + /// Gets the number of free file nodes on the filesystem. + /// + public long? AvailableFileNodes + { + get + { + return _freeFiles; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FtpBannerCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FtpBannerCheckDetails.cs new file mode 100644 index 000000000..7d47456fe --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/FtpBannerCheckDetails.cs @@ -0,0 +1,45 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class FtpBannerCheckDetails : ConnectionCheckDetails + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected FtpBannerCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port. + /// + /// The port number of the FTP service. If this value is , the default value (21) for the service is used. + /// If is less than or equal to 0, or if is greater than 65535. + public FtpBannerCheckDetails(int? port) + : base(port) + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteFtpBanner; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/GenericCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/GenericCheckDetails.cs new file mode 100644 index 000000000..8feaf5763 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/GenericCheckDetails.cs @@ -0,0 +1,73 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + + /// + /// This class represents the detailed configuration parameters for a + /// generic check. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class GenericCheckDetails : CheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonExtensionData] + private IDictionary _properties; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GenericCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// A collection of configuration properties for the check. + /// If is . + /// If contains a or empty key. + public GenericCheckDetails(IDictionary properties) + { + if (properties == null) + throw new ArgumentNullException("properties"); + if (properties.ContainsKey(string.Empty)) + throw new ArgumentException("properties cannot contain any empty keys", "properties"); + + _properties = properties; + } + + /// + /// Gets a collection of configuration properties for the check. + /// + public ReadOnlyDictionary Properties + { + get + { + return new ReadOnlyDictionary(_properties); + } + } + + /// + /// + /// This class can be used for any check type. Clients using this class are responsible + /// for adding the necessary properties for their specific check type. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return true; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/GenericNotificationDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/GenericNotificationDetails.cs new file mode 100644 index 000000000..dbcd5230c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/GenericNotificationDetails.cs @@ -0,0 +1,73 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + + /// + /// This class represents the detailed configuration parameters for a + /// generic notification. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class GenericNotificationDetails : NotificationDetails + { + /// + /// This is the backing field for the property. + /// + [JsonExtensionData] + private IDictionary _properties; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GenericNotificationDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// A collection of configuration properties for the notification. + /// If is . + /// If contains a or empty key. + public GenericNotificationDetails(IDictionary properties) + { + if (properties == null) + throw new ArgumentNullException("properties"); + if (properties.ContainsKey(string.Empty)) + throw new ArgumentException("properties cannot contain any empty keys", "properties"); + + _properties = properties; + } + + /// + /// Gets a collection of configuration properties for the notification. + /// + public ReadOnlyDictionary Properties + { + get + { + return new ReadOnlyDictionary(_properties); + } + } + + /// + /// + /// This class can be used for any notification type. Clients using this class are responsible + /// for adding the necessary properties for their specific notification type. + /// + protected internal override bool SupportsNotificationType(NotificationTypeId notificationTypeId) + { + return true; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HostInformationType.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HostInformationType.cs new file mode 100644 index 000000000..88cc75f08 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HostInformationType.cs @@ -0,0 +1,168 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a host information type in the monitoring service. + /// + /// + /// This class functions as a strongly-typed enumeration of known host information types, + /// with added support for unknown types supported by a server extension. + /// + /// + /// + [JsonConverter(typeof(HostInformationType.Converter))] + public sealed class HostInformationType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly HostInformationType _cpus = HostInformationType.FromName("cpus"); + private static readonly HostInformationType _disks = HostInformationType.FromName("disks"); + private static readonly HostInformationType _filesystems = HostInformationType.FromName("filesystems"); + private static readonly HostInformationType _memory = HostInformationType.FromName("memory"); + private static readonly HostInformationType _networkInterfaces = HostInformationType.FromName("network_interfaces"); + private static readonly HostInformationType _processes = HostInformationType.FromName("processes"); + private static readonly HostInformationType _system = HostInformationType.FromName("system"); + private static readonly HostInformationType _who = HostInformationType.FromName("who"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private HostInformationType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static HostInformationType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new HostInformationType(i)); + } + + /// + /// Gets a for information on the host's CPUs. + /// + /// + public static HostInformationType Cpus + { + get + { + return _cpus; + } + } + + /// + /// Gets a for information on the host's disks. + /// + /// + public static HostInformationType Disks + { + get + { + return _disks; + } + } + + /// + /// Gets a for information on the host's filesystems. + /// + /// + public static HostInformationType Filesystems + { + get + { + return _filesystems; + } + } + + /// + /// Gets a for information on the host's memory. + /// + /// + public static HostInformationType Memory + { + get + { + return _memory; + } + } + + /// + /// Gets a for information on the host's network interfaces. + /// + /// + public static HostInformationType NetworkInterfaces + { + get + { + return _networkInterfaces; + } + } + + /// + /// Gets a for information on the host's processes. + /// + /// + public static HostInformationType Processes + { + get + { + return _processes; + } + } + + /// + /// Gets a for system information for the host. + /// + /// + public static HostInformationType System + { + get + { + return _system; + } + } + + /// + /// Gets a for information on users who are logged into the host. + /// + /// + public static HostInformationType Who + { + get + { + return _who; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override HostInformationType FromName(string name) + { + return HostInformationType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HostInformation`1.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HostInformation`1.cs new file mode 100644 index 000000000..b7a3a5ec4 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HostInformation`1.cs @@ -0,0 +1,62 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of agent host information reported by various API calls in the . + /// + /// The type modeling the JSON representation of the host information reported by the agent. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class HostInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("timestamp")] + private long? _timestamp; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("info")] + private T _info; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected HostInformation() + { + } + + /// + /// Gets a timestamp indicating when the agent reported the information. + /// + public DateTimeOffset? Timestamp + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timestamp); + } + } + + /// + /// Gets the information reported by the agent. + /// + public T Info + { + get + { + return _info; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HttpCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HttpCheckDetails.cs new file mode 100644 index 000000000..b40f6018e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/HttpCheckDetails.cs @@ -0,0 +1,263 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + using HttpMethod = JSIStudios.SimpleRESTServices.Client.HttpMethod; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class HttpCheckDetails : CheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("url", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _url; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("auth_password", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _authPassword; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("auth_user", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _authUser; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("body", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _body; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("body_matches", DefaultValueHandling = DefaultValueHandling.Ignore)] + private IDictionary _bodyMatches; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("follow_redirects", DefaultValueHandling = DefaultValueHandling.Ignore)] + private bool? _followRedirects; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("headers", DefaultValueHandling = DefaultValueHandling.Ignore)] + private IDictionary _headers; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("method", DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + private HttpMethod? _method; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("payload", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _payload; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected HttpCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The target URI. + /// The username of the user to authenticate over HTTP. + /// The password of the user to authenticate over HTTP. + /// The regular expression to match against the body of the reply. For more information, see . + /// A collection of named regular expressions to match against the body of the reply. For more information, see . + /// to follow redirects; otherwise, . + /// A collection of additional HTTP headers which are sent with the request. + /// The HTTP method to use for the request. + /// The body to include with the HTTP request. + /// If is . + /// + /// If contains any empty keys. + /// -or- + /// If contains any empty keys. + /// + public HttpCheckDetails(Uri url, string authUser, string authPassword, string body, IDictionary bodyMatches, bool? followRedirects, IDictionary headers, HttpMethod? method, string payload) + { + if (url == null) + throw new ArgumentNullException("url"); + if (bodyMatches != null && bodyMatches.ContainsKey(string.Empty)) + throw new ArgumentException("bodyMatches cannot contain any empty keys", "bodyMatches"); + if (headers != null && headers.ContainsKey(string.Empty)) + throw new ArgumentException("headers cannot contain any empty keys", "headers"); + + _url = url.ToString(); + _authUser = authUser; + _authPassword = authPassword; + _body = body; + _bodyMatches = bodyMatches; + _followRedirects = followRedirects; + _headers = headers; + _method = method; + _payload = payload; + } + + /// + /// Gets the target URI. + /// + public Uri Url + { + get + { + if (_url == null) + return null; + + return new Uri(_url); + } + } + + /// + /// Gets the password of the user to authenticate over HTTP. + /// + public string AuthPassword + { + get + { + return _authPassword; + } + } + + /// + /// Gets the username of the user to authenticate over HTTP. + /// + public string AuthUser + { + get + { + return _authUser; + } + } + + /// + /// Gets the regular expression to match against the body of the reply. + /// + /// + /// The data matched by this regular expression is provided by the + /// body_match metric in the alarm criteria. + /// + public string Body + { + get + { + return _body; + } + } + + /// + /// Gets a collection of named regular expressions to match against the + /// body of the reply. + /// + /// + /// When this property is specified, a metric will be available for each of + /// the named regular expressions. The keys of this dictionary provide the + /// names for each of the regular expressions and determine the names of + /// alarm criteria metrics which provide the data matched by the expression. + /// For example, if contains a key + /// helloworld, the metric + /// body_match_helloworld provides the data in the body + /// matched by the associated regular expression. + /// + public ReadOnlyDictionary BodyMatches + { + get + { + if (_bodyMatches == null) + return null; + + return new ReadOnlyDictionary(_bodyMatches); + } + } + + /// + /// Gets a value indicating whether redirects should be followed. + /// + /// + /// to follow redirects; otherwise, . + /// + public bool? FollowRedirects + { + get + { + return _followRedirects; + } + } + + /// + /// Gets a collection of additional HTTP headers which are sent with the request. + /// + public ReadOnlyDictionary Headers + { + get + { + if (_headers == null) + return null; + + return new ReadOnlyDictionary(_headers); + } + } + + /// + /// Gets the HTTP method to use for the request. + /// + public HttpMethod? Method + { + get + { + return _method; + } + } + + /// + /// Gets the body to send with the request. + /// + /// + /// If following a redirect, the payload will only be sent to the initial URI. + /// + public string Payload + { + get + { + return _payload; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteHttp; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ImapBannerCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ImapBannerCheckDetails.cs new file mode 100644 index 000000000..f829367f3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ImapBannerCheckDetails.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ImapBannerCheckDetails : SecureConnectionCheckDetails + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ImapBannerCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port and SSL configuration. + /// + /// The port to use for connecting to the remote service. If this value is , the default port (143) for the associated service should be used. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// If is less than or equal to 0, or if is greater than 65535. + public ImapBannerCheckDetails(int? port = null, bool? enableSsl = null) + : base(port, enableSsl) + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteImapBanner; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/LoadAverageCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/LoadAverageCheckDetails.cs new file mode 100644 index 000000000..5b7dcc023 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/LoadAverageCheckDetails.cs @@ -0,0 +1,31 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoadAverageCheckDetails : CheckDetails + { + /// + /// Initializes a new instance of the class. + /// + public LoadAverageCheckDetails() + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.AgentLoadAverage; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/LoginInformation.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/LoginInformation.cs new file mode 100644 index 000000000..bb6cf96a1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/LoginInformation.cs @@ -0,0 +1,96 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the login data reported agents for + /// the information type. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class LoginInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("user")] + private string _user; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("device")] + private string _device; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("time")] + private long? _time; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("host")] + private string _host; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected LoginInformation() + { + } + + /// + /// Gets the username of the logged in user. + /// + public string User + { + get + { + return _user; + } + } + + /// + /// Gets the device the user is attached to. + /// + public string Device + { + get + { + return _device; + } + } + + /// + /// Gets the login time. + /// + public DateTimeOffset? Time + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_time); + } + } + + /// + /// Gets the originating host of the login. + /// + public string Host + { + get + { + return _host; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MemoryCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MemoryCheckDetails.cs new file mode 100644 index 000000000..950e93cca --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MemoryCheckDetails.cs @@ -0,0 +1,31 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MemoryCheckDetails : CheckDetails + { + /// + /// Initializes a new instance of the class. + /// + public MemoryCheckDetails() + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.AgentMemory; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MemoryInformation.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MemoryInformation.cs new file mode 100644 index 000000000..9c2611c53 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MemoryInformation.cs @@ -0,0 +1,203 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the disk data reported agents for + /// the information type. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MemoryInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + private long? _ram; + + /// + /// This is the backing field for the property. + /// + private long? _actualFree; + + /// + /// This is the backing field for the property. + /// + private long? _actualUsed; + + /// + /// This is the backing field for the property. + /// + private long? _free; + + /// + /// This is the backing field for the property. + /// + private long? _used; + + /// + /// This is the backing field for the property. + /// + private long? _swapFree; + + /// + /// This is the backing field for the property. + /// + private long? _swapUsed; + + /// + /// This is the backing field for the property. + /// + private long? _swapPageIn; + + /// + /// This is the backing field for the property. + /// + private long? _swapPageOut; + + /// + /// This is the backing field for the property. + /// + private long? _swapTotal; + + /// + /// This is the backing field for the property. + /// + private long? _total; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected MemoryInformation() + { + } + + /// + /// Gets the number of bytes of RAM available to the system. + /// + public long? Available + { + get + { + return _ram * 1024 * 1024; + } + } + + /// + /// Gets the number of bytes of free memory. This property counts purgeable operating system caches as free. + /// + public long? ActualFree + { + get + { + return _actualFree; + } + } + + /// + /// Gets the number of bytes of used memory. This property counts purgeable operating system caches as free. + /// + public long? ActualUsed + { + get + { + return _actualUsed; + } + } + + /// + /// Gets the number of bytes of free memory. This property counts purgeable operating system caches as used. + /// + public long? Free + { + get + { + return _free; + } + } + + /// + /// Gets the number of bytes of used memory. This property counts purgeable operating system caches as used. + /// + public long? Used + { + get + { + return _used; + } + } + + /// + /// Gets the number of bytes of free swap space. + /// + public long? SwapFree + { + get + { + return _swapFree; + } + } + + /// + /// Gets the number of bytes of used swap space. + /// + public long? SwapUsed + { + get + { + return _swapUsed; + } + } + + /// + /// Gets the number of pages swapped in. + /// + public long? SwapPageIn + { + get + { + return _swapPageIn; + } + } + + /// + /// Gets the number of pages swapped out. + /// + public long? SwapPageOut + { + get + { + return _swapPageOut; + } + } + + /// + /// Gets the total number of bytes of swap space. + /// + public long? SwapTotal + { + get + { + return _swapTotal; + } + } + + /// + /// Gets the total number of bytes of memory. + /// + public long? Total + { + get + { + return _total; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Metric.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Metric.cs new file mode 100644 index 000000000..ce4bbea8f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Metric.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a Metric resource in the . + /// + /// + /// When Monitoring checks run, they generate metrics. These metrics are stored as + /// full resolution data points in the Cloud Monitoring system. Full resolution data + /// points are periodically rolled-up (condensed) into coarser data points. + /// + /// Depending on your needs, you can use the metrics API to fetch individual + /// data points (fine-grained) or rolled-up data points (coarse-grained) over a + /// period of time. + /// + /// Metrics (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Metric : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private MetricName _name; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Metric() + { + } + + /// + /// Gets the name of the metric. + /// + public MetricName Name + { + get + { + return _name; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MetricName.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MetricName.cs new file mode 100644 index 000000000..5de7fa718 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MetricName.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a metric in the . + /// + /// + /// + /// + [JsonConverter(typeof(MetricName.Converter))] + public sealed class MetricName : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The metric identifier value. + /// If is . + /// If is empty. + public MetricName(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override MetricName FromValue(string id) + { + return new MetricName(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringAccount.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringAccount.cs new file mode 100644 index 000000000..a92401b6c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringAccount.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class represents an account in the . + /// + /// + /// An account contains attributes describing a customer's account. This description + /// contains mostly read only data; however, a few properties can be modified with the API. + /// + /// Account (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MonitoringAccount : AccountConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private MonitoringAccountId _id; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected MonitoringAccount() + { + } + + /// + /// Gets the unique identifier for the monitoring account. + /// + public MonitoringAccountId Id + { + get + { + return _id; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringAccountId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringAccountId.cs new file mode 100644 index 000000000..3975ac857 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringAccountId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a monitoring account in the . + /// + /// + /// + /// + [JsonConverter(typeof(MonitoringAccountId.Converter))] + public sealed class MonitoringAccountId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The monitoring account identifier value. + /// If is . + /// If is empty. + public MonitoringAccountId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override MonitoringAccountId FromValue(string id) + { + return new MonitoringAccountId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringLimits.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringLimits.cs new file mode 100644 index 000000000..623aea6ed --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringLimits.cs @@ -0,0 +1,144 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the resource and rate limits + /// applied to the . + /// + /// + /// Get Limits (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MonitoringLimits : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("resource")] + private IDictionary _resourceLimits; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rate")] + private IDictionary _rateLimits; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected MonitoringLimits() + { + } + + /// + /// Gets a collection of absolute resource limits in effect for the monitoring service. + /// + public ReadOnlyDictionary ResourceLimits + { + get + { + if (_resourceLimits == null) + return null; + + return new ReadOnlyDictionary(_resourceLimits); + } + } + + /// + /// Gets a collection of rate limits in effect for the monitoring service. + /// + public ReadOnlyDictionary RateLimits + { + get + { + if (_rateLimits == null) + return null; + + return new ReadOnlyDictionary(_rateLimits); + } + } + + /// + /// This class models the JSON representation of the details of a rate limit in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class RateLimit : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("limit")] + private int? _limit; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("used")] + private int? _used; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("window")] + private string _window; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected RateLimit() + { + } + + /// + /// Gets the number of times the rate limited item is allowed to be used during a rate limit period. + /// + public int? Limit + { + get + { + return _limit; + } + } + + /// + /// Gets the number of times the rate limited item has been used during the current rate limiting period. + /// + public int? Used + { + get + { + return _used; + } + } + + /// + /// Gets a description of the period between resetting the rate limit. + /// + public string Window + { + get + { + return _window; + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringZone.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringZone.cs new file mode 100644 index 000000000..dc3ec8648 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringZone.cs @@ -0,0 +1,112 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a monitoring zone resource in the . + /// + /// + /// A monitoring zone is a location that Rackspace Cloud Monitoring collects data from. + /// Examples of monitoring zones are "US West", "DFW1" or "ORD1". It is an abstraction + /// for a general location from which data is collected. + /// + /// An "endpoint," also known as a "collector," collects data from the monitoring + /// zone. The endpoint is mapped directly to an individual machine or a virtual machine. + /// A monitoring zone contains many endpoints, all of which will be within the IP address + /// range listed in the response. The opposite is not true, however, as there may be + /// unallocated IP addresses or unrelated machines within that IP address range. + /// + /// A check references a list of monitoring zones it should be run from. + /// + /// Monitoring Zones (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MonitoringZone : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private MonitoringZoneId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("label")] + private string _label; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("country_code")] + private string _countryCode; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("source_ips")] + private string[] _sourceAddresses; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected MonitoringZone() + { + } + + /// + /// Gets the unique identifier of the monitoring zone. + /// + public MonitoringZoneId Id + { + get + { + return _id; + } + } + + /// + /// Gets the name of the monitoring zone. + /// + public string Label + { + get + { + return _label; + } + } + + /// + /// Gets the country code for the monitoring zone. + /// + public string CountryCode + { + get + { + return _countryCode; + } + } + + /// + /// Gets a collection of IP addresses and/or address ranges (in CIDR notation) from + /// which checks from this monitoring zone may be performed. + /// + public ReadOnlyCollection SourceAddresses + { + get + { + if (_sourceAddresses == null) + return null; + + return new ReadOnlyCollection(_sourceAddresses); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringZoneId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringZoneId.cs new file mode 100644 index 000000000..9f9454318 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MonitoringZoneId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a monitoring zone in the . + /// + /// + /// + /// + [JsonConverter(typeof(MonitoringZoneId.Converter))] + public sealed class MonitoringZoneId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The monitoring zone identifier value. + /// If is . + /// If is empty. + public MonitoringZoneId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override MonitoringZoneId FromValue(string id) + { + return new MonitoringZoneId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MssqlBannerCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MssqlBannerCheckDetails.cs new file mode 100644 index 000000000..037803c1f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MssqlBannerCheckDetails.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MssqlBannerCheckDetails : SecureConnectionCheckDetails + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected MssqlBannerCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port and SSL configuration. + /// + /// The port to use for connecting to the remote service. If this value is , the default port (1433) for the associated service should be used. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// If is less than or equal to 0, or if is greater than 65535. + public MssqlBannerCheckDetails(int? port = null, bool? enableSsl = null) + : base(port, enableSsl) + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteMssqlBanner; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MysqlBannerCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MysqlBannerCheckDetails.cs new file mode 100644 index 000000000..3c9076a47 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/MysqlBannerCheckDetails.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class MysqlBannerCheckDetails : SecureConnectionCheckDetails + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected MysqlBannerCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port and SSL configuration. + /// + /// The port to use for connecting to the remote service. If this value is , the default port (3306) for the associated service should be used. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// If is less than or equal to 0, or if is greater than 65535. + public MysqlBannerCheckDetails(int? port = null, bool? enableSsl = null) + : base(port, enableSsl) + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteMysqlBanner; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NamespaceDoc.cs new file mode 100644 index 000000000..c9a0863fe --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines + /// the object model for communicating with Rackspace's Cloud Monitoring service over REST APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NetworkCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NetworkCheckDetails.cs new file mode 100644 index 000000000..481369104 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NetworkCheckDetails.cs @@ -0,0 +1,68 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NetworkCheckDetails : CheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("target")] + private string _target; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NetworkCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified target. + /// + /// The network device to check. + /// If is . + /// If is empty. + public NetworkCheckDetails(string target) + { + if (target == null) + throw new ArgumentNullException("target"); + if (string.IsNullOrEmpty(target)) + throw new ArgumentException("target cannot be empty"); + + _target = target; + } + + /// + /// Gets the network device to check. + /// + public string Target + { + get + { + return _target; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.AgentNetwork; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NetworkInterfaceInformation.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NetworkInterfaceInformation.cs new file mode 100644 index 000000000..527b053c7 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NetworkInterfaceInformation.cs @@ -0,0 +1,408 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Net; + using System.Net.NetworkInformation; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the network interface data reported agents for + /// the information type. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NetworkInterfaceInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type")] + private string _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("address")] + [JsonConverter(typeof(IPAddressSimpleConverter))] + private IPAddress _address; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("address6")] + [JsonConverter(typeof(IPAddressSimpleConverter))] + private IPAddress _address6; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("broadcast")] + [JsonConverter(typeof(IPAddressSimpleConverter))] + private IPAddress _broadcast; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("hwaddr")] + [JsonConverter(typeof(PhysicalAddressSimpleConverter))] + private PhysicalAddress _physicalAddress; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("netmask")] + private string _netmask; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("mtu")] + private int? _mtu; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("tx_bytes")] + private long? _transmitBytes; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("tx_packets")] + private long? _transmitPackets; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("tx_errors")] + private long? _transmitErrors; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("tx_overruns")] + private long? _transmitOverruns; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("tx_carrier")] + private long? _transmitCarrierErrors; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("tx_collisions")] + private long? _transmitCollisions; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("tx_dropped")] + private long? _transmitDropped; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rx_bytes")] + private long? _receiveBytes; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rx_packets")] + private long? _receivePackets; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rx_errors")] + private long? _receiveErrors; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rx_overruns")] + private long? _receiveOverruns; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rx_frame")] + private long? _receiveInvalidFrames; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rx_dropped")] + private long? _receiveDropped; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("flags")] + private long? _flags; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NetworkInterfaceInformation() + { + } + + /// + /// Gets the name of the network interface. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the interface type (e.g. Ethernet, Local Loopback, etc.). + /// + public string Type + { + get + { + return _type; + } + } + + /// + /// Gets the IP V4 address of the network interface. + /// + public IPAddress IPAddress + { + get + { + return _address; + } + } + + /// + /// Gets the IP V6 address of the network interface. + /// + public IPAddress IPAddressV6 + { + get + { + return _address6; + } + } + + /// + /// Gets the broadcast address of the network. + /// + public IPAddress Broadcast + { + get + { + return _broadcast; + } + } + + /// + /// Gets the physical address of the network interface. + /// + public PhysicalAddress PhysicalAddress + { + get + { + return _physicalAddress; + } + } + + /// + /// Gets the network mask as a string. + /// + public string NetworkMask + { + get + { + return _netmask; + } + } + + /// + /// Gets the Ethernet maximum transmission unit (MTU). + /// + public int? MaximumTransmissionUnit + { + get + { + return _mtu; + } + } + + /// + /// Gets the total number of bytes sent. + /// + public long? TransmitBytes + { + get + { + return _transmitBytes; + } + } + + /// + /// Gets the total number of packets sent. + /// + public long? TransmitPackets + { + get + { + return _transmitPackets; + } + } + + /// + /// Gets the total number of transmit errors. + /// + public long? TransmitErrors + { + get + { + return _transmitErrors; + } + } + + /// + /// Gets the total number of transmit buffer overruns. + /// + public long? TransmitOverruns + { + get + { + return _transmitOverruns; + } + } + + /// + /// Gets the total number of carrier errors (usually cable disconnects). + /// + public long? TransmitCarrierErrors + { + get + { + return _transmitCarrierErrors; + } + } + + /// + /// Gets the total number of packet collisions on transmit. + /// + public long? TransmitCollisions + { + get + { + return _transmitCollisions; + } + } + + /// + /// Gets the total number of dropped transmit packets. + /// + public long? TransmitDropped + { + get + { + return _transmitDropped; + } + } + + /// + /// Gets the total number of bytes received. + /// + public long? ReceiveBytes + { + get + { + return _receiveBytes; + } + } + + /// + /// Gets the total number of packets received. + /// + public long? ReceivePackets + { + get + { + return _receivePackets; + } + } + + /// + /// Gets the total number of receive errors. + /// + public long? ReceiveErrors + { + get + { + return _receiveErrors; + } + } + + /// + /// Gets the total number of receive buffer overruns. + /// + public long? ReceiveOverruns + { + get + { + return _receiveOverruns; + } + } + + /// + /// Gets the total number of errors caused by malformed frames. + /// + public long? ReceiveInvalidFrames + { + get + { + return _receiveInvalidFrames; + } + } + + /// + /// Gets the total number of dropped packets received. + /// + public long? ReceiveDropped + { + get + { + return _receiveDropped; + } + } + + /// + /// Gets the operating system-specific interface flags. + /// + public long? Flags + { + get + { + return _flags; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewAlarmConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewAlarmConfiguration.cs new file mode 100644 index 000000000..bd31025d2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewAlarmConfiguration.cs @@ -0,0 +1,53 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to create a new + /// resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewAlarmConfiguration : AlarmConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NewAlarmConfiguration() + { + } + + /// + /// Initializes a new instance of the class with the specified + /// values. + /// + /// The ID of the check to alert on. This is obtained from Check.Id. + /// The ID of the notification plan to execute when the state changes. This is obtained from NotificationPlan.Id. + /// The alarm DSL for describing alerting conditions and their output states. + /// to enable processing and alerts on this alarm; otherwise, . If this value is , . + /// A friendly label for the alarm. + /// A collection of metadata to associate with the alarm. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If contains any values with empty keys. + /// + public NewAlarmConfiguration(CheckId checkId, NotificationPlanId notificationPlanId, string criteria = null, bool? enabled = null, string label = null, IDictionary metadata = null) + : base(checkId, notificationPlanId, criteria, enabled, label, metadata) + { + if (checkId == null) + throw new ArgumentNullException("checkId"); + if (notificationPlanId == null) + throw new ArgumentNullException("notificationPlanId"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewCheckConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewCheckConfiguration.cs new file mode 100644 index 000000000..1ee5f3a94 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewCheckConfiguration.cs @@ -0,0 +1,88 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to create or test a new + /// resource in the . + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewCheckConfiguration : CheckConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NewCheckConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The friendly name of the check. If this is , the label assigned to the new check is unspecified. + /// The check type ID. This is obtained from CheckType.Id, or from the predefined values in . + /// A object containing detailed configuration information for the specific check type. + /// A collection of objects identifying the monitoring zones to poll from. + /// The timeout of a check operation. If this value is , a provider-specific default value is used. + /// The period between check operations. If this value is , a provider-specific default value is used. + /// The alias of the target for this check in the associated entity's map. + /// The hostname this check should target. + /// The type of resolver to use for converting to an IP address. + /// A collection of metadata to associate with the check. If this parameter is , the check is created without any custom metadata. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is non- but empty. + /// -or- + /// If the specified object does support checks of type . + /// -or- + /// If is a remote check (i.e. the property is ) and is or empty. + /// -or- + /// If is a remote check (i.e. the property is ) and both and are . + /// -or- + /// If contains any values. + /// -or- + /// If is less than or equal to . + /// -or- + /// If is non- but empty. + /// -or- + /// If is non- but empty. + /// -or- + /// If contains any empty keys, or any values. + /// + /// + /// If is less than or equal to . + /// -or- + /// If is less than or equal to . + /// + /// + /// If and are both non-. + /// + public NewCheckConfiguration(string label, CheckTypeId checkTypeId, CheckDetails details, IEnumerable monitoringZonesPoll, TimeSpan? timeout, TimeSpan? period, string targetAlias, string targetHostname, TargetResolverType resolverType, IDictionary metadata) + : base(label, checkTypeId, details, monitoringZonesPoll, timeout, period, targetAlias, targetHostname, resolverType, metadata) + { + if (checkTypeId == null) + throw new ArgumentNullException("checkTypeId"); + if (details == null) + throw new ArgumentNullException("details"); + if (checkTypeId.IsRemote && monitoringZonesPoll == null) + throw new ArgumentException("monitoringZonesPoll cannot be null or empty for remote checks", "monitoringZonesPoll"); + if (checkTypeId.IsRemote && targetAlias == null && targetHostname == null) + throw new ArgumentException("targetAlias and targetHostname cannot both be null for remote checks"); + if (checkTypeId.IsRemote && MonitoringZonesPoll.Count == 0) + throw new ArgumentException("monitoringZonesPoll cannot be null or empty for remote checks", "monitoringZonesPoll"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewEntityConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewEntityConfiguration.cs new file mode 100644 index 000000000..f378ab44d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewEntityConfiguration.cs @@ -0,0 +1,50 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + using IPAddress = System.Net.IPAddress; + + /// + /// This class models the JSON representation of a request to create a new + /// resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewEntityConfiguration : EntityConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NewEntityConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The name for the entity. + /// The agent which this entity is bound to. If this parameter is , placeholder. + /// The IP addresses which can be referenced by checks on this entity. If this parameter is , placeholder. + /// A collection of metadata to associate with the entity. If this parameter is , the entity is created without any custom metadata. + /// If is . + /// + /// If is empty. + /// -or- + /// If contains any empty keys. + /// -or- + /// If contains any empty keys. + /// + public NewEntityConfiguration(string label, AgentId agentId, IDictionary ipAddresses, IDictionary metadata) + : base(label, agentId, ipAddresses, metadata) + { + if (label == null) + throw new ArgumentNullException("label"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewNotificationConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewNotificationConfiguration.cs new file mode 100644 index 000000000..ebfd7a469 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewNotificationConfiguration.cs @@ -0,0 +1,58 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to create or test a new + /// resource in the . + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewNotificationConfiguration : NotificationConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NewNotificationConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The friendly name of the notification. + /// The notification type ID. This is obtained from NotificationType.Id, or from the predefined values in . + /// A object containing the detailed configuration properties for the specified notification type. + /// A collection of metadata to associate with the notification. If the value is , no custom metadata is associated with the notification. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is non- and is . + /// -or- + /// If does not support notifications of type . + /// -or- + /// If contains any empty keys. + /// + public NewNotificationConfiguration(string label, NotificationTypeId notificationTypeId, NotificationDetails details, IDictionary metadata = null) + : base(label, notificationTypeId, details, metadata) + { + if (label == null) + throw new ArgumentNullException("label"); + if (details == null) + throw new ArgumentNullException("details"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewNotificationPlanConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewNotificationPlanConfiguration.cs new file mode 100644 index 000000000..8e57e5a9d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NewNotificationPlanConfiguration.cs @@ -0,0 +1,54 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to create a new + /// resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewNotificationPlanConfiguration : NotificationPlanConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NewNotificationPlanConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The label for the notification plan. + /// The notification list to send to when the state is . If this value is , notifications are not sent for this state. + /// The notification list to send to when the state is . If this value is , notifications are not sent for this state. + /// The notification list to send to when the state is . If this value is , notifications are not sent for this state. + /// The metadata to associate with the notification plan. If this value is , no custom metadata is associated with the notification plan. + /// If is . + /// + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// -or- + /// If contains any empty keys. + /// + public NewNotificationPlanConfiguration(string label, IEnumerable criticalState = null, IEnumerable warningState = null, IEnumerable okState = null, IDictionary metadata = null) + : base(label, criticalState, warningState, okState, metadata) + { + if (label == null) + throw new ArgumentNullException("label"); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Notification.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Notification.cs new file mode 100644 index 000000000..171c822a6 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Notification.cs @@ -0,0 +1,78 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a notification resource + /// in the . + /// + /// Notifications (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Notification : NotificationConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private NotificationId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created_at")] + private long? _createdAt; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated_at")] + private long? _updatedAt; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Notification() + { + } + + /// + /// Gets the unique identifier for the notification resource. + /// + public NotificationId Id + { + get + { + return _id; + } + } + + /// + /// Gets a timestamp indicating when the notification was first created. + /// + public DateTimeOffset? Created + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_createdAt); + } + } + + /// + /// Gets a timestamp indicating when the notification was last modified. + /// + public DateTimeOffset? LastModified + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_updatedAt); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationAttempt.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationAttempt.cs new file mode 100644 index 000000000..b6c86cdb8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationAttempt.cs @@ -0,0 +1,61 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the detailed information + /// describing an attempt to send a notification. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NotificationAttempt : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("message")] + private string _message; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("from")] + private string _from; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NotificationAttempt() + { + } + + /// + /// Gets a message describing the result of the notification attempt. + /// + public string Message + { + get + { + return _message; + } + } + + /// + /// Gets the name of the system responsible for the notification attempt. + /// + public string From + { + get + { + return _from; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationConfiguration.cs new file mode 100644 index 000000000..ec75648a1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationConfiguration.cs @@ -0,0 +1,143 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the configurable properties of the JSON representation of + /// a notification resource in the . + /// + /// + /// + /// + /// + /// Notifications (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class NotificationConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("label", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _label; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NotificationTypeId _type; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("details", DefaultValueHandling = DefaultValueHandling.Ignore)] + private JObject _details; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private IDictionary _metadata; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NotificationConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The friendly name of the notification. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The notification type ID. This is obtained from NotificationType.Id, or from the predefined values in . If this value is , the underlying property will be omitted from the JSON representation of the object. + /// A object containing the detailed configuration properties for the specified notification type. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// A collection of metadata to associate with the notification. If the value is , no custom metadata is associated with the notification. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// + /// If is empty. + /// -or- + /// If is non- and is . + /// -or- + /// If does not support notifications of type . + /// -or- + /// If contains any empty keys. + /// + protected NotificationConfiguration(string label, NotificationTypeId notificationTypeId, NotificationDetails details, IDictionary metadata) + { + if (label == string.Empty) + throw new ArgumentException("label cannot be empty"); + if (details != null && notificationTypeId == null) + throw new ArgumentException("notificationTypeId must be specified if details is specified", "notificationTypeId"); + if (details != null && !details.SupportsNotificationType(notificationTypeId)) + throw new ArgumentException(string.Format("The notification details object does not support '{0}' notifications.", notificationTypeId), "details"); + if (metadata != null && metadata.ContainsKey(string.Empty)) + throw new ArgumentException("metadata cannot contain any empty keys", "metadata"); + + _label = label; + _type = notificationTypeId; + _details = details != null ? JObject.FromObject(details) : null; + _metadata = metadata; + } + + /// + /// Gets the friendly name of the notification. + /// + public string Label + { + get + { + return _label; + } + } + + /// + /// Gets the ID of the notification type to send. + /// + public NotificationTypeId Type + { + get + { + return _type; + } + } + + /// + /// Gets the detailed configuration properties for the notification. + /// + public NotificationDetails Details + { + get + { + if (_details == null) + return null; + + return NotificationDetails.FromJObject(Type, _details); + } + } + + /// + /// Gets a collection of metadata associated with the notification. + /// + public ReadOnlyDictionary Metadata + { + get + { + if (_metadata == null) + return null; + + return new ReadOnlyDictionary(_metadata); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationData.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationData.cs new file mode 100644 index 000000000..32b79e2b3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationData.cs @@ -0,0 +1,61 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the results of testing a notification. + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NotificationData : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("status")] + private string _status; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("message")] + private string _message; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NotificationData() + { + } + + /// + /// Gets the result of testing the notification. + /// + public string Status + { + get + { + return _status; + } + } + + /// + /// Gets a message describing the result of testing the notification. + /// + public string Message + { + get + { + return _message; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationDetails.cs new file mode 100644 index 000000000..773af8853 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationDetails.cs @@ -0,0 +1,54 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This is the base class for classes modeling the detailed configuration parameters + /// of various types of notifications. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class NotificationDetails : ExtensibleJsonObject + { + /// + /// Deserializes a JSON object to a instance of the proper type. + /// + /// The notification type ID. + /// The JSON object representing the notification details. + /// A object corresponding to the JSON object. + /// + /// If is . + /// -or- + /// If is . + /// + public static NotificationDetails FromJObject(NotificationTypeId notificationTypeId, JObject obj) + { + if (notificationTypeId == null) + throw new ArgumentNullException("notificationTypeId"); + if (obj == null) + throw new ArgumentNullException("obj"); + + if (notificationTypeId == NotificationTypeId.Webhook) + return obj.ToObject(); + else if (notificationTypeId == NotificationTypeId.Email) + return obj.ToObject(); + else if (notificationTypeId == NotificationTypeId.PagerDuty) + return obj.ToObject(); + else + return obj.ToObject(); + } + + /// + /// Determines whether the current object is compatible + /// with notifications of a particular type. + /// + /// The notification type ID. + /// if the current object is compatible with ; otherwise, . + /// If is . + protected internal abstract bool SupportsNotificationType(NotificationTypeId notificationTypeId); + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationId.cs new file mode 100644 index 000000000..f2bb5a35f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a notification in the . + /// + /// + /// + /// + [JsonConverter(typeof(NotificationId.Converter))] + public sealed class NotificationId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The notification identifier value. + /// If is . + /// If is empty. + public NotificationId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NotificationId FromValue(string id) + { + return new NotificationId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlan.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlan.cs new file mode 100644 index 000000000..43553cfc0 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlan.cs @@ -0,0 +1,79 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a notification plan resource + /// in the . + /// + /// Notification Plans (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NotificationPlan : NotificationPlanConfiguration + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private NotificationPlanId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("created_at")] + private long? _createdAt; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("updated_at")] + private long? _updatedAt; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NotificationPlan() + { + } + + /// + /// Gets the unique identifier for the notification plan resource. + /// + public NotificationPlanId Id + { + get + { + return _id; + } + } + + /// + /// Gets a timestamp indicating when the notification plan resource was created. + /// + public DateTimeOffset? Created + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_createdAt); + } + } + + /// + /// Gets a timestamp indicating when the notification plan resource was last modified. + /// + public DateTimeOffset? LastModified + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_updatedAt); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlanConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlanConfiguration.cs new file mode 100644 index 000000000..706e11284 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlanConfiguration.cs @@ -0,0 +1,187 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using net.openstack.Core.Collections; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the configurable properties of the JSON representation of + /// a notification plan resource in the . + /// + /// + /// + /// + /// + /// Notification Plans (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class NotificationPlanConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("label", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _label; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("critical_state", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NotificationId[] _criticalState; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("warning_state", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NotificationId[] _warningState; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ok_state", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NotificationId[] _okState; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Ignore)] + private IDictionary _metadata; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NotificationPlanConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The label for the notification plan. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The notification list to send to when the state is . If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The notification list to send to when the state is . If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The notification list to send to when the state is . If this value is , the underlying property will be omitted from the JSON representation of the object. + /// The metadata to associate with the notification plan. If this value is , the underlying property will be omitted from the JSON representation of the object. + /// + /// If is empty. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// -or- + /// If contains any empty keys. + /// + protected NotificationPlanConfiguration(string label, IEnumerable criticalState, IEnumerable warningState, IEnumerable okState, IDictionary metadata) + { + if (label == string.Empty) + throw new ArgumentException("label cannot be empty"); + + _label = label; + + if (criticalState != null) + { + _criticalState = criticalState.ToArray(); + if (_criticalState.Contains(null)) + throw new ArgumentException("criticalState cannot contain any null values", "criticalState"); + } + + if (warningState != null) + { + _warningState = warningState.ToArray(); + if (_warningState.Contains(null)) + throw new ArgumentException("warningState cannot contain any null values", "warningState"); + } + + if (okState != null) + { + _okState = okState.ToArray(); + if (_okState.Contains(null)) + throw new ArgumentException("okState cannot contain any null values", "okState"); + } + + if (metadata != null) + { + _metadata = metadata; + if (metadata.ContainsKey(string.Empty)) + throw new ArgumentException("metadata cannot contain any empty keys", "metadata"); + } + } + + /// + /// Gets the friendly name for the notification plan. + /// + public string Label + { + get + { + return _label; + } + } + + /// + /// Gets the notification list to send to when the state is . + /// + public ReadOnlyCollection CriticalState + { + get + { + if (_criticalState == null) + return null; + + return new ReadOnlyCollection(_criticalState); + } + } + + /// + /// Gets the notification list to send to when the state is . + /// + public ReadOnlyCollection WarningState + { + get + { + if (_warningState == null) + return null; + + return new ReadOnlyCollection(_warningState); + } + } + + /// + /// Gets the notification list to send to when the state is . + /// + public ReadOnlyCollection OkState + { + get + { + if (_okState == null) + return null; + + return new ReadOnlyCollection(_okState); + } + } + + /// + /// Gets a collection of metadata associated with the notification plan. + /// + public ReadOnlyDictionary Metadata + { + get + { + if (_metadata == null) + return null; + + return new ReadOnlyDictionary(_metadata); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlanId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlanId.cs new file mode 100644 index 000000000..3b4a171a7 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationPlanId.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a notification plan in the . + /// + /// + /// + /// + [JsonConverter(typeof(NotificationPlanId.Converter))] + public sealed class NotificationPlanId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The notification plan identifier value. + /// If is . + /// If is empty. + public NotificationPlanId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NotificationPlanId FromValue(string id) + { + return new NotificationPlanId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationResult.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationResult.cs new file mode 100644 index 000000000..b575f1a7a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationResult.cs @@ -0,0 +1,156 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the result of sending a monitoring + /// notification. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NotificationResult : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("notification_id")] + private NotificationId _notificationId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("notification_type")] + private NotificationTypeId _notificationTypeId; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("notification_details")] + private JObject _notificationDetails; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("in_progress")] + private bool? _inProgress; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("message")] + private string _message; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("success")] + private bool? _success; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("attempts")] + private NotificationAttempt[] _attempts; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NotificationResult() + { + } + + /// + /// Gets the ID of the notification which was sent as a result of this alarm + /// change. + /// + public NotificationId NotificationId + { + get + { + return _notificationId; + } + } + + /// + /// Gets the ID of the notification type of the notification which was sent. + /// + public NotificationTypeId NotificationTypeId + { + get + { + return _notificationTypeId; + } + } + + /// + /// Gets the detailed configuration information for the notification which was sent. + /// + public NotificationDetails NotificationDetails + { + get + { + if (_notificationDetails == null) + return null; + + return NotificationDetails.FromJObject(NotificationTypeId, _notificationDetails); + } + } + + /// + /// Gets a value indicating whether the notification is currently in progress. + /// + public bool? InProgress + { + get + { + return _inProgress; + } + } + + /// + /// Gets a message describing the result of the notification operation. + /// + public string Message + { + get + { + return _message; + } + } + + /// + /// Gets a value indicating whether the notification was successful. + /// + public bool? Success + { + get + { + return _success; + } + } + + /// + /// Gets a collection of objects describing the + /// results of individual attempts to sent the notification. + /// + public ReadOnlyCollection Attempts + { + get + { + if (_attempts == null) + return null; + + return new ReadOnlyCollection(_attempts); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationType.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationType.cs new file mode 100644 index 000000000..593a20a1c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationType.cs @@ -0,0 +1,65 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a notification type in the . + /// + /// Notification Types (Rackspace Cloud Monitoring Developer Guide - API v1.0) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NotificationType : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("id")] + private NotificationTypeId _id; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("fields", DefaultValueHandling = DefaultValueHandling.Ignore)] + private NotificationTypeField[] _fields; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NotificationType() + { + } + + /// + /// Gets the unique identifier for the notification type. + /// + public NotificationTypeId Id + { + get + { + return _id; + } + } + + /// + /// Gets a collection of objects describing the fields + /// of this notification type. + /// + public ReadOnlyCollection Fields + { + get + { + if (_fields == null) + return null; + + return new ReadOnlyCollection(_fields); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationTypeField.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationTypeField.cs new file mode 100644 index 000000000..1647d054a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationTypeField.cs @@ -0,0 +1,77 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class represents a single field associated with a notification type in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NotificationTypeField : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("description")] + private string _description; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("optional")] + private bool? _optional; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected NotificationTypeField() + { + } + + /// + /// Gets the name of the field. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets a description of the field. + /// + public string Description + { + get + { + return _description; + } + } + + /// + /// Gets a value indicating whether the field value is optional when creating a notification of the associated type + /// + public bool? Optional + { + get + { + return _optional; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationTypeId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationTypeId.cs new file mode 100644 index 000000000..0c917a0a8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/NotificationTypeId.cs @@ -0,0 +1,90 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a notification type in the . + /// + /// + /// + /// + [JsonConverter(typeof(NotificationTypeId.Converter))] + public sealed class NotificationTypeId : ResourceIdentifier + { + /// + /// This is the backing field for the property. + /// + private static readonly NotificationTypeId _webhook = new NotificationTypeId("webhook"); + + /// + /// This is the backing field for the property. + /// + private static readonly NotificationTypeId _email = new NotificationTypeId("email"); + + /// + /// This is the backing field for the property. + /// + private static readonly NotificationTypeId _pagerduty = new NotificationTypeId("pagerduty"); + + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The notification type identifier value. + /// If is . + /// If is empty. + public NotificationTypeId(string id) + : base(id) + { + } + + /// + /// Gets a instance representing a webhook notification. + /// + public static NotificationTypeId Webhook + { + get + { + return _webhook; + } + } + + /// + /// Gets a instance representing an email notification. + /// + public static NotificationTypeId Email + { + get + { + return _email; + } + } + + /// + /// Gets a instance representing a PagerDuty notification. + /// + public static NotificationTypeId PagerDuty + { + get + { + return _pagerduty; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override NotificationTypeId FromValue(string id) + { + return new NotificationTypeId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PagerDutyNotificationDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PagerDutyNotificationDetails.cs new file mode 100644 index 000000000..00ed60e20 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PagerDutyNotificationDetails.cs @@ -0,0 +1,67 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class extends with properties specific to + /// notifications. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class PagerDutyNotificationDetails : NotificationDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("service_key")] + private string _serviceKey; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected PagerDutyNotificationDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified service key. + /// + /// The PagerDuty service key to use for sending notifications. + /// If is . + /// If is empty. + public PagerDutyNotificationDetails(string serviceKey) + { + if (serviceKey == null) + throw new ArgumentNullException("serviceKey"); + if (string.IsNullOrEmpty(serviceKey)) + throw new ArgumentException("serviceKey cannot be empty"); + + _serviceKey = serviceKey; + } + + /// + /// Gets the PagerDuty service key to use for sending notifications. + /// + public string ServiceKey + { + get + { + return _serviceKey; + } + } + + /// + /// + /// This class only supports notifications. + /// + protected internal override bool SupportsNotificationType(NotificationTypeId notificationTypeId) + { + return notificationTypeId == NotificationTypeId.PagerDuty; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PingCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PingCheckDetails.cs new file mode 100644 index 000000000..fd13f2091 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PingCheckDetails.cs @@ -0,0 +1,65 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class PingCheckDetails : CheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("count", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _count; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected PingCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified count. + /// + /// The number of pings to send within a single check. If this value is , a provider-specific default value is used. + /// If is less than or equal to 0. + public PingCheckDetails(int? count = null) + { + if (count <= 0) + throw new ArgumentOutOfRangeException("count"); + + _count = count; + } + + /// + /// Gets the number of pings to send within a single check. + /// + public int? Count + { + get + { + return _count; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemotePing; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PluginCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PluginCheckDetails.cs new file mode 100644 index 000000000..010584be7 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PluginCheckDetails.cs @@ -0,0 +1,121 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class PluginCheckDetails : CheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("file")] + private string _file; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("args", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string[] _arguments; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("timeout", DefaultValueHandling = DefaultValueHandling.Ignore)] + private int? _timeout; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected PluginCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The name of the plugin file. + /// A collection of command line arguments which are passed to the plugin. If this argument is , no command line arguments are passed to the plugin. + /// The plugin execution timeout. If this value is , the plugin execution timeout is unspecified. + /// If is . + /// + /// If is empty. + /// -or- + /// If contains any or empty values. + /// + /// If is less than . + public PluginCheckDetails(string file, string[] arguments, TimeSpan? timeout) + { + if (file == null) + throw new ArgumentNullException("file"); + if (arguments != null && arguments.Any(string.IsNullOrEmpty)) + throw new ArgumentException("arguments cannot contain any null or empty values", "arguments"); + if (timeout < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeout cannot be negative"); + + _file = file; + _arguments = (string[])arguments.Clone(); + _timeout = timeout != null ? (int?)timeout.Value.TotalMilliseconds : null; + } + + /// + /// Gets the name of the plugin file. + /// + public string File + { + get + { + return _file; + } + } + + /// + /// Gets a collection of command line arguments passed to the plugin. + /// + public ReadOnlyCollection Arguments + { + get + { + if (_arguments == null) + return null; + + return new ReadOnlyCollection(_arguments); + } + } + + /// + /// Gets the plugin execution timeout. + /// + public TimeSpan? Timeout + { + get + { + if (_timeout == null) + return null; + + return TimeSpan.FromMilliseconds(_timeout.Value); + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.AgentPlugin; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Pop3CheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Pop3CheckDetails.cs new file mode 100644 index 000000000..fbc7e8724 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/Pop3CheckDetails.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Pop3CheckDetails : SecureConnectionCheckDetails + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected Pop3CheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port and SSL configuration. + /// + /// The port to use for connecting to the remote service. If this value is , the default port (110) for the associated service should be used. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// If is less than or equal to 0, or if is greater than 65535. + public Pop3CheckDetails(int? port = null, bool? enableSsl = null) + : base(port, enableSsl) + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemotePop3Banner; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PostgresqlBannerCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PostgresqlBannerCheckDetails.cs new file mode 100644 index 000000000..da84ec389 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/PostgresqlBannerCheckDetails.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class PostgresqlBannerCheckDetails : SecureConnectionCheckDetails + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected PostgresqlBannerCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port and SSL configuration. + /// + /// The port to use for connecting to the remote service. If this value is , the default port (5432) for the associated service should be used. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// If is less than or equal to 0, or if is greater than 65535. + public PostgresqlBannerCheckDetails(int? port = null, bool? enableSsl = null) + : base(port, enableSsl) + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemotePostgresqlBanner; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ProcessInformation.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ProcessInformation.cs new file mode 100644 index 000000000..72ad5392b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ProcessInformation.cs @@ -0,0 +1,409 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the process data reported agents for + /// the information type. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ProcessInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("pid")] + private int? _pid; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("exe_name")] + private string _exeName; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("exe_root")] + private string _exeRoot; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("exe_cwd")] + private string _exeCwd; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("cred_group")] + private string _credGroup; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("cred_user")] + private string _credUser; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("memory_size")] + private long? _memorySize; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("memory_resident")] + private long? _memoryResident; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("memory_page_faults")] + private long? _memoryPageFaults; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("memory_minor_faults")] + private long? _memoryMinorFaults; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("memory_major_faults")] + private long? _memoryMajorFaults; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("memory_share")] + private long? _memoryShare; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state_name")] + private string _stateName; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state_threads")] + private int? _stateThreads; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state_ppid")] + private int? _stateParentPid; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state_priority")] + private int? _statePriority; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("state_nice")] + private int? _stateNice; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("time_start_time")] + private long? _timeStartTime; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("time_sys")] + private long? _timeSys; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("time_total")] + private long? _timeTotal; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("time_user")] + private long? _timeUser; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ProcessInformation() + { + } + + /// + /// Gets the process ID. + /// + public int? ProcessId + { + get + { + return _pid; + } + } + + /// + /// Gets the path to the executable. + /// + public string ExecutableName + { + get + { + return _exeName; + } + } + + /// + /// Gets the root namespace of the process. + /// + public string ExecutableRoot + { + get + { + return _exeRoot; + } + } + + /// + /// Gets the current working directory of the process. + /// + public string CurrentDirectory + { + get + { + return _exeCwd; + } + } + + /// + /// Gets the group of the user who owns the process. + /// + public string OwnerGroup + { + get + { + return _credGroup; + } + } + + /// + /// Gets the user who owns the process. + /// + public string OwnerUser + { + get + { + return _credUser; + } + } + + /// + /// Gets the total address space of the process, in bytes. + /// + public long? MemorySize + { + get + { + return _memorySize; + } + } + + /// + /// Gets the total resident memory of the process, in bytes. + /// + public long? MemoryResident + { + get + { + return _memoryResident; + } + } + + /// + /// Gets the total number of faults. + /// + public long? MemoryPageFaults + { + get + { + return _memoryPageFaults; + } + } + + /// + /// Gets the total number of minor page faults. + /// + /// + /// Minor faults generally do not involve disk latency. + /// + public long? MemoryMinorFaults + { + get + { + return _memoryMinorFaults; + } + } + + /// + /// Gets the total number of major page faults. + /// + /// + /// Major faults generally involve disk latency. + /// + public long? MemoryMajorFaults + { + get + { + return _memoryMajorFaults; + } + } + + /// + /// Gets the total resident memory that is shared with other processes, in bytes. + /// + public long? MemoryShare + { + get + { + return _memoryShare; + } + } + + /// + /// Gets the name of the executable. + /// + public string Name + { + get + { + return _stateName; + } + } + + /// + /// Gets the number of threads the process owns. + /// + public int? ThreadCount + { + get + { + return _stateThreads; + } + } + + /// + /// Gets the parent process ID. + /// + public int? ParentProcessId + { + get + { + return _stateParentPid; + } + } + + /// + /// Gets the priority of the process. + /// + /// + /// Higher numbers indicate lower priority. + /// + public int? Priority + { + get + { + return _statePriority; + } + } + + /// + /// Gets the nice value set on the process. + /// + /// + /// Higher numbers indicate lower priority. + /// + /// + /// The nice value set on the process, or if nice is not set on the process. + /// + public int? Nice + { + get + { + return _stateNice; + } + } + + /// + /// Gets the start time of the process. + /// + public DateTimeOffset? StartTime + { + get + { + return DateTimeOffsetExtensions.ToDateTimeOffset(_timeStartTime); + } + } + + /// + /// Gets the total time spent executing system calls. + /// + public TimeSpan? SystemTime + { + get + { + if (_timeSys == null) + return null; + + return TimeSpan.FromMilliseconds(_timeSys.Value); + } + } + + /// + /// Gets the total time spent executing user code. + /// + public TimeSpan? UserTime + { + get + { + if (_timeUser == null) + return null; + + return TimeSpan.FromMilliseconds(_timeUser.Value); + } + } + + /// + /// Gets the total execution time of the process. + /// + public TimeSpan? TotalTime + { + get + { + if (_timeTotal == null) + return null; + + return TimeSpan.FromMilliseconds(_timeTotal.Value); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ReadOnlyCollectionPage`2.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ReadOnlyCollectionPage`2.cs new file mode 100644 index 000000000..cf5412325 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/ReadOnlyCollectionPage`2.cs @@ -0,0 +1,111 @@ +using System.Collections.ObjectModel; + +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using net.openstack.Core; + using net.openstack.Core.Collections; + using Newtonsoft.Json.Linq; + + /// + /// This class provides read-only access to a single page of results returned + /// by a paginated API call in the . + /// + /// The type of data in the list. + /// The type of marker used to identify the pages in this collection. + /// + /// + public class ReadOnlyCollectionPage : ReadOnlyCollectionPage + where TMarker : ResourceIdentifier + { + /// + /// This is the backing field for both and . + /// + private readonly Func>> _getNextPageAsync; + + /// + /// This is the backing field for the property. + /// + private IDictionary _metadata; + + /// + /// Initializes a new instance of the class + /// that is a read-only wrapper around the specified list and metadata. + /// + /// The list to wrap. + /// A function that returns a representing the asynchronous operation to get the next page of items in the collection. If specified, this function implements . If the value is , then will return . + /// The metadata associated with the list. + /// If is . + public ReadOnlyCollectionPage(IList list, Func>> getNextPageAsync, IDictionary metadata) + : base(list) + { + _getNextPageAsync = getNextPageAsync; + _metadata = metadata ?? new Dictionary(); + } + + /// + /// Gets a collection of metadata associated with the page of results. + /// + public ReadOnlyDictionary Metadata + { + get + { + return new ReadOnlyDictionary(_metadata); + } + } + + /// + /// Gets the marker for the current page. + /// + public TMarker Marker + { + get + { + object marker; + if (!_metadata.TryGetValue("marker", out marker) || marker == null) + return null; + + JToken token = JToken.FromObject(marker); + return token.ToObject(); + } + } + + /// + /// Gets the marker for the next page. + /// + public TMarker NextMarker + { + get + { + object marker; + if (!_metadata.TryGetValue("next_marker", out marker) || marker == null) + return null; + + JToken token = JToken.FromObject(marker); + return token.ToObject(); + } + } + + /// + public override bool CanHaveNextPage + { + get + { + return _getNextPageAsync != null && NextMarker != null; + } + } + + /// + public override Task> GetNextPageAsync(CancellationToken cancellationToken) + { + if (!CanHaveNextPage) + throw new InvalidOperationException("Cannot obtain the next page when CanHaveNextPage is false."); + + return _getNextPageAsync(NextMarker, cancellationToken) + .Select(task => (ReadOnlyCollectionPage)task.Result); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SecureConnectionCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SecureConnectionCheckDetails.cs new file mode 100644 index 000000000..0b41ddb3c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SecureConnectionCheckDetails.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class extends the class + /// for check types which may use an SSL secure connection. + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class SecureConnectionCheckDetails : ConnectionCheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("ssl", DefaultValueHandling = DefaultValueHandling.Ignore)] + private bool? _enableSsl; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected SecureConnectionCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port and SSL configuration. + /// + /// The port to use for connecting to the remote service. If this value is , the default port for the associated service should be used. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// If is less than or equal to 0, or if is greater than 65535. + protected SecureConnectionCheckDetails(int? port, bool? enableSsl) + : base(port) + { + _enableSsl = enableSsl; + } + + /// + /// Gets a value indicating whether an SSL connection should be used to connect to the service. + /// + public bool? EnableSsl + { + get + { + return _enableSsl; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SmtpBannerCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SmtpBannerCheckDetails.cs new file mode 100644 index 000000000..1c330ad49 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SmtpBannerCheckDetails.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class SmtpBannerCheckDetails : SecureConnectionCheckDetails + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected SmtpBannerCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port and SSL configuration. + /// + /// The port to use for connecting to the remote service. If this value is , the default port (25) for the associated service should be used. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// If is less than or equal to 0, or if is greater than 65535. + public SmtpBannerCheckDetails(int? port = null, bool? enableSsl = null) + : base(port, enableSsl) + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteSmtpBanner; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SmtpCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SmtpCheckDetails.cs new file mode 100644 index 000000000..799bd57e7 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SmtpCheckDetails.cs @@ -0,0 +1,140 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class SmtpCheckDetails : ConnectionCheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("ehlo", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _ehlo; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("from", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _from; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("to", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _to; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("payload", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _payload; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("starttls", DefaultValueHandling = DefaultValueHandling.Ignore)] + private bool? _startTls; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected SmtpCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified parameters. + /// + /// The port to use for connecting to the remote service. If this value is , the default port (25) for the associated service should be used. + /// The EHLO parameter of the SMTP message to send. + /// The From parameter of the SMTP message to send. + /// The To parameter of the SMTP message to send. If the value is , a quit is issued before sending a To line, and the connection is terminated. + /// The body of the message to send. + /// to use a TLS/SSL connection when connecting to the service; otherwise, . + /// If is less than or equal to 0, or if is greater than 65535. + public SmtpCheckDetails(int? port, string ehlo, string from, string to, string payload, bool? startTls) + : base(port) + { + _ehlo = ehlo; + _from = from; + _to = to; + _payload = payload; + _startTls = startTls; + } + + /// + /// Gets the EHLO parameter of the SMTP message to send. + /// + public string Ehlo + { + get + { + return _ehlo; + } + } + + /// + /// Gets the From parameter of the SMTP message to send. + /// + public string From + { + get + { + return _from; + } + } + + /// + /// Gets the To parameter of the SMTP message to send. + /// + public string To + { + get + { + return _to; + } + } + + /// + /// Gets the body of the message to send. + /// + public string Payload + { + get + { + return _payload; + } + } + + /// + /// Gets a value indicating whether a TLS/SSL connection should be used to connect to the service. + /// + public bool? StartTls + { + get + { + return _startTls; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteSmtp; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SshCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SshCheckDetails.cs new file mode 100644 index 000000000..5a01a0309 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SshCheckDetails.cs @@ -0,0 +1,45 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class SshCheckDetails : ConnectionCheckDetails + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected SshCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified port. + /// + /// The port number of the SSH service. If this value is , the default value (22) for the service is used. + /// If is less than or equal to 0, or if is greater than 65535. + public SshCheckDetails(int? port = null) + : base(port) + { + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteSsh; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SystemInformation.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SystemInformation.cs new file mode 100644 index 000000000..d8935573c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/SystemInformation.cs @@ -0,0 +1,112 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of the system data reported agents for + /// the information type. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class SystemInformation : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("arch")] + private string _arch; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("name")] + private string _name; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("vendor")] + private string _vendor; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("vendor_version")] + private string _vendorVersion; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("version")] + private string _version; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected SystemInformation() + { + } + + /// + /// Gets the CPU architecture. + /// + public string Architecture + { + get + { + return _arch; + } + } + + /// + /// Gets the generic name of the operating system. + /// + public string Name + { + get + { + return _name; + } + } + + /// + /// Gets the name of the vendor. + /// + public string Vendor + { + get + { + return _vendor; + } + } + + /// + /// Gets the vendor version name. + /// + public string VendorVersion + { + get + { + return _vendorVersion; + } + } + + /// + /// Gets the version. + /// + public string Version + { + get + { + return _version; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TargetResolverType.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TargetResolverType.cs new file mode 100644 index 000000000..5aeafa294 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TargetResolverType.cs @@ -0,0 +1,88 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Concurrent; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents a target resolver type in the monitoring service. + /// + /// + /// This class functions as a strongly-typed enumeration of known target resolver types, + /// with added support for unknown types supported by a server extension. + /// + /// + /// + [JsonConverter(typeof(TargetResolverType.Converter))] + public sealed class TargetResolverType : ExtensibleEnum + { + private static readonly ConcurrentDictionary _types = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly TargetResolverType _ipv4 = FromName("IPv4"); + private static readonly TargetResolverType _ipv6 = FromName("IPv6"); + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// + private TargetResolverType(string name) + : base(name) + { + } + + /// + /// Gets the instance with the specified name. + /// + /// The name. + /// The unique instance with the specified name. + /// If is . + /// If is empty. + public static TargetResolverType FromName(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("name cannot be empty"); + + return _types.GetOrAdd(name, i => new TargetResolverType(i)); + } + + /// + /// Gets a representing a resolver that resolves hostnames to IP V4 addresses. + /// + public static TargetResolverType IPv4 + { + get + { + return _ipv4; + } + } + + /// + /// Gets a representing a resolver that resolves hostnames to IP V6 addresses. + /// + public static TargetResolverType IPv6 + { + get + { + return _ipv6; + } + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override TargetResolverType FromName(string name) + { + return TargetResolverType.FromName(name); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TcpCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TcpCheckDetails.cs new file mode 100644 index 000000000..4fcf545f2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TcpCheckDetails.cs @@ -0,0 +1,103 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class TcpCheckDetails : SecureConnectionCheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("banner_match", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _bannerMatch; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("body_match", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _bodyMatch; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("send_body", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _sendBody; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected TcpCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the values. + /// + /// The port to use for connecting to the remote service. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// A regular expression to match against the TCP banner returned by the service. + /// A regular expression to match against the TCP body returned by the service. + /// The body to send to the service after the banner is verified. + /// If is less than or equal to 0, or if is greater than 65535. + public TcpCheckDetails(int port, bool? enableSsl = null, string bannerMatch = null, string bodyMatch = null, string sendBody = null) + : base(port, enableSsl) + { + _bannerMatch = bannerMatch; + _bodyMatch = bodyMatch; + _sendBody = sendBody; + } + + /// + /// Gets the regular expression to match against the TCP banner returned by the service. + /// + public string BannerMatch + { + get + { + return _bannerMatch; + } + } + + /// + /// Gets the regular expression to match against the TCP body returned by the service. + /// + public string BodyMatch + { + get + { + return _bodyMatch; + } + } + + /// + /// Gets the body to send to the service after the banner is verified. + /// + public string SendBody + { + get + { + return _sendBody; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteTcp; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TelnetBannerCheckDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TelnetBannerCheckDetails.cs new file mode 100644 index 000000000..f80c52e15 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TelnetBannerCheckDetails.cs @@ -0,0 +1,65 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class represents the detailed configuration parameters for a + /// check. + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class TelnetBannerCheckDetails : SecureConnectionCheckDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("banner_match", DefaultValueHandling = DefaultValueHandling.Ignore)] + private string _bannerMatch; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected TelnetBannerCheckDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the values. + /// + /// The port to use for connecting to the remote service. + /// to enable SSL for connecting to the service; otherwise, . If this value is , a provider-specific default value is used. + /// A regular expression to match against the telnet banner returned by the service. If this value is , the behavior of the service is unspecified. + /// If is less than or equal to 0, or if is greater than 65535. + public TelnetBannerCheckDetails(int port, bool? enableSsl = null, string bannerMatch = null) + : base(port, enableSsl) + { + _bannerMatch = bannerMatch; + } + + /// + /// Gets the regular expression to match against the telnet banner returned by the remote service. + /// + public string BannerMatch + { + get + { + return _bannerMatch; + } + } + + /// + /// + /// This class only supports checks. + /// + protected internal override bool SupportsCheckType(CheckTypeId checkTypeId) + { + return checkTypeId == CheckTypeId.RemoteTelnetBanner; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TestAlarmConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TestAlarmConfiguration.cs new file mode 100644 index 000000000..b6c9bd373 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TestAlarmConfiguration.cs @@ -0,0 +1,98 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a request to test an alarm + /// in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class TestAlarmConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("criteria")] + private string _criteria; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("check_data")] + private CheckData[] _checkData; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected TestAlarmConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The alarm DSL for describing alerting conditions and their output states. + /// A collection of objects describing the result of running a check. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is contains any values. + /// + public TestAlarmConfiguration(string criteria, IEnumerable checkData) + { + if (criteria == null) + throw new ArgumentNullException("criteria"); + if (checkData == null) + throw new ArgumentNullException("checkData"); + if (string.IsNullOrEmpty(criteria)) + throw new ArgumentException("criteria cannot be empty"); + if (checkData.Contains(null)) + throw new ArgumentException("checkData cannot contain any null values", "checkData"); + + _criteria = criteria; + _checkData = checkData.ToArray(); + } + + /// + /// Gets the alarm DSL describing alerting conditions and their output states. + /// + public string Criteria + { + get + { + return _criteria; + } + } + + /// + /// Gets a collection of instances describing the results + /// of running a check. + /// + public ReadOnlyCollection CheckData + { + get + { + if (_checkData == null) + return null; + + return new ReadOnlyCollection(_checkData); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRoute.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRoute.cs new file mode 100644 index 000000000..143a2e03b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRoute.cs @@ -0,0 +1,49 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System.Collections.ObjectModel; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON result of a traceroute operation from + /// a monitoring zone in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class TraceRoute : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("result")] + private TraceRouteHop[] _hops; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected TraceRoute() + { + } + + /// + /// Gets a collection of objects describing the + /// results of each hop in the traceroute. + /// + public ReadOnlyCollection Hops + { + get + { + if (_hops == null) + return null; + + return new ReadOnlyCollection(_hops); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRouteConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRouteConfiguration.cs new file mode 100644 index 000000000..a53ab8336 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRouteConfiguration.cs @@ -0,0 +1,98 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Net; + using System.Net.Sockets; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a request to perform a traceroute + /// from a monitoring zone in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class TraceRouteConfiguration : ExtensibleJsonObject + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("target")] + private string _target; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("target_resolver")] + private TargetResolverType _targetResolver; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected TraceRouteConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified target address. + /// + /// The IP address to target for the traceroute operation. + /// If is . + /// If the of is not or . + public TraceRouteConfiguration(IPAddress target) + { + if (target == null) + throw new ArgumentNullException("target"); + if (target.AddressFamily != AddressFamily.InterNetwork && target.AddressFamily != AddressFamily.InterNetworkV6) + throw new NotSupportedException("The family of the target address is not supported."); + + _target = target.ToString(); + } + + /// + /// Initializes a new instance of the class + /// with the specified target and resolver type. + /// + /// The target for the traceroute operation. + /// The type of resolver to use for resolving the target to an IP address. + /// If is . + /// If is empty. + public TraceRouteConfiguration(string target, TargetResolverType resolverType) + { + if (target == null) + throw new ArgumentNullException("target"); + if (string.IsNullOrEmpty(target)) + throw new ArgumentException("target cannot be empty"); + + _target = target; + _targetResolver = resolverType; + } + + /// + /// Gets the target of the traceroute operation. + /// + public string Target + { + get + { + return _target; + } + } + + /// + /// Gets the type of resolver to use for resolving the target to an IP address. + /// + public TargetResolverType ResolverType + { + get + { + return _targetResolver; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRouteHop.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRouteHop.cs new file mode 100644 index 000000000..3de90c879 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TraceRouteHop.cs @@ -0,0 +1,138 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.ObjectModel; + using System.Net; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + using ExtensibleJsonObject = net.openstack.Core.Domain.ExtensibleJsonObject; + + /// + /// This class models the JSON representation of a single hop in the + /// result of a traceroute operation in the . + /// + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class TraceRouteHop : ExtensibleJsonObject + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("number")] + private int? _number; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("ip")] + [JsonConverter(typeof(IPAddressConverter))] + private IPAddress _ip; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("hostname")] + private string _hostname; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("rtts")] + private double[] _responseTimes; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected TraceRouteHop() + { + } + + /// + /// Gets the index of this hop in the trace. + /// + /// + /// The first hop in the trace has =1. + /// + /// Hop numbers may repeat themselves in , which + /// just indicates a split in the route. + /// + /// + public int? Number + { + get + { + return _number; + } + } + + /// + /// Gets the IP address for this hop in the trace. + /// + public IPAddress IPAddress + { + get + { + return _ip; + } + } + + /// + /// Gets the hostname associated in reverse DNS of this hop in the trace. + /// + public string Hostname + { + get + { + return _hostname; + } + } + + /// + /// Gets the response times for ping operations to this hop in the trace. + /// + public ReadOnlyCollection ResponseTimes + { + get + { + if (_responseTimes == null) + return null; + + return new ReadOnlyCollection(Array.ConvertAll(_responseTimes, TimeSpan.FromSeconds)); + } + } + + /// + /// This implementation of allows for JSON serialization + /// and deserialization of objects using a simple string + /// representation. Serialization is performed using , + /// and deserialization is performed using . + /// + /// + /// + protected class IPAddressConverter : IPAddressSimpleConverter + { + /// + /// If is an empty string or equal to *, this method returns . + /// Otherwise, this method uses for deserialization. + /// + /// + protected override IPAddress ConvertToObject(string str) + { + if (string.IsNullOrEmpty(str)) + return null; + + if (str == "*") + return null; + + return base.ConvertToObject(str); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TransactionId.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TransactionId.cs new file mode 100644 index 000000000..7a92b4f72 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/TransactionId.cs @@ -0,0 +1,41 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a transaction in the . + /// + /// + /// + [JsonConverter(typeof(TransactionId.Converter))] + public sealed class TransactionId : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The transaction identifier value. + /// If is . + /// If is empty. + public TransactionId(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override TransactionId FromValue(string id) + { + return new TransactionId(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateAlarmConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateAlarmConfiguration.cs new file mode 100644 index 000000000..0a9ed2681 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateAlarmConfiguration.cs @@ -0,0 +1,44 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to update the properties + /// of an resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UpdateAlarmConfiguration : AlarmConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected UpdateAlarmConfiguration() + { + } + + /// + /// Initializes a new instance of the class with the specified + /// values. + /// + /// The ID of the check to alert on. This is obtained from Check.Id. If this value is , the existing value for the alarm is not changed. + /// The ID of the notification plan to execute when the state changes. This is obtained from NotificationPlan.Id. If this value is , the existing value for the alarm is not changed. + /// The alarm DSL for describing alerting conditions and their output states. If this value is , the existing value for the alarm is not changed. + /// to enable processing and alerts on this alarm; otherwise, . If this value is , the existing value for the alarm is not changed. + /// A friendly label for the alarm. If this value is , the existing value for the alarm is not changed. + /// A collection of metadata to associate with the alarm. If this value is , the existing value for the alarm is not changed. + /// + /// If contains any values with empty keys. + /// + public UpdateAlarmConfiguration(CheckId checkId = null, NotificationPlanId notificationPlanId = null, string criteria = null, bool? enabled = null, string label = null, IDictionary metadata = null) + : base(checkId, notificationPlanId, criteria, enabled, label, metadata) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateCheckConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateCheckConfiguration.cs new file mode 100644 index 000000000..763771f43 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateCheckConfiguration.cs @@ -0,0 +1,68 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to update the properties + /// of a resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UpdateCheckConfiguration : CheckConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected UpdateCheckConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The friendly name of the check. If this value is , the existing value for the check is not changed. + /// The check type ID. This is obtained from CheckType.Id, or from the predefined values in . If this value is , the existing value for the check is not changed. + /// A object containing detailed configuration information for the specific check type. If this value is , the existing value for the check is not changed. + /// A collection of objects identifying the monitoring zones to poll from. If this value is , the existing value for the check is not changed. + /// The timeout of a check operation. If this value is , the existing value for the check is not changed. + /// The period between check operations. If this value is , the existing value for the check is not changed. + /// The alias of the target for this check in the associated entity's map. If this value is , the existing value for the check is not changed. + /// The hostname this check should target. If this value is , the existing value for the check is not changed. + /// The type of resolver to use for converting to an IP address. If this value is , the existing value for the check is not changed. + /// A collection of metadata to associate with the check. If this value is , the existing value for the check is not changed. + /// + /// If is non- but empty. + /// -or- + /// If the specified object does support checks of type . + /// -or- + /// If contains any values. + /// -or- + /// If is less than or equal to . + /// -or- + /// If is non- but empty. + /// -or- + /// If is non- but empty. + /// -or- + /// If contains any empty keys. + /// + /// + /// If is less than or equal to . + /// -or- + /// If is less than or equal to . + /// + /// + /// If and are both non-. + /// + public UpdateCheckConfiguration(string label = null, CheckTypeId checkTypeId = null, CheckDetails details = null, IEnumerable monitoringZonesPoll = null, TimeSpan? timeout = null, TimeSpan? period = null, string targetAlias = null, string targetHostname = null, TargetResolverType resolverType = null, IDictionary metadata = null) + : base(label, checkTypeId, details, monitoringZonesPoll, timeout, period, targetAlias, targetHostname, resolverType, metadata) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateEntityConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateEntityConfiguration.cs new file mode 100644 index 000000000..b7f0acd8b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateEntityConfiguration.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + using IPAddress = System.Net.IPAddress; + + /// + /// This class models the JSON representation of a request to update the properties + /// of an resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UpdateEntityConfiguration : EntityConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected UpdateEntityConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified values. + /// + /// The name for the entity. If this parameter is , the name for the entity is not changed. + /// The agent which this entity is bound to. If this parameter is , the agent for the entity is not changed. + /// The IP addresses which can be referenced by checks on this entity. If this parameter is , the IP addresses for the entity are not changed. + /// A collection of metadata to associate with the entity. If this parameter is , the metadata for the entity is not changed. + /// + /// If is empty. + /// -or- + /// If contains any empty keys, or any values. + /// -or- + /// If contains any empty keys, or any values. + /// + public UpdateEntityConfiguration(string label = null, AgentId agentId = null, IDictionary ipAddresses = null, IDictionary metadata = null) + : base(label, agentId, ipAddresses, metadata) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateNotificationConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateNotificationConfiguration.cs new file mode 100644 index 000000000..bf948cdd1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateNotificationConfiguration.cs @@ -0,0 +1,48 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to update the properties + /// of a resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UpdateNotificationConfiguration : NotificationConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected UpdateNotificationConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The friendly name of the notification. If this value is , the existing value for the notification is not changed. + /// The notification type ID. This is obtained from NotificationType.Id, or from the predefined values in . If this value is , the existing value for the notification is not changed. + /// A object containing the detailed configuration properties for the specified notification type. If this value is , the existing value for the notification is not changed. + /// A collection of metadata to associate with the notification. If this value is , the existing value for the notification is not changed. + /// + /// If is empty. + /// -or- + /// If is non- and is . + /// -or- + /// If does not support notifications of type . + /// -or- + /// If contains any empty keys. + /// + public UpdateNotificationConfiguration(string label = null, NotificationTypeId notificationTypeId = null, NotificationDetails details = null, IDictionary metadata = null) + : base(label, notificationTypeId, details, metadata) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateNotificationPlanConfiguration.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateNotificationPlanConfiguration.cs new file mode 100644 index 000000000..1dd2056f2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/UpdateNotificationPlanConfiguration.cs @@ -0,0 +1,51 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// This class models the JSON representation of a request to update the properties + /// of a resource in the . + /// + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class UpdateNotificationPlanConfiguration : NotificationPlanConfiguration + { + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected UpdateNotificationPlanConfiguration() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified properties. + /// + /// The label for the notification plan. If this value is , the existing value for the notification plan is not changed. + /// The notification list to send to when the state is . If this value is , the existing value for the notification plan is not changed. + /// The notification list to send to when the state is . If this value is , the existing value for the notification plan is not changed. + /// The notification list to send to when the state is . If this value is , the existing value for the notification plan is not changed. + /// The metadata to associate with the notification plan. If this value is , the existing value for the notification plan is not changed. + /// + /// If is non- but empty. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// -or- + /// If contains any values. + /// -or- + /// If contains any empty keys. + /// + public UpdateNotificationPlanConfiguration(string label = null, IEnumerable criticalState = null, IEnumerable warningState = null, IEnumerable okState = null, IDictionary metadata = null) + : base(label, criticalState, warningState, okState, metadata) + { + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/WebhookNotificationDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/WebhookNotificationDetails.cs new file mode 100644 index 000000000..f0176266f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/WebhookNotificationDetails.cs @@ -0,0 +1,67 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using Newtonsoft.Json; + + /// + /// This class extends with properties specific to + /// notifications. + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class WebhookNotificationDetails : NotificationDetails + { + /// + /// This is the backing field for the property. + /// + [JsonProperty("url")] + private string _url; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected WebhookNotificationDetails() + { + } + + /// + /// Initializes a new instance of the class + /// with the specified target URI. + /// + /// The URI of the webhook to notify. + /// If is . + public WebhookNotificationDetails(Uri url) + { + if (url == null) + throw new ArgumentNullException("url"); + + _url = url.ToString(); + } + + /// + /// Gets the URI a POST request will be sent to for this notification. + /// + public Uri Url + { + get + { + if (_url == null) + return null; + + return new Uri(_url); + } + } + + /// + /// + /// This class only supports notifications. + /// + protected internal override bool SupportsNotificationType(NotificationTypeId notificationTypeId) + { + return notificationTypeId == NotificationTypeId.Webhook; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Monitoring/WebhookToken.cs b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/WebhookToken.cs new file mode 100644 index 000000000..f1a368942 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Monitoring/WebhookToken.cs @@ -0,0 +1,42 @@ +namespace net.openstack.Providers.Rackspace.Objects.Monitoring +{ + using System; + using net.openstack.Core; + using Newtonsoft.Json; + + /// + /// Represents the unique identifier of a webhook token in the . + /// + /// + /// + /// + [JsonConverter(typeof(WebhookToken.Converter))] + public sealed class WebhookToken : ResourceIdentifier + { + /// + /// Initializes a new instance of the class + /// with the specified identifier value. + /// + /// The webhook token identifier value. + /// If is . + /// If is empty. + public WebhookToken(string id) + : base(id) + { + } + + /// + /// Provides support for serializing and deserializing + /// objects to JSON string values. + /// + /// + private sealed class Converter : ConverterBase + { + /// + protected override WebhookToken FromValue(string id) + { + return new WebhookToken(id); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/NamespaceDoc.cs new file mode 100644 index 000000000..6be5551c9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Providers.Rackspace.Objects +{ + using System.Runtime.CompilerServices; + + /// + /// The namespaces define + /// the object model for communicating with Rackspace services over REST APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Queues/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Queues/NamespaceDoc.cs new file mode 100644 index 000000000..0d1f1638f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Queues/NamespaceDoc.cs @@ -0,0 +1,13 @@ +namespace net.openstack.Providers.Rackspace.Objects.Queues +{ + using System.Runtime.CompilerServices; + + /// + /// The namespaces define + /// the object model for communicating with Rackspace's Cloud Queues service over REST APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Queues/Request/ClaimMessagesRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Queues/Request/ClaimMessagesRequest.cs new file mode 100644 index 000000000..4172c023b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Queues/Request/ClaimMessagesRequest.cs @@ -0,0 +1,28 @@ +namespace net.openstack.Providers.Rackspace.Objects.Queues.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ClaimMessagesRequest + { + [JsonProperty("ttl")] + private long _ttl; + + [JsonProperty("grace")] + private long _gracePeriod; + + public ClaimMessagesRequest(TimeSpan timeToLive, TimeSpan gracePeriod) + { + if (timeToLive < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("timeToLive"); + if (gracePeriod < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("gracePeriod"); + + _ttl = (long)timeToLive.TotalSeconds; + _gracePeriod = (long)gracePeriod.TotalSeconds; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Queues/Request/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Queues/Request/NamespaceDoc.cs new file mode 100644 index 000000000..6b34ffc99 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Queues/Request/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Objects.Queues.Request +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace + /// contains the object models for JSON request bodies sent in calls to Rackspace's + /// Cloud Queues API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/ListCloudQueueMessagesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/ListCloudQueueMessagesResponse.cs new file mode 100644 index 000000000..7de8b736a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/ListCloudQueueMessagesResponse.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Queues.Response +{ + using System.Collections.ObjectModel; + using net.openstack.Core.Domain; + using net.openstack.Core.Domain.Queues; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListCloudQueueMessagesResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + [JsonProperty("links")] + private Link[] _links; + + [JsonProperty("messages")] + private QueuedMessage[] _messages; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListCloudQueueMessagesResponse() + { + } + + public ReadOnlyCollection Links + { + get + { + if (_links == null) + return null; + + return new ReadOnlyCollection(_links); + } + } + + public ReadOnlyCollection Messages + { + get + { + if (_messages == null) + return null; + + return new ReadOnlyCollection(_messages); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/ListCloudQueuesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/ListCloudQueuesResponse.cs new file mode 100644 index 000000000..5f1010675 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/ListCloudQueuesResponse.cs @@ -0,0 +1,45 @@ +namespace net.openstack.Providers.Rackspace.Objects.Queues.Response +{ + using net.openstack.Core.Domain; + using net.openstack.Core.Domain.Queues; + using Newtonsoft.Json; + + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListCloudQueuesResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + [JsonProperty("links")] + private Link[] _links; + + [JsonProperty("queues")] + private CloudQueue[] _queues; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ListCloudQueuesResponse() + { + } + + public Link[] Links + { + get + { + return _links; + } + } + + public CloudQueue[] Queues + { + get + { + return _queues; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/NamespaceDoc.cs new file mode 100644 index 000000000..7b4d4a850 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Queues/Response/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Objects.Queues.Response +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace + /// contains the object models for JSON responses returned by calls to Rackspace's + /// Cloud Queues API. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/RackspaceCloudIdentity.cs b/src/OpenStack/Providers/Rackspace/Objects/RackspaceCloudIdentity.cs new file mode 100644 index 000000000..2bb2fd3ac --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/RackspaceCloudIdentity.cs @@ -0,0 +1,52 @@ +using net.openstack.Core.Domain; + +namespace net.openstack.Providers.Rackspace.Objects +{ + using System; + + /// + /// Extends the class by adding support for specifying + /// a for the identity. + /// + /// + public class RackspaceCloudIdentity : CloudIdentity + { + /// + /// Initializes a new instance of the class + /// with the default values. + /// + public RackspaceCloudIdentity() + { + } + + /// + /// Initializes a new instance of the class + /// from the given instance. + /// + /// The generic cloud identity. + /// If is . + public RackspaceCloudIdentity(CloudIdentity cloudIdentity) : this() + { + if (cloudIdentity == null) + throw new ArgumentNullException("cloudIdentity"); + + this.Username = cloudIdentity.Username; + this.Password = cloudIdentity.Password; + this.APIKey = cloudIdentity.APIKey; + + RackspaceCloudIdentity raxIdentity = cloudIdentity as RackspaceCloudIdentity; + if (raxIdentity != null) + this.Domain = raxIdentity.Domain; + } + + /// + /// Gets or sets the for this account. + /// + /// + /// The class represents credentials (as opposed + /// to an account), so any changes made to this property value will not be + /// reflected in the account. + /// + public Domain Domain { get; set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/AddRoleRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/AddRoleRequest.cs new file mode 100644 index 000000000..11c58c92d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/AddRoleRequest.cs @@ -0,0 +1,35 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Add Role request. + /// + /// Add Role (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class AddRoleRequest + { + /// + /// Gets additional information about the role to add. + /// + [JsonProperty("role")] + public Role Role { get; private set; } + + /// + /// Initializes a new instance of the class for the + /// specified . + /// + /// The role. + /// If is . + public AddRoleRequest(Role role) + { + if (role == null) + throw new ArgumentNullException("role"); + + Role = role; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/AddServiceCatalogEndpointRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/AddServiceCatalogEndpointRequest.cs new file mode 100644 index 000000000..44cfcf415 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/AddServiceCatalogEndpointRequest.cs @@ -0,0 +1,75 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Add endpoint HTTP API request in the OpenStack + /// Identity Service V2. + /// + /// + /// This object is part of the OS-KSCATALOG extension to the OpenStack Identity Service V2. + /// + /// OS-KSCATALOG admin extension (Identity API v2.0 - OpenStack Complete API Reference) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class AddServiceCatalogEndpointRequest + { + /// + /// This is the backing field for the property. + /// + /// + /// This API call wraps the endpoint template identifier inside an "EndpointTemplateWithOnlyId" + /// resource. + /// + [JsonProperty("OS-KSCATALOG:endpointTemplate", DefaultValueHandling = DefaultValueHandling.Ignore)] + private EndpointTemplate _endpointTemplate; + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected AddServiceCatalogEndpointRequest() + { + } + + /// + /// Initializes a new instance of the class with the specified + /// endpoint template identifier. + /// + /// + /// The unique identifier of the endpoint template to use for the endpoint. + /// + /// + /// If is . + /// + public AddServiceCatalogEndpointRequest(EndpointTemplateId endpointTemplateId) + { + if (endpointTemplateId == null) + throw new ArgumentNullException("endpointTemplateId"); + + _endpointTemplate = new EndpointTemplate(endpointTemplateId); + } + + /// + /// Gets the unique identifier of the endpoint template to use when creating the endpoint. + /// + /// + /// The unique identifier of the endpoint template to use when creating the endpoint. + /// NullIfNotIncluded + /// + public EndpointTemplateId EndpointTemplateId + { + get + { + if (_endpointTemplate == null) + return null; + + return _endpointTemplate.Id; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/AddUserRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/AddUserRequest.cs new file mode 100644 index 000000000..16324d272 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/AddUserRequest.cs @@ -0,0 +1,35 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Add User request. + /// + /// Add User (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class AddUserRequest + { + /// + /// Gets additional information about the user to add. + /// + [JsonProperty("user")] + public NewUser User { get; private set; } + + /// + /// Initializes a new instance of the class for the + /// specified . + /// + /// The user. + /// If is . + public AddUserRequest(NewUser user) + { + if (user == null) + throw new ArgumentNullException("user"); + + User = user; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/AttachServerVolumeRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/AttachServerVolumeRequest.cs new file mode 100644 index 000000000..6b7033dfc --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/AttachServerVolumeRequest.cs @@ -0,0 +1,86 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Attach Volume to Server request. + /// + /// Attach Volume to Server (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class AttachServerVolumeRequest + { + /// + /// Gets additional information about the volume to attach. + /// + [JsonProperty("volumeAttachment")] + public AttachServerVolumeData ServerVolumeData { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the given device name and volume ID. + /// + /// + /// The name of the device, such as /dev/xvdb. If the value + /// is , an automatically generated device name will be used. + /// + /// The volume ID. This is obtained from . + /// If is . + /// If is empty. + public AttachServerVolumeRequest(string device, string volumeId) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + + ServerVolumeData = new AttachServerVolumeData(device, volumeId); + } + + /// + /// This models the JSON body containing the details of the Attach Volume to Server request. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class AttachServerVolumeData + { + /// + /// Gets the name of the device, such as /dev/xvdb. + /// If the value is , the server automatically assigns a device + /// name. + /// + [JsonProperty("device")] + public string Device { get; private set; } + + /// + /// Gets the ID of the volume to attach to the server instance. + /// + [JsonProperty("volumeId")] + public string VolumeId { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the given device name and volume ID. + /// + /// + /// The name of the device, such as /dev/xvdb. If the value + /// is , an automatically generated device name will be used. + /// + /// The volume ID. This is obtained from . + /// If is . + /// If is empty. + public AttachServerVolumeData(string device, string volumeId) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + + Device = device; + VolumeId = volumeId; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/AuthRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/AuthRequest.cs new file mode 100644 index 000000000..84367a6fb --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/AuthRequest.cs @@ -0,0 +1,46 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Authenticate request. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class AuthRequest + { + /// + /// Gets additional information about the credentials to authenticate. + /// + [JsonProperty("auth")] + public AuthDetails Credentials { get; private set; } + + /// + /// Initializes a new instance of the class with the + /// given identity. + /// + /// The identity of the user to authenticate. + /// If is . + /// If given type is not supported. + public AuthRequest(CloudIdentity identity) + { + if (identity == null) + throw new ArgumentNullException("identity"); + + var credentials = new AuthDetails(); + if (string.IsNullOrEmpty(identity.Password)) + credentials.APIKeyCredentials = new Credentials(identity.Username, null, identity.APIKey); + else + credentials.PasswordCredentials = new Credentials(identity.Username, identity.Password, null); + + var raxIdentity = identity as RackspaceCloudIdentity; + if (raxIdentity != null) + credentials.Domain = raxIdentity.Domain; + + Credentials = credentials; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/ChangeServerAdminPasswordRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/ChangeServerAdminPasswordRequest.cs new file mode 100644 index 000000000..416edaf57 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/ChangeServerAdminPasswordRequest.cs @@ -0,0 +1,64 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Change Administrator Password request. + /// + /// Change Administrator Password (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ChangeServerAdminPasswordRequest + { + /// + /// Gets additional information about the new password to assign to the server. + /// + [JsonProperty("changePassword")] + public ChangeAdminPasswordDetails Details { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the given password. + /// + /// The new password to use on the server. + public ChangeServerAdminPasswordRequest(string password) + { + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + + Details = new ChangeAdminPasswordDetails(password); + } + + /// + /// This models the JSON body containing the details of the Change Administrator Password request. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ChangeAdminPasswordDetails + { + /// + /// Gets the new password to assign to the server. + /// + [JsonProperty("adminPass")] + public string AdminPassword { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the given password. + /// + /// The new password to use on the server. + public ChangeAdminPasswordDetails(string password) + { + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + + AdminPassword = password; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/ConfirmServerResizeRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/ConfirmServerResizeRequest.cs new file mode 100644 index 000000000..d26abccc1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/ConfirmServerResizeRequest.cs @@ -0,0 +1,18 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Confirm Resized Server request. + /// + /// Confirm Resized Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ConfirmServerResizeRequest + { +#pragma warning disable 414 // The field 'fieldName' is assigned but its value is never used + [JsonProperty("confirmResize")] + private string _command = "none"; +#pragma warning restore 414 + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageSnapshotDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageSnapshotDetails.cs new file mode 100644 index 000000000..50f4e0e46 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageSnapshotDetails.cs @@ -0,0 +1,65 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON body containing details for the Create Snapshot request. + /// + /// + /// Create Snapshot (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateCloudBlockStorageSnapshotDetails + { + /// + /// Gets the ID of the volume to snapshot. + /// + [JsonProperty("volume_id")] + public string VolumeId { get; private set; } + + /// + /// Gets a value indicating whether to create the snapshot even while the volume is attached to an active server. + /// + /// to create the snapshot even if the server is running; otherwise, . + [JsonProperty("force")] + public bool Force { get; private set; } + + /// + /// Gets the display name of the snapshot. + /// + [JsonProperty("display_name")] + public string DisplayName { get; private set; } + + /// + /// Gets the display description of the snapshot. + /// + [JsonProperty("display_description")] + public string DisplayDescription { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified volume ID, name, description, and value indicating whether or + /// not to create the snapshot even if the volume is attached to an active server. + /// + /// The ID of the volume to snapshot. The value should be obtained from Volume.Id. + /// to create the snapshot even if the volume is attached to an active server; otherwise, . + /// Name of the snapshot. + /// Description of snapshot. + /// If is . + /// If is empty. + public CreateCloudBlockStorageSnapshotDetails(string volumeId, bool force, string displayName, string displayDescription) + { + if (volumeId == null) + throw new ArgumentNullException("volumeId"); + if (string.IsNullOrEmpty(volumeId)) + throw new ArgumentException("volumeId cannot be empty"); + + VolumeId = volumeId; + Force = force; + DisplayName = displayName; + DisplayDescription = displayDescription; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageSnapshotRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageSnapshotRequest.cs new file mode 100644 index 000000000..631a1d235 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageSnapshotRequest.cs @@ -0,0 +1,34 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Create Snapshot request. + /// + /// Create Snapshot (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateCloudBlockStorageSnapshotRequest + { + /// + /// Gets additional details about the Create Snapshot request. + /// + [JsonProperty("snapshot")] + public CreateCloudBlockStorageSnapshotDetails CreateCloudBlockStorageSnapshotDetails { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified details. + /// + /// The details of the request. + /// If is . + public CreateCloudBlockStorageSnapshotRequest(CreateCloudBlockStorageSnapshotDetails details) + { + if (details == null) + throw new ArgumentNullException("details"); + + CreateCloudBlockStorageSnapshotDetails = details; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageVolumeDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageVolumeDetails.cs new file mode 100644 index 000000000..93119831a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageVolumeDetails.cs @@ -0,0 +1,70 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON body containing details for the Create Volume request. + /// + /// + /// Create Volume (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateCloudBlockStorageVolumeDetails + { + /// + /// Gets the size of the volume in GB. + /// + [JsonProperty("size")] + public int Size { get; private set; } + + /// + /// Gets the display description of the volume. + /// + [JsonProperty("display_description")] + public string DisplayDescription { get; private set; } + + /// + /// Gets the display name of the volume. + /// + [JsonProperty("display_name")] + public string DisplayName { get; private set; } + + /// + /// Gets the ID of the snapshot to create the volume from, if any. + /// + /// The ID of the snapshot to create the volume from, or if the volume is not created from a snapshot. + /// + [JsonProperty("snapshot_id")] + public string SnapshotId { get; private set; } + + /// + /// Gets the ID of the type of volume to create. + /// + /// + [JsonProperty("volume_type")] + public string VolumeType { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The size of the volume in GB. + /// A description of the volume. + /// The name of the volume. + /// The snapshot from which to create a volume. The value should be or obtained from Snapshot.Id. + /// The type of volume to create. If not defined, then the default is used. The value should be or obtained from VolumeType.Id. + /// If is less than or equal to zero. + public CreateCloudBlockStorageVolumeDetails(int size, string displayDescription, string displayName, string snapshotId, string volumeType) + { + if (size <= 0) + throw new ArgumentOutOfRangeException("size"); + + Size = size; + DisplayDescription = displayDescription; + DisplayName = displayName; + SnapshotId = snapshotId; + VolumeType = volumeType; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageVolumeRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageVolumeRequest.cs new file mode 100644 index 000000000..0c43dfc0f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudBlockStorageVolumeRequest.cs @@ -0,0 +1,34 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Create Volume request. + /// + /// Create Volume (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateCloudBlockStorageVolumeRequest + { + /// + /// Gets additional details about the Create Volume request. + /// + [JsonProperty("volume")] + public CreateCloudBlockStorageVolumeDetails CreateCloudBlockStorageVolumeDetails { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified details. + /// + /// The details of the request. + /// If is . + public CreateCloudBlockStorageVolumeRequest(CreateCloudBlockStorageVolumeDetails details) + { + if (details == null) + throw new ArgumentNullException("details"); + + CreateCloudBlockStorageVolumeDetails = details; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudNetworkRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudNetworkRequest.cs new file mode 100644 index 000000000..30f974d32 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudNetworkRequest.cs @@ -0,0 +1,34 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Create Network request. + /// + /// Create Network (OpenStack Networking API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateCloudNetworkRequest + { + /// + /// Gets additional details about the Create Network request. + /// + [JsonProperty("network")] + public CreateCloudNetworksDetails Details { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified details. + /// + /// The details of the request. + /// If is . + public CreateCloudNetworkRequest(CreateCloudNetworksDetails details) + { + if (details == null) + throw new ArgumentNullException("details"); + + Details = details; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudNetworksDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudNetworksDetails.cs new file mode 100644 index 000000000..9525dc4e3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateCloudNetworksDetails.cs @@ -0,0 +1,58 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON body containing details for the Create Network request. + /// + /// + /// Create Network (OpenStack Networking API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateCloudNetworksDetails + { + /// + /// Gets the CIDR for the network. + /// + [JsonProperty("cidr")] + public string Cidr { get; private set; } + + /// + /// Gets the name of the network. + /// + [JsonProperty("label")] + public string Label { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified CIDR and name. + /// + /// The IP block from which to allocate the network. For example, 172.16.0.0/24 or 2001:DB8::/64. + /// The name of the new network. For example, my_new_network. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + public CreateCloudNetworksDetails(string cidr, string label) + { + if (cidr == null) + throw new ArgumentNullException("cidr"); + if (label == null) + throw new ArgumentNullException("label"); + if (string.IsNullOrEmpty(cidr)) + throw new ArgumentException("cidr cannot be empty"); + if (string.IsNullOrEmpty(label)) + throw new ArgumentException("label cannot be empty"); + + Cidr = cidr; + Label = label; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerImageDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerImageDetails.cs new file mode 100644 index 000000000..8d716689a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerImageDetails.cs @@ -0,0 +1,47 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON body containing details for the Create Image request. + /// + /// + /// Create Image (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateServerImageDetails + { + /// + /// Gets the name of the image to create. + /// + [JsonProperty("name")] + public string ImageName { get; private set; } + + /// + /// Gets the metadata to associate with the image. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Include)] + public Metadata Metadata { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified name and metadata. + /// + /// Name of the new image. + /// The metadata to associate to the new image. + /// If is . + /// If is empty. + public CreateServerImageDetails(string imageName, Metadata metadata) + { + if (imageName == null) + throw new ArgumentNullException("imageName"); + if (string.IsNullOrEmpty(imageName)) + throw new ArgumentException("imageName cannot be empty"); + + ImageName = imageName; + Metadata = metadata; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerImageRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerImageRequest.cs new file mode 100644 index 000000000..c9d22961a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerImageRequest.cs @@ -0,0 +1,34 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Create Image request. + /// + /// Create Image (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateServerImageRequest + { + /// + /// Gets additional details about the Create Image request. + /// + [JsonProperty("createImage")] + public CreateServerImageDetails Details { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified details. + /// + /// The details of the request. + /// If is . + public CreateServerImageRequest(CreateServerImageDetails details) + { + if (details == null) + throw new ArgumentNullException("details"); + + Details = details; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerRequest.cs new file mode 100644 index 000000000..66e1ce33b --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateServerRequest.cs @@ -0,0 +1,166 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using System.Collections.Generic; + using System.Linq; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Create Server request. + /// + /// Create Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateServerRequest + { + /// + /// Gets additional details about the Create Server request. + /// + [JsonProperty("server")] + public CreateServerDetails Details { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified details. + /// + /// Name of the new server. + /// The image to use for the new server instance. This is + /// specified as an image ID (see ) or a full URL. + /// The flavor to use for the new server instance. This + /// is specified as a flavor ID (see ) or a full URL. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// The metadata to associate with the server. + /// A collection of objects describing the paths and contents of files to inject in the target file system during the creation process. If the value is , no files are injected. + /// The behavior of this value is unspecified. Do not use. + /// The behavior of this value is unspecified. Do not use. + /// A collection of identifiers for networks to initially connect to the server. These are obtained from CloudNetwork.Id + public CreateServerRequest(string name, string imageName, string flavor, DiskConfiguration diskConfig, Dictionary metadata, string accessIPv4, string accessIPv6, IEnumerable networks, IEnumerable personality) + { + Details = new CreateServerDetails(name, imageName, flavor, diskConfig, metadata, accessIPv4, accessIPv6, networks, personality); + } + + /// + /// This models the JSON body containing details for a Create Server request. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class CreateServerDetails + { + /// + /// Gets the name of the new server to create. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the image to use for the new server instance. This is + /// specified as an image ID (see ) or a full URL. + /// + [JsonProperty("imageRef")] + public string ImageName { get; private set; } + + /// + /// Gets the flavor to use for the new server instance. This + /// is specified as a flavor ID (see ) or a full URL. + /// + [JsonProperty("flavorRef")] + public string Flavor { get; private set; } + + /// + /// Gets the disk configuration. If the value is , the default configuration for the specified image is used. + /// + [JsonProperty("OS-DCF:diskConfig")] + public DiskConfiguration DiskConfig { get; private set; } + + /// + /// Gets the metadata to associate with the server. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Include)] + public Dictionary Metadata { get; private set; } + + /// + /// The behavior of this value is unspecified. Do not use. + /// + [JsonProperty("accessIPv4", DefaultValueHandling = DefaultValueHandling.Include)] + public string AccessIPv4 { get; private set; } + + /// + /// The behavior of this value is unspecified. Do not use. + /// + [JsonProperty("accessIPv6", DefaultValueHandling = DefaultValueHandling.Include)] + public string AccessIPv6 { get; private set; } + + /// + /// Gets a collection of information about networks to initially connect to the server. + /// + [JsonProperty("networks", DefaultValueHandling = DefaultValueHandling.Include)] + public NewServerNetwork[] Networks { get; private set; } + + /// + /// Gets a collection of objects describing the paths and + /// contents of files to inject in the target file system during the creation process. + /// If the value is , no files are injected. + /// + [JsonProperty("personality", DefaultValueHandling = DefaultValueHandling.Include)] + public Personality[] Personality { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified details. + /// + /// Name of the new server. + /// The image to use for the new server instance. This is + /// specified as an image ID (see ) or a full URL. + /// The flavor to use for the new server instance. This + /// is specified as a flavor ID (see ) or a full URL. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// The metadata to associate with the server. + /// A collection of objects describing the paths and contents of files to inject in the target file system during the creation process. If the value is , no files are injected. + /// The behavior of this value is unspecified. Do not use. + /// The behavior of this value is unspecified. Do not use. + /// A collection of identifiers for networks to initially connect to the server. These are obtained from CloudNetwork.Id + public CreateServerDetails(string name, string imageName, string flavor, DiskConfiguration diskConfig, Dictionary metadata, string accessIPv4, string accessIPv6, IEnumerable networks, IEnumerable personality) + { + Name = name; + ImageName = imageName; + Flavor = flavor; + DiskConfig = diskConfig; + Metadata = metadata; + AccessIPv4 = accessIPv4; + AccessIPv6 = accessIPv6; + Networks = networks.Select(i => new NewServerNetwork(i)).ToArray(); + Personality = personality != null ? personality.ToArray() : null; + } + + /// + /// This models the JSON body containing details for a connected network + /// within the Create Server request. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class NewServerNetwork + { + /// + /// Gets the ID of the network. + /// + /// + [JsonProperty("uuid")] + public string NetworkId { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified ID. + /// + /// The network ID. This is obtained from CloudNetwork.Id. + public NewServerNetwork(string networkId) + { + if (networkId == null) + throw new ArgumentNullException("networkId"); + + NetworkId = networkId; + } + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/CreateVirtualInterfaceRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateVirtualInterfaceRequest.cs new file mode 100644 index 000000000..1564c3813 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/CreateVirtualInterfaceRequest.cs @@ -0,0 +1,70 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Create Virtual Interface request. + /// + /// Create Virtual Interface (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateVirtualInterfaceRequest + { + /// + /// Gets additional details about the virtual interface to create. + /// + [JsonProperty("virtual_interface")] + public CreateVirtualInterface VirtualInterface { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified network ID. + /// + /// The network ID. This is obtained from CloudNetwork.Id. + /// If is . + /// If is empty. + public CreateVirtualInterfaceRequest(string networkId) + { + if (networkId == null) + throw new ArgumentNullException("networkId"); + if (string.IsNullOrEmpty(networkId)) + throw new ArgumentException("networkId cannot be empty"); + + VirtualInterface = new CreateVirtualInterface(networkId); + } + + /// + /// This models the JSON body containing details for a Create Virtual Interface request. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateVirtualInterface + { + /// + /// Gets the network ID. + /// + /// + [JsonProperty("network_id")] + public string NetworkId { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified network ID. + /// + /// The network ID. This is obtained from CloudNetwork.Id. + /// If is . + /// If is empty. + public CreateVirtualInterface(string networkId) + { + if (networkId == null) + throw new ArgumentNullException("networkId"); + if (string.IsNullOrEmpty(networkId)) + throw new ArgumentException("networkId cannot be empty"); + + NetworkId = networkId; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/NamespaceDoc.cs new file mode 100644 index 000000000..9dad141b8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace + /// contains the object models for JSON request bodies sent in calls to Rackspace's + /// REST APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/PasswordCredential.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/PasswordCredential.cs new file mode 100644 index 000000000..e0cf2ea19 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/PasswordCredential.cs @@ -0,0 +1,65 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON representation of password credentials. + /// + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + public class PasswordCredential + { + /// + /// Gets the username for the credentials. + /// + [JsonProperty("username")] + public string Username + { + get; + private set; + } + + /// + /// Gets the password for the credentials. + /// + [JsonProperty("password")] + public string Password + { + get; + private set; + } + + /// + /// Initializes a new instance of the class + /// with the specified username and password. + /// + /// The username. + /// The password. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + public PasswordCredential(string username, string password) + { + if (username == null) + throw new ArgumentNullException("username"); + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(username)) + throw new ArgumentException("username cannot be empty"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + + Username = username; + Password = password; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/Personality.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/Personality.cs new file mode 100644 index 000000000..e1e85fc2c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/Personality.cs @@ -0,0 +1,121 @@ +using System; +using System.Text; +using Newtonsoft.Json; + +namespace OpenStack.Compute.v2_1 +{ + /// + /// Describes a file to inject into the file system while creating or + /// rebuilding a server. + /// + /// + /// You can customize the personality of a server instance by injecting data into + /// its file system. For example, you might want to insert SSH keys, set configuration + /// files, or store data that you want to retrieve from inside the instance. This + /// feature provides a minimal amount of launch-time personalization. If you require + /// significant customization, create a custom image. + /// + /// + public class Personality + { + /// + /// Initializes a new instance of the class with the specified + /// path and contents. + /// + /// The path of the file to create on the target file system. + /// The contents of the file to create on the target file system. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public Personality(string path, byte[] content) + { + if (path == null) + throw new ArgumentNullException("path"); + if (content == null) + throw new ArgumentNullException("content"); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("path cannot be empty"); + + Path = path; + Content = content; + } + + /// + /// Initializes a new instance of the class with the specified + /// path and text content, using for the content encoding. + /// + /// The path of the text file to create on the target file system. + /// The contents of the text file to create on the target file system. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public Personality(string path, string content) + : this(path, content, Encoding.UTF8) + { + } + + /// + /// Initializes a new instance of the class with the specified + /// path, text content, and context encoding. + /// + /// The path of the text file to create on the target file system. + /// The contents of the text file to create on the target file system. + /// The encoding to use for the text file. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public Personality(string path, string content, Encoding encoding) + { + if (path == null) + throw new ArgumentNullException("path"); + if (content == null) + throw new ArgumentNullException("content"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("path cannot be empty"); + + Path = path; + Content = encoding.GetBytes(content); + } + + /// + /// The path of the file to create on the target file system. + /// + /// + /// The behavior of the related methods is undefined + /// if the UTF-8 encoded value is longer than 255 bytes. + /// + [JsonProperty("path")] + public string Path { get; set; } + + /// + /// The contents of the file to create on the target file system. + /// + /// + /// The maximum size of the file contents is determined by the compute provider + /// and may vary based on the image that is used to create the server. The provider + /// may provide a maxPersonalitySize absolute limit, which is a byte limit + /// that is guaranteed to apply to all images in the deployment. Providers can set + /// additional per-image personality limits. + /// + /// + /// The behavior of the related methods is undefined + /// if the value is not a UTF-8 encoded text file. + /// + /// + [JsonProperty("contents")] + public byte[] Content { get; set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/RescueServerRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/RescueServerRequest.cs new file mode 100644 index 000000000..f8b341068 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/RescueServerRequest.cs @@ -0,0 +1,18 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Rescue Server request. + /// + /// Rescue Server (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class RescueServerRequest + { +#pragma warning disable 414 // The field 'fieldName' is assigned but its value is never used + [JsonProperty("rescue")] + private string _command = "none"; +#pragma warning restore 414 + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/RevertServerResizeRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/RevertServerResizeRequest.cs new file mode 100644 index 000000000..124ec81d2 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/RevertServerResizeRequest.cs @@ -0,0 +1,18 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Revert Resized Server request. + /// + /// Revert Resized Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class RevertServerResizeRequest + { +#pragma warning disable 414 // The field 'fieldName' is assigned but its value is never used + [JsonProperty("revertResize")] + private string _command = "none"; +#pragma warning restore 414 + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebootDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebootDetails.cs new file mode 100644 index 000000000..c1339636d --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebootDetails.cs @@ -0,0 +1,40 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON body containing details for the Reboot Server request. + /// + /// + /// Reboot Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerRebootDetails + { + /// + /// Gets the type of reboot to perform. + /// + [JsonProperty("type")] + public RebootType Type + { + get; + private set; + } + + /// + /// Initializes a new instance of the + /// class with the specified reboot type. + /// + /// The type of reboot to perform. See for predefined values. + /// If is . + public ServerRebootDetails(RebootType type) + { + if (type == null) + throw new ArgumentNullException("type"); + + Type = type; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebootRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebootRequest.cs new file mode 100644 index 000000000..af2d111a9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebootRequest.cs @@ -0,0 +1,34 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Reboot Server request. + /// + /// Reboot Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerRebootRequest + { + /// + /// Gets additional details about the Reboot Server request. + /// + [JsonProperty("reboot")] + public ServerRebootDetails Details { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified details. + /// + /// The details of the request. + /// If is . + public ServerRebootRequest(ServerRebootDetails details) + { + if (details == null) + throw new ArgumentNullException("details"); + + Details = details; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebuildDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebuildDetails.cs new file mode 100644 index 000000000..603cd7a28 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebuildDetails.cs @@ -0,0 +1,136 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using System.Collections.Generic; + using System.Net; + using System.Net.Sockets; + using net.openstack.Core.Domain; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + + /// + /// This models the JSON body containing details for the Rebuild Server request. + /// + /// + /// Rebuild Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerRebuildDetails + { + /// + /// Gets the new name for the server. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the image to rebuild the server from. This is specified as an image ID (see ) or a full URL. + /// + [JsonProperty("imageRef")] + public string ImageName { get; private set; } + + /// + /// The new flavor for server. This is obtained from . + /// + [JsonProperty("flavorRef")] + public string Flavor { get; private set; } + + /// + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// + [JsonProperty("OS-DCF:diskConfig", DefaultValueHandling = DefaultValueHandling.Include)] + public DiskConfiguration DiskConfig { get; private set; } + + /// + /// Gets the new admin password for the server. + /// + [JsonProperty("adminPass")] + public string AdminPassword { get; private set; } + + /// + /// Gets the list of metadata to associate with the server. If the value is , the metadata associated with the server is not changed during the rebuild operation. + /// + [JsonProperty("metadata", DefaultValueHandling = DefaultValueHandling.Include)] + public Dictionary Metadata { get; private set; } + + /// + /// The path and contents of a file to inject in the target file system during the rebuild operation. If the value is , no file is injected. + /// + [JsonProperty("personality", DefaultValueHandling = DefaultValueHandling.Include)] + public Personality Personality { get; private set; } + + /// + /// The new IP v4 address for the server. If the value is , the server's IP v4 address is not updated. + /// + [JsonProperty("accessIPv4", DefaultValueHandling = DefaultValueHandling.Include)] + [JsonConverter(typeof(IPAddressNoneIsNullSimpleConverter))] + public IPAddress AccessIPv4 { get; private set; } + + /// + /// The new IP v6 address for the server. If the value is , the server's IP v6 address is not updated. + /// + [JsonProperty("accessIPv6", DefaultValueHandling = DefaultValueHandling.Include)] + [JsonConverter(typeof(IPAddressNoneIsNullSimpleConverter))] + public IPAddress AccessIPv6 { get; private set; } + + /// + /// Initializes a new instance of the class with the specified details. + /// + /// The new name for the server. If the value is , the server name is not changed. + /// The image to rebuild the server from. This is specified as an image ID (see ) or a full URL. + /// The new flavor for server. This is obtained from . + /// The new admin password for the server. + /// The new IP v4 address for the server, or to remove the configured IP v4 address for the server. If the value is , the server's IP v4 address is not updated. + /// The new IP v6 address for the server, or to remove the configured IP v6 address for the server. If the value is , the server's IP v6 address is not updated. + /// The list of metadata to associate with the server. If the value is , the metadata associated with the server is not changed during the rebuild operation. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// The path and contents of a file to inject in the target file system during the rebuild operation. If the value is , no file is injected. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is empty. + /// -or- + /// If is not and the of is not . + /// -or- + /// If is not and the of is not . + /// + public ServerRebuildDetails(string name, string imageName, string flavor, string adminPassword, IPAddress accessIPv4, IPAddress accessIPv6, Metadata metadata, DiskConfiguration diskConfig, Personality personality) + { + if (imageName == null) + throw new ArgumentNullException("imageName"); + if (flavor == null) + throw new ArgumentNullException("flavor"); + if (adminPassword == null) + throw new ArgumentNullException("adminPassword"); + if (string.IsNullOrEmpty(imageName)) + throw new ArgumentException("imageName cannot be empty"); + if (string.IsNullOrEmpty(flavor)) + throw new ArgumentException("flavor cannot be empty"); + if (string.IsNullOrEmpty(adminPassword)) + throw new ArgumentException("adminPassword cannot be empty"); + if (accessIPv4 != null && !IPAddress.None.Equals(accessIPv4) && accessIPv4.AddressFamily != AddressFamily.InterNetwork) + throw new ArgumentException("The specified value for accessIPv4 is not an IP v4 address.", "accessIPv4"); + if (accessIPv6 != null && !IPAddress.None.Equals(accessIPv6) && accessIPv6.AddressFamily != AddressFamily.InterNetworkV6) + throw new ArgumentException("The specified value for accessIPv6 is not an IP v6 address.", "accessIPv6"); + + Name = name; + ImageName = imageName; + Flavor = flavor; + AdminPassword = adminPassword; + AccessIPv4 = accessIPv4; + AccessIPv6 = accessIPv6; + Metadata = metadata; + DiskConfig = diskConfig; + Personality = personality; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebuildRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebuildRequest.cs new file mode 100644 index 000000000..ba7efb3f5 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerRebuildRequest.cs @@ -0,0 +1,34 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Rebuild Server request. + /// + /// Rebuild Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerRebuildRequest + { + /// + /// Gets additional information about the Rebuild Server request. + /// + [JsonProperty("rebuild")] + public ServerRebuildDetails Details { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified details. + /// + /// The details of the request. + /// If is . + public ServerRebuildRequest(ServerRebuildDetails details) + { + if (details == null) + throw new ArgumentNullException("details"); + + Details = details; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/ServerResizeDetails.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerResizeDetails.cs new file mode 100644 index 000000000..b96a6caff --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerResizeDetails.cs @@ -0,0 +1,67 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON body containing details for the Resize Server request. + /// + /// + /// Resize Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerResizeDetails + { + /// + /// Gets the new name for the resized server. + /// + [JsonProperty("name")] + public string Name { get; private set; } + + /// + /// Gets the ID of the new flavor. + /// + /// + [JsonProperty("flavorRef")] + public string Flavor { get; private set; } + + /// + /// The disk configuration. If the value is , the default configuration for the image is used. + /// + [JsonProperty("OS-DCF:diskConfig", DefaultValueHandling = DefaultValueHandling.Include)] + public DiskConfiguration DiskConfig { get; private set; } + + /// + /// Initializes a new instance of the class with the specified details. + /// + /// The new name for the resized server. + /// The new flavor. This is obtained from Flavor.Id. + /// The disk configuration. If the value is , the default configuration for the specified image is used. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + public ServerResizeDetails(string name, string flavor, DiskConfiguration diskConfig) + { + if (name == null) + throw new ArgumentNullException("name"); + if (flavor == null) + throw new ArgumentNullException("flavor"); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("serverName cannot be empty"); + if (string.IsNullOrEmpty(flavor)) + throw new ArgumentException("flavor cannot be empty"); + + Name = name; + Flavor = flavor; + DiskConfig = diskConfig; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/ServerResizeRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerResizeRequest.cs new file mode 100644 index 000000000..5a91b179f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/ServerResizeRequest.cs @@ -0,0 +1,34 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Resize Server request. + /// + /// Resize Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerResizeRequest + { + /// + /// Gets additional information about the Resize Server request. + /// + [JsonProperty("resize")] + public ServerResizeDetails Details { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified details. + /// + /// The details of the request. + /// If is . + public ServerResizeRequest(ServerResizeDetails details) + { + if (details == null) + throw new ArgumentNullException("details"); + + Details = details; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/SetPasswordRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/SetPasswordRequest.cs new file mode 100644 index 000000000..1eb491764 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/SetPasswordRequest.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Update User Credentials request + /// when used with password credentials. + /// + /// + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class SetPasswordRequest + { + /// + /// Gets the password credentials to use for the Update User Credentials request. + /// + [JsonProperty("passwordCredentials")] + public PasswordCredential PasswordCredential { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified username and password. + /// + /// The new username. + /// The new password. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + public SetPasswordRequest(string username, string password) + { + if (username == null) + throw new ArgumentNullException("username"); + if (password == null) + throw new ArgumentNullException("password"); + if (string.IsNullOrEmpty(username)) + throw new ArgumentException("username cannot be empty"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password cannot be empty"); + + PasswordCredential = new PasswordCredential(username, password); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/UnrescueServerRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/UnrescueServerRequest.cs new file mode 100644 index 000000000..4569818c4 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/UnrescueServerRequest.cs @@ -0,0 +1,18 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Unrescue Server request. + /// + /// Unrescue Server (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UnrescueServerRequest + { +#pragma warning disable 414 // The field 'fieldName' is assigned but its value is never used + [JsonProperty("unrescue")] + private string _command = "none"; +#pragma warning restore 414 + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateMetadataItemRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateMetadataItemRequest.cs new file mode 100644 index 000000000..ab7be5452 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateMetadataItemRequest.cs @@ -0,0 +1,48 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Set Metadata Item request. + /// + /// Set Metadata Item (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UpdateMetadataItemRequest + { + /// + /// Gets the metadata item to associate with the server or image. + /// + /// + /// The value is never and always contains exactly one entry. + /// + [JsonProperty("meta")] + public Metadata Metadata { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified key and value. + /// + /// The metadata key. + /// The new value for the metadata item. + /// + /// If is . + /// -or- + /// If is . + /// + /// If is empty. + public UpdateMetadataItemRequest(string key, string value) + { + if (key == null) + throw new ArgumentNullException("key"); + if (value == null) + throw new ArgumentNullException("value"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + + Metadata = new Metadata() { { key, value } }; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateMetadataRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateMetadataRequest.cs new file mode 100644 index 000000000..f6958fc28 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateMetadataRequest.cs @@ -0,0 +1,36 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Set Metadata and Update Metadata requests. + /// + /// Set Metadata (OpenStack Compute API v2 and Extensions Reference) + /// Update Metadata (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UpdateMetadataRequest + { + /// + /// Gets the metadata. + /// + [JsonProperty("metadata")] + public Metadata Metadata { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the given metadata. + /// + /// The metadata. + /// If is . + public UpdateMetadataRequest(Metadata metadata) + { + if (metadata == null) + throw new ArgumentNullException("metadata"); + + Metadata = metadata; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateServerRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateServerRequest.cs new file mode 100644 index 000000000..dee82b962 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateServerRequest.cs @@ -0,0 +1,97 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using System.Net; + using System.Net.Sockets; + using net.openstack.Core.Domain.Converters; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Update Server request. + /// + /// Update Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UpdateServerRequest + { + /// + /// Gets additional details about the updated server. + /// + [JsonProperty("server")] + public ServerUpdateDetails Server { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified name and access IP addresses. + /// + /// The new name for the server. If the value is , the server name is not changed. + /// The new IP v4 address for the server, or to remove the configured IP v4 address for the server. If the value is , the server's IP v4 address is not updated. + /// The new IP v6 address for the server, or to remove the configured IP v6 address for the server. If the value is , the server's IP v6 address is not updated. + /// + /// If is not and the of is not . + /// -or- + /// If is not and the of is not . + /// + public UpdateServerRequest(string name, IPAddress accessIPv4, IPAddress accessIPv6) + { + if (accessIPv4 != null && !IPAddress.None.Equals(accessIPv4) && accessIPv4.AddressFamily != AddressFamily.InterNetwork) + throw new ArgumentException("The specified value for accessIPv4 is not an IP v4 address.", "accessIPv4"); + if (accessIPv6 != null && !IPAddress.None.Equals(accessIPv6) && accessIPv6.AddressFamily != AddressFamily.InterNetworkV6) + throw new ArgumentException("The specified value for accessIPv6 is not an IP v6 address.", "accessIPv6"); + + Server = new ServerUpdateDetails(name, accessIPv4, accessIPv6); + } + + /// + /// This models the JSON body containing details for the Update Server request. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ServerUpdateDetails + { + /// + /// Gets the new name for the server, or if the server's name should not be changed by the update. + /// + [JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Include)] + public string Name { get; private set; } + + /// + /// Gets the IP v4 access address for the server, or if the access address should not be changed by the update. + /// + [JsonProperty("accessIPv4", DefaultValueHandling = DefaultValueHandling.Include)] + [JsonConverter(typeof(IPAddressNoneIsNullSimpleConverter))] + public IPAddress AccessIPv4 { get; private set; } + + /// + /// Gets the IP v6 access address for the server, or if the access address should not be changed by the update. + /// + [JsonProperty("accessIPv6", DefaultValueHandling = DefaultValueHandling.Include)] + [JsonConverter(typeof(IPAddressNoneIsNullSimpleConverter))] + public IPAddress AccessIPv6 { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified name and access IP addresses. + /// + /// The new name for the server. If the value is , the server name is not changed. + /// The new IP v4 address for the server, or to remove the configured IP v4 address for the server. If the value is , the server's IP v4 address is not updated. + /// The new IP v6 address for the server, or to remove the configured IP v6 address for the server. If the value is , the server's IP v6 address is not updated. + /// + /// If is not and the of is not . + /// -or- + /// If is not and the of is not . + /// + public ServerUpdateDetails(string name, IPAddress accessIPv4, IPAddress accessIPv6) + { + if (accessIPv4 != null && !IPAddress.None.Equals(accessIPv4) && accessIPv4.AddressFamily != AddressFamily.InterNetwork) + throw new ArgumentException("The specified value for accessIPv4 is not an IP v4 address.", "accessIPv4"); + if (accessIPv6 != null && !IPAddress.None.Equals(accessIPv6) && accessIPv6.AddressFamily != AddressFamily.InterNetworkV6) + throw new ArgumentException("The specified value for accessIPv6 is not an IP v6 address.", "accessIPv6"); + + Name = name; + AccessIPv4 = accessIPv4; + AccessIPv6 = accessIPv6; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateUserCredentialRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateUserCredentialRequest.cs new file mode 100644 index 000000000..41ce83832 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateUserCredentialRequest.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Update User Credentials request + /// when used with API Key credentials. + /// + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UpdateUserCredentialRequest + { + /// + /// Gets the API Key credentials to use for the Update User Credentials request. + /// + [JsonProperty("RAX-KSKEY:apiKeyCredentials")] + public UserCredential UserCredential { get; private set; } + + /// + /// Initializes a new instance of the + /// class with the specified API Key credentials. + /// + /// The new username. + /// The new API key. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is empty. + /// -or- + /// If is empty. + /// + public UpdateUserCredentialRequest(string username, string apiKey) + { + if (username == null) + throw new ArgumentNullException("username"); + if (apiKey == null) + throw new ArgumentNullException("apiKey"); + if (string.IsNullOrEmpty(username)) + throw new ArgumentException("username cannot be empty"); + if (string.IsNullOrEmpty(apiKey)) + throw new ArgumentException("apiKey cannot be empty"); + + UserCredential = new UserCredential(null, username, apiKey); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateUserRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateUserRequest.cs new file mode 100644 index 000000000..23c652fd9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateUserRequest.cs @@ -0,0 +1,38 @@ +namespace net.openstack.Providers.Rackspace.Objects.Request +{ + using System; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON request used for the Update User request. + /// + /// Update User (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UpdateUserRequest + { + /// + /// Gets the updated user information for the request. + /// + [JsonProperty("user")] + public User User { get; private set; } + + /// + /// Initializes a new instance of the class + /// with the specified user. + /// + /// A instance containing the updated details for the user. + /// If is . + /// If . is or empty. + public UpdateUserRequest(User user) + { + if (user == null) + throw new ArgumentNullException("user"); + if (string.IsNullOrEmpty(user.Id)) + throw new ArgumentException("user.Id cannot be null or empty"); + + User = user; + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/AuthenticationResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/AuthenticationResponse.cs new file mode 100644 index 000000000..c7d68b5ad --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/AuthenticationResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Authenticate request. + /// + /// Authenticate (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class AuthenticationResponse + { + /// + /// Gets additional information about the authenticated user. + /// + /// + [JsonProperty("access")] + public UserAccess UserAccess { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/BulkDeleteResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/BulkDeleteResponse.cs new file mode 100644 index 000000000..696364c42 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/BulkDeleteResponse.cs @@ -0,0 +1,32 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + [JsonObject(MemberSerialization.OptIn)] + internal class BulkDeleteResponse + { + [JsonProperty("Number Not Found")] + public int NumberNotFound { get; set; } + + [JsonProperty("Response Status")] + public string Status { get; set; } + + [JsonProperty("Errors")] + public IEnumerable> Errors { get; set; } + + [JsonProperty("Number Deleted")] + public int NumberDeleted { get; set; } + + [JsonProperty("Response Body")] + public string ResponseBody { get; set; } + + public IEnumerable AllItems { get; set; } + + public bool IsItemError(string s) + { + return Errors.Any(e => e.Any(e2 => e2.Equals(s))); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/CloudNetworkResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/CloudNetworkResponse.cs new file mode 100644 index 000000000..5db072aca --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/CloudNetworkResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Create Network and Show Network requests. + /// + /// Create Network (OpenStack Networking API v2.0 Reference) + /// Show Network (OpenStack Networking API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CloudNetworkResponse + { + /// + /// Gets additional information about the network. + /// + [JsonProperty("network")] + public CloudNetwork Network { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/CreateServerResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/CreateServerResponse.cs new file mode 100644 index 000000000..a4703aca1 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/CreateServerResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Create Server request. + /// + /// Create Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class CreateServerResponse + { + /// + /// Gets information about the created server. + /// + [JsonProperty("server")] + public NewServer Server { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ExtractArchiveError.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ExtractArchiveError.cs new file mode 100644 index 000000000..2f95e2494 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ExtractArchiveError.cs @@ -0,0 +1,65 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using System; + + /// + /// Represents an error which occurred while extracting a file during an Extract Archive operation. + /// + /// + /// + /// + /// + public class ExtractArchiveError + { + /// + /// This is the backing field for the property. + /// + private readonly string _path; + + /// + /// This is the backing field for the property. + /// + private readonly string _status; + + /// + /// Initializes a new instance of the class + /// with the specified path and status. + /// + /// The path of the file affected by this error. + /// The specific status for the error affecting the file. + /// If is . + /// If is empty. + public ExtractArchiveError(string path, string status) + { + if (path == null) + throw new ArgumentNullException("path"); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("path cannot be empty"); + + _path = path; + _status = status; + } + + /// + /// Gets the path of the file affected by this error. + /// + public string Path + { + get + { + return _path; + } + } + + /// + /// Gets the specific status for the error affecting the file. + /// + public string Status + { + get + { + return _status; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ExtractArchiveResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ExtractArchiveResponse.cs new file mode 100644 index 000000000..1f440efa3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ExtractArchiveResponse.cs @@ -0,0 +1,132 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using System.Collections.Generic; + using System.Collections.ObjectModel; + using Newtonsoft.Json; + + /// + /// This class models the JSON response to an Extract Archive operation. + /// + /// + /// + /// Extracting Archive Files (Rackspace Cloud Files Developer Guide - API v1) + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class ExtractArchiveResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("Number Files Created")] + private int? _createdFiles; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("Response Status")] + private string _responseStatus; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("Response Body")] + private string _responseBody; + + /// + /// This is the backing field for the property. + /// + [JsonProperty("Errors")] + private string[][] _errors; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected ExtractArchiveResponse() + { + } + + /// + /// Gets the number of files created by the Extract Archive operation. + /// + /// + /// The number of files created by the Extract Archive operation, or if + /// the JSON response from the server did not include the underlying property. + /// + public int? CreatedFiles + { + get + { + return _createdFiles; + } + } + + /// + /// Gets the response status for the Extract Archive operation. + /// + /// + /// The response status for the Extract Archive operation, or if + /// the JSON response from the server did not include the underlying property. + /// + public string ResponseStatus + { + get + { + return _responseStatus; + } + } + + /// + /// Gets the response body for the Extract Archive operation. + /// + /// + /// The response body for the Extract Archive operation, or if + /// the JSON response from the server did not include the underlying property. + /// + public string ResponseBody + { + get + { + return _responseBody; + } + } + + /// + /// Gets a collection of objects describing errors + /// which occurred while processing specific files within the archive. + /// + /// + /// A collection of errors, if any, which occurred for specific files during the + /// Extract Archive operation, or if the JSON response from the server + /// did not include the underlying property. + /// + public ReadOnlyCollection Errors + { + get + { + if (_errors == null) + return null; + + List errors = new List(); + foreach (string[] error in _errors) + { + if (error == null) + continue; + + if (error.Length >= 2) + errors.Add(new ExtractArchiveError(error[0], error[1])); + else if (error.Length == 1) + errors.Add(new ExtractArchiveError(error[0], "Unknown Error")); + else + errors.Add(new ExtractArchiveError("Unknown File", "Unknown Error")); + } + + return errors.AsReadOnly(); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/FlavorDetailsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/FlavorDetailsResponse.cs new file mode 100644 index 000000000..21142d16c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/FlavorDetailsResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Get Flavor Details request. + /// + /// Get Flavor Details (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class FlavorDetailsResponse + { + /// + /// Gets detailed information about the flavor. + /// + [JsonProperty("flavor")] + public FlavorDetails Flavor { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageSnapshotResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageSnapshotResponse.cs new file mode 100644 index 000000000..498ad2909 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageSnapshotResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Create Snapshot and Show Snapshot requests. + /// + /// Create Snapshot (OpenStack Block Storage Service API Reference) + /// Show Snapshot (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetCloudBlockStorageSnapshotResponse + { + /// + /// Gets information about the snapshot. + /// + [JsonProperty("snapshot")] + public Snapshot Snapshot { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageVolumeResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageVolumeResponse.cs new file mode 100644 index 000000000..f4a9ac80a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageVolumeResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Create Volume and Show Volume requests. + /// + /// Create Volume (OpenStack Block Storage Service API Reference) + /// Show Volume (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetCloudBlockStorageVolumeResponse + { + /// + /// Gets additional information about the volume. + /// + [JsonProperty("volume")] + public Volume Volume { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageVolumeTypeResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageVolumeTypeResponse.cs new file mode 100644 index 000000000..e4086066c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/GetCloudBlockStorageVolumeTypeResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Show Volume Type request. + /// + /// Show Volume Type (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetCloudBlockStorageVolumeTypeResponse + { + /// + /// Gets additional information about the volume type. + /// + [JsonProperty("volume_type")] + public VolumeType VolumeType { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/GetEndpointResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/GetEndpointResponse.cs new file mode 100644 index 000000000..18b13218e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/GetEndpointResponse.cs @@ -0,0 +1,52 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using Newtonsoft.Json; + using net.openstack.Core.Domain; + + /// + /// This class models the JSON representation of the response to the Get endpoint HTTP API call in + /// the OpenStack Identity Service V2. + /// + /// + /// This call is part of the OS-KSCATALOG extension to the OpenStack Identity Service V2. + /// + /// OS-KSCATALOG admin extension (Identity API v2.0 - OpenStack Complete API Reference) + /// + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetEndpointResponse + { +#pragma warning disable 649 // Field 'fieldName' is never assigned to, and will always have its default value {value} + /// + /// This is the backing field for the property. + /// + [JsonProperty("endpoint", DefaultValueHandling = DefaultValueHandling.Ignore)] + private ExtendedEndpoint _endpoint; +#pragma warning restore 649 + + /// + /// Initializes a new instance of the class + /// during JSON deserialization. + /// + [JsonConstructor] + protected GetEndpointResponse() + { + } + + /// + /// Gets additional information about the endpoint. + /// + /// + /// An object containing the details of the endpoint. + /// NullIfNotIncluded + /// + public ExtendedEndpoint Endpoint + { + get + { + return _endpoint; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/GetImageDetailsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/GetImageDetailsResponse.cs new file mode 100644 index 000000000..45ef57d18 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/GetImageDetailsResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Get Image Details request. + /// + /// Get Image Details (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class GetImageDetailsResponse + { + /// + /// Gets detailed information about the image. + /// + [JsonProperty("image")] + public ServerImage Image { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListAddressesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListAddressesResponse.cs new file mode 100644 index 000000000..52a3592d3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListAddressesResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Addresses request. + /// + /// List Addresses (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListAddressesResponse + { + /// + /// Gets the IP address details. + /// + [JsonProperty("addresses")] + public ServerAddresses Addresses { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListCloudNetworksResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListCloudNetworksResponse.cs new file mode 100644 index 000000000..827f67691 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListCloudNetworksResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Networks request. + /// + /// List Networks (OpenStack Networking API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListCloudNetworksResponse + { + /// + /// Gets a collection of networks. + /// + [JsonProperty("networks")] + public CloudNetwork[] Networks { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListEndpointsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListEndpointsResponse.cs new file mode 100644 index 000000000..9cf1d56b3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListEndpointsResponse.cs @@ -0,0 +1,22 @@ +using net.openstack.Core.Domain; +using Newtonsoft.Json; + +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + /// + /// This models the JSON response used for the List Endpoints request. + /// + /// List Token Endpoints (OpenStack Identity Service API v2.0 Reference) + /// List Service Catalog Endpoints (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListEndpointsResponse + { + /// + /// Gets additional information about the endpoints. + /// + /// + [JsonProperty("endpoints", DefaultValueHandling = DefaultValueHandling.Ignore)] + public ExtendedEndpoint[] Endpoints { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListFlavorDetailsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListFlavorDetailsResponse.cs new file mode 100644 index 000000000..4d937af7f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListFlavorDetailsResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Flavors with Details request. + /// + /// List Flavors (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListFlavorDetailsResponse + { + /// + /// Gets a collection of detailed information about the flavors. + /// + [JsonProperty("flavors")] + public FlavorDetails[] Flavors { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListFlavorsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListFlavorsResponse.cs new file mode 100644 index 000000000..c834f6ea3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListFlavorsResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Flavors request. + /// + /// List Flavors (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListFlavorsResponse + { + /// + /// Gets a collection of basic information about the available flavors. + /// + [JsonProperty("flavors")] + public Flavor[] Flavors { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListImagesDetailsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListImagesDetailsResponse.cs new file mode 100644 index 000000000..a5c9dd63c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListImagesDetailsResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Images with Details request. + /// + /// List Images (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListImagesDetailsResponse + { + /// + /// Gets a collection of detailed information about the images. + /// + [JsonProperty("images")] + public ServerImage[] Images { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListImagesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListImagesResponse.cs new file mode 100644 index 000000000..965eb9d24 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListImagesResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Images request. + /// + /// List Images (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListImagesResponse + { + /// + /// Gets a collection of basic information about the images. + /// + [JsonProperty("images")] + public SimpleServerImage[] Images { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListServersResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListServersResponse.cs new file mode 100644 index 000000000..8d292ad07 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListServersResponse.cs @@ -0,0 +1,26 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Servers and List Servers with Details requests. + /// + /// List Servers (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListServersResponse + { + /// + /// Gets a collection of information about the servers. + /// + [JsonProperty("servers")] + public Server[] Servers { get; private set; } + + /// + /// Gets a collection of links related to the collection of servers. + /// + [JsonProperty("servers_links")] + public Link[] Links { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListSnapshotResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListSnapshotResponse.cs new file mode 100644 index 000000000..6ecc9f3fa --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListSnapshotResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Snapshot Summaries request. + /// + /// List Snapshot Summaries (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListSnapshotResponse + { + /// + /// Gets a collection of information about the snapshots. + /// + [JsonProperty("snapshots")] + public Snapshot[] Snapshots { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListVirtualInterfacesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListVirtualInterfacesResponse.cs new file mode 100644 index 000000000..62cb1c350 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListVirtualInterfacesResponse.cs @@ -0,0 +1,22 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using System.Collections.Generic; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Create Virtual Interface and List Virtual Interfaces requests. + /// + /// Create Virtual Interface (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + /// List Virtual Interfaces (Rackspace Cloud Networks Developer Guide - OpenStack Networking API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListVirtualInterfacesResponse + { + /// + /// Gets a collection of information about the virtual interfaces. + /// + [JsonProperty("virtual_interfaces")] + public IEnumerable VirtualInterfaces { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListVolumeResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListVolumeResponse.cs new file mode 100644 index 000000000..58fdc17a0 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListVolumeResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Volume Summaries request. + /// + /// List Volume Summaries (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListVolumeResponse + { + /// + /// Gets a collection of information about the volumes. + /// + [JsonProperty("volumes")] + public Volume[] Volumes { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ListVolumeTypeResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ListVolumeTypeResponse.cs new file mode 100644 index 000000000..da8df2719 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ListVolumeTypeResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Volume Types request. + /// + /// List Volume Types (OpenStack Block Storage Service API Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ListVolumeTypeResponse + { + /// + /// Gets a collection of information about the volume types. + /// + [JsonProperty("volume_types")] + public VolumeType[] VolumeTypes { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/MetaDataResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/MetaDataResponse.cs new file mode 100644 index 000000000..8e59b9559 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/MetaDataResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Metadata request. + /// + /// List Metadata (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class MetaDataResponse + { + /// + /// Gets the metadata information. + /// + [JsonProperty("metadata")] + public Metadata Metadata { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/MetadataItemResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/MetadataItemResponse.cs new file mode 100644 index 000000000..d62555385 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/MetadataItemResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Get Metadata Item request. + /// + /// Get Metadata Item (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class MetadataItemResponse + { + /// + /// Gets information about the metadata item. The returned object + /// will only have one item, containing the key and value for the metadata item. + /// + [JsonProperty("meta")] + public Metadata Metadata { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/NamespaceDoc.cs new file mode 100644 index 000000000..97b993282 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace + /// contains the object models for JSON responses returned by calls to Rackspace's + /// REST APIs. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/NewUserResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/NewUserResponse.cs new file mode 100644 index 000000000..f92e8efd0 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/NewUserResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Add User request. + /// + /// Add User (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class NewUserResponse + { + /// + /// Gets the information about the newly created user, including the generated + /// if no password was specified in the request. + /// + [JsonProperty("user")] + public NewUser NewUser { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/PasswordCredentialResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/PasswordCredentialResponse.cs new file mode 100644 index 000000000..cca204f5f --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/PasswordCredentialResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Providers.Rackspace.Objects.Request; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Update User Credentials request + /// when used with password credentials. + /// + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class PasswordCredentialResponse + { + /// + /// Gets the password credentials used for the Update User Credentials request. + /// + [JsonProperty("passwordCredentials")] + public PasswordCredential PasswordCredential { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/RescueServerResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/RescueServerResponse.cs new file mode 100644 index 000000000..f460dd078 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/RescueServerResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Rescue Server request. + /// + /// Rescue Server (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class RescueServerResponse + { + /// + /// Gets the temporary administrator password assigned for use while the server + /// is in rescue mode. + /// + [JsonProperty("adminPass")] + public string AdminPassword { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/RoleResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/RoleResponse.cs new file mode 100644 index 000000000..37355cba8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/RoleResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Add Role and Get Role by Name requests. + /// + /// Add Role (OpenStack Identity Service API v2.0 Reference) + /// Get Role by Name (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class RoleResponse + { + /// + /// Gets information about the role. + /// + [JsonProperty("role")] + public Role Role { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/RolesResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/RolesResponse.cs new file mode 100644 index 000000000..45e3d721e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/RolesResponse.cs @@ -0,0 +1,27 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Roles and List User Global Roles requests. + /// + /// List Roles (Rackspace OS-KSADM Extension - API v2.0) + /// List User Global Roles (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class RolesResponse + { + /// + /// Gets a collection of roles. + /// + [JsonProperty("roles")] + public Role[] Roles { get; private set; } + + /// + /// Gets a collection of links related to . + /// + [JsonProperty("roles_links")] + public string[] RoleLinks { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ServerDetailsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ServerDetailsResponse.cs new file mode 100644 index 000000000..2462db835 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ServerDetailsResponse.cs @@ -0,0 +1,22 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Get Server Details, Update Server, and Rebuild Server requests. + /// + /// Get Server Details (OpenStack Compute API v2 and Extensions Reference) + /// Update Server (OpenStack Compute API v2 and Extensions Reference) + /// Rebuild Server (OpenStack Compute API v2 and Extensions Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerDetailsResponse + { + /// + /// Gets the detailed information about the server. + /// + [JsonProperty("server")] + public Server Server { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ServerVolumeListResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ServerVolumeListResponse.cs new file mode 100644 index 000000000..5885df283 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ServerVolumeListResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using System.Collections.Generic; + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Volume Attachments request. + /// + /// List Volume Attachments (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerVolumeListResponse + { + /// + /// Gets a collection of information about the volume attachments. + /// + [JsonProperty("volumeAttachments")] + public IEnumerable ServerVolumes { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/ServerVolumeResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/ServerVolumeResponse.cs new file mode 100644 index 000000000..fd413048e --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/ServerVolumeResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Attach Volume to Server and Get Volume Attachment Details requests. + /// + /// Attach Volume to Server (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// Get Volume Attachment Details (Rackspace Next Generation Cloud Servers Developer Guide - API v2) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class ServerVolumeResponse + { + /// + /// Gets information about the volume attachment. + /// + [JsonProperty("volumeAttachment")] + public ServerVolume ServerVolume { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/TenantsResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/TenantsResponse.cs new file mode 100644 index 000000000..020389c7c --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/TenantsResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Tenants request. + /// + /// List Tenants (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class TenantsResponse + { + /// + /// Gets a collection of information about the tenants. + /// + [JsonProperty("tenants")] + public Tenant[] Tenants { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/UserCredentialResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/UserCredentialResponse.cs new file mode 100644 index 000000000..987c094b5 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/UserCredentialResponse.cs @@ -0,0 +1,21 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Update User Credentials request + /// when used with API Key credentials. + /// + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UserCredentialResponse + { + /// + /// Gets the API key credentials sent with the Update User Credentials request. + /// + [JsonProperty("RAX-KSKEY:apiKeyCredentials")] + public UserCredential UserCredential { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/UserImpersonationResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/UserImpersonationResponse.cs new file mode 100644 index 000000000..9165521a3 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/UserImpersonationResponse.cs @@ -0,0 +1,43 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Impersonate User request. + /// + /// + /// The Impersonate User API is a Rackspace-specific extension to the OpenStack + /// Identity Service, and is documented in the Rackspace Cloud Identity + /// Admin Developer Guide - API v2.0. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UserImpersonationResponse + { + /// + /// Gets the details for the response. + /// + [JsonProperty("access")] + public UserImpersonationData UserAccess { get; private set; } + + /// + /// This models the JSON body containing details for the Impersonate User response. + /// + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UserImpersonationData + { + /// + /// Gets the which allows providers to make + /// impersonated calls to API methods. + /// + [JsonProperty("token")] + public IdentityToken Token + { + get; + private set; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/UserResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/UserResponse.cs new file mode 100644 index 000000000..a5cdd03b8 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/UserResponse.cs @@ -0,0 +1,28 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the Get User Information by Name, Get User Information by ID, and Update User requests. + /// + /// + /// In certain situations with certain vendors, the List Users request is known to result + /// in a response that resembles this model. When such a situation is detected, this + /// response model is also used for the List Users response. + /// + /// Get User Information by Name (OpenStack Identity Service API v2.0 Reference) + /// Get User Information by ID (OpenStack Identity Service API v2.0 Reference) + /// Update User (OpenStack Identity Service API v2.0 Reference) + /// List Users (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UserResponse + { + /// + /// Gets information about the user. + /// + [JsonProperty("user")] + public User User { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/UsersResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/UsersResponse.cs new file mode 100644 index 000000000..bb49389aa --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/UsersResponse.cs @@ -0,0 +1,20 @@ +namespace net.openstack.Providers.Rackspace.Objects.Response +{ + using net.openstack.Core.Domain; + using Newtonsoft.Json; + + /// + /// This models the JSON response used for the List Users request. + /// + /// List Users (OpenStack Identity Service API v2.0 Reference) + /// + [JsonObject(MemberSerialization.OptIn)] + internal class UsersResponse + { + /// + /// Gets a collection of information about the users. + /// + [JsonProperty("users")] + public User[] Users { get; private set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/ProviderBase`1.cs b/src/OpenStack/Providers/Rackspace/ProviderBase`1.cs new file mode 100644 index 000000000..8fdb8f197 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/ProviderBase`1.cs @@ -0,0 +1,1405 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http.Headers; +using System.Net.Mime; +using System.Threading.Tasks; +using JSIStudios.SimpleRESTServices.Client; +using JSIStudios.SimpleRESTServices.Client.Json; +using net.openstack.Core; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Providers; +using net.openstack.Core.Validators; +using net.openstack.Providers.Rackspace.Validators; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using CancellationToken = System.Threading.CancellationToken; +using Encoding = System.Text.Encoding; +using Thread = System.Threading.Thread; + +namespace net.openstack.Providers.Rackspace +{ + /// + /// Adds common functionality for all Rackspace Providers. + /// + /// The service provider interface this object implements. + /// + public abstract class ProviderBase : IRackspaceProvider + where TProvider : class + { + /// + /// The to use for authenticating requests to this provider. + /// + protected readonly IIdentityProvider IdentityProvider; + + /// + /// The REST service implementation to use for requests sent from this provider. + /// + protected readonly IRestService RestService; + + /// + /// The default identity to use when none is specified in the specific request. + /// + protected readonly CloudIdentity DefaultIdentity; + + /// + /// The validator to use for determining whether a particular HTTP status code represents + /// a success or failure. + /// + protected readonly IHttpResponseCodeValidator ResponseCodeValidator; + + /// + /// This is the backing field for the property. + /// + private int? _connectionLimit; + + /// + /// This is the backing field for the property. + /// + private string _defaultRegion; + + /// + /// This is the backing field for the property. + /// + private IBackoffPolicy _backoffPolicy; + + /// + /// This is the backing field for the property. + /// + private string _applicationUserAgent; + + /// + /// Initializes a new instance of the class using + /// the specified default identity, default region, identity provider, and REST service + /// implementation, and the default HTTP response code validator. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + protected ProviderBase(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService) + : this(defaultIdentity, defaultRegion, identityProvider, restService, null) { } + + /// + /// Initializes a new instance of the class + /// using the specified values. + /// + /// The default identity to use for calls that do not explicitly specify an identity. If this value is , no default identity is available so all calls must specify an explicit identity. + /// The default region to use for calls that do not explicitly specify a region. If this value is , the default region for the user will be used; otherwise if the service uses region-specific endpoints all calls must specify an explicit region. + /// The identity provider to use for authenticating requests to this provider. If this value is , a new instance of is created using as the default identity. + /// The implementation of to use for executing REST requests. If this value is , the provider will use a new instance of . + /// The HTTP status code validator to use. If this value is , the provider will use . + protected ProviderBase(CloudIdentity defaultIdentity, string defaultRegion, IIdentityProvider identityProvider, IRestService restService, IHttpResponseCodeValidator httpStatusCodeValidator) + { + DefaultIdentity = defaultIdentity; + _defaultRegion = defaultRegion; + IdentityProvider = identityProvider ?? this as IIdentityProvider ?? new CloudIdentityProvider(defaultIdentity); + RestService = restService ?? new ExtendedJsonRestServices(); + ResponseCodeValidator = httpStatusCodeValidator ?? HttpResponseCodeValidator.Default; + } + + /// + /// This event is fired immediately before sending an asynchronous web request. + /// + /// + public event EventHandler BeforeAsyncWebRequest; + + /// + /// This event is fired when the result of an asynchronous web request is received. + /// + /// + public event EventHandler AfterAsyncWebResponse; + + /// + /// Gets or sets the maximum number of connections allowed on the + /// objects used for requests. If the value is , the connection limit value for the + /// object is not altered. + /// + /// If is less than or equal to 0. + public int? ConnectionLimit + { + get + { + return _connectionLimit; + } + + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + _connectionLimit = value; + } + } + + /// + /// Gets the default region for this provider instance, if one was specified. + /// + /// + /// The default region to use for API calls where an explicit region is not specified in the call; + /// or to use the default region associated with the identity making the call. + /// + public string DefaultRegion + { + get + { + return _defaultRegion; + } + } + + /// + /// Gets or sets the back-off policy to use for polling operations. + /// + /// + /// If this value is set to , the default back-off policy for the current + /// provider will be used. + /// + /// + public IBackoffPolicy BackoffPolicy + { + get + { + return _backoffPolicy ?? DefaultBackoffPolicy; + } + + set + { + _backoffPolicy = value; + } + } + + /// + /// Gets or sets the application-specific user agent for the provider instance. + /// + /// + /// This value is used for determining the value. The documentation for + /// that property includes specific information. + /// The default value is . + /// + /// + /// The application-specific user agent, as a string. This string should be a valid + /// User-Agent header value according to RFC 7231. + /// -or- + /// (or ) if the provider should not include an + /// application-specific user agent in HTTP requests, or if the user agent is customized in another manner (such + /// as overriding the method. + /// + /// + public string ApplicationUserAgent + { + get + { + return _applicationUserAgent; + } + + set + { + _applicationUserAgent = value; + } + } + + /// + /// Gets the default back-off policy for the current provider. + /// + /// + /// The default implementation returns . + /// Providers may override this property to change the default back-off policy. + /// + /// + protected virtual IBackoffPolicy DefaultBackoffPolicy + { + get + { + return net.openstack.Core.BackoffPolicy.Default; + } + } + + /// + /// Gets the default value for the User-Agent header for HTTP requests sent by this provider. + /// + /// + /// The default value for the User-Agent header for HTTP requests sent by this provider. + /// + protected string DefaultUserAgent + { + get + { + List userAgents = OpenStack.OpenStackNet.Configuration.UserAgents.Select(x => x.ToString()).ToList(); + if(!string.IsNullOrEmpty(ApplicationUserAgent)) + userAgents.Add(ApplicationUserAgent); + return string.Join(" ", userAgents); + } + } + + /// + /// Execute a REST request with an body and strongly-typed result. + /// + /// + /// If the request fails due to an authorization failure, i.e. the is , + /// the request is attempted a second time. + /// + /// This method calls , which results in a if the request fails. + /// + /// This method uses to handle the underlying REST request(s). + /// + /// The type of the data returned in the REST response. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The absolute URI for the request. + /// The HTTP method to use for the request. + /// + /// The body of the request. This parameter is optional. If the value is , + /// the request is sent without a body. + /// + /// + /// A collection of parameters to add to the query string portion of the request + /// URI. This parameter is optional. If the value is , no parameters are + /// added to the query string. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter + /// is optional. If the value is , no custom headers are added to the HTTP + /// request. + /// + /// if this request is retrying a previously failed operation; otherwise, . + /// if this is an authentication request; otherwise, . Authentication requests do not perform separate authentication prior to the call. + /// + /// The settings to use for the request. This parameter is optional. If the value + /// is , will be called to + /// provide the settings. + /// + /// + /// Returns a object containing the HTTP status code, + /// headers, body, and strongly-typed data from the REST response. + /// + /// If is . + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If the REST API request failed. + protected Response ExecuteRESTRequest(CloudIdentity identity, Uri absoluteUri, HttpMethod method, object body = null, Dictionary queryStringParameter = null, Dictionary headers = null, bool isRetry = false, bool isTokenRequest = false, RequestSettings settings = null) + { + if (absoluteUri == null) + throw new ArgumentNullException("absoluteUri"); + CheckIdentity(identity); + + return ExecuteRESTRequest>(identity, absoluteUri, method, body, queryStringParameter, headers, isRetry, isTokenRequest, settings, RestService.Execute); + } + + /// + /// Execute a REST request with an body and basic result (text or no content). + /// + /// + /// If the request fails due to an authorization failure, i.e. the is , + /// the request is attempted a second time. + /// + /// This method calls , which results in a if the request fails. + /// + /// This method uses to handle the underlying REST request(s). + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The absolute URI for the request. + /// The HTTP method to use for the request. + /// + /// The body of the request. This parameter is optional. If the value is , + /// the request is sent without a body. + /// + /// + /// A collection of parameters to add to the query string portion of the request + /// URI. This parameter is optional. If the value is , no parameters are + /// added to the query string. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter + /// is optional. If the value is , no custom headers are added to the HTTP + /// request. + /// + /// if this request is retrying a previously failed operation; otherwise, . + /// if this is an authentication request; otherwise, . Authentication requests do not perform separate authentication prior to the call. + /// + /// The settings to use for the request. This parameter is optional. If the value + /// is , will be called to + /// provide the settings. + /// + /// + /// Returns a object containing the HTTP status code, + /// headers, and body from the REST response. + /// + /// If is . + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If the REST API request failed. + protected Response ExecuteRESTRequest(CloudIdentity identity, Uri absoluteUri, HttpMethod method, object body = null, Dictionary queryStringParameter = null, Dictionary headers = null, bool isRetry = false, bool isTokenRequest = false, RequestSettings settings = null) + { + if (absoluteUri == null) + throw new ArgumentNullException("absoluteUri"); + CheckIdentity(identity); + + return ExecuteRESTRequest(identity, absoluteUri, method, body, queryStringParameter, headers, isRetry, isTokenRequest, settings, RestService.Execute); + } + + /// + /// Execute a REST request with an body and user-defined callback function + /// for constructing the resulting object. + /// + /// + /// If the request fails due to an authorization failure, i.e. the is , + /// the request is attempted a second time. + /// + /// This method calls , which results in a if the request fails. + /// + /// This method uses to handle the underlying REST request(s). + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The absolute URI for the request. + /// The HTTP method to use for the request. + /// + /// A user-specified function used to construct the resulting + /// object from the and a Boolean value specifying + /// whether or not a was thrown during the request. If + /// this value is , this method is equivalent to calling + /// . + /// + /// + /// The body of the request. This parameter is optional. If the value is , + /// the request is sent without a body. + /// + /// + /// A collection of parameters to add to the query string portion of the request + /// URI. This parameter is optional. If the value is , no parameters are + /// added to the query string. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter + /// is optional. If the value is , no custom headers are added to the HTTP + /// request. + /// + /// if this request is retrying a previously failed operation; otherwise, . + /// if this is an authentication request; otherwise, . Authentication requests do not perform separate authentication prior to the call. + /// + /// The settings to use for the request. This parameter is optional. If the value + /// is , will be called to + /// provide the settings. + /// + /// A object containing the result of the REST call. + /// If is . + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If the REST API request failed. + protected Response ExecuteRESTRequest(CloudIdentity identity, Uri absoluteUri, HttpMethod method, Func buildResponseCallback, object body = null, Dictionary queryStringParameter = null, Dictionary headers = null, bool isRetry = false, bool isTokenRequest = false, RequestSettings settings = null) + { + if (absoluteUri == null) + throw new ArgumentNullException("absoluteUri"); + CheckIdentity(identity); + + return ExecuteRESTRequest(identity, absoluteUri, method, body, queryStringParameter, headers, isRetry, isTokenRequest, settings, + (uri, requestMethod, requestBody, requestHeaders, requestQueryParams, requestSettings) => RestService.Execute(uri, requestMethod, buildResponseCallback, requestBody, requestHeaders, requestQueryParams, requestSettings)); + } + + /// + /// Execute a REST request, using a callback method to deserialize the result into a or object. + /// + /// + /// If the request fails due to an authorization failure, i.e. the is , + /// the request is attempted a second time. + /// + /// This method calls , which results in a if the request fails. + /// + /// The type used for representing the response to the REST call. + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The absolute URI for the request. + /// The HTTP method to use for the request. + /// + /// The body of the request. This parameter is optional. If the value is , + /// the request is sent without a body. + /// + /// + /// A collection of parameters to add to the query string portion of the request + /// URI. This parameter is optional. If the value is , no parameters are + /// added to the query string. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter + /// is optional. If the value is , no custom headers are added to the HTTP + /// request. + /// + /// if this request is retrying a previously failed operation; otherwise, . + /// if this is an authentication request; otherwise, . Authentication requests do not perform separate authentication prior to the call. + /// + /// The settings to use for the request. This parameter is optional. If the value + /// is , will be called to + /// provide the settings. + /// + /// A callback function that prepares and executes the HTTP request, and returns the deserialized result as an object of type . + /// A response object of type containing the result of the REST call. + /// If is . + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If the REST API request failed. + private T ExecuteRESTRequest(CloudIdentity identity, Uri absoluteUri, HttpMethod method, object body, Dictionary queryStringParameter, Dictionary headers, bool isRetry, bool isTokenRequest, RequestSettings requestSettings, + Func, Dictionary, RequestSettings, T> callback) where T : Response + { + if (absoluteUri == null) + throw new ArgumentNullException("absoluteUri"); + CheckIdentity(identity); + + identity = GetDefaultIdentity(identity); + + if (requestSettings == null) + requestSettings = BuildDefaultRequestSettings(); + + if (headers == null) + headers = new Dictionary(); + + if (!isTokenRequest) + headers["X-Auth-Token"] = IdentityProvider.GetToken(identity, isRetry).Id; + + string bodyStr = null; + if (body != null) + { + if (body is JObject) + bodyStr = body.ToString(); + else if (body is string) + bodyStr = body as string; + else + bodyStr = JsonConvert.SerializeObject(body, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + } + + if (string.IsNullOrEmpty(requestSettings.UserAgent)) + requestSettings.UserAgent = DefaultUserAgent; + + var response = callback(absoluteUri, method, bodyStr, headers, queryStringParameter, requestSettings); + + // on errors try again 1 time. + if (response.StatusCode == HttpStatusCode.Unauthorized && !isRetry && !isTokenRequest) + { + return ExecuteRESTRequest(identity, absoluteUri, method, body, queryStringParameter, headers, true, isTokenRequest, requestSettings, callback); + } + + CheckResponse(response); + + return response; + } + + /// + /// Executes a streaming REST request with a and basic result (text or no content). + /// + /// + /// If the request fails due to an authorization failure, i.e. the is , + /// the request is attempted a second time. + /// + /// This method uses an HTTP request timeout of 4 hours. + /// + /// This method calls , which results in a if the request fails. + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The absolute URI for the request. + /// The HTTP method to use for the request. + /// A stream providing the body of the request. + /// The size of the buffer used for copying data from to the HTTP request stream. + /// The maximum number of bytes to send with the request. This parameter is optional. If the value is 0, the request will include all data from . + /// + /// A collection of parameters to add to the query string portion of the request + /// URI. This parameter is optional. If the value is , no parameters are + /// added to the query string. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter + /// is optional. If the value is , no custom headers are added to the HTTP + /// request. + /// + /// if this request is retrying a previously failed operation; otherwise, . + /// + /// The settings to use for the request. This parameter is optional. If the value + /// is , will be called to + /// provide the settings. + /// + /// A user-defined callback function for reporting progress of the send operation. This parameter is optional. If the value is , the method does not report progress updates to the caller. + /// + /// Returns a object containing the HTTP status code, + /// headers, and body from the REST response. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is less than or equal to 0. + /// -or- + /// If is less than 0. + /// + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If the REST API request failed. + protected Response StreamRESTRequest(CloudIdentity identity, Uri absoluteUri, HttpMethod method, Stream stream, int chunkSize, long maxReadLength = 0, Dictionary queryStringParameter = null, Dictionary headers = null, bool isRetry = false, RequestSettings requestSettings = null, Action progressUpdated = null) + { + if (absoluteUri == null) + throw new ArgumentNullException("absoluteUri"); + if (stream == null) + throw new ArgumentNullException("stream"); + if (chunkSize <= 0) + throw new ArgumentOutOfRangeException("chunkSize"); + if (maxReadLength < 0) + throw new ArgumentOutOfRangeException("maxReadLength"); + CheckIdentity(identity); + + identity = GetDefaultIdentity(identity); + + if (requestSettings == null) + requestSettings = BuildDefaultRequestSettings(); + + requestSettings.Timeout = TimeSpan.FromMilliseconds(14400000); // Need to pass this in. + + if (headers == null) + headers = new Dictionary(); + + headers["X-Auth-Token"] = IdentityProvider.GetToken(identity, isRetry).Id; + + if (string.IsNullOrEmpty(requestSettings.UserAgent)) + requestSettings.UserAgent = DefaultUserAgent; + + long? initialPosition; + try + { + initialPosition = stream.Position; + } + catch (NotSupportedException) + { + initialPosition = null; + } + + Response response; + try + { + response = RestService.Stream(absoluteUri, method, stream, chunkSize, maxReadLength, headers, queryStringParameter, requestSettings, progressUpdated); + } + catch (ProtocolViolationException) + { + ServicePoint servicePoint = ServicePointManager.FindServicePoint(absoluteUri); + if (servicePoint.ProtocolVersion < HttpVersion.Version11) + { + // this is a workaround for issue #333 + // https://github.com/openstacknetsdk/openstack.net/issues/333 + // http://stackoverflow.com/a/22976809/138304 + int maxIdleTime = servicePoint.MaxIdleTime; + servicePoint.MaxIdleTime = 0; + Thread.Sleep(1); + servicePoint.MaxIdleTime = maxIdleTime; + } + + response = RestService.Stream(absoluteUri, method, stream, chunkSize, maxReadLength, headers, queryStringParameter, requestSettings, progressUpdated); + } + + // on errors try again 1 time. + if (response.StatusCode == HttpStatusCode.Unauthorized && !isRetry && initialPosition != null) + { + bool canRetry; + + try + { + if (stream.Position != initialPosition.Value) + stream.Position = initialPosition.Value; + + canRetry = true; + } + catch (NotSupportedException) + { + // unable to retry the operation + canRetry = false; + } + + if (canRetry) + { + return StreamRESTRequest(identity, absoluteUri, method, stream, chunkSize, maxReadLength, queryStringParameter, headers, true, requestSettings, progressUpdated); + } + } + + CheckResponse(response); + + return response; + } + + /// + /// Gets the default object to use for REST requests sent by this provider. + /// + /// + /// The base implementation returns a object initialized with the following values. + /// + /// + /// The is 0. + /// The is 200 milliseconds. + /// The contains and , along with the values in (if any). + /// The is set to . + /// The is set to . + /// The is set to . + /// Other properties are set to the default values for . + /// + /// + /// The caller may directly modify the object returned by this call, so a new object should be returned each time this method is called. + /// + /// A collection of non-200 HTTP status codes to consider as "success" codes for the request. This value may be or an empty collection to use the default value. + /// A object containing the default settings to use for a REST request sent by this provider. + protected virtual RequestSettings BuildDefaultRequestSettings(IEnumerable non200SuccessCodes = null) + { + var non200SuccessCodesAggregate = new List{ HttpStatusCode.Unauthorized, HttpStatusCode.Conflict }; + if(non200SuccessCodes != null) + non200SuccessCodesAggregate.AddRange(non200SuccessCodes); + + return new JsonRequestSettings + { + RetryCount = 0, + RetryDelay = TimeSpan.FromMilliseconds(200), + Non200SuccessCodes = non200SuccessCodesAggregate, + UserAgent = DefaultUserAgent, + AllowZeroContentLength = true, + ConnectionLimit = ConnectionLimit, + }; + } + + /// + /// Gets the associated with the specified service in the user's service catalog. + /// + /// + /// The endpoint returned by this method may not be an exact match for all arguments to this method. + /// This method filters the service catalog in the following order to locate an acceptable endpoint. + /// If more than one acceptable endpoint remains after all filters are applied, it is unspecified + /// which one is returned by this method. + /// + /// + /// This method only considers services which match the specified . + /// This method attempts to filter the remaining items to those matching . If is , or if no services match the specified name, this argument is ignored. + /// This method attempts to filter the remaining items to those matching . If is , the user's default region is used. If no services match the specified region, this argument is ignored. + /// If the argument is ignored as a result of the previous rule, this method filters the remaining items to only include region-independent endpoints, i.e. endpoints where is or empty. + /// + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The service type (see ). + /// The preferred name of the service (see ). + /// The preferred region for the service. If this value is , the user's default region will be used. + /// An object containing the details of the requested service. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If is , the service does not provide a region-independent endpoint, and no default region is available for the identity or provider. + /// If no service catalog is available for the user. + /// If no endpoint is available for the requested service. + /// If the REST API request failed. + protected Endpoint GetServiceEndpoint(CloudIdentity identity, string serviceType, string serviceName, string region) + { + if (serviceType == null) + throw new ArgumentNullException("serviceType"); + if (string.IsNullOrEmpty(serviceType)) + throw new ArgumentException("serviceType cannot be empty"); + CheckIdentity(identity); + + identity = GetDefaultIdentity(identity); + + var userAccess = IdentityProvider.GetUserAccess(identity); + + if (userAccess == null || userAccess.ServiceCatalog == null) + throw new UserAuthenticationException("Unable to authenticate user and retrieve authorized service endpoints."); + + IEnumerable services = userAccess.ServiceCatalog.Where(sc => string.Equals(sc.Type, serviceType, StringComparison.OrdinalIgnoreCase)); + + if (serviceName != null) + { + IEnumerable namedServices = services.Where(sc => string.Equals(sc.Name, serviceName, StringComparison.OrdinalIgnoreCase)); + if (namedServices.Any()) + services = namedServices; + } + + IEnumerable> endpoints = + services.SelectMany(service => service.Endpoints.Select(endpoint => Tuple.Create(service, endpoint))); + + string effectiveRegion = region; + if (string.IsNullOrEmpty(effectiveRegion)) + { + if (!string.IsNullOrEmpty(DefaultRegion)) + effectiveRegion = DefaultRegion; + else if (!string.IsNullOrEmpty(userAccess.User.DefaultRegion)) + effectiveRegion = userAccess.User.DefaultRegion; + } + + IEnumerable> regionEndpoints = + endpoints.Where(i => string.Equals(i.Item2.Region ?? string.Empty, effectiveRegion ?? string.Empty, StringComparison.OrdinalIgnoreCase)); + + if (regionEndpoints.Any()) + endpoints = regionEndpoints; + else + endpoints = endpoints.Where(i => string.IsNullOrEmpty(i.Item2.Region)); + + if (effectiveRegion == null && !endpoints.Any()) + throw new NoDefaultRegionSetException("No region was provided, the service does not provide a region-independent endpoint, and there is no default region set for the user's account."); + + Tuple serviceEndpoint = endpoints.FirstOrDefault(); + if (serviceEndpoint == null) + throw new UserAuthorizationException("The user does not have access to the requested service or region."); + + return serviceEndpoint.Item2; + } + + /// + /// Gets the for the associated with the + /// specified service in the user's service catalog. + /// + /// + /// For details on how endpoint resolution is performed, see . + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The service type (see ). + /// The preferred name of the service (see ). + /// The preferred region for the service. If this value is , the user's default region will be used. + /// The value for the object containing the details of the requested service. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If is and no default region is available for the identity or provider. + /// If no service catalog is available for the user. + /// If no endpoint is available for the requested service. + /// If the REST API request failed. + protected virtual string GetPublicServiceEndpoint(CloudIdentity identity, string serviceType, string serviceName, string region) + { + var endpoint = GetServiceEndpoint(identity, serviceType, serviceName, region); + + return endpoint.PublicURL; + } + + /// + /// Gets the for the associated with the + /// specified service in the user's service catalog. + /// + /// + /// For details on how endpoint resolution is performed, see . + /// + /// The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used. + /// The service type (see ). + /// The preferred name of the service (see ). + /// The preferred region for the service. If this value is , the user's default region will be used. + /// The value for the object containing the details of the requested service. + /// If is . + /// If is empty. + /// + /// If the provider does not support the given type. + /// -or- + /// The specified is not supported. + /// + /// + /// If is and no default identity is available for the provider. + /// + /// If is and no default region is available for the identity or provider. + /// If no service catalog is available for the user. + /// If no endpoint is available for the requested service. + /// If the REST API request failed. + protected virtual string GetInternalServiceEndpoint(CloudIdentity identity, string serviceType, string serviceName, string region) + { + var endpoint = GetServiceEndpoint(identity, serviceType, serviceName, region); + + return endpoint.InternalURL; + } + + /// + /// Validate the response to an HTTP request. + /// + /// + /// The validation is performed by calling . + /// + /// The response to the HTTP request. + /// If is . + /// If indicates the REST API call failed. + internal void CheckResponse(Response response) + { + if (response == null) + throw new ArgumentNullException("response"); + + ResponseCodeValidator.Validate(response); + } + + /// + /// Sets the , , + /// and properties of a collection of object to values + /// matching the request parameters used when the objects were created. + /// + /// The type of the provider-aware object to initialize. + /// The collection of provider-aware objects. + /// The region used for the request that created this object. + /// The identity used for the request that created this object. + /// This method returns an enumerable collection containing the objects in . + /// If is . + /// If the current provider object is not an instance of . + protected IEnumerable BuildCloudServersProviderAwareObject(IEnumerable input, string region, CloudIdentity identity) + where T : ProviderStateBase + { + if (input == null) + throw new ArgumentNullException("input"); + + foreach (T obj in input) + { + if (obj == null) + continue; + + BuildCloudServersProviderAwareObject(obj, region, identity); + } + + return input; + } + + /// + /// Sets the , , + /// and properties of an object to values + /// matching the request parameters used when the object was created. + /// + /// The type of the provider-aware object to initialize. + /// The provider-aware object. + /// The region used for the request that created this object. + /// The identity used for the request that created this object. + /// This method returns the argument. + /// If is . + /// If the current provider object is not an instance of . + protected T BuildCloudServersProviderAwareObject(T input, string region, CloudIdentity identity) + where T : ProviderStateBase + { + if (input == null) + throw new ArgumentNullException("input"); + + TProvider provider = this as TProvider; + if (provider == null) + throw new InvalidOperationException(string.Format("The current provider type {0} does not implement the provider type {1} required for the provider-aware object.", GetType(), typeof(TProvider))); + + input.Provider = provider; + input.Region = region; + input.Identity = identity; + return input; + } + + /// + /// Gets the effective cloud identity to use for a request based on the + /// argument and the configured default identity. + /// + /// The explicitly specified identity for the request, or if no identity was specified for the request. + /// The effective identity to use for the request, or if is and no default identity is available. + protected CloudIdentity GetDefaultIdentity(CloudIdentity identity) + { + if (identity != null) + return identity; + + if (DefaultIdentity != null) + return DefaultIdentity; + + return IdentityProvider.DefaultIdentity; + } + + /// + /// Creates a new dictionary from with all + /// entries with null or empty values removed. + /// + /// The dictionary of optional parameters. + /// + /// Returns a new dictionary created from with all + /// entries with or empty values removed. If + /// is , or if the resulting dictionary is empty, this method returns . + /// + protected Dictionary BuildOptionalParameterList(Dictionary optionalParameters) + { + if (optionalParameters == null) + return null; + + var paramList = optionalParameters.Where(optionalParameter => !string.IsNullOrEmpty(optionalParameter.Value)).ToDictionary(optionalParameter => optionalParameter.Key, optionalParameter => optionalParameter.Value, optionalParameters.Comparer); + if (!paramList.Any()) + return null; + + return paramList; + } + + /// + /// Ensures that an identity is available for a request. + /// + /// The explicitly specified identity for the request, or if the request should use the default identity for the provider. + /// If is and no default identity is available for the request. + protected virtual void CheckIdentity(CloudIdentity identity) + { + if (GetDefaultIdentity(identity) == null) + throw new InvalidOperationException("No identity was specified for the request, and no default is available for the provider."); + } + + /// + /// Creates a task continuation function responsible for creating an for use + /// in asynchronous REST API calls. The input to the continuation function is a completed task which + /// computes an for an authenticated user and a base URI for use in binding + /// the URI templates for REST API calls. The continuation function calls + /// to create and prepare the resulting . + /// + /// The to use for the request. + /// The for the target URI. + /// A collection of parameters for binding the URI template in a call to . + /// An optional transformation to apply to the bound URI for the request. If this value is , the result of binding the with will be used as the absolute request URI. + /// A task continuation delegate which can be used to create an following the completion of a task that obtains an and the base URI for a service. + /// + /// If is . + /// -or- + /// If is . + /// + /// + protected Func>, HttpWebRequest> PrepareRequestAsyncFunc(HttpMethod method, UriTemplate template, IDictionary parameters, Func uriTransform = null) + { + if (template == null) + throw new ArgumentNullException("template"); + if (parameters == null) + throw new ArgumentNullException("parameters"); + + return + task => + { + Uri baseUri = task.Result.Item2; + return PrepareRequestImpl(method, task.Result.Item1, template, baseUri, parameters, uriTransform); + }; + } + + /// + /// Creates a task continuation function responsible for creating an for use + /// in asynchronous REST API calls. The input to the continuation function is a completed task which + /// computes an for an authenticated user and a base URI for use in binding + /// the URI templates for REST API calls. The continuation function calls + /// to create and prepare the resulting , and then asynchronously obtains + /// the request stream for the request and writes the specified in JSON notation. + /// + /// The type modeling the body of the request. + /// The to use for the request. + /// The for the target URI. + /// A collection of parameters for binding the URI template in a call to . + /// A object modeling the body of the web request. The object is serialized in JSON notation for inclusion in the request. + /// An optional transformation to apply to the bound URI for the request. If this value is , the result of binding the with will be used as the absolute request URI. + /// A task continuation delegate which can be used to create an following the completion of a task that obtains an and the base URI for a service. + /// + /// If is . + /// -or- + /// If is . + /// + /// + protected Func>, Task> PrepareRequestAsyncFunc(HttpMethod method, UriTemplate template, IDictionary parameters, TBody body, Func uriTransform = null) + { + return + task => + { + Uri baseUri = task.Result.Item2; + HttpWebRequest request = PrepareRequestImpl(method, task.Result.Item1, template, baseUri, parameters, uriTransform); + byte[] encodedBody = EncodeRequestBodyImpl(request, body); + + Task streamTask = Task.Factory.FromAsync(request.BeginGetRequestStream(null, null), request.EndGetRequestStream); + return + streamTask.Then(subTask => + { + return + Task.Factory.FromAsync((callback, state) => subTask.Result.BeginWrite(encodedBody, 0, encodedBody.Length, callback, state), subTask.Result.EndWrite, null) + .Select(t => request); + }); + }; + } + + /// + /// Encode the body of a request, and update the properties + /// as necessary to support the encoded body. + /// + /// + /// The default implementation uses to convert + /// to JSON notation, and then uses to encode the text. The + /// and + /// properties are updated to reflect the JSON content. + /// + /// The type modeling the body of the request. + /// The object for the request. + /// The object modeling the body of the request. + /// The encoded content to send with the . + /// If is . + /// + protected virtual byte[] EncodeRequestBodyImpl(HttpWebRequest request, TBody body) + { + if (request == null) + throw new ArgumentNullException("request"); + + string bodyText = JsonConvert.SerializeObject(body); + byte[] encodedBody = Encoding.UTF8.GetBytes(bodyText); + if (string.IsNullOrEmpty(request.ContentType)) + request.ContentType = new ContentType() { MediaType = JsonRequestSettings.JsonContentType, CharSet = "UTF-8" }.ToString(); + + request.ContentLength = encodedBody.Length; + + return encodedBody; + } + + /// + /// Creates and prepares an for an asynchronous REST API call. + /// + /// + /// The base implementation sets the following properties of the web request. + /// + /// + /// + /// Property + /// Value + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// ["X-Auth-Token"] + /// + /// + /// + /// + /// + /// + /// + /// + /// 14400 seconds (4 hours) + /// + /// + /// + /// + /// + /// + /// + /// The to use for the request. + /// The to use for making an authenticated REST API call. + /// The for the target URI. + /// The base URI to use for binding the URI template. + /// A collection of parameters for binding the URI template in a call to . + /// An optional transformation to apply to the bound URI for the request. If this value is , the result of binding the with will be used as the absolute request URI. + /// An to use for making the asynchronous REST API call. + /// + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// -or- + /// If is . + /// + /// If is not an absolute URI. + /// + protected virtual HttpWebRequest PrepareRequestImpl(HttpMethod method, IdentityToken identityToken, UriTemplate template, Uri baseUri, IDictionary parameters, Func uriTransform) + { + Uri boundUri = template.BindByName(baseUri, parameters); + if (uriTransform != null) + boundUri = uriTransform(boundUri); + + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(boundUri); + request.Method = method.ToString().ToUpperInvariant(); + request.Accept = JsonRequestSettings.JsonContentType; + request.Headers["X-Auth-Token"] = identityToken.Id; + request.UserAgent = DefaultUserAgent; + request.Timeout = (int)TimeSpan.FromSeconds(14400).TotalMilliseconds; + if (ConnectionLimit.HasValue) + request.ServicePoint.ConnectionLimit = ConnectionLimit.Value; + + return request; + } + + /// + /// Gets the base absolute URI to use for making asynchronous REST API calls to this service. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task + /// completes successfully, the property will contain + /// a representing the base absolute URI for the service. + /// + /// + protected virtual Task GetBaseUriAsync(CancellationToken cancellationToken) + { + throw new NotSupportedException(); + } + + /// + /// Authenticate with the identity service prior to making an asynchronous REST API call. + /// + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the task + /// completes successfully, the property will contain + /// a tuple containing the authentication information. The first element of the tuple is + /// an for the authenticated user, and the second element is + /// a base absolute the service should use for making authenticated + /// asynchronous web requests. + /// + /// + protected virtual Task> AuthenticateServiceAsync(CancellationToken cancellationToken) + { + Task authenticate; + IIdentityService identityService = IdentityProvider as IIdentityService; + if (identityService != null) + authenticate = identityService.GetTokenAsync(GetDefaultIdentity(null), cancellationToken); + else + authenticate = Task.Factory.StartNew(() => IdentityProvider.GetToken(GetDefaultIdentity(null))); + + Func, Task>> getBaseUri = + task => + { + Task[] tasks = { task, GetBaseUriAsync(cancellationToken) }; + return Task.Factory.ContinueWhenAll(tasks, + ts => + { + Task first = (Task)ts[0]; + Task second = (Task)ts[1]; + return Tuple.Create(first.Result, second.Result); + }); + }; + + return authenticate.Then(getBaseUri); + } + + /// + /// Invokes the event for the specified . + /// + /// The web request. + /// If is . + /// + protected virtual void OnBeforeAsyncWebRequest(HttpWebRequest request) + { + var handler = BeforeAsyncWebRequest; + if (handler != null) + handler(this, new WebRequestEventArgs(request)); + } + + /// + /// Invokes the event for the specified . + /// + /// The web response. + /// If is . + /// + protected virtual void OnAfterAsyncWebResponse(HttpWebResponse response) + { + if (response == null) + throw new ArgumentNullException("response"); + + var handler = AfterAsyncWebResponse; + if (handler != null) + handler(this, new WebResponseEventArgs(response)); + } + + /// + /// Gets the response from an asynchronous web request, with the body of the response (if any) returned as a string. + /// + /// The that the task will observe. + /// + /// A continuation function delegate which takes an asynchronously prepared + /// and returns the resulting body of the operation, if any, as a string. + /// + /// + protected virtual Func, Task> GetResponseAsyncFunc(CancellationToken cancellationToken) + { + Func, Task> requestResource = + task => RequestResourceImplAsync(task, cancellationToken); + + Func, Tuple> readResult = + task => ReadResultImpl(task, cancellationToken); + + Func>, string> parseResult = + task => task.Result.Item2; + + Func, Task> result = + task => + { + return task.Then(requestResource) + .Select(readResult, true) + .Select(parseResult); + }; + + return result; + } + + /// + /// Gets the response from an asynchronous web request, with the body of the response (if any) returned as an object of type . + /// + /// The type for the response object. + /// The that the task will observe. + /// + /// A continuation function delegate which parses the body of the + /// and returns an object of type , as an asynchronous operation. If + /// this value is , the conversion will be performed by calling . + /// + /// + /// A continuation function delegate which takes an asynchronously prepared + /// and returns the resulting body of the operation, if any, as an instance of type . + /// + /// + protected virtual Func, Task> GetResponseAsyncFunc(CancellationToken cancellationToken, Func>, Task> parseResult = null) + { + Func, Task> requestResource = + task => RequestResourceImplAsync(task, cancellationToken); + + Func, Tuple> readResult = + task => ReadResultImpl(task, cancellationToken); + + if (parseResult == null) + { + parseResult = task => ParseJsonResultImplAsync(task, cancellationToken); + } + + Func, Task> result = + task => + { + return task.Then(requestResource) + .Select(readResult, true) + .Then(parseResult); + }; + + return result; + } + + /// + /// This method calls and then asynchronously gets the response + /// to the web request. + /// + /// + /// This method is the first step of implementing and . + /// + /// A task which created and prepared the . + /// The that the task will observe. + /// A object representing the asynchronous operation. + /// If is . + /// + protected virtual Task RequestResourceImplAsync(Task task, CancellationToken cancellationToken) + { + if (task == null) + throw new ArgumentNullException("task"); + + OnBeforeAsyncWebRequest(task.Result); + return task.Result.GetResponseAsync(cancellationToken); + } + + /// + /// This method reads the complete body of an asynchronous as a string. + /// + /// A object representing the asynchronous operation to get the . + /// The that the task will observe. + /// A object. The first element of the tuple contains the + /// provided by as an . + /// The second element of the tuple contains the complete body of the response as a string. + /// + /// If is . + /// + protected virtual Tuple ReadResultImpl(Task task, CancellationToken cancellationToken) + { + if (task == null) + throw new ArgumentNullException("task"); + + HttpWebResponse response; + WebException webException = null; + if (task.IsFaulted) + { + webException = task.Exception.Flatten().InnerException as WebException; + if (webException == null) + task.PropagateExceptions(); + + response = webException.Response as HttpWebResponse; + if (response == null) + task.PropagateExceptions(); + } + else + { + response = (HttpWebResponse)task.Result; + } + + OnAfterAsyncWebResponse(response); + using (StreamReader reader = new StreamReader(response.GetResponseStream())) + { + string body = reader.ReadToEnd(); + if (task.IsFaulted) + { + if (!string.IsNullOrEmpty(body)) + { + WebExceptionStatus webExceptionStatus = webException != null ? webException.Status : WebExceptionStatus.UnknownError; + WebResponse webResponse = webException != null ? webException.Response : null; + throw new WebException(body, task.Exception, webExceptionStatus, webResponse); + } + + task.PropagateExceptions(); + } + + return Tuple.Create(response, body); + } + } + + /// + /// Provides a default object parser for which converts the + /// body of an to an object of type by calling + /// + /// + /// The type for the response object. + /// A object representing the asynchronous operation to get the . + /// The that the task will observe. + /// + /// A object representing the asynchronous operation. When the operation + /// completes successfully, the property will contain an + /// object of type representing the serialized body of the response. + /// + /// If is . + /// + protected virtual Task ParseJsonResultImplAsync(Task> task, CancellationToken cancellationToken) + { + return Task.Factory.StartNew(() => JsonConvert.DeserializeObject(task.Result.Item2)); + } + + IIdentityProvider IRackspaceProvider.IdentityProvider + { + get { return IdentityProvider; } + } + + CloudIdentity IRackspaceProvider.DefaultIdentity + { + get { return DefaultIdentity; } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/RackspaceImpersonationIdentity.cs b/src/OpenStack/Providers/Rackspace/RackspaceImpersonationIdentity.cs new file mode 100644 index 000000000..b89de38df --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/RackspaceImpersonationIdentity.cs @@ -0,0 +1,21 @@ +using net.openstack.Providers.Rackspace.Objects; + +namespace net.openstack.Providers.Rackspace +{ + /// + /// Represents a cloud identity that impersonates another . + /// + /// + public class RackspaceImpersonationIdentity : RackspaceCloudIdentity + { + /// + /// Gets or sets the of the user to impersonate. + /// + /// + /// The class represents credentials + /// (as opposed to an account), so any changes made to this property value will + /// not be reflected in the account. + /// + public RackspaceCloudIdentity UserToImpersonate { get; set; } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Validators/CloudBlockStorageValidator.cs b/src/OpenStack/Providers/Rackspace/Validators/CloudBlockStorageValidator.cs new file mode 100644 index 000000000..7e989bd31 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Validators/CloudBlockStorageValidator.cs @@ -0,0 +1,40 @@ +using System; +using net.openstack.Core.Validators; +using net.openstack.Providers.Rackspace.Exceptions; + +namespace net.openstack.Providers.Rackspace.Validators +{ + /// + /// Provides an implementation of for + /// operation with Rackspace's Cloud Block Storage product. + /// + /// + public class CloudBlockStorageValidator : IBlockStorageValidator + { + /// + /// A default instance of . + /// + private static readonly CloudBlockStorageValidator _default = new CloudBlockStorageValidator(); + + /// + /// Gets a default implementation of . + /// + public static CloudBlockStorageValidator Default + { + get + { + return _default; + } + } + + /// + public void ValidateVolumeSize(int size) + { + if (size < 0) + throw new ArgumentOutOfRangeException("size"); + + if (size < 1 || size > 1000) + throw new InvalidVolumeSizeException(size); + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Validators/CloudFilesValidator.cs b/src/OpenStack/Providers/Rackspace/Validators/CloudFilesValidator.cs new file mode 100644 index 000000000..b0c2c66ca --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Validators/CloudFilesValidator.cs @@ -0,0 +1,58 @@ +using System; +using net.openstack.Core; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Validators; + +namespace net.openstack.Providers.Rackspace.Validators +{ + /// + /// Provides an implementation of for + /// operation with Rackspace's Cloud Files product. + /// + /// + public class CloudFilesValidator : IObjectStorageValidator + { + /// + /// A default instance of . + /// + private static readonly CloudFilesValidator _default = new CloudFilesValidator(); + + /// + /// Gets a default instance of . + /// + public static CloudFilesValidator Default + { + get + { + return _default; + } + } + + /// + public void ValidateContainerName(string containerName) + { + if (containerName == null) + throw new ArgumentNullException("containerName"); + + var containerNameString = string.Format("Container Name:[{0}]", containerName); + if (string.IsNullOrEmpty(containerName)) + throw new ArgumentNullException("containerName", "ERROR: Container Name cannot be empty."); + if (UriUtility.UriEncode(containerName, UriPart.AnyUrl).Length > 256) + throw new ContainerNameException(string.Format("ERROR: encoded URL Length greater than 256 char's. {0}", containerNameString)); + if (containerName.Contains("/")) + throw new ContainerNameException(string.Format("ERROR: Container Name contains a /. {0}", containerNameString)); + } + + /// + public void ValidateObjectName(string objectName) + { + if (objectName == null) + throw new ArgumentNullException("objectName"); + + if (string.IsNullOrEmpty(objectName)) + throw new ArgumentNullException(); + if (UriUtility.UriEncode(objectName, UriPart.AnyUrl).Length > 1024) + throw new ObjectNameException("ERROR: Url Encoded Object Name exceeds 1024 char's"); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Providers/Rackspace/Validators/CloudNetworksValidator.cs b/src/OpenStack/Providers/Rackspace/Validators/CloudNetworksValidator.cs new file mode 100644 index 000000000..1e46339a5 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Validators/CloudNetworksValidator.cs @@ -0,0 +1,74 @@ +using System; +using System.Net; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Validators; + +namespace net.openstack.Providers.Rackspace.Validators +{ + /// + /// Provides an implementation of for + /// operation with Rackspace's Cloud Networks product. + /// + /// + public class CloudNetworksValidator : INetworksValidator + { + /// + /// A default instance of . + /// + private static readonly CloudNetworksValidator _default = new CloudNetworksValidator(); + + /// + /// Gets a default instance of . + /// + public static CloudNetworksValidator Default + { + get + { + return _default; + } + } + + /// + public void ValidateCidr(string cidr) + { + if (cidr == null) + throw new ArgumentNullException("cidr"); + if (string.IsNullOrEmpty(cidr)) + throw new CidrFormatException("cidr cannot be empty"); + + if (!cidr.Contains("/")) + throw new CidrFormatException(string.Format("ERROR: CIDR {0} is missing /", cidr)); + + var parts = cidr.Split('/'); + + if (parts.Length != 2) + throw new CidrFormatException(string.Format("ERROR: CIDR {0} must have exactly one / character", cidr)); + + var ipAddress = parts[0]; + var cidr_range = parts[1]; + + if (!IsIpAddress(ipAddress)) + throw new CidrFormatException(string.Format("ERROR: IP address segment ({0}) of CIDR is not a valid IP address", ipAddress)); + + int cidrInt; + if (!int.TryParse(cidr_range, out cidrInt)) + throw new CidrFormatException(string.Format("ERROR: CIDR range segment {0} must be an integer", cidr_range)); + + if (cidrInt < 1 || cidrInt > 32) + throw new CidrFormatException(string.Format("ERROR: CIDR range segment {0} must be between 1 and 32", cidr_range)); + } + + /// + /// Returns true if the string matches the ip address pattern (xxx.xxx.xxx.xxx) + /// and all octets are numeric and less than 256 + /// + /// + /// + private bool IsIpAddress(string address) + { + IPAddress ipAddress; + return IPAddress.TryParse(address, out ipAddress); + } + + } +} diff --git a/src/OpenStack/Providers/Rackspace/Validators/HttpResponseCodeValidator.cs b/src/OpenStack/Providers/Rackspace/Validators/HttpResponseCodeValidator.cs new file mode 100644 index 000000000..61ddc69ed --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Validators/HttpResponseCodeValidator.cs @@ -0,0 +1,66 @@ +using System; +using System.Net; +using JSIStudios.SimpleRESTServices.Client; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Core.Validators; + +namespace net.openstack.Providers.Rackspace.Validators +{ + /// + /// Provides an implementation of for + /// operation with Rackspace's products. + /// + /// + public class HttpResponseCodeValidator : IHttpResponseCodeValidator + { + /// + /// A default instance of . + /// + private static readonly HttpResponseCodeValidator _default = new HttpResponseCodeValidator(); + + /// + /// Gets a default instance of . + /// + public static HttpResponseCodeValidator Default + { + get + { + return _default; + } + } + + /// + public void Validate(Response response) + { + if (response == null) + throw new ArgumentNullException("response"); + + if (response.StatusCode <= (HttpStatusCode)299) + return; + + switch (response.StatusCode) + { + case HttpStatusCode.BadRequest: + throw new BadServiceRequestException(response); + case HttpStatusCode.Unauthorized: + case HttpStatusCode.Forbidden: + case HttpStatusCode.MethodNotAllowed: + throw new UserNotAuthorizedException(response); + case HttpStatusCode.NotFound: + throw new ItemNotFoundException(response); + case HttpStatusCode.Conflict: + throw new ServiceConflictException(response); + case HttpStatusCode.RequestEntityTooLarge: + throw new ServiceLimitReachedException(response); + case HttpStatusCode.InternalServerError: + throw new ServiceFaultException(response); + case HttpStatusCode.NotImplemented: + throw new MethodNotImplementedException(response); + case HttpStatusCode.ServiceUnavailable: + throw new ServiceUnavailableException(response); + default: + throw new ResponseException(string.Format("Unexpected HTTP error: {0}", response.StatusCode), response); + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/Validators/NamespaceDoc.cs b/src/OpenStack/Providers/Rackspace/Validators/NamespaceDoc.cs new file mode 100644 index 000000000..d9bbca08a --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/Validators/NamespaceDoc.cs @@ -0,0 +1,14 @@ +namespace net.openstack.Providers.Rackspace.Validators +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines + /// classes for validating various arguments before they are used in API calls to Rackspace + /// services. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/OpenStack/Providers/Rackspace/WebRequestEventArgs.cs b/src/OpenStack/Providers/Rackspace/WebRequestEventArgs.cs new file mode 100644 index 000000000..f61ff64c9 --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/WebRequestEventArgs.cs @@ -0,0 +1,44 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Net; + + /// + /// This class contains data for events that happen in the context of a + /// . + /// + /// + /// + public class WebRequestEventArgs : EventArgs + { + /// + /// This is the backing field for the property. + /// + private readonly HttpWebRequest _request; + + /// + /// Initializes a new instance of the class + /// with the specified web request. + /// + /// The HTTP web request. + /// If is . + public WebRequestEventArgs(HttpWebRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + _request = request; + } + + /// + /// Gets the associated with the event. + /// + public HttpWebRequest Request + { + get + { + return _request; + } + } + } +} diff --git a/src/OpenStack/Providers/Rackspace/WebResponseEventArgs.cs b/src/OpenStack/Providers/Rackspace/WebResponseEventArgs.cs new file mode 100644 index 000000000..1162f7cda --- /dev/null +++ b/src/OpenStack/Providers/Rackspace/WebResponseEventArgs.cs @@ -0,0 +1,44 @@ +namespace net.openstack.Providers.Rackspace +{ + using System; + using System.Net; + + /// + /// This class contains data for events that happen in the context of a + /// . + /// + /// + /// + public class WebResponseEventArgs : EventArgs + { + /// + /// This is the backing field for the property. + /// + private readonly HttpWebResponse _response; + + /// + /// Initializes a new instance of the class + /// with the specified web response. + /// + /// The HTTP web response. + /// If is . + public WebResponseEventArgs(HttpWebResponse response) + { + if (response == null) + throw new ArgumentNullException("response"); + + _response = response; + } + + /// + /// Gets the associated with the event. + /// + public HttpWebResponse Response + { + get + { + return _response; + } + } + } +} diff --git a/src/OpenStack/Serialization/DefaultJsonConverter.cs b/src/OpenStack/Serialization/DefaultJsonConverter.cs new file mode 100644 index 000000000..5cbde39af --- /dev/null +++ b/src/OpenStack/Serialization/DefaultJsonConverter.cs @@ -0,0 +1,76 @@ +using System; +using Newtonsoft.Json; + +namespace OpenStack.Serialization +{ + /// + /// Converter which uses the default serialization/deserialization. + /// + /// + public abstract class DefaultJsonConverter : JsonConverter + { + /// These are on by default so that the converter is picked up and used. + /// Once we have wrapped/unwrapped, we set to false so that the default serialization/deserialization logic is used. + private static bool _canRead = true; + private static bool _canWrite = true; + private static readonly object ReadLock = new object(); + private static readonly object WriteLock = new object(); + + /// + public override bool CanRead + { + get + { + lock (ReadLock) + { + return _canRead; + } + } + } + + /// + public override bool CanWrite + { + get + { + lock (WriteLock) + { + return _canWrite; + } + } + } + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + lock (WriteLock) + { + // Regular Serialization + _canWrite = false; + serializer.Serialize(writer, value); + _canWrite = true; + } + } + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + object result; + + lock (ReadLock) + { + _canRead = false; + result = serializer.Deserialize(reader, objectType); + _canRead = true; + } + + return result; + } + + /// + public override bool CanConvert(Type objectType) + { + return true; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/IHaveExtraData.cs b/src/OpenStack/Serialization/IHaveExtraData.cs new file mode 100644 index 000000000..0c25c64f1 --- /dev/null +++ b/src/OpenStack/Serialization/IHaveExtraData.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; + +namespace OpenStack.Serialization +{ + /// + /// Identifies a resource as potentially containing more data than what is exposed via properties. + /// + /// + public interface IHaveExtraData + { + /// + /// Contains any additional data returned from the cloud provider which has not already been mapped to a property. + /// + IDictionary Data { get; set; } + } + + /// + /// Provides convenience methods for working with custom resource properties. + /// + /// + public static class IHaveExtraDataExtensions + { + /// + /// Get a custom resource property. + /// + public static T GetExtraData(this IHaveExtraData dataContainer, string key) + where T : class + { + JToken jsonValue; + if (dataContainer.Data.TryGetValue(key, out jsonValue)) + return jsonValue.Value(); + + return null; + } + + /// + /// Sets a custom resource property. + /// + public static void SetExtraData(this IHaveExtraData dataContainer, string key, object value) + { + dataContainer.Data[key] = value != null ? JToken.FromObject(value) : JValue.CreateNull(); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/IPageBuilder.cs b/src/OpenStack/Serialization/IPageBuilder.cs new file mode 100644 index 000000000..79a52e024 --- /dev/null +++ b/src/OpenStack/Serialization/IPageBuilder.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Flurl; + +namespace OpenStack.Serialization +{ + /// + public interface IPageBuilder + { + /// + /// Sets the next page handler. + /// + /// The handler. + void SetNextPageHandler(Func> value); + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/IPageLink.cs b/src/OpenStack/Serialization/IPageLink.cs new file mode 100644 index 000000000..f7a0ece5e --- /dev/null +++ b/src/OpenStack/Serialization/IPageLink.cs @@ -0,0 +1,12 @@ +namespace OpenStack.Serialization +{ + /// + public interface IPageLink + { + /// + string Url { get; } + + /// + bool IsNextPage { get; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/IQueryStringBuilder.cs b/src/OpenStack/Serialization/IQueryStringBuilder.cs new file mode 100644 index 000000000..3ec27402b --- /dev/null +++ b/src/OpenStack/Serialization/IQueryStringBuilder.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace OpenStack.Serialization +{ + /// + public interface IQueryStringBuilder + { + /// + IDictionary Build(); + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/IServiceResource.cs b/src/OpenStack/Serialization/IServiceResource.cs new file mode 100644 index 000000000..767ded194 --- /dev/null +++ b/src/OpenStack/Serialization/IServiceResource.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace OpenStack.Serialization +{ + /// + /// Resources which want to expose service operations directly (e.g. resource.Delete()) + /// should implement this interface and the service will use it to add a reference to itself. + /// + /// + public interface IServiceResource + { + /// + /// The service which originally constructed the resource. This instance will be used for further operations on the resource. + /// + object Owner { get; set; } + } + + /// + /// Resources which are children of another resource. + /// + /// + public interface IChildResource : IServiceResource + { + /// + /// Called after deserialization to bootstrap a link from the child back to the parent resource. + /// + void SetParent(object parent); + + /// + /// Called after deserialization to bootstrap a link from the child back to the parent resource. + /// + void SetParent(string parentId); + } + + /// + public static class ServiceResourceExtensions + { + /// + public static async Task PropogateOwner(this Task task, object owner) + where T : IServiceResource + { + T resource = await task.ConfigureAwait(false); + return PropogateOwner(resource, owner); + } + + /// + public static T PropogateOwner(this T resource, object owner) + where T : IServiceResource + { + if (resource == null) + return default(T); + + resource.Owner = owner; + + foreach (PropertyInfo prop in resource.GetType().GetProperties()) + { + object propVal; + try + { + propVal = prop.GetValue(resource); + } + catch + { + continue; + } + + (propVal as IServiceResource)?.PropogateOwner(owner); + (propVal as IEnumerable)?.PropogateOwnerToChildren(owner); + } + + return resource; + } + + /// + public static async Task PropogateOwnerToChildren(this Task task, object owner) + where T : IEnumerable + { + T resources = await task.ConfigureAwait(false); + return resources.PropogateOwnerToChildren(owner); + } + + /// + public static T PropogateOwnerToChildren(this T resources, object owner) + where T : IEnumerable + { + foreach (var resource in resources) + { + resource.PropogateOwner(owner); + } + return resources; + } + + /// + /// Thrown when a resource as not constructed by the SDK. + public static T GetOwnerOrThrow(this IServiceResource resource, [CallerMemberName] string callerName = "") + where T : class + { + var owner = resource.Owner as T; + if (owner != null) + return owner; + + var ownerName = typeof(T).Name; + throw new InvalidOperationException(string.Format($"{callerName} can only be used on instances which were constructed by {ownerName}. Use {ownerName}.{callerName} instead.")); + } + + /// + public static async Task SetParent(this Task task, string parentId) + where T : IChildResource + { + var resource = await task.ConfigureAwait(false); + resource.SetParent(parentId); + return resource; + } + + /// + public static async Task SetParentOnChildren(this Task task, string parentId) + where T : IEnumerable + { + var resources = await task.ConfigureAwait(false); + return SetParentOnChildren(resources, parentId); + } + + /// + public static T SetParentOnChildren(this T resources, string parentId) + where T : IEnumerable + { + foreach (var resource in resources) + { + resource.SetParent(parentId); + } + + return resources; + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/IdentifierConverter.cs b/src/OpenStack/Serialization/IdentifierConverter.cs new file mode 100644 index 000000000..e0722bcf0 --- /dev/null +++ b/src/OpenStack/Serialization/IdentifierConverter.cs @@ -0,0 +1,40 @@ +using System; +using Newtonsoft.Json; + +namespace OpenStack.Serialization +{ + /// + public class IdentifierConverter : JsonConverter + { + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + return; + + Identifier id = (Identifier) value; + writer.WriteValue(id.ToString()); + } + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch (reader.TokenType) + { + case JsonToken.Null: + return null; + case JsonToken.String: + var id = reader.Value.ToString(); + return string.IsNullOrEmpty(id) ? null : new Identifier(id); + } + + throw new JsonSerializationException(string.Format("Unexpected token when deserializing {0}", objectType.FullName)); + } + + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Identifier); + } + } +} diff --git a/src/OpenStack/Serialization/JsonConverterWithConstructorAttribute.cs b/src/OpenStack/Serialization/JsonConverterWithConstructorAttribute.cs new file mode 100644 index 000000000..8b3472ce8 --- /dev/null +++ b/src/OpenStack/Serialization/JsonConverterWithConstructorAttribute.cs @@ -0,0 +1,63 @@ +using System; +using System.Globalization; +using Newtonsoft.Json; + +namespace OpenStack.Serialization +{ + /// + /// Acts like Json.NET's [JsonConverter] but allows for constructor arguments + /// + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Parameter)] + public sealed class JsonConverterWithConstructorAttribute : Attribute + { + private readonly Type _converterType; + private readonly object[] _constructorArguments; + + /// + /// Initializes a new instance of the class. + /// + /// Type of the converter. + /// The constructor arguments. + /// The converterType argument is null. + /// No constructor arguments were specified. + public JsonConverterWithConstructorAttribute(Type converterType, params object[] constructorArguments) + { + if(converterType == null) + throw new ArgumentNullException("converterType"); + if(constructorArguments.Length == 0) + throw new ArgumentException("No constructor arguments were specified. If none are required, use JsonConverterAttribute instead", "constructorArguments"); + + _converterType = converterType; + _constructorArguments = constructorArguments; + } + + /// + public Type ConverterType + { + get { return _converterType; } + } + + /// + public object[] ConstructorArguments + { + get { return _constructorArguments; } + } + + /// + /// Creates the converter instance. + /// + /// The converter could not be instantiated. + public JsonConverter CreateJsonConverterInstance() + { + try + { + return (JsonConverter)Activator.CreateInstance(_converterType, _constructorArguments); + } + catch (Exception ex) + { + throw new Exception(string.Format(CultureInfo.InvariantCulture, "Error creating {0}", _converterType), ex); + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/OpenStackContractResolver.cs b/src/OpenStack/Serialization/OpenStackContractResolver.cs new file mode 100644 index 000000000..d9a886349 --- /dev/null +++ b/src/OpenStack/Serialization/OpenStackContractResolver.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace OpenStack.Serialization +{ + /// + /// Provides the same serialization capabilities as json.net with some additions: + /// * Ensures that empty enumerables are not serialized. + /// + /// + public class OpenStackContractResolver : DefaultContractResolver + { + /// + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + JsonProperty property = base.CreateProperty(member, memberSerialization); + + DoNotSerializeEmptyLists(property); + + return property; + } + + private static void DoNotSerializeEmptyLists(JsonProperty property) + { + if (IsEnumerable(property)) + { + PropertyInfo propertyInfo = property.DeclaringType.GetProperty(property.UnderlyingName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (propertyInfo == null) // We can't figure out what it's bound to, so don't modify it's serialization settings + return; + + property.ShouldSerialize = containerInstance => + { + var propertyValue = propertyInfo.GetValue(containerInstance); + return propertyValue != null && ((IEnumerable) propertyValue).OfType().Any(); + }; + } + } + + /// + protected override JsonConverter ResolveContractConverter(Type objectType) + { + var converter = base.ResolveContractConverter(objectType); + + var jsonConverterAttr = objectType.GetCustomAttribute(inherit:true); + if (jsonConverterAttr != null) + return jsonConverterAttr.CreateJsonConverterInstance(); + + return converter; + } + + /// + /// Check if a property implements IEnumerable and IEnumerable<> + /// + private static bool IsEnumerable(JsonProperty property) + { + if (property.PropertyType == typeof (string)) + return false; + + var interfaces = property.PropertyType.GetInterfaces(); + return interfaces.Any(i => i == typeof(IEnumerable)); + } + } +} diff --git a/src/OpenStack/Serialization/Page.cs b/src/OpenStack/Serialization/Page.cs new file mode 100644 index 000000000..f76766f80 --- /dev/null +++ b/src/OpenStack/Serialization/Page.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Flurl; +using Newtonsoft.Json; + +namespace OpenStack.Serialization +{ + /// + /// + [JsonObject(MemberSerialization.OptIn)] + public class Page : ResourceCollection, IPage, IPageBuilder + where TPage : IPage + where TLink : IPageLink + { + private Func> _nextPageHandler; + + /// + /// Initializes a new instance of the class. + /// + public Page() + { + Links = new List(); + } + + /// + [JsonIgnore] + public bool HasNextPage => GetNextLink() != null; + + /// + void IPageBuilder.SetNextPageHandler(Func> value) + { + _nextPageHandler = value; + } + + /// + public async Task> GetNextPageAsync(CancellationToken cancellationToken) + { + var nextPageLink = GetNextLink(); + if (nextPageLink == null) + return Empty(); + + return await _nextPageHandler(new Url(nextPageLink.Url), cancellationToken); + } + + /// + /// Returns an empty page + /// + public static IPage Empty() + { + return EmptyPage.Instance; + } + + /// + /// The paging navigation links. + /// + public IList Links { get; set; } + + /// + /// Finds the next link. + /// + protected virtual TLink GetNextLink() + { + return Links.FirstOrDefault(x => x.IsNextPage); + } + + private sealed class EmptyPage : Page + { + public static readonly EmptyPage Instance = new EmptyPage(); + + private EmptyPage() { } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/PageLink.cs b/src/OpenStack/Serialization/PageLink.cs new file mode 100644 index 000000000..b0749e592 --- /dev/null +++ b/src/OpenStack/Serialization/PageLink.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace OpenStack.Serialization +{ + /// + public class PageLink : IPageLink, IHaveExtraData + { + /// + [JsonConstructor] + protected PageLink() + { } + + /// + public PageLink(string relationship, string url) + { + Relationship = relationship; + Url = url; + } + + /// + [JsonProperty("href")] + public string Url { get; private set; } + + /// + [JsonIgnore] + public bool IsNextPage => Relationship == "next"; + + /// + [JsonProperty("rel")] + public string Relationship { get; private set; } + + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/ResourceCollection.cs b/src/OpenStack/Serialization/ResourceCollection.cs new file mode 100644 index 000000000..f4172da41 --- /dev/null +++ b/src/OpenStack/Serialization/ResourceCollection.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace OpenStack.Serialization +{ + /// + /// Represents a collection of resources. + /// + /// The resource type. + /// + [JsonObject(MemberSerialization.OptIn)] // Using JsonObject to force the entire object to be serialized, ignoring the IEnumerable interface + public class ResourceCollection : IEnumerable, IHaveExtraData + { + /// + /// Initializes a new instance of the class. + /// + public ResourceCollection() + { + Items = new List(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The items. + public ResourceCollection(IEnumerable items) + { + Items = items.ToNonNullList(); + } + + /// + /// The requested items. + /// + public IList Items { get; set; } + + /// + /// Adds an item. + /// + /// The item. + public void Add(T item) + { + Items.Add(item); + } + + /// + public IEnumerator GetEnumerator() + { + return Items.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + [JsonExtensionData] + IDictionary IHaveExtraData.Data { get; set; } = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/ResourceStatus.cs b/src/OpenStack/Serialization/ResourceStatus.cs new file mode 100644 index 000000000..ed0c629e8 --- /dev/null +++ b/src/OpenStack/Serialization/ResourceStatus.cs @@ -0,0 +1,9 @@ +namespace OpenStack.Serialization +{ + /// + public class ResourceStatus : StringEnumeration + { + /// + public bool IsError { get; protected set; } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/RootWrapperConverter.cs b/src/OpenStack/Serialization/RootWrapperConverter.cs new file mode 100644 index 000000000..8ce3be3b7 --- /dev/null +++ b/src/OpenStack/Serialization/RootWrapperConverter.cs @@ -0,0 +1,75 @@ +using System; +using Newtonsoft.Json; + +namespace OpenStack.Serialization +{ + /// + /// Some of the OpenStack API's like to return a wrapper around the real object requested. This will deal with that root level wrapper. + /// Note that it only affects the root, if there are nested objects that also use this converter, it is assumed that they don't have a wrapper. + /// + /// + public class RootWrapperConverter : DefaultJsonConverter + { + private readonly string _name; + + /// + /// Initializes a new instance of the class. + /// + /// The root json property wrapper. + public RootWrapperConverter(string name) + { + _name = name; + } + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + bool isRoot = writer.WriteState == WriteState.Start; + + if (isRoot) + { + // Wrap + writer.WriteStartObject(); + writer.WritePropertyName(_name); + } + + // Default serialization + base.WriteJson(writer, value, serializer); + + if (isRoot) + { + writer.WriteEndObject(); + } + } + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + bool isRoot = reader.Depth == 0; + + if (isRoot) + { + // Skip to the desired property + while (reader.Read()) + { + if (reader.TokenType != JsonToken.PropertyName || reader.Value.ToString() != _name) + continue; + + // Advance to the contained value + reader.Read(); + break; + } + } + + // Default Deserialization + object result = base.ReadJson(reader, objectType, existingValue, serializer); + + if (isRoot) + { + while (reader.Read()) { } // Advance to end + } + + return result; + } + } +} diff --git a/src/OpenStack/Serialization/ServiceEndpoint.cs b/src/OpenStack/Serialization/ServiceEndpoint.cs new file mode 100644 index 000000000..b63dcd30f --- /dev/null +++ b/src/OpenStack/Serialization/ServiceEndpoint.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Flurl; +using Flurl.Extensions; +using Flurl.Http; +using OpenStack.Authentication; + +namespace OpenStack.Serialization +{ + /// + /// Creates urls + /// + /// + public class ServiceEndpoint + { + private readonly IServiceType _serviceType; + private readonly IAuthenticationProvider _authenticationProvider; + private readonly string _microversion; + private readonly string _microversionHeader; + + /// + /// The service region. + /// + public string Region { get; } + + /// + /// Specifies if internal URLs will be used. + /// + public bool UseInternalUrl { get; } + + /// + /// Initializes a new instance of the class. + /// + /// Type of the service. + /// The authentication provider. + /// The region. + /// Specifies if internal URLs should be used. + public ServiceEndpoint(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl) + : this(serviceType, authenticationProvider, region, useInternalUrl, microversion: null, microversionHeader: null) + {} + + /// + /// Initializes a new instance of the class. + /// + /// Type of the service. + /// The authentication provider. + /// The region. + /// Specifies if internal URLs should be used. + /// Specifies the microversion to send with each request. + /// Specifies the header to use when setting the microversion. + public ServiceEndpoint(IServiceType serviceType, IAuthenticationProvider authenticationProvider, string region, bool useInternalUrl, + string microversion, string microversionHeader) + { + _serviceType = serviceType; + _authenticationProvider = authenticationProvider; + Region = region; + UseInternalUrl = useInternalUrl; + _microversion = microversion; + _microversionHeader = microversionHeader; + } + + /// + /// Gets the service endpoint. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// A representing the service endpoint. + public async Task GetEndpoint(CancellationToken cancellationToken) + { + string endpoint = await _authenticationProvider.GetEndpoint(_serviceType, Region, UseInternalUrl, cancellationToken).ConfigureAwait(false); + return new Url(endpoint); + } + + /// + /// Sets the microversion header, if present + /// + /// The api request. + public void SetMicroversion(PreparedRequest request) + { + if (_microversion == null) + return; + + request.WithHeader(_microversionHeader, _microversion); + } + + /// + /// Builds an authenticated request. + /// + /// The endpoint's path suffix. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public async Task PrepareRequest(string path, CancellationToken cancellationToken) + { + Url endpoint = await GetEndpoint(cancellationToken).ConfigureAwait(false); + endpoint.AppendPathSegment(path); + + return PrepareRequest(endpoint, cancellationToken); + } + + /// + /// Builds an authenticated request. + /// + /// The API endpoint. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public PreparedRequest PrepareRequest(Url endpoint, CancellationToken cancellationToken) + { + PreparedRequest request = endpoint.Authenticate(_authenticationProvider); + + SetMicroversion(request); + + return request; + } + + /// + /// Builds a request to retrieve a resource. + /// + /// The resource path, e.g. "servers". + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// resourceId + public async Task PrepareGetResourceRequest(string resourcePath, CancellationToken cancellationToken) + { + PreparedRequest request = await PrepareRequest(resourcePath, cancellationToken); + return request.PrepareGet(cancellationToken); + } + + /// + /// Builds a request to create a resource + /// + /// The resource path, e.g. "servers". + /// The resource. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// resource + public virtual async Task PrepareCreateResourceRequest(string resourcePath, object resource, CancellationToken cancellationToken) + { + if(resource == null) + throw new ArgumentNullException("resource"); + + PreparedRequest request = await PrepareRequest(resourcePath, cancellationToken); + return request.PreparePostJson(resource, cancellationToken); + } + + /// + /// Builds a request to retrieve a list of resources. + /// + /// The resource path, e.g. "servers". + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// resourceId + public async Task PrepareListResourcesRequest(string resourcePath, CancellationToken cancellationToken) + { + PreparedRequest request = await PrepareRequest(resourcePath, cancellationToken); + return request.PrepareGet(cancellationToken); + } + + /// + /// Builds a request to update a resource. + /// + /// The resource path, e.g. "servers". + /// The resource. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// resourceId or resource + public virtual async Task PrepareUpdateResourceRequest(string resourcePath, object resource, CancellationToken cancellationToken) + { + PreparedRequest request = await PrepareRequest(resourcePath, cancellationToken); + return request.PreparePutJson(resource, cancellationToken); + } + + /// + /// Builds a request to delete a resource. + /// + /// The resource path. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// serverId + public virtual async Task PrepareDeleteResourceRequest(string resourcePath, CancellationToken cancellationToken) + { + PreparedRequest request = await PrepareRequest(resourcePath, cancellationToken); + return request + .PrepareDelete(cancellationToken) + .AllowHttpStatus(HttpStatusCode.NotFound); + } + + /// + /// Gets a page of resources. + /// + /// The resource type. + /// The page URL. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + public virtual async Task GetResourcePageAsync(Url pageUrl, CancellationToken cancellationToken) + where TPage : IPageBuilder + { + PreparedRequest request = PrepareRequest(pageUrl, cancellationToken); + + var results = await request + .PrepareGet(cancellationToken) + .SendAsync() + .ReceiveJson(); + + results.SetNextPageHandler(GetResourcePageAsync); + + return results; + } + + /// + /// Waits for the server to reach the specified status. + /// + /// The resource identifier. + /// The status to wait for. + /// Function which retrieves the resource. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public Task WaitForStatusAsync(string resourceId, TStatus status, Func> getResource, TimeSpan? refreshDelay, TimeSpan? timeout, IProgress progress, CancellationToken cancellationToken) + where TStatus : ResourceStatus + { + return WaitForStatusAsync(resourceId, new[] { status }, getResource, refreshDelay, timeout, progress, cancellationToken); + } + + /// + /// Waits for the server to reach the specified status. + /// + /// The resource identifier. + /// The status to wait for. + /// Function which retrieves the resource. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitForStatusAsync(string resourceId, IEnumerable statuses, Func> getResource, TimeSpan? refreshDelay, TimeSpan? timeout, IProgress progress, CancellationToken cancellationToken) + where TStatus : ResourceStatus + { + if (string.IsNullOrEmpty(resourceId)) + throw new ArgumentNullException("resourceId"); + + if(statuses == null) + throw new ArgumentNullException("statuses"); + + refreshDelay = refreshDelay ?? TimeSpan.FromSeconds(5); + timeout = timeout ?? TimeSpan.FromMinutes(5); + + using (var timeoutSource = new CancellationTokenSource(timeout.Value)) + using (var rootCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutSource.Token)) + { + while (true) + { + dynamic resource = await getResource().ConfigureAwait(false); + if (resource.Status?.IsError == true) + throw new ResourceErrorException($"The resource ({resourceId}) is in an error state ({resource.Status})"); + + bool complete = statuses.Contains((TStatus)resource.Status); + + progress?.Report(complete); + + if (complete) + return resource; + + try + { + await Task.Delay(refreshDelay.Value, rootCancellationToken.Token).ConfigureAwait(false); + } + catch (OperationCanceledException ex) + { + if (timeoutSource.IsCancellationRequested) + throw new TimeoutException($"The requested timeout of {timeout.Value.TotalSeconds} seconds has been reached while waiting for the resource ({resourceId}) to reach the {statuses} state.", ex); + + throw; + } + } + } + } + + /// + /// Waits for the resource to be deleted. + /// Treats a 404 NotFound exception as confirmation that it is deleted. + /// + /// The resource identifier. + /// The deleted status for the specified resource. + /// Function which retrieves the resource. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitUntilDeletedAsync(string resourceId, TStatus deletedStatus, Func> getResource, TimeSpan? refreshDelay, TimeSpan? timeout, IProgress progress, CancellationToken cancellationToken) + where TStatus : ResourceStatus + { + try + { + await WaitForStatusAsync(resourceId, deletedStatus, getResource, refreshDelay, timeout, progress, cancellationToken); + } + catch (FlurlHttpException httpError) when (httpError.Call.HttpStatus == HttpStatusCode.NotFound) + { + progress?.Report(true); + } + } + + /// + /// Waits for the resource to be deleted. + /// Treats a 404 NotFound exception as confirmation that it is deleted. + /// + /// The resource identifier. + /// Function which retrieves the resource. + /// The amount of time to wait between requests. + /// The amount of time to wait before throwing a . + /// The progress callback. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// If the value is reached. + /// If the API call returns a bad . + public async Task WaitUntilDeletedAsync(string resourceId, Func> getResource, TimeSpan? refreshDelay, TimeSpan? timeout, IProgress progress, CancellationToken cancellationToken) + where TStatus : ResourceStatus + { + try + { + await WaitForStatusAsync(resourceId, Enumerable.Empty(), getResource, refreshDelay, timeout, progress, cancellationToken); + } + catch (FlurlHttpException httpError) when (httpError.Call.HttpStatus == HttpStatusCode.NotFound) + { + progress?.Report(true); + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/StringEnumeration.cs b/src/OpenStack/Serialization/StringEnumeration.cs new file mode 100644 index 000000000..32f3a7239 --- /dev/null +++ b/src/OpenStack/Serialization/StringEnumeration.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; + +namespace OpenStack.Serialization +{ + /// + /// Using classes for enumerations allows us to use inheritance and enable API versions or other providers to share and extend "enums" + /// + /// + /// + [JsonConverter(typeof(StringEnumerationConverter))] + public abstract class StringEnumeration : IComparable + { + /// + protected StringEnumeration() + { } + + /// + protected StringEnumeration(string displayName) + { + DisplayName = displayName; + } + + /// + public string DisplayName { get; protected set; } + + /// + public override string ToString() + { + return DisplayName; + } + + /// + public static IEnumerable GetAll() + where T : StringEnumeration + { + return GetAll(typeof(T)).Cast(); + } + + /// + public static IEnumerable GetAll(Type type) + { + IEnumerable fields = type + .GetFields(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static) + .Where(field => field.FieldType == type); + + return fields.Select(info => info.GetValue(null)).Cast(); + } + + /// + public override bool Equals(object obj) + { + var otherValue = obj as StringEnumeration; + + if (otherValue == null) + { + return false; + } + + var typeMatches = GetType().Equals(obj.GetType()); + var valueMatches = DisplayName.Equals(otherValue.DisplayName); + + return typeMatches && valueMatches; + } + + /// + public static bool operator ==(StringEnumeration left, StringEnumeration right) + { + return Equals(left, right); + } + + /// + public static bool operator !=(StringEnumeration left, StringEnumeration right) + { + return !Equals(left, right); + } + + /// + public override int GetHashCode() + { + return DisplayName.GetHashCode(); + } + + /// + public static T FromDisplayName(string displayName) + where T : StringEnumeration + { + return (T)FromDisplayName(typeof(T), displayName); + } + + /// + public static StringEnumeration FromDisplayName(Type objectType, string displayName) + { + return GetAll(objectType).FirstOrDefault(item => item.DisplayName == displayName); + } + + /// + public int CompareTo(object other) + { + return string.Compare(DisplayName, ((StringEnumeration)other).DisplayName, StringComparison.Ordinal); + } + } +} diff --git a/src/OpenStack/Serialization/StringEnumerationConverter.cs b/src/OpenStack/Serialization/StringEnumerationConverter.cs new file mode 100644 index 000000000..da11c2f9f --- /dev/null +++ b/src/OpenStack/Serialization/StringEnumerationConverter.cs @@ -0,0 +1,32 @@ +using System; +using Newtonsoft.Json; + +namespace OpenStack.Serialization +{ + /// + /// Attempts to convert a string to a . + /// + /// + public class StringEnumerationConverter : JsonConverter + { + /// + public override bool CanConvert(Type objectType) + { + return objectType.IsSubclassOf(typeof(StringEnumeration)); + } + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + string displayName = serializer.Deserialize(reader); + return StringEnumeration.FromDisplayName(objectType, displayName); + } + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var enumeration = (StringEnumeration)value; + serializer.Serialize(writer, enumeration.DisplayName); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/TimeSpanInSecondsConverter.cs b/src/OpenStack/Serialization/TimeSpanInSecondsConverter.cs new file mode 100644 index 000000000..91ee34a7d --- /dev/null +++ b/src/OpenStack/Serialization/TimeSpanInSecondsConverter.cs @@ -0,0 +1,32 @@ +using System; +using Newtonsoft.Json; + +namespace OpenStack.Serialization +{ + /// + /// Converts a json number representing seconds to a . + /// + /// + public class TimeSpanInSecondsConverter : JsonConverter + { + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var timeSpan = (TimeSpan) value; + writer.WriteValue(timeSpan.TotalSeconds); + } + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + double seconds = double.Parse(reader.Value.ToString()); + return TimeSpan.FromSeconds(seconds); + } + + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof (TimeSpan); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Serialization/TolerantEnumConverter.cs b/src/OpenStack/Serialization/TolerantEnumConverter.cs new file mode 100644 index 000000000..e8f7c561e --- /dev/null +++ b/src/OpenStack/Serialization/TolerantEnumConverter.cs @@ -0,0 +1,65 @@ +using System; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace OpenStack.Serialization +{ + /// + /// Attempts to convert a string to an enum using the following resolution strategy: + /// 1. Use StringEnumConverter. + /// 2. Use null if the property is nullable. + /// 3. Use the Unknown enum value. + /// 4. Use the first enum value. + /// + /// + /// + public class TolerantEnumConverter : StringEnumConverter + { + /// + public override bool CanConvert(Type objectType) + { + Type type = IsNullableType(objectType) ? Nullable.GetUnderlyingType(objectType) : objectType; + return type.IsEnum; + } + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + try + { + return base.ReadJson(reader, objectType, existingValue, serializer); + } + catch (JsonSerializationException) + { + + } + bool isNullable = IsNullableType(objectType); + Type enumType = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType; + + string[] names = Enum.GetNames(enumType); + + if (!isNullable) + { + string defaultName = names.FirstOrDefault(n => string.Equals(n, "Unknown", StringComparison.OrdinalIgnoreCase)); + if (defaultName == null) + defaultName = names.First(); + + return Enum.Parse(enumType, defaultName); + } + + return null; + } + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString()); + } + + private bool IsNullableType(Type t) + { + return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Testing/HttpTest.cs b/src/OpenStack/Testing/HttpTest.cs new file mode 100644 index 000000000..f26328914 --- /dev/null +++ b/src/OpenStack/Testing/HttpTest.cs @@ -0,0 +1,84 @@ +using System; +using System.Net; +using System.Net.Http; +using Flurl; +using Flurl.Http.Configuration; +using Flurl.Http.Content; +using OpenStack.Authentication; + +namespace OpenStack.Testing +{ + /// + /// Use this instead of for any OpenStack.NET unit tests. + /// + /// This extends Flurl's default HttpTest to use in unit tests. + /// If you use the default HttpTest, then any tests which rely upon authentication handling (e.g retrying a request when a token expires) will fail. + /// + /// + public class HttpTest : Flurl.Http.Testing.HttpTest, IDisposable + { + /// + /// Initializes a new instance of the class. + /// + public HttpTest() + { + OpenStackNet.ResetDefaults(); + OpenStackNet.Configuring += SetTestMode; + } + + private void SetTestMode(OpenStackNetConfigurationOptions options) + { + options.FlurlHttpSettings.HttpClientFactory = new TestHttpClientFactory(this); + options.FlurlHttpSettings.AfterCall = call => + { + CallLog.Add(call); + }; + } + + /// + public new void Dispose() + { + OpenStackNet.ResetDefaults(); + base.Dispose(); + } + + /// + public new HttpTest RespondWithJson(object data) + { + return RespondWithJson(200, data); + } + + /// + public new HttpTest RespondWithJson(int status, object data) + { + ResponseQueue.Enqueue(new HttpResponseMessage + { + StatusCode = (HttpStatusCode)status, + Content = new CapturedJsonContent(OpenStackNet.Serialize(data)) + }); + return this; + } + + class TestHttpClientFactory : IHttpClientFactory + { + private readonly Flurl.Http.Testing.TestHttpClientFactory _testMessageHandler; + private readonly AuthenticatedHttpClientFactory _authenticatedClientFactory; + + public TestHttpClientFactory(HttpTest test) + { + _testMessageHandler = new Flurl.Http.Testing.TestHttpClientFactory(test); + _authenticatedClientFactory = new AuthenticatedHttpClientFactory(); + } + + public HttpClient CreateClient(Url url, HttpMessageHandler handler) + { + return _authenticatedClientFactory.CreateClient(url, handler); + } + + public HttpMessageHandler CreateMessageHandler() + { + return new AuthenticatedMessageHandler(_testMessageHandler.CreateMessageHandler()); + } + } + } +} \ No newline at end of file diff --git a/src/OpenStack/Testing/NamespaceDoc.cs b/src/OpenStack/Testing/NamespaceDoc.cs new file mode 100644 index 000000000..b7e8ac8a8 --- /dev/null +++ b/src/OpenStack/Testing/NamespaceDoc.cs @@ -0,0 +1,12 @@ +namespace OpenStack.Testing +{ + using System.Runtime.CompilerServices; + + /// + /// The namespace defines utilities for unit and integration testing. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} diff --git a/src/corelib/OpenStack.csproj b/src/corelib/OpenStack.csproj deleted file mode 100644 index 557b01642..000000000 --- a/src/corelib/OpenStack.csproj +++ /dev/null @@ -1,1265 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {1A4FB67F-8642-4402-B931-118955AE7538} - Library - Properties - OpenStack - openstacknet - v4.5 - 512 - obj\v4.0\ - ..\ - - - - true - full - false - bin\v4.0\Debug\ - DEBUG;TRACE - prompt - 4 - bin\v4.0\Debug\openstacknet.xml - false - true - 612,618 - - - pdbonly - true - bin\v4.0\Release\ - TRACE - prompt - 4 - bin\v4.0\Release\openstacknet.xml - false - true - - - true - - - ..\..\build\keys\OpenStackNetV1.snk - ..\..\build\keys\OpenStackNetV1.dev.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OpenStackNetV1.dev.snk - - - OpenStackNetV1.snk - - - - - - - - - - - - - - - - ..\..\packages\Flurl.Http.Signed\lib\net45\Flurl.Http.dll - True - True - - - - - - - ..\..\packages\Flurl.Http.Signed\lib\portable-net45+sl50+win+wpa81+wp80\Flurl.Http.dll - True - True - - - - - - - - - ..\..\packages\Flurl.Signed\lib\portable-net40+sl50+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Flurl.dll - True - True - - - - - - - True - - - - - - - ..\..\packages\Marvin.JsonPatch.Signed\lib\portable-net40+win+wpa81\Marvin.JsonPatch.dll - True - True - - - - - - - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.IO.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.Runtime.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.IO.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.Runtime.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.IO.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.Runtime.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.IO.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.Runtime.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.IO.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.Runtime.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.IO.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.Runtime.dll - True - True - - - ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.Threading.Tasks.dll - True - True - - - - - - - - - ..\..\packages\Microsoft.Bcl.Async\lib\portable-net40+sl4+win8+wp71+wpa81\Microsoft.Threading.Tasks.dll - True - True - - - ..\..\packages\Microsoft.Bcl.Async\lib\portable-net40+sl4+win8+wp71+wpa81\Microsoft.Threading.Tasks.Extensions.dll - True - True - - - - - - - ..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.dll - True - True - - - ..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.Extensions.dll - True - True - - - - - - - ..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wpa81\Microsoft.Threading.Tasks.dll - True - True - - - ..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wpa81\Microsoft.Threading.Tasks.Extensions.dll - True - True - - - - - - - - - ..\..\packages\Microsoft.Net.Http\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Extensions.dll - True - True - - - ..\..\packages\Microsoft.Net.Http\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Primitives.dll - True - True - - - - - - - ..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8\System.Net.Http.Extensions.dll - True - True - - - ..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8\System.Net.Http.Primitives.dll - True - True - - - - - - - ..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8+wpa81\System.Net.Http.Extensions.dll - True - True - - - ..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8+wpa81\System.Net.Http.Primitives.dll - True - True - - - - - - - - - ..\..\packages\Newtonsoft.Json\lib\net20\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\net35\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\netcore45\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Newtonsoft.Json.dll - True - True - - - - - - - - - ..\..\packages\PCLStorage\lib\portable-net45+sl5+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll - True - True - - - ..\..\packages\PCLStorage\lib\portable-net45+sl5+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll - True - True - - - - - - - ..\..\packages\PCLStorage\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll - True - True - - - ..\..\packages\PCLStorage\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll - True - True - - - - - - - ..\..\packages\PCLStorage\lib\portable-win8+wpa81\PCLStorage.dll - True - True - - - ..\..\packages\PCLStorage\lib\portable-win8+wpa81\PCLStorage.Abstractions.dll - True - True - - - - - - - - - ..\..\packages\SimpleRESTServices\lib\net35\SimpleRESTServices.dll - True - True - - - - - - - ..\..\packages\SimpleRESTServices\lib\net40\SimpleRESTServices.dll - True - True - - - - - \ No newline at end of file diff --git a/src/openstack.net.sln b/src/openstack.net.sln index 42d94cf18..9acbca1ce 100644 --- a/src/openstack.net.sln +++ b/src/openstack.net.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.27604.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{AB148713-068A-48E0-B8D9-4D53310809FC}" ProjectSection(SolutionItems) = preProject @@ -23,12 +23,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{EFFA0DAE ..\build\build.proj = ..\build\build.proj EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack", "corelib\OpenStack.csproj", "{1A4FB67F-8642-4402-B931-118955AE7538}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.old", "corelib\OpenStack.old.csproj", "{1A4FB67F-8642-4402-B931-118955AE7538}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.UnitTests", "testing\unit\OpenStack.UnitTests.csproj", "{AC3D4496-F18B-4907-9FEB-E87F9C6CB7E4}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.IntegrationTests", "testing\integration\OpenStack.IntegrationTests.csproj", "{0C731980-8780-4F9B-9D14-DED790FD649A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack", "OpenStack\OpenStack.csproj", "{DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,10 +63,21 @@ Global {0C731980-8780-4F9B-9D14-DED790FD649A}.Release|Any CPU.Build.0 = Release|Any CPU {0C731980-8780-4F9B-9D14-DED790FD649A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {0C731980-8780-4F9B-9D14-DED790FD649A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Release|Any CPU.Build.0 = Release|Any CPU + {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {579897E8-2B3D-4D02-918C-43E99D1CA4CF} + EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = openstack.net.vsmdi EndGlobalSection diff --git a/src/testing/integration/OpenStack.IntegrationTests.csproj b/src/testing/integration/OpenStack.IntegrationTests.csproj index 7c9882a98..3cfeccfb3 100644 --- a/src/testing/integration/OpenStack.IntegrationTests.csproj +++ b/src/testing/integration/OpenStack.IntegrationTests.csproj @@ -91,9 +91,9 @@ - - {7DBA11EB-DBA7-4D3A-8D42-B5312E74B9C0} - OpenStack + + {1A4FB67F-8642-4402-B931-118955AE7538} + OpenStack.old diff --git a/src/testing/unit/OpenStack.UnitTests.csproj b/src/testing/unit/OpenStack.UnitTests.csproj index 88381c8e5..51e9ddc29 100644 --- a/src/testing/unit/OpenStack.UnitTests.csproj +++ b/src/testing/unit/OpenStack.UnitTests.csproj @@ -111,9 +111,9 @@ - - {7DBA11EB-DBA7-4D3A-8D42-B5312E74B9C0} - OpenStack + + {1A4FB67F-8642-4402-B931-118955AE7538} + OpenStack.old From 5fc0fe39315d960c0adeaebac062dc8e0df927e2 Mon Sep 17 00:00:00 2001 From: Daryl Walleck Date: Mon, 16 Apr 2018 18:10:25 -0500 Subject: [PATCH 2/6] Corrected enumeration of query parameters from KeyValuePair to QueryParameter --- src/OpenStack/Extensions/FlurlExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenStack/Extensions/FlurlExtensions.cs b/src/OpenStack/Extensions/FlurlExtensions.cs index 6fec955fa..8e9d67114 100644 --- a/src/OpenStack/Extensions/FlurlExtensions.cs +++ b/src/OpenStack/Extensions/FlurlExtensions.cs @@ -41,7 +41,7 @@ public static Url RemoveNullOrEmptyQueryParams(this string url) /// The URL. public static Url RemoveNullOrEmptyQueryParams(this Url url) { - foreach (KeyValuePair queryParam in url.QueryParams.ToList()) + foreach (QueryParameter queryParam in url.QueryParams.ToList()) { if (queryParam.Value == null || queryParam.Value.ToString() == string.Empty) url.QueryParams.Remove(queryParam); From 1ce6a3a845b264b05ef3005d6b2c025ee2e1110c Mon Sep 17 00:00:00 2001 From: Daryl Walleck Date: Mon, 16 Apr 2018 18:45:35 -0500 Subject: [PATCH 3/6] Rolled back versions of Flurl to avoid major refactoring. Starting work on re-creating test projects --- src/OpenStack/Extensions/FlurlExtensions.cs | 2 +- src/OpenStack/OpenStack.csproj | 5 +- .../Providers/Rackspace/ProviderBase`1.cs | 1 - src/openstack.net.sln | 14 +- src/testing/unit/OpenStack.UnitTests.csproj | 698 ------------------ 5 files changed, 16 insertions(+), 704 deletions(-) delete mode 100644 src/testing/unit/OpenStack.UnitTests.csproj diff --git a/src/OpenStack/Extensions/FlurlExtensions.cs b/src/OpenStack/Extensions/FlurlExtensions.cs index 8e9d67114..6fec955fa 100644 --- a/src/OpenStack/Extensions/FlurlExtensions.cs +++ b/src/OpenStack/Extensions/FlurlExtensions.cs @@ -41,7 +41,7 @@ public static Url RemoveNullOrEmptyQueryParams(this string url) /// The URL. public static Url RemoveNullOrEmptyQueryParams(this Url url) { - foreach (QueryParameter queryParam in url.QueryParams.ToList()) + foreach (KeyValuePair queryParam in url.QueryParams.ToList()) { if (queryParam.Value == null || queryParam.Value.ToString() == string.Empty) url.QueryParams.Remove(queryParam); diff --git a/src/OpenStack/OpenStack.csproj b/src/OpenStack/OpenStack.csproj index 237132fd9..7d50f541b 100644 --- a/src/OpenStack/OpenStack.csproj +++ b/src/OpenStack/OpenStack.csproj @@ -5,8 +5,8 @@ - - + + @@ -15,6 +15,7 @@ + diff --git a/src/OpenStack/Providers/Rackspace/ProviderBase`1.cs b/src/OpenStack/Providers/Rackspace/ProviderBase`1.cs index 8fdb8f197..2f5d95544 100644 --- a/src/OpenStack/Providers/Rackspace/ProviderBase`1.cs +++ b/src/OpenStack/Providers/Rackspace/ProviderBase`1.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Net; -using System.Net.Http.Headers; using System.Net.Mime; using System.Threading.Tasks; using JSIStudios.SimpleRESTServices.Client; diff --git a/src/openstack.net.sln b/src/openstack.net.sln index 9acbca1ce..28e7467ee 100644 --- a/src/openstack.net.sln +++ b/src/openstack.net.sln @@ -25,11 +25,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{EFFA0DAE EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.old", "corelib\OpenStack.old.csproj", "{1A4FB67F-8642-4402-B931-118955AE7538}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.UnitTests", "testing\unit\OpenStack.UnitTests.csproj", "{AC3D4496-F18B-4907-9FEB-E87F9C6CB7E4}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.UnitTests.old", "testing\unit\OpenStack.UnitTests.old.csproj", "{AC3D4496-F18B-4907-9FEB-E87F9C6CB7E4}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.IntegrationTests", "testing\integration\OpenStack.IntegrationTests.csproj", "{0C731980-8780-4F9B-9D14-DED790FD649A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack", "OpenStack\OpenStack.csproj", "{DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenStack", "OpenStack\OpenStack.csproj", "{DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.UnitTests", "OpenStack.UnitTests\OpenStack.UnitTests.csproj", "{010E0D43-1B48-447E-8DBD-FDC1F1197AE3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -71,6 +73,14 @@ Global {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Release|Any CPU.Build.0 = Release|Any CPU {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Release|Any CPU.Build.0 = Release|Any CPU + {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/testing/unit/OpenStack.UnitTests.csproj b/src/testing/unit/OpenStack.UnitTests.csproj deleted file mode 100644 index 51e9ddc29..000000000 --- a/src/testing/unit/OpenStack.UnitTests.csproj +++ /dev/null @@ -1,698 +0,0 @@ - - - - Debug - AnyCPU - - - 2.0 - {AC3D4496-F18B-4907-9FEB-E87F9C6CB7E4} - Library - Properties - OpenStack - OpenStackNet.Testing.Unit - v4.5 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - ..\..\ - - 73bfe604 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - true - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - true - - - ..\..\..\build\keys\SDKTestingKey.snk - - - - - - - 3.5 - - - - - - - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SDKTestingKey.snk - - - - - - - {1A4FB67F-8642-4402-B931-118955AE7538} - OpenStack.old - - - - - - - <__paket__xunit_runner_visualstudio_props>net20\xunit.runner.visualstudio - - - - - <__paket__xunit_runner_visualstudio_props>portable-net45+win8+wp8+wpa81\xunit.runner.visualstudio - - - - - <__paket__xunit_runner_visualstudio_props>uap10.0\xunit.runner.visualstudio - <__paket__xunit_runner_visualstudio_targets>uap10.0\xunit.runner.visualstudio - - - - - <__paket__xunit_runner_visualstudio_props>win81\xunit.runner.visualstudio - <__paket__xunit_runner_visualstudio_targets>win81\xunit.runner.visualstudio - - - - - <__paket__xunit_runner_visualstudio_props>wpa81\xunit.runner.visualstudio - <__paket__xunit_runner_visualstudio_targets>wpa81\xunit.runner.visualstudio - - - - - - - - <__paket__xunit_core_props>portable-net45+win8+wp8+wpa81\xunit.core - - - - - <__paket__xunit_core_props>win81\xunit.core - - - - - <__paket__xunit_core_props>wpa81\xunit.core - - - - - - - - - - - ..\..\..\packages\Flurl.Http.Signed\lib\net45\Flurl.Http.dll - True - True - - - - - - - ..\..\..\packages\Flurl.Http.Signed\lib\portable-net45+sl50+win+wpa81+wp80\Flurl.Http.dll - True - True - - - - - - - - - ..\..\..\packages\Flurl.Signed\lib\portable-net40+sl50+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Flurl.dll - True - True - - - - - - - - - ..\..\..\packages\Marvin.JsonPatch.Signed\lib\portable-net40+win+wpa81\Marvin.JsonPatch.dll - True - True - - - - - - - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.IO.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.Runtime.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.IO.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.Runtime.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.IO.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.Runtime.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.IO.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.Runtime.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.IO.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.Runtime.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.Threading.Tasks.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.IO.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.Runtime.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.Threading.Tasks.dll - True - True - - - - - - - - - ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net40+sl4+win8+wp71+wpa81\Microsoft.Threading.Tasks.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net40+sl4+win8+wp71+wpa81\Microsoft.Threading.Tasks.Extensions.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.Extensions.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wpa81\Microsoft.Threading.Tasks.dll - True - True - - - ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wpa81\Microsoft.Threading.Tasks.Extensions.dll - True - True - - - - - - - - - ..\..\..\packages\Microsoft.Net.Http\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Extensions.dll - True - True - - - ..\..\..\packages\Microsoft.Net.Http\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Primitives.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8\System.Net.Http.Extensions.dll - True - True - - - ..\..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8\System.Net.Http.Primitives.dll - True - True - - - - - - - ..\..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8+wpa81\System.Net.Http.Extensions.dll - True - True - - - ..\..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8+wpa81\System.Net.Http.Primitives.dll - True - True - - - - - - - - - ..\..\..\packages\Moq\lib\net35\Moq.dll - True - True - - - - - - - ..\..\..\packages\Moq\lib\net40\Moq.dll - True - True - - - - - - - ..\..\..\packages\Moq\lib\sl5\Moq.Silverlight.dll - True - True - - - - - - - - - ..\..\..\packages\Newtonsoft.Json\lib\net20\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\..\packages\Newtonsoft.Json\lib\net35\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\..\packages\Newtonsoft.Json\lib\netcore45\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\..\packages\Newtonsoft.Json\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\..\packages\Newtonsoft.Json\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Newtonsoft.Json.dll - True - True - - - - - - - - - ..\..\..\packages\PCLStorage\lib\portable-net45+sl5+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll - True - True - - - ..\..\..\packages\PCLStorage\lib\portable-net45+sl5+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll - True - True - - - - - - - ..\..\..\packages\PCLStorage\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll - True - True - - - ..\..\..\packages\PCLStorage\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll - True - True - - - - - - - ..\..\..\packages\PCLStorage\lib\portable-win8+wpa81\PCLStorage.dll - True - True - - - ..\..\..\packages\PCLStorage\lib\portable-win8+wpa81\PCLStorage.Abstractions.dll - True - True - - - - - - - - - ..\..\..\packages\SimpleRESTServices\lib\net35\SimpleRESTServices.dll - True - True - - - - - - - ..\..\..\packages\SimpleRESTServices\lib\net40\SimpleRESTServices.dll - True - True - - - - - - - - - ..\..\..\packages\xunit.abstractions\lib\net35\xunit.abstractions.dll - True - True - - - - - - - ..\..\..\packages\xunit.abstractions\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.abstractions.dll - True - True - - - - - - - - - ..\..\..\packages\xunit.assert\lib\portable-net45+win8+wp8+wpa81\xunit.assert.dll - True - True - - - - - - - - - ..\..\..\packages\xunit.extensibility.core\lib\portable-net45+win8+wp8+wpa81\xunit.core.dll - True - True - - - - - - - - - ..\..\..\packages\xunit.extensibility.execution\lib\monoandroid\xunit.execution.dotnet.dll - True - True - - - - - - - ..\..\..\packages\xunit.extensibility.execution\lib\monotouch\xunit.execution.dotnet.dll - True - True - - - - - - - ..\..\..\packages\xunit.extensibility.execution\lib\net45\xunit.execution.desktop.dll - True - True - - - - - - - ..\..\..\packages\xunit.extensibility.execution\lib\portable-net45+win8+wp8+wpa81\xunit.execution.dotnet.dll - True - True - - - - - - - ..\..\..\packages\xunit.extensibility.execution\lib\win8\xunit.execution.dotnet.dll - True - True - - - - - - - ..\..\..\packages\xunit.extensibility.execution\lib\wp8\xunit.execution.dotnet.dll - True - True - - - - - - - ..\..\..\packages\xunit.extensibility.execution\lib\wpa81\xunit.execution.dotnet.dll - True - True - - - - - - - ..\..\..\packages\xunit.extensibility.execution\lib\xamarinios\xunit.execution.dotnet.dll - True - True - - - - - - \ No newline at end of file From 293f09afd414814365e2b6a713feb279288cb911 Mon Sep 17 00:00:00 2001 From: Daryl Walleck Date: Mon, 16 Apr 2018 19:01:23 -0500 Subject: [PATCH 4/6] Fixing class visibility issues discovered by tests --- src/OpenStack/Extensions/EnumerableExtensions.cs | 2 +- src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs | 2 +- .../Providers/Rackspace/Objects/Request/UpdateServerRequest.cs | 2 +- .../Rackspace/Objects/Response/AuthenticationResponse.cs | 2 +- .../Rackspace/Objects/Response/PasswordCredentialResponse.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OpenStack/Extensions/EnumerableExtensions.cs b/src/OpenStack/Extensions/EnumerableExtensions.cs index 3a925dc28..a65c94ce7 100644 --- a/src/OpenStack/Extensions/EnumerableExtensions.cs +++ b/src/OpenStack/Extensions/EnumerableExtensions.cs @@ -2,7 +2,7 @@ namespace System.Collections.Generic { - internal static class EnumerableExtensions + public static class EnumerableExtensions { /// /// Creates a new list wrapping the specified items. diff --git a/src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs b/src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs index f8e610dad..ba485d67e 100644 --- a/src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs +++ b/src/OpenStack/Providers/Rackspace/EncodeDecodeProvider.cs @@ -9,7 +9,7 @@ /// and decodes text with . /// /// - internal class EncodeDecodeProvider : IEncodeDecodeProvider + public class EncodeDecodeProvider : IEncodeDecodeProvider { /// /// A default instance of . diff --git a/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateServerRequest.cs b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateServerRequest.cs index dee82b962..daf14de2e 100644 --- a/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateServerRequest.cs +++ b/src/OpenStack/Providers/Rackspace/Objects/Request/UpdateServerRequest.cs @@ -12,7 +12,7 @@ /// Update Server (OpenStack Compute API v2 and Extensions Reference) /// [JsonObject(MemberSerialization.OptIn)] - internal class UpdateServerRequest + public class UpdateServerRequest { /// /// Gets additional details about the updated server. diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/AuthenticationResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/AuthenticationResponse.cs index c7d68b5ad..9f5bdb0a8 100644 --- a/src/OpenStack/Providers/Rackspace/Objects/Response/AuthenticationResponse.cs +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/AuthenticationResponse.cs @@ -9,7 +9,7 @@ /// Authenticate (OpenStack Identity Service API v2.0 Reference) /// [JsonObject(MemberSerialization.OptIn)] - internal class AuthenticationResponse + public class AuthenticationResponse { /// /// Gets additional information about the authenticated user. diff --git a/src/OpenStack/Providers/Rackspace/Objects/Response/PasswordCredentialResponse.cs b/src/OpenStack/Providers/Rackspace/Objects/Response/PasswordCredentialResponse.cs index cca204f5f..2ac3533c2 100644 --- a/src/OpenStack/Providers/Rackspace/Objects/Response/PasswordCredentialResponse.cs +++ b/src/OpenStack/Providers/Rackspace/Objects/Response/PasswordCredentialResponse.cs @@ -10,7 +10,7 @@ /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) /// [JsonObject(MemberSerialization.OptIn)] - internal class PasswordCredentialResponse + public class PasswordCredentialResponse { /// /// Gets the password credentials used for the Update User Credentials request. From 25683e07b7dbcacee75a4b1829ae01b54336bac2 Mon Sep 17 00:00:00 2001 From: Daryl Walleck Date: Mon, 16 Apr 2018 19:06:58 -0500 Subject: [PATCH 5/6] Re-adding unit tests --- .../AuthenticationTests.cs | 39 + .../Compute/v2_1/ComputeServiceTests.cs | 88 ++ .../Compute/v2_1/FlavorTests.cs | 101 +++ .../Compute/v2_1/ImageTests.cs | 346 +++++++ .../Compute/v2_1/KeyPairTests.cs | 136 +++ .../v2_1/Operator/ComputeServiceTests.cs | 89 ++ .../Compute/v2_1/Operator/ServerTests.cs | 42 + .../Compute/v2_1/SecurityGroupTests.cs | 257 ++++++ .../Compute/v2_1/ServerAddressTests.cs | 65 ++ .../Compute/v2_1/ServerGroupTests.cs | 94 ++ .../Compute/v2_1/ServerTests.cs | 856 ++++++++++++++++++ .../Compute/v2_1/VolumeTests.cs | 234 +++++ .../Compute/v2_2/ConsoleTypeTests.cs | 13 + .../Compute/v2_6/ServerTests.cs | 33 + .../v1/ContentDeliveryNetworkServiceTests.cs | 23 + .../ContentDeliveryNetworks/v1/FlavorTests.cs | 56 ++ .../v1/ServiceCacheTests.cs | 32 + .../ServiceOperationFailedExceptionTests.cs | 28 + .../v1/ServiceTests.cs | 302 ++++++ .../NetworkAddressDeserializationTests.cs | 96 ++ .../Extensions/EnumerableExtensionsTests.cs | 15 + .../Extensions/TypeExtensionsTests.cs | 41 + src/OpenStack.UnitTests/IdentifierTests.cs | 73 ++ .../Networking/v2/DHCPOptionConverterTests.cs | 62 ++ .../Networking/v2/Layer3/Layer3Tests.cs | 368 ++++++++ .../Networking/v2/NetworkTests.cs | 133 +++ .../Networking/v2/PortTests.cs | 152 ++++ .../Networking/v2/SubnetTests.cs | 139 +++ .../OpenStack.UnitTests.csproj | 29 + src/OpenStack.UnitTests/OpenStackNetTests.cs | 141 +++ .../Rackspace/CloudBlockStorageTests.cs | 65 ++ .../Rackspace/CloudNetworksValidatorTests.cs | 198 ++++ .../Rackspace/EncodeDecodeProviderTests.cs | 54 ++ .../Rackspace/IdentityProviderCacheTests.cs | 55 ++ .../Providers/Rackspace/JsonModelTests.cs | 233 +++++ .../Rackspace/ObjectProviderHelperTests.cs | 124 +++ .../Providers/Rackspace/ProviderBaseTests.cs | 310 +++++++ .../Providers/Rackspace/SerializationTests.cs | 63 ++ .../Serialization/EmptyEnumerableTests.cs | 43 + .../RootWrapperConverterTests.cs | 86 ++ .../TolerantEnumConverterTests.cs | 65 ++ src/OpenStack.UnitTests/Stubs.cs | 34 + src/OpenStack.UnitTests/TestCategories.cs | 11 + src/OpenStack.UnitTests/XunitTraceListener.cs | 41 + 44 files changed, 5465 insertions(+) create mode 100644 src/OpenStack.UnitTests/AuthenticationTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/ComputeServiceTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/FlavorTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/ImageTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/KeyPairTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/Operator/ComputeServiceTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/Operator/ServerTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/SecurityGroupTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/ServerAddressTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/ServerGroupTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/ServerTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_1/VolumeTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_2/ConsoleTypeTests.cs create mode 100644 src/OpenStack.UnitTests/Compute/v2_6/ServerTests.cs create mode 100644 src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceTests.cs create mode 100644 src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/FlavorTests.cs create mode 100644 src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceCacheTests.cs create mode 100644 src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceOperationFailedExceptionTests.cs create mode 100644 src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceTests.cs create mode 100644 src/OpenStack.UnitTests/Domain/Mapping/NetworkAddressDeserializationTests.cs create mode 100644 src/OpenStack.UnitTests/Extensions/EnumerableExtensionsTests.cs create mode 100644 src/OpenStack.UnitTests/Extensions/TypeExtensionsTests.cs create mode 100644 src/OpenStack.UnitTests/IdentifierTests.cs create mode 100644 src/OpenStack.UnitTests/Networking/v2/DHCPOptionConverterTests.cs create mode 100644 src/OpenStack.UnitTests/Networking/v2/Layer3/Layer3Tests.cs create mode 100644 src/OpenStack.UnitTests/Networking/v2/NetworkTests.cs create mode 100644 src/OpenStack.UnitTests/Networking/v2/PortTests.cs create mode 100644 src/OpenStack.UnitTests/Networking/v2/SubnetTests.cs create mode 100644 src/OpenStack.UnitTests/OpenStack.UnitTests.csproj create mode 100644 src/OpenStack.UnitTests/OpenStackNetTests.cs create mode 100644 src/OpenStack.UnitTests/Providers/Rackspace/CloudBlockStorageTests.cs create mode 100644 src/OpenStack.UnitTests/Providers/Rackspace/CloudNetworksValidatorTests.cs create mode 100644 src/OpenStack.UnitTests/Providers/Rackspace/EncodeDecodeProviderTests.cs create mode 100644 src/OpenStack.UnitTests/Providers/Rackspace/IdentityProviderCacheTests.cs create mode 100644 src/OpenStack.UnitTests/Providers/Rackspace/JsonModelTests.cs create mode 100644 src/OpenStack.UnitTests/Providers/Rackspace/ObjectProviderHelperTests.cs create mode 100644 src/OpenStack.UnitTests/Providers/Rackspace/ProviderBaseTests.cs create mode 100644 src/OpenStack.UnitTests/Providers/Rackspace/SerializationTests.cs create mode 100644 src/OpenStack.UnitTests/Serialization/EmptyEnumerableTests.cs create mode 100644 src/OpenStack.UnitTests/Serialization/RootWrapperConverterTests.cs create mode 100644 src/OpenStack.UnitTests/Serialization/TolerantEnumConverterTests.cs create mode 100644 src/OpenStack.UnitTests/Stubs.cs create mode 100644 src/OpenStack.UnitTests/TestCategories.cs create mode 100644 src/OpenStack.UnitTests/XunitTraceListener.cs diff --git a/src/OpenStack.UnitTests/AuthenticationTests.cs b/src/OpenStack.UnitTests/AuthenticationTests.cs new file mode 100644 index 000000000..d036d8da5 --- /dev/null +++ b/src/OpenStack.UnitTests/AuthenticationTests.cs @@ -0,0 +1,39 @@ +using System.Net; +using System.Threading.Tasks; +using Flurl.Http; +using OpenStack.ContentDeliveryNetworks.v1; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack +{ + public class AuthenticationTests + { + [Fact] + public async Task When401UnauthorizedIsReturned_RetryRequest() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWith((int)HttpStatusCode.Unauthorized, "Your token has expired"); + httpTest.RespondWithJson(new Flavor()); + + var service = new ContentDeliveryNetworkService(Stubs.AuthenticationProvider, "DFW"); + var flavor = await service.GetFlavorAsync("flavor-id"); + Assert.NotNull(flavor); + } + } + + [Fact] + public async Task When401AuthenticationFailsMultipleTimes_ThrowException() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWith((int)HttpStatusCode.Unauthorized, "Your token has expired"); + httpTest.RespondWith((int)HttpStatusCode.Unauthorized, "Your token has expired"); + + var service = new ContentDeliveryNetworkService(Stubs.AuthenticationProvider, "DFW"); + await Assert.ThrowsAsync(() => service.GetFlavorAsync("flavor-id")); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/ComputeServiceTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/ComputeServiceTests.cs new file mode 100644 index 000000000..ad25f19a2 --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/ComputeServiceTests.cs @@ -0,0 +1,88 @@ +using System.Linq; +using Newtonsoft.Json.Linq; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class ComputeServiceTests + { + private readonly ComputeService _compute; + + public ComputeServiceTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void GetLimits() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWith(JObject.Parse(@" +{ + 'limits': { + 'rate': [ + { + 'limit': [ + { + 'next-available': '2012-09-10T20:11:45.146Z', + 'remaining': 0, + 'unit': 'DAY', + 'value': 0, + 'verb': 'POST' + }, + { + 'next-available': '2012-09-10T20:11:45.146Z', + 'remaining': 0, + 'unit': 'MINUTE', + 'value': 0, + 'verb': 'GET' + } + ], + 'regex': '/v[^/]/(\\d+)/(rax-networks)/?.*', + 'uri': '/rax-networks' + } + ], + 'absolute': { + 'maxServerMeta': 128, + 'maxPersonality': 5, + 'totalServerGroupsUsed': 0, + 'maxImageMeta': 128, + 'maxPersonalitySize': 10240, + 'maxTotalKeypairs': 100, + 'maxSecurityGroupRules': 20, + 'maxServerGroups': 10, + 'totalCoresUsed': 1, + 'totalRAMUsed': 2048, + 'totalInstancesUsed': 1, + 'maxSecurityGroups': 10, + 'totalFloatingIpsUsed': 0, + 'maxTotalCores': 20, + 'maxServerGroupMembers': 10, + 'maxTotalFloatingIps': 10, + 'totalSecurityGroupsUsed': 1, + 'maxTotalInstances': 10, + 'maxTotalRAMSize': 51200 + } + } +}").ToString()); + + var limits = _compute.GetLimits(); + + Assert.NotNull(limits); + + Assert.NotNull(limits.RateLimits); + Assert.Equal(1, limits.RateLimits.Count); + var networkLimits = limits.RateLimits.FirstOrDefault(l => l.Name.Contains("rax-networks")); + Assert.NotNull(networkLimits); + var networkGetLimit = networkLimits.Limits.FirstOrDefault(l => l.HttpMethod == "GET"); + Assert.NotNull(networkGetLimit); + + Assert.NotNull(limits.ResourceLimits); + Assert.NotNull(limits.ResourceLimits.CoresMax); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/FlavorTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/FlavorTests.cs new file mode 100644 index 000000000..b7dffa24d --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/FlavorTests.cs @@ -0,0 +1,101 @@ +using System; +using System.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class FlavorTests + { + private readonly ComputeService _compute; + + public FlavorTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void GetFlavor() + { + using (var httpTest = new HttpTest()) + { + const string flavorId = "1"; + httpTest.RespondWithJson(new Flavor { Id = flavorId }); + + var result = _compute.GetFlavor(flavorId); + + httpTest.ShouldHaveCalled($"*/flavors/{flavorId}"); + Assert.NotNull(result); + Assert.Equal(flavorId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetFlavorExtension() + { + using (var httpTest = new HttpTest()) + { + Identifier flavorId = Guid.NewGuid(); + httpTest.RespondWithJson(new FlavorSummaryCollection + { + new FlavorSummary {Id = flavorId} + }); + httpTest.RespondWithJson(new Flavor { Id = flavorId }); + + var results = _compute.ListFlavorSummaries(); + var flavorRef = results.First(); + var result = flavorRef.GetFlavor(); + + Assert.NotNull(result); + Assert.Equal(flavorId, result.Id); + } + } + + [Fact] + public void ListFlavorSummaries() + { + using (var httpTest = new HttpTest()) + { + const string flavorId = "1"; + httpTest.RespondWithJson(new FlavorSummaryCollection + { + Items = { new FlavorSummary { Id = flavorId } } + }); + + var results = _compute.ListFlavorSummaries(); + + httpTest.ShouldHaveCalled("*/flavors"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(flavorId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListFlavors() + { + using (var httpTest = new HttpTest()) + { + const string flavorId = "1"; + httpTest.RespondWithJson(new FlavorCollection + { + Items = { new Flavor { Id = flavorId } } + }); + httpTest.RespondWithJson(new Flavor { Id = flavorId }); + + var results = _compute.ListFlavors(); + + httpTest.ShouldHaveCalled("*/flavors"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(flavorId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/ImageTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/ImageTests.cs new file mode 100644 index 000000000..e52249856 --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/ImageTests.cs @@ -0,0 +1,346 @@ +using System; +using System.Linq; +using System.Net; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Images.v2; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class ImageTests + { + private readonly ComputeService _compute; + + public ImageTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void GetImage() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = "1"; + httpTest.RespondWithJson(new Image { Id = imageId }); + + var result = _compute.GetImage(imageId); + + httpTest.ShouldHaveCalled($"*/images/{imageId}"); + Assert.NotNull(result); + Assert.Equal(imageId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetImageMetadata() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = "1"; + httpTest.RespondWithJson(new ImageSummaryCollection { new ImageSummary { Id = imageId } }); + httpTest.RespondWithJson(new ImageMetadata { ["stuff"] = "things" }); + + var imageReferences = _compute.ListImageSummaries(); + ImageMetadata result = imageReferences.First().GetMetadata(); + + httpTest.ShouldHaveCalled($"*/images/{imageId}/metadata"); + Assert.NotNull(result); + Assert.Equal(1, result.Count); + Assert.True(result.ContainsKey("stuff")); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetImageMetadataItem() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = "1"; + httpTest.RespondWithJson(new ImageSummaryCollection { new ImageSummary { Id = imageId } }); + httpTest.RespondWithJson(new + { + meta = new + { + stuff = "things" + } + + }); + + var imageReferences = _compute.ListImageSummaries(); + string result = imageReferences.First().GetMetadataItem("stuff"); + + httpTest.ShouldHaveCalled($"*/images/{imageId}/metadata"); + Assert.NotNull(result); + Assert.Equal("things", result); + } + } + + [Fact] + public void GetImageExtension() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWithJson(new ImageSummaryCollection + { + new ImageSummary {Id = imageId} + }); + httpTest.RespondWithJson(new Image { Id = imageId }); + + var results = _compute.ListImageSummaries(); + var flavorRef = results.First(); + var result = flavorRef.GetImage(); + + Assert.NotNull(result); + Assert.Equal(imageId, result.Id); + } + } + + [Fact] + public void WaitForImageActive() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWithJson(new Image { Id = imageId, Status = ImageStatus.Unknown }); + httpTest.RespondWithJson(new Image { Id = imageId, Status = ImageStatus.Saving }); + httpTest.RespondWithJson(new Image { Id = imageId, Status = ImageStatus.Active }); + + var result = _compute.GetImage(imageId); + result.WaitUntilActive(); + + httpTest.ShouldHaveCalled($"*/images/{imageId}"); + Assert.NotNull(result); + Assert.Equal(imageId, result.Id); + Assert.Equal(ImageStatus.Active, result.Status); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void CreateImageMetadata() + { + using (var httpTest = new HttpTest()) + { + const string key = "stuff"; + Identifier imageId = "1"; + httpTest.RespondWithJson(new Image { Id = imageId }); + + var image = _compute.GetImage(imageId); + image.Metadata.Create(key, "things"); + + Assert.True(image.Metadata.ContainsKey(key)); + httpTest.ShouldHaveCalled($"*/images/{imageId}/metadata/{key}"); + } + } + + [Fact] + public void ListImages() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWithJson(new ImageSummaryCollection + { + Items = { new ImageSummary { Id = imageId } }, + Links = { new PageLink("next", "http://api.com/next") } + }); + + var results = _compute.ListImageSummaries(); + + httpTest.ShouldHaveCalled("*/images"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(imageId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListImagesWithFilter() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new ImageCollection()); + + const string name = "foo"; + const int minRam = 2; + const int minDisk = 1; + Identifier serverId = Guid.NewGuid(); + var lastModified = DateTimeOffset.Now.AddDays(-1); + var imageType = ImageType.Snapshot; + + _compute.ListImageSummaries(new ImageListOptions { Name = name, ServerId = serverId, UpdatedAfter = lastModified, MininumDiskSize = minDisk, MininumMemorySize = minRam, Type = imageType}); + + httpTest.ShouldHaveCalled($"*name={name}"); + httpTest.ShouldHaveCalled($"*server={serverId}"); + httpTest.ShouldHaveCalled($"*minRam={minRam}"); + httpTest.ShouldHaveCalled($"*minDisk={minDisk}"); + httpTest.ShouldHaveCalled($"*type={imageType}"); + httpTest.ShouldHaveCalled("*changes-since="); + } + } + + [Fact] + public void ListImagesWithPaging() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new ImageCollection()); + + Identifier startingAt = Guid.NewGuid(); + const int pageSize = 10; + _compute.ListImageSummaries(new ImageListOptions { PageSize = pageSize, StartingAt = startingAt }); + + httpTest.ShouldHaveCalled($"*marker={startingAt}*"); + httpTest.ShouldHaveCalled($"*limit={pageSize}*"); + } + } + + [Theory] + [InlineData(false, "POST")] + [InlineData(true, "PUT")] + public void UpdateImageMetadata(bool overwrite, string expectedHttpVerb) + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = "1"; + httpTest.RespondWithJson(new Image {Id = imageId}); + httpTest.RespondWithJson(new ImageMetadata {["stuff"] = "things" }); + + var image = _compute.GetImage(imageId); + image.Metadata["color"] = "blue"; + image.Metadata.Update(overwrite); + + httpTest.ShouldHaveCalled($"*/images/{imageId}/metadata"); + Assert.Equal(expectedHttpVerb, httpTest.CallLog.Last().Request.Method.Method); + Assert.True(image.Metadata.ContainsKey("stuff")); + } + } + + [Fact] + public void DeleteImage() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + _compute.DeleteImage(imageId); + + httpTest.ShouldHaveCalled($"*/images/{imageId}"); + } + } + + [Fact] + public void DeleteImageExtension() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWithJson(new Image { Id = imageId }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + httpTest.RespondWithJson(new Image { Id = imageId, Status = ImageStatus.Deleted }); + + var image = _compute.GetImage(imageId); + + image.Delete(); + image.WaitUntilDeleted(); + Assert.Equal(image.Status, ImageStatus.Deleted); + } + } + + [Fact] + public void WhenDeleteImage_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Not here, boss..."); + + _compute.DeleteImage(imageId); + + httpTest.ShouldHaveCalled($"*/images/{imageId}"); + } + } + + [Fact] + public void WaitForImageDeleted() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWithJson(new Image { Id = imageId, Status = ImageStatus.Active }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + httpTest.RespondWithJson(new Image { Id = imageId, Status = ImageStatus.Deleted }); + + var result = _compute.GetImage(imageId); + result.Delete(); + result.WaitUntilDeleted(); + + Assert.Equal(ImageStatus.Deleted, result.Status); + } + } + + [Fact] + public void WaitForImageDeleted_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWithJson(new Image { Id = imageId, Status = ImageStatus.Active }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Nothing here, boss"); + + var result = _compute.GetImage(imageId); + result.Delete(); + result.WaitUntilDeleted(); + + Assert.Equal(ImageStatus.Deleted, result.Status); + } + } + + [Fact] + public void DeleteImageMetadata() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + const string key = "stuff"; + httpTest.RespondWithJson(new Image + { + Id = imageId, + Metadata = + { + [key] = "things" + } + }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + var image = _compute.GetImage(imageId); + + image.Metadata.Delete(key); + Assert.False(image.Metadata.ContainsKey(key)); + httpTest.ShouldHaveCalled($"*/images/{imageId}/metadata/{key}"); + } + } + + [Fact] + public void WhenDeleteImageMetadata_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Not here, boss..."); + + _compute.DeleteImageMetadataAsync(imageId, "{invalid-key}"); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/KeyPairTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/KeyPairTests.cs new file mode 100644 index 000000000..69e391475 --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/KeyPairTests.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class KeyPairTests + { + private readonly ComputeService _computeService; + + public KeyPairTests() + { + _computeService = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void DeserializeKeyPairCollection() + { + // this one is odd because even in the list, the items are wrapped with a root that needs to be unwrapped + string json = JObject.Parse(@"{ + 'keypairs': [ + { + 'keypair': { + 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDrBzodZLiWO6nIGGy9ZOVeFhbF6EaG8HUqrknNVKynH6+Hc5ToY71gmeQGJ7XZTAlyKKdFmPhNPCQCYqFQxjPKD3xTIAoGChlRHfkjYwjefbqxFswi9S0Fi3Lq8mawUVuPmPnuTr8KhL8ibnBbAxZnrcfTKBIoxhU+kN56CCmLnkJc5ouG/UcF+UpqUso45pYRf0YWANyyuafyCmj6NiDxMCGy/vnKUBLzMg8wQ01xGSGOfyGDIwuTFZpoPzjeqEV8oUGvxYt9Xyzh/pPKoOz1cz0wBDaVDpucTz3UEq65F9HhCmdwwjso8MP1K46LkM2JNQWQ0eTotqFvUJEoP2ff Generated-by-Nova', + 'name': 'keypair-d20a3d59-9433-4b79-8726-20b431d89c78', + 'fingerprint': 'ce:88:fe:6a:9e:c0:d5:91:08:8b:57:80:be:e6:ec:3d' + } +}, + { + 'keypair': { + 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDx8nkQv/zgGgB4rMYmIf+6A4l6Rr+o/6lHBQdW5aYd44bd8JttDCE/F/pNRr0lRE+PiqSPO8nDPHw0010JeMH9gYgnnFlyY3/OcJ02RhIPyyxYpv9FhY+2YiUkpwFOcLImyrxEsYXpD/0d3ac30bNH6Sw9JD9UZHYcpSxsIbECHw== Generated-by-Nova', + 'name': 'uploaded-keypair', + 'fingerprint': '1e:2c:9b:56:79:4b:45:77:f9:ca:7a:98:2c:b0:d5:3c' + } + } + ] +}").ToString(); + + var results = OpenStackNet.Deserialize(json); + Assert.NotNull(results); + Assert.Equal(2, results.Count()); + var result = results.First(); + Assert.Empty(((IHaveExtraData)result).Data); + Assert.NotNull(result.PublicKey); + } + + [Fact] + public void GetKeyPair() + { + using (var httpTest = new HttpTest()) + { + const string name = "keypair-name"; + httpTest.RespondWithJson(new KeyPair { Name = name }); + KeyPair result = _computeService.GetKeyPair(name); + + httpTest.ShouldHaveCalled($"*/os-keypairs/{name}"); + Assert.NotNull(result); + Assert.Equal(name, result.Name); + } + } + + [Fact] + public void CreateKeyPair() + { + using (var httpTest = new HttpTest()) + { + const string name = "keypair-name"; + httpTest.RespondWithJson(new KeyPairResponse {Name = name, PrivateKey = Guid.NewGuid().ToString()}); + KeyPairResponse result = _computeService.CreateKeyPair(new KeyPairRequest(name)); + + httpTest.ShouldHaveCalled("*/os-keypairs"); + Assert.NotNull(result); + Assert.Equal(name, result.Name); + Assert.NotNull(result.PrivateKey); + } + } + + [Fact] + public void ImportKeyPair() + { + using (var httpTest = new HttpTest()) + { + const string name = "keypair-name"; + httpTest.RespondWithJson(new KeyPairSummary {Name = name}); + KeyPairSummary result = _computeService.ImportKeyPair(new KeyPairDefinition(name, Guid.NewGuid().ToString())); + + httpTest.ShouldHaveCalled("*/os-keypairs"); + Assert.NotNull(result); + Assert.Equal(name, result.Name); + } + } + + [Fact] + public void ListKeypairs() + { + using (var httpTest = new HttpTest()) + { + const string name = "keypair-name"; + httpTest.RespondWithJson(new KeyPairSummaryCollection + { + new KeyPairSummary { Name = name } + }); + IEnumerable results = _computeService.ListKeyPairs(); + + httpTest.ShouldHaveCalled("*/os-keypairs"); + Assert.NotNull(results); + Assert.Equal(1, results.Count()); + Assert.Equal(name, results.First().Name); + } + } + + [Theory] + [InlineData(HttpStatusCode.Accepted)] + [InlineData(HttpStatusCode.NotFound)] + public void DeleteKeyPair(HttpStatusCode responseCode) + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new KeyPair {Name = "keypair-name"}); + httpTest.RespondWith((int) responseCode, "All gone!"); + + KeyPairSummary result = _computeService.GetKeyPair("keypair-name"); + result.Delete(); + + httpTest.ShouldHaveCalled("*/os-keypairs"); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/Operator/ComputeServiceTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/Operator/ComputeServiceTests.cs new file mode 100644 index 000000000..dd5eec5b4 --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/Operator/ComputeServiceTests.cs @@ -0,0 +1,89 @@ +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1.Operator +{ + public class ComputeServiceTests + { + private readonly ComputeService _compute; + + public ComputeServiceTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public async Task GetCurrentQuotas() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWith(JObject.Parse(@" +{ + 'quota_set': { + 'injected_file_content_bytes': 10240, + 'metadata_items': 128, + 'server_group_members': 10, + 'server_groups': 10, + 'ram': 51200, + 'floating_ips': 10, + 'key_pairs': 100, + 'id': 'details', + 'instances': 10, + 'security_group_rules': 20, + 'injected_files': 5, + 'cores': 20, + 'fixed_ips': -1, + 'injected_file_path_bytes': 255, + 'security_groups': 10 + } +}").ToString()); + + var quotas = await _compute.GetCurrentQuotasAsync(); + + httpTest.ShouldHaveCalled("*/os-quota-sets/detail"); + Assert.NotNull(quotas); + + Assert.Equal(100, quotas.KeyPairs); + Assert.Equal(-1, quotas.FixedIPs); + } + } + + [Fact] + public async Task GetDefaultQuotas() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWith(JObject.Parse(@" +{ + 'quota_set': { + 'injected_file_content_bytes': 10240, + 'metadata_items': 128, + 'server_group_members': 10, + 'server_groups': 10, + 'ram': 51200, + 'floating_ips': 10, + 'key_pairs': 100, + 'id': 'defaults', + 'instances': 10, + 'security_group_rules': 20, + 'injected_files': 5, + 'cores': 20, + 'fixed_ips': -1, + 'injected_file_path_bytes': 255, + 'security_groups': 10 + } +}").ToString()); + + var quotas = await _compute.GetDefaultQuotasAsync(); + + httpTest.ShouldHaveCalled("*/os-quota-sets/defaults"); + Assert.NotNull(quotas); + + Assert.Equal(100, quotas.KeyPairs); + Assert.Equal(-1, quotas.FixedIPs); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/Operator/ServerTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/Operator/ServerTests.cs new file mode 100644 index 000000000..1dbc632c1 --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/Operator/ServerTests.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1.Operator +{ + public class ServerTests + { + private readonly ComputeService _compute; + + public ServerTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public async Task EvacuateServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss"); + + var server = _compute.GetServer(serverId); + await server.EvacuateAsync(new EvacuateServerRequest(false)); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + string lastRequest = httpTest.CallLog.Last().RequestBody; + Assert.True(lastRequest.Contains("evacuate")); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/SecurityGroupTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/SecurityGroupTests.cs new file mode 100644 index 000000000..b67deee14 --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/SecurityGroupTests.cs @@ -0,0 +1,257 @@ +using System; +using System.Linq; +using System.Net; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class SecurityGroupTests + { + private readonly ComputeService _compute; + + public SecurityGroupTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void GetSecurityGroup() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroup { Id = securityGroupId }); + + var result = _compute.GetSecurityGroup(securityGroupId); + + httpTest.ShouldHaveCalled($"*/os-security-groups/{securityGroupId}"); + Assert.NotNull(result); + Assert.Equal(securityGroupId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetSecurityGroupFromReferenceTest() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + Identifier securityGroupId = Guid.NewGuid(); + const string securityGroupName = "{group-name}"; + httpTest.RespondWithJson(new Server + { + SecurityGroups = {new SecurityGroupReference {Name = securityGroupName}} + }); + httpTest.RespondWithJson(new SecurityGroupCollection + { + new SecurityGroup {Id = Guid.NewGuid(), Name = "default"}, + new SecurityGroup {Id = securityGroupId, Name = securityGroupName} + }); + httpTest.RespondWithJson(new SecurityGroup { Id = securityGroupId }); + + var server = _compute.GetServer(serverId); + var securityGroupRef = server.SecurityGroups.First(); + + SecurityGroup result = securityGroupRef.GetSecurityGroup(); + + Assert.NotNull(result); + Assert.Equal(securityGroupId, result.Id); + } + } + + [Fact] + public void CreateSecurityGroup() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroup {Id = securityGroupId}); + + var request = new SecurityGroupDefinition("{name}", "{description}"); + var result = _compute.CreateSecurityGroup(request); + + httpTest.ShouldHaveCalled("*/os-security-groups"); + Assert.Equal(securityGroupId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void DeserializeSecurityGroupRule() + { + const string json = @"{ +'security_group_rule': { + 'from_port': 22, + 'group': {}, + 'ip_protocol': 'tcp', + 'to_port': 22, + 'parent_group_id': 'bfa0c0ed-274b-4711-b3ee-37d35660fb06', + 'ip_range': { + 'cidr': '0.0.0.0 / 24' + }, + 'id': '55d75417-37df-48e2-96aa-20ba53a82900' +}}"; + var result = OpenStackNet.Deserialize(JObject.Parse(json).ToString()); + Assert.Equal("0.0.0.0 / 24", result.CIDR); + } + + [Fact] + public void AddSecurityGroupRule() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + Identifier securityGroupRuleId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroup { Id = securityGroupId }); + httpTest.RespondWithJson(new SecurityGroupRule {Id = securityGroupRuleId}); + + var request = new SecurityGroupRuleDefinition(IPProtocol.TCP, 0, 0, "{cidr}"); + var securityGroup = _compute.GetSecurityGroup(securityGroupId); + var result = securityGroup.AddRule(request); + + httpTest.ShouldHaveCalled("*/os-security-group-rules"); + Assert.Contains(securityGroupId, httpTest.CallLog.Last().RequestBody); // Make sure that we automatically set the parent group id + + Assert.NotNull(result); + Assert.Contains(result, securityGroup.Rules); + Assert.Equal(securityGroupRuleId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListSecurityGroups() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroupCollection + { + new SecurityGroup {Id = securityGroupId} + }); + + var results = _compute.ListSecurityGroups(); + + httpTest.ShouldHaveCalled("*/os-security-groups"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(securityGroupId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListSecurityGroupForServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroupCollection + { + new SecurityGroup {Id = Guid.NewGuid()} + }); + + var results = _compute.ListSecurityGroups(serverId); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/os-security-groups"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void DeleteSecurityGroup() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroup { Id = securityGroupId }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + var securityGroup = _compute.GetSecurityGroup(securityGroupId); + + securityGroup.Delete(); + httpTest.ShouldHaveCalled($"*/os-security-groups/{securityGroupId}"); + } + } + + [Fact] + public void DeleteSecurityGroupReference() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroup { Id = securityGroupId }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + SecurityGroupReference securityGroup = _compute.GetSecurityGroup(securityGroupId); + + securityGroup.Delete(); + httpTest.ShouldHaveCalled($"*/os-security-groups/{securityGroupId}"); + } + } + + [Fact] + public void DeleteSecurityGroupRule() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + Identifier securityGroupRuleId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroup + { + Id = securityGroupId, + Rules = + { + new SecurityGroupRule {Id = securityGroupRuleId} + } + }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + var securityGroup = _compute.GetSecurityGroup(securityGroupId); + var rule = securityGroup.Rules.First(); + rule.Delete(); + + httpTest.ShouldHaveCalled($"*/os-security-groups/{securityGroupId}"); + } + } + + [Fact] + public void WhenDeleteSecurityGroup_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Not here, boss..."); + + _compute.DeleteSecurityGroup(securityGroupId); + + httpTest.ShouldHaveCalled($"*/os-security-groups/{securityGroupId}"); + } + } + + [Fact] + public void UpdateSecurityGroup() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroup {Id = securityGroupId}); + + var securityGroup = _compute.GetSecurityGroup(securityGroupId); + securityGroup.Name = "new-name"; + securityGroup.Update(); + + httpTest.ShouldHaveCalled($"*/os-security-groups/{securityGroupId}"); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/ServerAddressTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/ServerAddressTests.cs new file mode 100644 index 000000000..9946f76a2 --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/ServerAddressTests.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class ServerAddressTests + { + private readonly ComputeService _compute; + + public ServerAddressTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void GetServerAddress() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new ServerCollection { new Server { Id = serverId } }); + httpTest.RespondWithJson(new Dictionary> + { + ["private"] = new List + { + new ServerAddress {IP = "1.2.3.4"} + } + }); + + var serverReferences = _compute.ListServerSummaries(); + var result = (serverReferences.First().GetAddress("private")).First(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/ips/private"); + Assert.NotNull(result); + Assert.Equal("1.2.3.4", result.IP); + } + } + + [Fact] + public void ListServerAddresses() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new ServerCollection { new Server { Id = serverId } }); + httpTest.RespondWithJson(new ServerAddressCollection {["ServiceNet"] = new List {new ServerAddress {IP = "192.168.1.189"}}}); + + var serverReferences = _compute.ListServerSummaries(); + var results = serverReferences.First().ListAddresses(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/ips"); + Assert.NotNull(results); + Assert.True(results.ContainsKey("ServiceNet")); + + var result = results["ServiceNet"].First(); + Assert.Equal("192.168.1.189", result.IP); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/ServerGroupTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/ServerGroupTests.cs new file mode 100644 index 000000000..42d97ce52 --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/ServerGroupTests.cs @@ -0,0 +1,94 @@ +using System; +using System.Linq; +using System.Net; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class ServerGroupTests + { + private readonly ComputeService _compute; + + public ServerGroupTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void GetServerGroup() + { + using (var httpTest = new HttpTest()) + { + Identifier serverGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new ServerGroup { Id = serverGroupId }); + + var result = _compute.GetServerGroup(serverGroupId); + + httpTest.ShouldHaveCalled($"*/os-server-groups/{serverGroupId}"); + Assert.NotNull(result); + Assert.Equal(serverGroupId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void CreateServerGroup() + { + using (var httpTest = new HttpTest()) + { + Identifier serverGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new ServerGroup {Id = serverGroupId}); + + var request = new ServerGroupDefinition("{name}", "{policy-name}"); + var result = _compute.CreateServerGroup(request); + + httpTest.ShouldHaveCalled("*/os-server-groups"); + Assert.Equal(serverGroupId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListServerGroups() + { + using (var httpTest = new HttpTest()) + { + Identifier serverGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new ServerGroupCollection + { + new ServerGroup {Id = serverGroupId} + }); + + var results = _compute.ListServerGroups(); + + httpTest.ShouldHaveCalled("*/os-server-groups"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(serverGroupId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Theory] + [InlineData(HttpStatusCode.Accepted)] + [InlineData(HttpStatusCode.NotFound)] + public void DeleteServerGroup(HttpStatusCode responseCode) + { + using (var httpTest = new HttpTest()) + { + Identifier serverGroupId = Guid.NewGuid(); + httpTest.RespondWithJson(new ServerGroup { Id = serverGroupId }); + httpTest.RespondWith((int)responseCode, "All gone!"); + + var serverGroup = _compute.GetServerGroup(serverGroupId); + + serverGroup.Delete(); + httpTest.ShouldHaveCalled($"*/os-server-groups/{serverGroupId}"); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/ServerTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/ServerTests.cs new file mode 100644 index 000000000..3b926a19b --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/ServerTests.cs @@ -0,0 +1,856 @@ +using System; +using System.Linq; +using System.Net; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class ServerTests + { + private readonly ComputeService _compute; + + public ServerTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void SerializeServerWithSchedulerHints() + { + string expectedJson = JObject.Parse(@"{'server':{'name':'name','imageRef':'00000000-0000-0000-0000-000000000000','flavorRef':'00000000-0000-0000-0000-000000000000'},'os:scheduler_hints':{'group':'groupId'}}") + .ToString(Formatting.None); + var server = new ServerCreateDefinition("name", Guid.Empty, Guid.Empty); + server.SchedulerHints = new SchedulerHints(); + server.SchedulerHints.Add("group", "groupId"); + + var json = OpenStackNet.Serialize(server); + Assert.Equal(expectedJson, json); + } + + [Fact] + public void SerializeServerWithoutSchedulerHints() + { + string expectedJson = JObject.Parse(@"{'server':{'name':'name','imageRef':'00000000-0000-0000-0000-000000000000','flavorRef':'00000000-0000-0000-0000-000000000000'}}") + .ToString(Formatting.None); + var server = new ServerCreateDefinition("name", Guid.Empty, Guid.Empty); + + var json = OpenStackNet.Serialize(server); + Assert.Equal(expectedJson, json); + } + + [Fact] + public void SerializeListServerOptionsInUrl() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new ServerSummaryCollection()); + _compute.ListServerSummaries(new ServerListOptions()); + httpTest.ShouldNotHaveCalled("*metadata*"); + } + } + + [Fact] + public void CreateServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server {Id = serverId}); + + var definition = new ServerCreateDefinition("{name}", Guid.NewGuid(), "{flavor-id}"); + var result = _compute.CreateServer(definition); + + httpTest.ShouldHaveCalled("*/servers"); + Assert.NotNull(result); + Assert.Equal(serverId,result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void CreateServerMetadata() + { + using (var httpTest = new HttpTest()) + { + const string key = "stuff"; + Identifier serverId = "1"; + httpTest.RespondWithJson(new Server { Id = serverId }); + + var server = _compute.GetServer(serverId); + server.Metadata.Create(key, "things"); + + Assert.True(server.Metadata.ContainsKey(key)); + httpTest.ShouldHaveCalled($"*/servers/{serverId}/metadata/{key}"); + } + } + + [Fact] + public void GetServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + + var result = _compute.GetServer(serverId); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}"); + Assert.NotNull(result); + Assert.Equal(serverId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetServerExtension() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new ServerSummaryCollection + { + Items = { new ServerSummary { Id = serverId } } + }); + httpTest.RespondWithJson(new Server { Id = serverId }); + + var serverRef = _compute.ListServerSummaries().First(); + var result = serverRef.GetServer(); + + Assert.NotNull(result); + Assert.Equal(serverId, result.Id); + } + } + + [Fact] + public void GetServerMetadata() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = "1"; + httpTest.RespondWithJson(new ServerSummaryCollection { new ServerSummary { Id = serverId } }); + httpTest.RespondWithJson(new ServerMetadata { ["stuff"] = "things" }); + + var servers = _compute.ListServerSummaries(); + ServerMetadata result = servers.First().GetMetadata(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/metadata"); + Assert.NotNull(result); + Assert.Equal(1, result.Count); + Assert.True(result.ContainsKey("stuff")); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetServerMetadataItem() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = "1"; + httpTest.RespondWithJson(new ServerSummaryCollection { new ServerSummary { Id = serverId } }); + httpTest.RespondWithJson(new + { + meta = new + { + stuff = "things" + } + + }); + + var servers = _compute.ListServerSummaries(); + string result = servers.First().GetMetadataItem("stuff"); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/metadata"); + Assert.NotNull(result); + Assert.Equal("things", result); + } + } + + [Fact] + public void WaitForServerActive() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId, Status = ServerStatus.Building}); + httpTest.RespondWithJson(new Server { Id = serverId, Status = ServerStatus.Active }); + + var result = _compute.GetServer(serverId); + result.WaitUntilActive(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}"); + Assert.NotNull(result); + Assert.Equal(serverId, result.Id); + Assert.Equal(ServerStatus.Active, result.Status); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListServerSummaries() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new ServerSummaryCollection + { + Items = { new ServerSummary { Id = serverId}}, + Links = { new PageLink("next", "http://api.com/next") } + }); + + var results = _compute.ListServerSummaries(); + + httpTest.ShouldHaveCalled("*/servers"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(serverId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListServerSummariesWithFilter() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new ServerCollection()); + + const string name = "foo"; + const string flavorId = "1"; + Identifier imageId = Guid.NewGuid(); + var lastModified = DateTimeOffset.Now.AddDays(-1); + ServerStatus status = ServerStatus.Active; + + _compute.ListServerSummaries(new ServerListOptions { Name = name, FlavorId = flavorId, ImageId = imageId, UpdatedAfter = lastModified, Status = status}); + + httpTest.ShouldHaveCalled($"*name={name}"); + httpTest.ShouldHaveCalled($"*flavor={flavorId}"); + httpTest.ShouldHaveCalled($"*image={imageId}"); + httpTest.ShouldHaveCalled($"*status={status}"); + httpTest.ShouldHaveCalled("*changes-since="); + } + } + + [Fact] + public void ListServerSummariesWithPaging() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new ServerCollection + { + Items = {new Server()}, + Links = {new PageLink("next", "http://example.com")} + }); + + Identifier startingAt = Guid.NewGuid(); + const int pageSize = 10; + _compute.ListServerSummaries(new ServerListOptions { PageSize = pageSize, StartingAt = startingAt }); + + httpTest.ShouldHaveCalled($"*marker={startingAt}*"); + httpTest.ShouldHaveCalled($"*limit={pageSize}*"); + } + } + + [Fact] + public void UpdateServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId, Name = "{new-name}"}); + + var request = new ServerUpdateDefinition {Name = "{new-name}"}; + var result = _compute.UpdateServer(serverId, request); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}"); + Assert.NotNull(result); + Assert.Equal(serverId, result.Id); + Assert.Equal(request.Name, result.Name); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void UpdateServerExtension() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId, Name = "{old-name}" }); + var lastModified = DateTimeOffset.Now; + httpTest.RespondWithJson(new Server { Id = serverId, Name = "{new-name}", LastModified = lastModified}); + + var server = _compute.GetServer(serverId); + server.Name = "{new-name}"; + server.Update(); + + Assert.Equal(serverId, server.Id); + Assert.Equal("{new-name}", server.Name); + Assert.Equal(lastModified, server.LastModified); + Assert.IsType(((IServiceResource)server).Owner); + } + } + + [Theory] + [InlineData(false, "POST")] + [InlineData(true, "PUT")] + public void UpdateServerMetadata(bool overwrite, string expectedHttpVerb) + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = "1"; + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWithJson(new ServerMetadata { ["stuff"] = "things" }); + + var server = _compute.GetServer(serverId); + server.Metadata["color"] = "blue"; + server.Metadata.Update(overwrite); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/metadata"); + Assert.Equal(expectedHttpVerb, httpTest.CallLog.Last().Request.Method.Method); + Assert.True(server.Metadata.ContainsKey("stuff")); + } + } + + [Fact] + public void DeleteServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + _compute.DeleteServer(serverId); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}"); + } + } + + [Fact] + public void DeleteServerExtension() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server {Id = serverId}); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + httpTest.RespondWithJson(new Server { Id = serverId, Status = ServerStatus.Deleted}); + + var server =_compute.GetServer(serverId); + server.Delete(); + Assert.NotEqual(server.Status, ServerStatus.Deleted); + + server.WaitUntilDeleted(); + Assert.Equal(server.Status, ServerStatus.Deleted); + } + } + + [Fact] + public void WhenDeleteServer_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Not here, boss..."); + + _compute.DeleteServer(serverId); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}"); + } + } + + [Theory] + [InlineData(HttpStatusCode.Accepted)] + [InlineData(HttpStatusCode.NotFound)] + public void DeleteServerMetadata(HttpStatusCode responseCode) + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + const string key = "stuff"; + httpTest.RespondWithJson(new Server + { + Id = serverId, + Metadata = + { + [key] = "things" + } + }); + httpTest.RespondWith((int)responseCode, "All gone!"); + + var server = _compute.GetServer(serverId); + + server.Metadata.Delete(key); + Assert.False(server.Metadata.ContainsKey(key)); + httpTest.ShouldHaveCalled($"*/servers/{serverId}/metadata/{key}"); + } + } + + [Fact] + public void WaitForServerDeleted() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId, Status = ServerStatus.Active }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + httpTest.RespondWithJson(new Server { Id = serverId, Status = ServerStatus.Deleted }); + + var result = _compute.GetServer(serverId); + result.Delete(); + result.WaitUntilDeleted(); + + Assert.Equal(ServerStatus.Deleted, result.Status); + } + } + + [Fact] + public void WaitForServerDeleted_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId, Status = ServerStatus.Active }); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Nothing here, boss"); + + var result = _compute.GetServer(serverId); + result.Delete(); + result.WaitUntilDeleted(); + + Assert.Equal(ServerStatus.Deleted, result.Status); + } + } + + [Fact] + public void SnapshotServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + Identifier imageId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss"); + httpTest.ResponseQueue.Last().Headers.Location = new Uri($"http://api.example.com/images/{imageId}"); + httpTest.RespondWithJson(new Image { Id = imageId }); + + var server = _compute.GetServer(serverId); + Image result = server.Snapshot(new SnapshotServerRequest("{image-name")); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.True(httpTest.CallLog.First(x => x.Url.EndsWith("/action")).RequestBody.Contains("createImage")); + Assert.NotNull(result); + Assert.Equal(imageId, result.Id); + } + } + + [Fact] + public void StartServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss"); + + var server = _compute.GetServer(serverId); + server.Start(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.True(httpTest.CallLog.Last().RequestBody.Contains("os-start")); + } + } + + [Fact] + public void StopServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss"); + + var server = _compute.GetServer(serverId); + server.Stop(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.True(httpTest.CallLog.Last().RequestBody.Contains("os-stop")); + } + } + + [Fact] + public void SuspendServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss"); + + var server = _compute.GetServer(serverId); + server.Suspend(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.True(httpTest.CallLog.Last().RequestBody.Contains("suspend")); + } + } + + [Fact] + public void ResumeServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss"); + + var server = _compute.GetServer(serverId); + server.Resume(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.True(httpTest.CallLog.Last().RequestBody.Contains("resume")); + } + } + + [Fact] + public void RebootServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss"); + + var server = _compute.GetServer(serverId); + server.Reboot(new RebootServerRequest {Type = RebootType.Hard}); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + string lastRequest = httpTest.CallLog.Last().RequestBody; + Assert.True(lastRequest.Contains("reboot")); + Assert.True(lastRequest.Contains("HARD")); + } + } + + [Fact] + public void AttachVolume() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWithJson(new ServerVolume {Id = volumeId, DeviceName = "/dev/vdd"}); + + var server = _compute.GetServer(serverId); + var result = server.AttachVolume(new ServerVolumeDefinition(volumeId)); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/os-volume_attachments"); + Assert.NotNull(result); + Assert.Equal(volumeId, result.Id); + Assert.True(server.AttachedVolumes.Any(v => v.Id == volumeId)); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void DetachVolume() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server + { + Id = serverId, + AttachedVolumes = { new ServerVolume { Id = volumeId, DeviceName = "/dev/vdd" } } + }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, good buddy"); + + var server = _compute.GetServer(serverId); + ServerVolumeReference attachedVolume = server.AttachedVolumes[0]; + attachedVolume.Detach(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/os-volume_attachments/{volumeId}"); + Assert.False(server.AttachedVolumes.Any(v => v.Id == volumeId)); + } + } + + [Fact] + public void GetVolume() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server {Id = serverId, AttachedVolumes = {new ServerVolumeReference {Id = volumeId}}}); + httpTest.RespondWithJson(new ServerVolume {Id = volumeId, DeviceName = "/dev/vdd"}); + + var server = _compute.GetServer(serverId); + var result = server.AttachedVolumes[0].GetServerVolume(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/os-volume_attachments/{volumeId}"); + Assert.NotNull(result); + Assert.Equal(volumeId, result.Id); + } + } + + [Fact] + public void ListVolumes() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server {Id = serverId}); + httpTest.RespondWithJson(new ServerVolumeCollection + { + new ServerVolume + { + Id = volumeId, DeviceName = "/dev/vdd" + } + }); + + var server = _compute.GetServer(serverId); + var results = server.ListVolumes(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/os-volume_attachments"); + Assert.NotNull(results); + Assert.Equal(1, results.Count()); + Assert.Equal(volumeId, results.First().Id); + } + } + + [Theory] + [InlineData("novnc")] + [InlineData("xvpvnc")] + public void GetVncConsole(string typeName) + { + var type = StringEnumeration.FromDisplayName(typeName); + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server {Id = serverId}); + httpTest.RespondWithJson(new RemoteConsole {Type = type}); + + var server = _compute.GetServer(serverId); + var result = server.GetVncConsole(RemoteConsoleType.NoVnc); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("os-getVNCConsole", httpTest.CallLog.Last().RequestBody); + Assert.NotNull(result); + Assert.Equal(type, result.Type); + } + } + + [Fact] + public void GetSpiceConsole() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWithJson(new RemoteConsole { Type = RemoteConsoleType.SpiceHtml5 }); + + var server = _compute.GetServer(serverId); + var result = server.GetSpiceConsole(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("os-getSPICEConsole", httpTest.CallLog.Last().RequestBody); + Assert.NotNull(result); + Assert.Equal(RemoteConsoleType.SpiceHtml5, result.Type); + } + } + + [Fact] + public void GetSerialConsole() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWithJson(new RemoteConsole { Type = RemoteConsoleType.Serial }); + + var server = _compute.GetServer(serverId); + var result = server.GetSerialConsole(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("os-getSerialConsole", httpTest.CallLog.Last().RequestBody); + Assert.NotNull(result); + Assert.Equal(RemoteConsoleType.Serial, result.Type); + } + } + + [Fact] + public void GetRdpConsole() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWithJson(new RemoteConsole { Type = RemoteConsoleType.RdpHtml5 }); + + var server = _compute.GetServer(serverId); + var result = server.GetRdpConsole(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("os-getRDPConsole", httpTest.CallLog.Last().RequestBody); + Assert.NotNull(result); + Assert.Equal(RemoteConsoleType.RdpHtml5, result.Type); + } + } + + [Fact] + public void GetConsoleOutput() + { + const string output = "FAKE CONSOLE OUTPUT\nANOTHER\nLAST LINE"; + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith(JObject.Parse("{'output': '" + output + "'}").ToString()); + + var server = _compute.GetServer(serverId); + var result = server.GetConsoleOutput(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("os-getConsoleOutput", httpTest.CallLog.Last().RequestBody); + Assert.Equal(output, result); + } + } + + [Fact] + public void RescueServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server {Id = serverId}); + httpTest.RespondWithJson(new {adminPass = "top-secret"}); + + var server = _compute.GetServer(serverId); + server.Rescue(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("rescue", httpTest.CallLog.Last().RequestBody); + } + } + + [Fact] + public void UnrescueServer() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWithJson(new { adminPass = "top-secret" }); + + var server = _compute.GetServer(serverId); + server.UnrescueAsync(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("unrescue", httpTest.CallLog.Last().RequestBody); + } + } + + [Fact] + public void ResizeServer() + { + using (var httpTest = new HttpTest()) + { + Identifier flavorId = "1"; + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, good buddy!"); + + var server = _compute.GetServer(serverId); + server.Resize(flavorId); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("resize", httpTest.CallLog.Last().RequestBody); + } + } + + [Fact] + public void ConfirmResizeServer() + { + using (var httpTest = new HttpTest()) + { + Identifier flavorId = "1"; + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, good buddy!"); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, good buddy!"); + + var server = _compute.GetServer(serverId); + server.Resize(flavorId); + server.ConfirmResize(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("confirmResize", httpTest.CallLog.Last().RequestBody); + } + } + + [Fact] + public void CancelResizeServer() + { + using (var httpTest = new HttpTest()) + { + Identifier flavorId = "1"; + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, good buddy!"); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, good buddy!"); + + var server = _compute.GetServer(serverId); + server.Resize(flavorId); + server.CancelResize(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/action"); + Assert.Contains("revertResize", httpTest.CallLog.Last().RequestBody); + } + } + + [Fact] + public void ListServerActions() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + Identifier actionId = Guid.NewGuid(); + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWithJson(new ServerActionSummaryCollection {new ServerActionSummary {Id = actionId, ServerId = serverId, Name = "create"}}); + httpTest.RespondWithJson(new ServerAction + { + Id = actionId, + Name = "create", + Events = {new ServerEvent {Name = "create_instance"}} + }); + + var server = _compute.GetServer(serverId); + var results = server.ListActionSummaries(); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/os-instance-actions"); + Assert.NotNull(results); + Assert.Equal(1, results.Count()); + + var actionRef = results.First(); + Assert.Equal(actionId, actionRef.Id); + Assert.NotNull(actionRef.Name); + + var action = actionRef.GetAction(); + httpTest.ShouldHaveCalled($"*/servers/{serverId}/os-instance-actions/{actionId}"); + Assert.NotNull(action); + Assert.NotNull(action.Name); + Assert.NotNull(action.Events); + Assert.Equal(1, action.Events.Count); + Assert.NotNull(action.Events.First().Name); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_1/VolumeTests.cs b/src/OpenStack.UnitTests/Compute/v2_1/VolumeTests.cs new file mode 100644 index 000000000..bcfca48fc --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_1/VolumeTests.cs @@ -0,0 +1,234 @@ +using System; +using System.Linq; +using System.Net; +using Newtonsoft.Json.Linq; +using OpenStack.BlockStorage.v2; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_1 +{ + public class VolumeTests + { + private readonly ComputeService _compute; + + public VolumeTests() + { + _compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void DeserializeVolumeWithEmptyAttachment() + { + var json = JObject.Parse(@"{'volume': {'attachments': [{}]}}").ToString(); + var result = OpenStackNet.Deserialize(json); + Assert.Empty(result.Attachments); + } + + [Fact] + public void GetVolume() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + httpTest.RespondWithJson(new Volume { Id = volumeId }); + + var result = _compute.GetVolume(volumeId); + + httpTest.ShouldHaveCalled($"*/os-volumes/{volumeId}"); + Assert.NotNull(result); + Assert.Equal(volumeId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetVolumeSnapshot() + { + using (var httpTest = new HttpTest()) + { + Identifier snapshotId = Guid.NewGuid(); + httpTest.RespondWithJson(new VolumeSnapshot { Id = snapshotId }); + + var result = _compute.GetVolumeSnapshot(snapshotId); + + httpTest.ShouldHaveCalled($"*/os-snapshots/{snapshotId}"); + Assert.NotNull(result); + Assert.Equal(snapshotId, result.Id); + } + } + + [Fact] + public void CreateVolume() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + httpTest.RespondWithJson(new Volume {Id = volumeId}); + + var request = new VolumeDefinition(size: 1); + var result = _compute.CreateVolume(request); + + httpTest.ShouldHaveCalled("*/os-volumes"); + Assert.Equal(volumeId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void WaitForVolumeAvailable() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + httpTest.RespondWithJson(new Volume { Id = volumeId, Status = VolumeStatus.Creating }); + httpTest.RespondWithJson(new Volume { Id = volumeId, Status = VolumeStatus.Available }); + + var result = _compute.GetVolume(volumeId); + result.WaitUntilAvailable(); + + httpTest.ShouldHaveCalled($"*/os-volumes/{volumeId}"); + Assert.NotNull(result); + Assert.Equal(volumeId, result.Id); + Assert.Equal(VolumeStatus.Available, result.Status); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void SnapshotVolume() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + httpTest.RespondWithJson(new Volume() { Id = volumeId }); + httpTest.RespondWithJson(new VolumeSnapshot { VolumeId = volumeId }); + + var volume = _compute.GetVolume(volumeId); + var result = volume.Snapshot(); + + httpTest.ShouldHaveCalled("*/os-snapshots"); + Assert.Contains(volumeId, httpTest.CallLog.Last().RequestBody); + Assert.Equal(volumeId, result.VolumeId); + Assert.IsType(((IServiceResource)volume).Owner); + } + } + + [Fact] + public void ListVolumes() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + httpTest.RespondWithJson(new VolumeCollection + { + new Volume {Id = volumeId} + }); + + var results = _compute.ListVolumes(); + + httpTest.ShouldHaveCalled("*/os-volumes"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(volumeId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + //[Fact] + //public void ListVolumeTypes() + //{ + // using (var httpTest = new HttpTest()) + // { + // Identifier volumeTypeId = Guid.NewGuid(); + // httpTest.RespondWithJson(new VolumeTypeCollection + // { + // new VolumeType {Id = volumeTypeId} + // }); + + // var results = _compute.ListVolumeTypes(); + + // httpTest.ShouldHaveCalled("*/os-volume-types"); + // Assert.Equal(1, results.Count()); + // var result = results.First(); + // Assert.Equal(volumeTypeId, result.Id); + // } + //} + + [Fact] + public void ListVolumeSnapshots() + { + using (var httpTest = new HttpTest()) + { + Identifier snapshotId = Guid.NewGuid(); + httpTest.RespondWithJson(new VolumeSnapshotCollection + { + new VolumeSnapshot {Id = snapshotId} + }); + + var results = _compute.ListVolumeSnapshots(); + + httpTest.ShouldHaveCalled("*/os-snapshots"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(snapshotId, result.Id); + } + } + + [Theory] + [InlineData(HttpStatusCode.Accepted)] + [InlineData(HttpStatusCode.NotFound)] + public void DeleteVolume(HttpStatusCode responseCode) + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + httpTest.RespondWithJson(new Volume { Id = volumeId }); + httpTest.RespondWith((int)responseCode, "All gone!"); + + var volume = _compute.GetVolume(volumeId); + + volume.Delete(); + httpTest.ShouldHaveCalled($"*/os-volumes/{volumeId}"); + } + } + + [Fact] + public void WaitForVolumeDeleted() + { + using (var httpTest = new HttpTest()) + { + Identifier volumeId = Guid.NewGuid(); + httpTest.RespondWithJson(new Volume { Id = volumeId, Status = VolumeStatus.Available }); + httpTest.RespondWith((int)HttpStatusCode.Accepted, "All gone!"); + httpTest.RespondWithJson(new Volume { Id = volumeId, Status = VolumeStatus.Deleting }); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Not here, boss!"); + + var result = _compute.GetVolume(volumeId); + result.Delete(); + result.WaitUntilDeleted(); + } + } + + [Theory] + [InlineData(HttpStatusCode.Accepted)] + [InlineData(HttpStatusCode.NotFound)] + public void DeleteVolumeSnapshot(HttpStatusCode responseCode) + { + using (var httpTest = new HttpTest()) + { + Identifier snapshotId = Guid.NewGuid(); + httpTest.RespondWithJson(new VolumeSnapshot { Id = snapshotId }); + httpTest.RespondWith((int)responseCode, "All gone!"); + + var snapshot = _compute.GetVolumeSnapshot(snapshotId); + + snapshot.Delete(); + httpTest.ShouldHaveCalled($"*/os-snapshots/{snapshotId}"); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_2/ConsoleTypeTests.cs b/src/OpenStack.UnitTests/Compute/v2_2/ConsoleTypeTests.cs new file mode 100644 index 000000000..3bc4ad3de --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_2/ConsoleTypeTests.cs @@ -0,0 +1,13 @@ +using Xunit; + +namespace OpenStack.Compute.v2_2 +{ + public class ConsoleTypeTests + { + [Fact] + public void Serialize() + { + + } + } +} diff --git a/src/OpenStack.UnitTests/Compute/v2_6/ServerTests.cs b/src/OpenStack.UnitTests/Compute/v2_6/ServerTests.cs new file mode 100644 index 000000000..2bf311ebb --- /dev/null +++ b/src/OpenStack.UnitTests/Compute/v2_6/ServerTests.cs @@ -0,0 +1,33 @@ +using System; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Compute.v2_6 +{ + public class ServerTests + { + private readonly ComputeService _computeService; + + public ServerTests() + { + _computeService = new ComputeService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void GetConsole() + { + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + httpTest.RespondWithJson(new Console {Type = RemoteConsoleType.NoVnc}); + + Console result = _computeService.GetConsole(serverId, ConsoleProtocol.VNC, RemoteConsoleType.NoVnc); + + httpTest.ShouldHaveCalled($"*/servers/{serverId}/remote-consoles"); + Assert.NotNull(result); + Assert.Equal(RemoteConsoleType.NoVnc, result.Type); + } + } + } +} diff --git a/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceTests.cs b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceTests.cs new file mode 100644 index 000000000..daf480222 --- /dev/null +++ b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceTests.cs @@ -0,0 +1,23 @@ +using Flurl.Http.Testing; +using OpenStack.Synchronous; +using Xunit; +using HttpTest = OpenStack.Testing.HttpTest; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + public class ContentDeliveryNetworkServiceTests + { + private const string Region = "DFW"; + + [Fact] + public void Ping() + { + using (new HttpTest()) + { + var service = new ContentDeliveryNetworkService(Stubs.AuthenticationProvider, Region); + + service.Ping(); + } + } + } +} diff --git a/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/FlavorTests.cs b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/FlavorTests.cs new file mode 100644 index 000000000..e932563cf --- /dev/null +++ b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/FlavorTests.cs @@ -0,0 +1,56 @@ +using System; +using System.Linq; +using OpenStack.Synchronous; +using Xunit; +using HttpTest = OpenStack.Testing.HttpTest; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + public class FlavorTests + { + private const string DefaultRegion = "DFW"; + + [Fact] + public void ListFlavors() + { + using (var httpTest = new HttpTest()) + { + var cdnService = new ContentDeliveryNetworkService(Stubs.AuthenticationProvider, DefaultRegion); + httpTest.RespondWithJson(new FlavorCollection(new[] {new Flavor()})); + + var flavors = cdnService.ListFlavors(); + + Assert.NotNull(flavors); + Assert.Equal(1, flavors.Count()); + } + } + + [Fact] + public void GetFlavor() + { + using (var httpTest = new HttpTest()) + { + var cdnService = new ContentDeliveryNetworkService(Stubs.AuthenticationProvider, DefaultRegion); + httpTest.RespondWithJson(new Flavor {Id = "flavor-id"}); + + var flavor = cdnService.GetFlavor("flavor-id"); + + Assert.NotNull(flavor); + Assert.Equal("flavor-id", flavor.Id); + } + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void WhenGetFlavor_IsCalledWithoutAnId_ItShoudldThrowAnException(string flavorId) + { + using (new HttpTest()) + { + var cdnService = new ContentDeliveryNetworkService(Stubs.AuthenticationProvider, DefaultRegion); + + Assert.Throws(() => cdnService.GetFlavor(flavorId)); + } + } + } +} diff --git a/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceCacheTests.cs b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceCacheTests.cs new file mode 100644 index 000000000..696b31ead --- /dev/null +++ b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceCacheTests.cs @@ -0,0 +1,32 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + public class ServiceCacheTests + { + [Fact] + public void SerializeTimeToLiveToSeconds() + { + var cache = new ServiceCache("cache", TimeSpan.FromSeconds(60)); + + var json = OpenStackNet.Serialize(cache); + + var result = JObject.Parse(json); + Assert.Equal(60, result.Value("ttl")); + } + + [Fact] + public void DeserializeTimeToLiveFromSeconds() + { + var cache = new ServiceCache("cache", TimeSpan.FromSeconds(60)); + var json = OpenStackNet.Serialize(cache); + + var result = OpenStackNet.Deserialize(json); + + Assert.Equal(60, result.TimeToLive.TotalSeconds); + } + } +} diff --git a/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceOperationFailedExceptionTests.cs b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceOperationFailedExceptionTests.cs new file mode 100644 index 000000000..163ba5707 --- /dev/null +++ b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceOperationFailedExceptionTests.cs @@ -0,0 +1,28 @@ +using System.IO; +using System.Linq; +using System.Runtime.Serialization.Formatters.Binary; +using Xunit; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + public class ServiceOperationFailedExceptionTests + { + [Fact] + public void SerializeCustomProperties() + { + var errors = new[] {new ServiceError{Message = "oops!"}}; + var ex = new ServiceOperationFailedException(errors); + + var formatter = new BinaryFormatter(); + using (var ms = new MemoryStream()) + { + formatter.Serialize(ms, ex); + ms.Seek(0, 0); + ex = (ServiceOperationFailedException)formatter.Deserialize(ms); + } + + Assert.NotEmpty(ex.Errors); + Assert.Equal("oops!", ex.Errors.First().Message); + } + } +} diff --git a/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceTests.cs b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceTests.cs new file mode 100644 index 000000000..f1c75a469 --- /dev/null +++ b/src/OpenStack.UnitTests/ContentDeliveryNetworks/v1/ServiceTests.cs @@ -0,0 +1,302 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Flurl; +using Flurl.Extensions; +using Marvin.JsonPatch; +using Newtonsoft.Json; +using OpenStack.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + public class ServiceTests + { + private readonly ContentDeliveryNetworkService _cdnService; + + public ServiceTests() + { + _cdnService = new ContentDeliveryNetworkService(Stubs.AuthenticationProvider, "DFW"); + } + + [Fact] + public void SerializeServiceCollection() + { + var services = new ServiceCollection + { + Items = {new Service {Id = "service-id"}}, + Links = {new PageLink("next", "http://api.com/next")} + }; + string json = OpenStackNet.Serialize(services); + Assert.Contains("\"services\"", json); + Assert.DoesNotContain("\"service\"", json); + + var result = OpenStackNet.Deserialize(json); + Assert.NotNull(result); + Assert.Equal(1, result.Count()); + Assert.Equal(1, result.Items.Count()); + Assert.Equal(1, result.Links.Count()); + Assert.True(result.HasNextPage); + } + + [Fact] + public void SerializePageLink() + { + var link = new PageLink("next", "http://api.com/next"); + string json = OpenStackNet.Serialize(link); + + var result = OpenStackNet.Deserialize(json); + Assert.NotNull(result); + Assert.True(result.IsNextPage); + } + + [Fact] + public void FindServiceOnAPage() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new ServiceCollection + { + Items = {new Service()}, + Links = {new PageLink("next", "http://api.com/next")} + }); + httpTest.RespondWithJson(new ServiceCollection + { + Items = {new Service {Name = "MyService"}} + }); + + var currentPage = _cdnService.ListServices(); + Service myService; + do + { + myService = currentPage.FirstOrDefault(x => x.Name == "MyService"); + if (myService != null) + break; + + currentPage = currentPage.GetNextPage(); + } while (currentPage.Any()); + + Assert.NotNull(myService); + } + } + + [Fact] + public void GetService() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new Service{Id = "service-id"}); + + var service = _cdnService.GetService("service-id"); + + Assert.NotNull(service); + Assert.Equal("service-id", service.Id); + } + } + + [Fact] + public void CreateService() + { + using (var httpTest = new HttpTest()) + { + var response = new HttpResponseMessage(HttpStatusCode.Created); + response.Headers.Location = "http://api.com".AppendPathSegments("services", "service-id").ToUri(); + httpTest.ResponseQueue.Enqueue(response); + + var service = new ServiceDefinition("service-name", "flavor-id", "www.example.com", "example.com") + { + Caches = + { + new ServiceCache("keep-one-day", TimeSpan.FromDays(1)) + }, + Restrictions = + { + new ServiceRestriction("internal-users-only", new[] + { + new ServiceRestrictionRule("intranet", "intranet.example.com") + }) + } + }; + var serviceId = _cdnService.CreateService(service); + + Assert.Equal("service-id", serviceId); + } + } + + [Fact] + public void DeleteService() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + _cdnService.DeleteService("service-id"); + } + } + + [Fact] + public void WaitForServiceDeployed() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new Service { Status = ServiceStatus.CreateInProgress }); + httpTest.RespondWithJson(new Service { Status = ServiceStatus.UpdateInProgress }); + httpTest.RespondWithJson(new Service { Status = ServiceStatus.Deployed }); + + var service = _cdnService.WaitForServiceDeployed("service-id", TimeSpan.FromMilliseconds(1)); + Assert.NotNull(service); + } + } + + [Fact] + public void WaitForServiceDeploy_ThrowsAnException_WhenTheOperationFailed() + { + using (var httpTest = new HttpTest()) + { + var failedServiceDeployment = new Service + { + Status = ServiceStatus.Failed, + Errors = new[] { new ServiceError { Message = "The domain is already in use." } } + }; + httpTest.RespondWithJson(failedServiceDeployment); + + var ex = Assert.Throws(() => _cdnService.WaitForServiceDeployed("failed-service-id")); + Assert.NotEmpty(ex.Errors); + } + } + + [Fact] + public async Task WaitForServiceDeployed_StopsWhenUserTokenIsCancelled() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new Service {Status = ServiceStatus.CreateInProgress}); + + var timedToken = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + + await Assert.ThrowsAsync(() => _cdnService.WaitForServiceDeployedAsync("service-id", Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan, null, timedToken.Token)); + } + } + + [Fact] + public async Task WaitForServiceDeployed_StopsWhenTimeoutIsReached() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new Service { Status = ServiceStatus.CreateInProgress }); + + await Assert.ThrowsAsync(() => _cdnService.WaitForServiceDeployedAsync("service-id", TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1))); + } + } + + [Fact] + public void WaitForServiceDeleted() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new Service { Status = ServiceStatus.DeleteInProgress }); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "All gone!"); + + _cdnService.WaitForServiceDeleted("service-id", TimeSpan.FromMilliseconds(1)); + } + } + + [Fact] + public async Task WaitForServiceDeleted_StopsWhenUserTokenIsCancelled() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new Service { Status = ServiceStatus.DeleteInProgress }); + + var timedToken = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + + await Assert.ThrowsAsync(() => _cdnService.WaitForServiceDeletedAsync("service-id", Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan, null, timedToken.Token)); + } + } + + [Fact] + public async Task WaitForServiceDeleted_StopsWhenTimeoutIsReached() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new Service { Status = ServiceStatus.CreateInProgress }); + + await Assert.ThrowsAsync(() => _cdnService.WaitForServiceDeletedAsync("service-id", TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1))); + } + } + + [Fact] + public void WaitForServiceDeleted_ThrowsAnException_WhenTheOperationFailed() + { + using (var httpTest = new HttpTest()) + { + var failedServiceDeployment = new Service + { + Status = ServiceStatus.Failed, + Errors = new[] { new ServiceError { Message = "Random error." } } + }; + httpTest.RespondWithJson(failedServiceDeployment); + + var ex = Assert.Throws(() => _cdnService.WaitForServiceDeleted("failed-service-id")); + Assert.NotEmpty(ex.Errors); + } + } + + [Fact] + public void WhenIDeleteANonExistingService_TheOperationShouldBeConsideredSuccessful() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Nothing to see here!"); + + _cdnService.DeleteService("bad-service-id"); + } + } + + [Fact] + public void UpdateService() + { + using (new HttpTest()) + { + var patch = new JsonPatchDocument(); + patch.Replace(x => x.Name, "My Cool New Name"); + + _cdnService.UpdateService("service-id", patch); + } + } + + [Fact] + public void PurgeAsset() + { + using (new HttpTest()) + { + _cdnService.PurgeCachedAsset("service-id", "asset-url"); + } + } + + [Fact] + public void PurgeAssets() + { + using (new HttpTest()) + { + _cdnService.PurgeCachedAssets("service-id"); + } + } + + [Fact] + public void WhenIPurgeANonExistingAsset_TheOperationShouldBeConsideredSuccessful() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Nothing to see here!"); + + _cdnService.PurgeCachedAsset("service-id", "missing-asset"); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Domain/Mapping/NetworkAddressDeserializationTests.cs b/src/OpenStack.UnitTests/Domain/Mapping/NetworkAddressDeserializationTests.cs new file mode 100644 index 000000000..d3a10d793 --- /dev/null +++ b/src/OpenStack.UnitTests/Domain/Mapping/NetworkAddressDeserializationTests.cs @@ -0,0 +1,96 @@ +using System.Linq; +using System.Net; +using System.Net.Sockets; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using net.openstack.Core.Domain; +using Newtonsoft.Json; + +namespace OpenStackNet.Testing.Unit.Domain.Mapping +{ + [TestClass] + public class NetworkAddressDeserializationTests + { + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Null_When_Null_String_Is_Mapped() + { + string obj = "null"; + var actual = JsonConvert.DeserializeObject(obj); + + Assert.IsNull(actual); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Null_When_Empty_String_Is_Mapped() + { + string obj = ""; + var actual = JsonConvert.DeserializeObject(obj); + + Assert.IsNull(actual); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Null_When_Whitespace_String_Is_Mapped() + { + string obj = " "; + var actual = JsonConvert.DeserializeObject(obj); + + Assert.IsNull(actual); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Network_With_No_Addresses() + { + string obj = "{\"public\": []}"; + var actual = JsonConvert.DeserializeObject(obj).Single(); + + Assert.IsNotNull(actual); + Assert.AreEqual(0, actual.Value.Count); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Network_With_Single_Addresses() + { + string obj = "{\"public\": [{\"version\": 4, \"addr\": \"166.78.156.150\"}]}"; + var actual = JsonConvert.DeserializeObject(obj).Single(); + + Assert.IsNotNull(actual); + Assert.AreEqual(1, actual.Value.Count); + CollectionAssert.AllItemsAreNotNull(actual.Value); + Assert.AreEqual(AddressFamily.InterNetwork, actual.Value[0].AddressFamily); + Assert.AreEqual(IPAddress.Parse("166.78.156.150"), actual.Value[0]); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Network_With_2_Addresseses() + { + string obj = "{\"public\": [{\"version\": 4, \"addr\": \"166.78.156.150\"}, {\"version\": 6, \"addr\": \"2001:4800:7812:0514:95e4:7f4d:ff04:d1eb\"}]}"; + var actual = JsonConvert.DeserializeObject(obj).Single(); + + Assert.IsNotNull(actual); + Assert.AreEqual(2, actual.Value.Count); + CollectionAssert.AllItemsAreNotNull(actual.Value); + Assert.AreEqual(AddressFamily.InterNetwork, actual.Value[0].AddressFamily); + Assert.AreEqual(IPAddress.Parse("166.78.156.150"), actual.Value[0]); + Assert.AreEqual(AddressFamily.InterNetworkV6, actual.Value[1].AddressFamily); + Assert.AreEqual(IPAddress.Parse("2001:4800:7812:0514:95e4:7f4d:ff04:d1eb"), actual.Value[1]); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Network_With_Both_v4_And_v6_Addresseses() + { + string obj = "{\"public\": [{\"version\": 4, \"addr\": \"166.78.156.150\"}, {\"version\": 6, \"addr\": \"2001:4800:7812:0514:95e4:7f4d:ff04:d1eb\"}]}"; + var actual = JsonConvert.DeserializeObject(obj).Single(); + + Assert.IsNotNull(actual); + Assert.IsNotNull(actual.Value.SingleOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork)); + Assert.IsNotNull(actual.Value.SingleOrDefault(a => a.AddressFamily == AddressFamily.InterNetworkV6)); + } + } +} diff --git a/src/OpenStack.UnitTests/Extensions/EnumerableExtensionsTests.cs b/src/OpenStack.UnitTests/Extensions/EnumerableExtensionsTests.cs new file mode 100644 index 000000000..8c7b7f915 --- /dev/null +++ b/src/OpenStack.UnitTests/Extensions/EnumerableExtensionsTests.cs @@ -0,0 +1,15 @@ +using Xunit; + +namespace System.Collections.Generic +{ + public class EnumerableExtensionsTests + { + [Fact] + public void ToCollection_ReturnsANewCollection_WhenPassedInNull() + { + IEnumerable items = null; + IList result = items.ToNonNullList(); + Assert.NotNull(result); + } + } +} diff --git a/src/OpenStack.UnitTests/Extensions/TypeExtensionsTests.cs b/src/OpenStack.UnitTests/Extensions/TypeExtensionsTests.cs new file mode 100644 index 000000000..167dc1039 --- /dev/null +++ b/src/OpenStack.UnitTests/Extensions/TypeExtensionsTests.cs @@ -0,0 +1,41 @@ +using System.Extensions; +using Xunit; + +namespace OpenStack.Extensions +{ + public class TypeExtensionsTests + { + public class A + { + public string Id { get; set; } + public string Name { get; set; } + public int Number { get; set; } + } + + public class B + { + public Identifier Id { get; set; } + public string Name { get; set; } + } + + [Fact] + public void CopyProperties_SameObjectType() + { + var src = new A {Id = "{id}", Name = "{name}", Number = 1}; + var dest = new A(); + src.CopyProperties(dest); + Assert.Equal(src.Id, dest.Id); + Assert.Equal(src.Name, dest.Name); + Assert.Equal(src.Number, dest.Number); + } + + [Fact] + public void CopyProperties_DifferentObjectType() + { + var src = new A { Id = "{id}", Name = "{name}", Number = 1 }; + var dest = new B(); + src.CopyProperties(dest); + Assert.Equal(src.Name, dest.Name); + } + } +} diff --git a/src/OpenStack.UnitTests/IdentifierTests.cs b/src/OpenStack.UnitTests/IdentifierTests.cs new file mode 100644 index 000000000..9503d28f9 --- /dev/null +++ b/src/OpenStack.UnitTests/IdentifierTests.cs @@ -0,0 +1,73 @@ +using System; +using Newtonsoft.Json; +using Xunit; + +namespace OpenStack +{ + public class IdentifierTests + { + public class Thing + { + public Identifier Id { get; set; } + } + + [Fact] + public void Serialize() + { + var rawId = Guid.NewGuid(); + var id = (Identifier)rawId; + + var result = OpenStackNet.Serialize(id); + + Assert.Equal(string.Format("\"{0}\"", rawId.ToString("D")), result); + } + + [Fact] + public void Serialize_WithinAClass() + { + var thing = new Thing {Id = Guid.NewGuid()}; + + var result = OpenStackNet.Serialize(thing); + + Assert.Equal(string.Format("{{\"Id\":\"{0}\"}}", thing.Id), result); + } + + [Fact] + public void Deserialize() + { + var id = new Identifier(Guid.NewGuid()); + + var json = OpenStackNet.Serialize(id); + var result = OpenStackNet.Deserialize(json); + + Assert.Equal(id, result); + } + + [Fact] + public void CanCompareWithString() + { + var rawId = Guid.NewGuid().ToString("D"); + var id = new Identifier(rawId); + + Assert.Equal(rawId, id); + Assert.Equal(id, rawId); + Assert.True(id == rawId); + Assert.True(rawId == id); + Assert.True(id.Equals(rawId)); + Assert.True(rawId.Equals(id)); + } + + [Fact] + public void CanCompareWithGuid() + { + var rawId = Guid.NewGuid(); + var id = new Identifier(rawId); + + Assert.Equal(rawId, id); + Assert.Equal(id, rawId); + Assert.True(id == rawId); + Assert.True(rawId == id); + Assert.True(id.Equals(rawId)); + } + } +} \ No newline at end of file diff --git a/src/OpenStack.UnitTests/Networking/v2/DHCPOptionConverterTests.cs b/src/OpenStack.UnitTests/Networking/v2/DHCPOptionConverterTests.cs new file mode 100644 index 000000000..a73f128e8 --- /dev/null +++ b/src/OpenStack.UnitTests/Networking/v2/DHCPOptionConverterTests.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace OpenStack.Networking.v2 +{ + public class DHCPOptionConverterTests + { + [Fact] + public void Serialize() + { + var input = new PortCreateDefinition(null) + { + DHCPOptions = + { + {"a", "stuff"}, + {"b", "things"} + } + }; + + string result = OpenStackNet.Serialize(input); + + string expectedJson = JObject.Parse("{'port':{'extra_dhcp_opts':[{'opt_name':'a','opt_value':'stuff'},{'opt_name':'b','opt_value':'things'}]}}").ToString(Formatting.None); + Assert.Equal(expectedJson, result); + } + + [Fact] + public void Deserialize() + { + string json = JObject.Parse("{'port':{'extra_dhcp_opts':[{'opt_name':'a','opt_value':'stuff'},{'opt_name':'b','opt_value':'things'}]}}").ToString(Formatting.None); + + var result = OpenStackNet.Deserialize(json).DHCPOptions; + + Assert.NotNull(result); + Assert.Equal(2, result.Count); + + Assert.Contains("a", result.Keys); + Assert.Contains("b", result.Keys); + Assert.Equal("stuff", result["a"]); + Assert.Equal("things", result["b"]); + } + + [Fact] + public void OpenStackNet_UsesDHCPOptionConverter() + { + var port = new Port + { + DHCPOptions = new Dictionary + { + {"a", "stuff"} + } + }; + + var json = OpenStackNet.Serialize(port); + var result = OpenStackNet.Deserialize(json); + + Assert.NotNull(result.DHCPOptions); + Assert.Equal(1, result.DHCPOptions.Count); + } + } +} diff --git a/src/OpenStack.UnitTests/Networking/v2/Layer3/Layer3Tests.cs b/src/OpenStack.UnitTests/Networking/v2/Layer3/Layer3Tests.cs new file mode 100644 index 000000000..7a3c70d28 --- /dev/null +++ b/src/OpenStack.UnitTests/Networking/v2/Layer3/Layer3Tests.cs @@ -0,0 +1,368 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using OpenStack.Compute.v2_1; +using OpenStack.Compute.v2_1.Serialization; +using OpenStack.Serialization; +using OpenStack.Networking.v2.Layer3.Synchronous; +using OpenStack.Networking.v2.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; +using SecurityGroupCollection = OpenStack.Networking.v2.Serialization.SecurityGroupCollection; + +namespace OpenStack.Networking.v2.Layer3 +{ + public class Layer3Tests + { + private readonly NetworkingService _networking; + + public Layer3Tests() + { + _networking = new NetworkingService(Stubs.AuthenticationProvider, "region"); + } + + #region Routers + [Fact] + public void CreateRouter() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + Identifier routerId = Guid.NewGuid(); + httpTest.RespondWithJson(new Router { Id = routerId, ExternalGateway = new ExternalGateway { ExternalNetworkId = networkId } }); + + var definition = new RouterCreateDefinition(); + var result = _networking.CreateRouter(definition); + + httpTest.ShouldHaveCalled("*/routers"); + Assert.NotNull(result); + Assert.Equal(routerId, result.Id); + Assert.Equal(networkId, result.ExternalGateway.ExternalNetworkId); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetRouter() + { + using (var httpTest = new HttpTest()) + { + Identifier routerId = Guid.NewGuid(); + httpTest.RespondWithJson(new Router { Id = routerId }); + + var result = _networking.GetRouter(routerId); + + httpTest.ShouldHaveCalled($"*/routers/{routerId}"); + Assert.NotNull(result); + Assert.Equal(routerId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListRouters() + { + using (var httpTest = new HttpTest()) + { + Identifier routerId = Guid.NewGuid(); + httpTest.RespondWithJson(new RouterCollection + { + new Router { Id = routerId } + }); + + var results = _networking.ListRouters(new RouterListOptions { Status = RouterStatus.Active }); + + httpTest.ShouldHaveCalled("*/routers?status=ACTIVE"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(routerId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Theory] + [InlineData(HttpStatusCode.Accepted)] + [InlineData(HttpStatusCode.NotFound)] + public void DeleteRouter(HttpStatusCode responseCode) + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + Identifier routerId = Guid.NewGuid(); + httpTest.RespondWithJson(new Router { Id = routerId}); + httpTest.RespondWithJson(new PortCollection + { + new Port {Id = portId} + }); + httpTest.RespondWith((int)responseCode, "All gone!"); + + var router = _networking.GetRouter(routerId); + router.Delete(); + + httpTest.ShouldHaveCalled($"*/routers/{routerId}/remove_router_interface"); + httpTest.ShouldHaveCalled($"*/routers/{routerId}"); + } + } + + [Fact] + public void AttachPort() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + Identifier routerId = Guid.NewGuid(); + httpTest.RespondWithJson(new Router { Id = routerId}); + + var router = _networking.GetRouter(routerId); + router.AttachPort(portId); + + httpTest.ShouldHaveCalled($"*/routers/{routerId}/add_router_interface"); + var capturedRequest = httpTest.CallLog.Last(); + Assert.Equal(HttpMethod.Put, capturedRequest.Request.Method); + } + } + + [Fact] + public void AttachSubnet() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + Identifier subnetId = Guid.NewGuid(); + Identifier routerId = Guid.NewGuid(); + httpTest.RespondWithJson(new Router { Id = routerId }); + httpTest.RespondWithJson(new {port_id = portId, subnet_id = subnetId}); + + var router = _networking.GetRouter(routerId); + var result =router.AttachSubnet(subnetId); + + httpTest.ShouldHaveCalled($"*/routers/{routerId}/add_router_interface"); + var capturedRequest = httpTest.CallLog.Last(); + Assert.Equal(HttpMethod.Put, capturedRequest.Request.Method); + Assert.NotNull(result); + Assert.Equal(portId, result); + } + } + #endregion + + #region Floating IPs + [Fact] + public void CreateFloatingIP() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + Identifier floatingIPId = Guid.NewGuid(); + httpTest.RespondWithJson(new FloatingIP { Id = floatingIPId }); + + var definition = new FloatingIPCreateDefinition(networkId); + var result = _networking.CreateFloatingIP(definition); + + httpTest.ShouldHaveCalled("*/floatingips"); + Assert.NotNull(result); + Assert.Equal(floatingIPId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void GetFloatingIP() + { + using (var httpTest = new HttpTest()) + { + Identifier floatingIPId = Guid.NewGuid(); + httpTest.RespondWithJson(new FloatingIP { Id = floatingIPId }); + + var result = _networking.GetFloatingIP(floatingIPId); + + httpTest.ShouldHaveCalled($"*/floatingips/{floatingIPId}"); + Assert.NotNull(result); + Assert.Equal(floatingIPId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void ListFloatingIPs() + { + using (var httpTest = new HttpTest()) + { + Identifier floatingIPId = Guid.NewGuid(); + httpTest.RespondWithJson(new FloatingIPCollection + { + new FloatingIP { Id = floatingIPId } + }); + + var results = _networking.ListFloatingIPs(new FloatingIPListOptions {Status = FloatingIPStatus.Active}); + + httpTest.ShouldHaveCalled("*/floatingips?status=ACTIVE"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(floatingIPId, result.Id); + Assert.IsType(((IServiceResource)result).Owner); + } + } + + [Fact] + public void AssociateFloatingIP() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + Identifier floatingIPId = Guid.NewGuid(); + httpTest.RespondWithJson(new FloatingIP { Id = floatingIPId }); + httpTest.RespondWithJson(new FloatingIP { Id = floatingIPId, PortId = portId}); + + var floatingIP = _networking.GetFloatingIP(floatingIPId); + floatingIP.Associate(portId); + + httpTest.ShouldHaveCalled($"*/floatingips/{floatingIPId}"); + Assert.Equal(floatingIP.PortId, portId); + } + } + + [Fact] + public void AssociateFloatingIPToServer() + { + var compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + const string ip = "10.0.0.1"; + httpTest.RespondWithJson(new Server { Id = serverId }); + httpTest.RespondWith((int)HttpStatusCode.OK, "ip associated!"); + httpTest.RespondWithJson(new ServerAddressCollection + { + ["network1"] = new List + { + new ServerAddress {IP = ip, Type = AddressType.Floating} + } + }); + + var server = compute.GetServer(serverId); + server.AssociateFloatingIP(new AssociateFloatingIPRequest(ip)); + + Assert.NotNull(server.Addresses["network1"].Single(a => a.IP == ip && a.Type == AddressType.Floating)); + } + } + + [Fact] + public void DisassociateFloatingIP() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + Identifier floatingIPId = Guid.NewGuid(); + httpTest.RespondWithJson(new FloatingIP { Id = floatingIPId, PortId = portId}); + httpTest.RespondWithJson(new FloatingIP { Id = floatingIPId }); + + var floatingIP = _networking.GetFloatingIP(floatingIPId); + floatingIP.Disassociate(); + + httpTest.ShouldHaveCalled($"*/floatingips/{floatingIPId}"); + Assert.Null(floatingIP.PortId); + } + } + + [Fact] + public void DisassociateFloatingIPFromServer() + { + var compute = new ComputeService(Stubs.AuthenticationProvider, "region"); + + using (var httpTest = new HttpTest()) + { + Identifier serverId = Guid.NewGuid(); + const string ip = "10.0.0.1"; + httpTest.RespondWithJson(new Server + { + Id = serverId, + Addresses = + { + ["network1"] = new List + { + new ServerAddress {IP = ip, Type = AddressType.Floating} + } + } + }); + httpTest.RespondWith((int)HttpStatusCode.OK, "ip disassociated!"); + + var server = compute.GetServer(serverId); + server.DisassociateFloatingIP(ip); + + Assert.Null(server.Addresses["network1"].FirstOrDefault(a => a.IP == ip && a.Type == AddressType.Floating)); + } + } + + [Theory] + [InlineData(HttpStatusCode.Accepted)] + [InlineData(HttpStatusCode.NotFound)] + public void DeleteFloatingIP(HttpStatusCode responseCode) + { + using (var httpTest = new HttpTest()) + { + Identifier floatingIPId = Guid.NewGuid(); + httpTest.RespondWith((int)responseCode, "All gone!"); + + _networking.DeleteFloatingIP(floatingIPId); + + httpTest.ShouldHaveCalled($"*/floatingips/{floatingIPId}"); + } + } + #endregion + + #region Security Groups + [Fact] + public void ListSecurityGroups() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + Identifier securityGroupRuleId = Guid.NewGuid(); + SecurityGroupRule rule = new SecurityGroupRule { Id = securityGroupRuleId }; + List rules = new List { rule }; + + httpTest.RespondWithJson(new SecurityGroupCollection + { + new SecurityGroup { Id = securityGroupId, SecurityGroupRules = rules } + }); + + var results = _networking.ListSecurityGroups(); + + httpTest.ShouldHaveCalled("*/security-groups"); + Assert.Equal(1, results.Count()); + var result = results.First(); + var resultRule = result.SecurityGroupRules.First(); + Assert.Equal(securityGroupId, result.Id); + Assert.Equal(rule.Id, resultRule.Id); + } + } + + [Fact] + public void ListSecurityGroupRules() + { + using (var httpTest = new HttpTest()) + { + Identifier securityGroupId = Guid.NewGuid(); + Identifier securityGroupRuleId = Guid.NewGuid(); + httpTest.RespondWithJson(new SecurityGroupRuleCollection + { + new SecurityGroupRule {Id = securityGroupRuleId, SecurityGroupId = securityGroupId} + }); + + var results = _networking.ListSecurityGroupRules(); + + httpTest.ShouldHaveCalled("*/security-group-rules"); + Assert.Equal(1, results.Count()); + var result = results.First(); + Assert.Equal(securityGroupRuleId, result.Id); + Assert.Equal(securityGroupId, result.SecurityGroupId); + } + } + #endregion + + } +} diff --git a/src/OpenStack.UnitTests/Networking/v2/NetworkTests.cs b/src/OpenStack.UnitTests/Networking/v2/NetworkTests.cs new file mode 100644 index 000000000..d99d90b8f --- /dev/null +++ b/src/OpenStack.UnitTests/Networking/v2/NetworkTests.cs @@ -0,0 +1,133 @@ +using System; +using System.Linq; +using System.Net; +using OpenStack.Networking.v2.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Networking.v2 +{ + public class NetworkTests + { + private readonly NetworkingService _networkingService; + + public NetworkTests() + { + _networkingService = new NetworkingService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void ListNetworks() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + httpTest.RespondWithJson(new NetworkCollection(new[] {new Network {Id = networkId}})); + + var networks = _networkingService.ListNetworks(); + + httpTest.ShouldHaveCalled("*/networks"); + Assert.NotNull(networks); + Assert.Equal(1, networks.Count()); + Assert.Equal(networkId, networks.First().Id); + } + } + + [Fact] + public void CreateNetwork() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + httpTest.RespondWithJson(new Network{Id = networkId}); + + var definition = new NetworkDefinition(); + var network = _networkingService.CreateNetwork(definition); + + httpTest.ShouldHaveCalled("*/networks"); + Assert.NotNull(network); + Assert.Equal(networkId, network.Id); + } + } + + [Fact] + public void CreateNetworks() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new NetworkCollection(new[] { new Network { Name = "network-1"}, new Network{Name = "network-2"} })); + + var definitions = new[] {new NetworkDefinition(), new NetworkDefinition()}; + var networks = _networkingService.CreateNetworks(definitions); + + httpTest.ShouldHaveCalled("*/networks"); + Assert.NotNull(networks); + Assert.Equal(2, networks.Count()); + Assert.Equal("network-1", networks.First().Name); + Assert.Equal("network-2", networks.Last().Name); + } + } + + [Fact] + public void GetNetwork() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + httpTest.RespondWithJson(new Network { Id = networkId }); + + var network = _networkingService.GetNetwork(networkId); + + httpTest.ShouldHaveCalled("*/networks/" + networkId); + Assert.NotNull(network); + Assert.Equal(networkId, network.Id); + } + } + + [Fact] + public void DeleteNetwork() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + _networkingService.DeleteNetwork(networkId); + + httpTest.ShouldHaveCalled("*/networks/" + networkId); + } + } + + [Fact] + public void WhenDeleteNetwork_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Not here, boss..."); + + _networkingService.DeleteNetwork(networkId); + + httpTest.ShouldHaveCalled("*/networks/" + networkId); + } + } + + [Fact] + public void UpdateNetwork() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + httpTest.RespondWithJson(new Network {Id = networkId}); + + var definition = new NetworkDefinition { Name = "new network name" }; + var network = _networkingService.UpdateNetwork(networkId, definition); + + httpTest.ShouldHaveCalled("*/networks/" + networkId); + Assert.NotNull(network); + Assert.Equal(networkId, network.Id); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Networking/v2/PortTests.cs b/src/OpenStack.UnitTests/Networking/v2/PortTests.cs new file mode 100644 index 000000000..cbd664c60 --- /dev/null +++ b/src/OpenStack.UnitTests/Networking/v2/PortTests.cs @@ -0,0 +1,152 @@ +using System; +using System.Linq; +using System.Net; +using OpenStack.Networking.v2.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Networking.v2 +{ + public class PortTests + { + private readonly NetworkingService _networkingService; + + public PortTests() + { + _networkingService = new NetworkingService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void ListPorts() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + httpTest.RespondWithJson(new PortCollection(new[] {new Port {Id = portId}})); + + var ports = _networkingService.ListPorts(); + + httpTest.ShouldHaveCalled("*/ports"); + Assert.NotNull(ports); + Assert.Equal(1, ports.Count()); + Assert.Equal(portId, ports.First().Id); + } + } + + [Fact] + public void FilterPorts() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new PortCollection()); + + _networkingService.ListPorts(new PortListOptions {DeviceId = "123"}); + + httpTest.ShouldHaveCalled("*/ports?device_id=123"); + } + } + + [Fact] + public void CreatePort() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + Identifier portId = Guid.NewGuid(); + httpTest.RespondWithJson(new Port { Id = portId }); + + var definition = new PortCreateDefinition(networkId); + var port = _networkingService.CreatePort(definition); + + httpTest.ShouldHaveCalled("*/ports"); + Assert.NotNull(port); + Assert.Equal(portId, port.Id); + } + } + + [Fact] + public void CreatePorts() + { + using (var httpTest = new HttpTest()) + { + httpTest.RespondWithJson(new PortCollection(new[] {new Port {Name = "port-1"}, new Port {Name = "port-2"}})); + + Identifier networkId = Guid.NewGuid(); + var definitions = new[] + { + new PortCreateDefinition(networkId), + new PortCreateDefinition(networkId) + }; + var ports = _networkingService.CreatePorts(definitions); + + httpTest.ShouldHaveCalled("*/ports"); + Assert.NotNull(ports); + Assert.Equal(2, ports.Count()); + Assert.Equal("port-1", ports.First().Name); + Assert.Equal("port-2", ports.Last().Name); + } + } + + [Fact] + public void GetPorts() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + httpTest.RespondWithJson(new Port { Id = portId }); + + var port = _networkingService.GetPort(portId); + + httpTest.ShouldHaveCalled("*/ports/" + portId); + Assert.NotNull(port); + Assert.Equal(portId, port.Id); + } + } + + [Fact] + public void DeletePort() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + _networkingService.DeletePort(portId); + + httpTest.ShouldHaveCalled("*/ports/" + portId); + } + } + + [Fact] + public void WhenDeletePort_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Not here, boss..."); + + _networkingService.DeletePort(portId); + + httpTest.ShouldHaveCalled("*/ports/" + portId); + } + } + + [Fact] + public void UpdatePort() + { + using (var httpTest = new HttpTest()) + { + Identifier portId = Guid.NewGuid(); + httpTest.RespondWithJson(new Port { Id = portId }); + + var definition = new PortUpdateDefinition { Name = "new subnet name" }; + var port = _networkingService.UpdatePort(portId, definition); + + httpTest.ShouldHaveCalled("*/ports/" + portId); + Assert.NotNull(port); + Assert.Equal(portId, port.Id); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Networking/v2/SubnetTests.cs b/src/OpenStack.UnitTests/Networking/v2/SubnetTests.cs new file mode 100644 index 000000000..a8cdf5d82 --- /dev/null +++ b/src/OpenStack.UnitTests/Networking/v2/SubnetTests.cs @@ -0,0 +1,139 @@ +using System; +using System.Linq; +using System.Net; +using OpenStack.Networking.v2.Serialization; +using OpenStack.Synchronous; +using OpenStack.Testing; +using Xunit; + +namespace OpenStack.Networking.v2 +{ + public class SubnetTests + { + private readonly NetworkingService _networkingService; + + public SubnetTests() + { + _networkingService = new NetworkingService(Stubs.AuthenticationProvider, "region"); + } + + [Fact] + public void ListSubnets() + { + using (var httpTest = new HttpTest()) + { + Identifier subnetId = Guid.NewGuid(); + httpTest.RespondWithJson(new SubnetCollection(new[] {new Subnet {Id = subnetId}})); + + var subnets = _networkingService.ListSubnets(); + + httpTest.ShouldHaveCalled("*/subnets"); + Assert.NotNull(subnets); + Assert.Equal(1, subnets.Count()); + Assert.Equal(subnetId, subnets.First().Id); + } + } + + [Fact] + public void CreateSubnet() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + Identifier subnetId = Guid.NewGuid(); + httpTest.RespondWithJson(new Subnet { Id = subnetId }); + + var definition = new SubnetCreateDefinition(networkId, IPVersion.IPv4, "10.0.0.0/24"); + var subnet = _networkingService.CreateSubnet(definition); + + httpTest.ShouldHaveCalled("*/subnets"); + Assert.NotNull(subnet); + Assert.Equal(subnetId, subnet.Id); + } + } + + [Fact] + public void CreateSubnets() + { + using (var httpTest = new HttpTest()) + { + Identifier networkId = Guid.NewGuid(); + httpTest.RespondWithJson(new SubnetCollection(new[] { new Subnet { Name = "subnet-1" }, new Subnet { Name = "subnet-2" } })); + + var definitions = new[] + { + new SubnetCreateDefinition(networkId, IPVersion.IPv4, "{cidr-1}"), + new SubnetCreateDefinition(networkId, IPVersion.IPv6, "{cidr-2}") + }; + var subnets = _networkingService.CreateSubnets(definitions); + + httpTest.ShouldHaveCalled("*/subnets"); + Assert.NotNull(subnets); + Assert.Equal(2, subnets.Count()); + Assert.Equal("subnet-1", subnets.First().Name); + Assert.Equal("subnet-2", subnets.Last().Name); + } + } + + [Fact] + public void GetSubnets() + { + using (var httpTest = new HttpTest()) + { + Identifier subnetId = Guid.NewGuid(); + httpTest.RespondWithJson(new Subnet { Id = subnetId }); + + var subnet = _networkingService.GetSubnet(subnetId); + + httpTest.ShouldHaveCalled("*/subnets/" + subnetId); + Assert.NotNull(subnet); + Assert.Equal(subnetId, subnet.Id); + } + } + + [Fact] + public void DeleteSubnet() + { + using (var httpTest = new HttpTest()) + { + Identifier subnetId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NoContent, "All gone!"); + + _networkingService.DeleteSubnet(subnetId); + + httpTest.ShouldHaveCalled("*/subnets/" + subnetId); + } + } + + [Fact] + public void WhenDeleteSubnet_Returns404NotFound_ShouldConsiderRequestSuccessful() + { + using (var httpTest = new HttpTest()) + { + Identifier subnetId = Guid.NewGuid(); + httpTest.RespondWith((int)HttpStatusCode.NotFound, "Not here, boss..."); + + _networkingService.DeleteSubnet(subnetId); + + httpTest.ShouldHaveCalled("*/subnets/" + subnetId); + } + } + + [Fact] + public void UpdateSubnet() + { + using (var httpTest = new HttpTest()) + { + Identifier subnetId = Guid.NewGuid(); + httpTest.RespondWithJson(new Subnet { Id = subnetId }); + + var definition = new SubnetUpdateDefinition { Name = "new subnet name" }; + var subnet = _networkingService.UpdateSubnet(subnetId, definition); + + httpTest.ShouldHaveCalled("*/subnets/" + subnetId); + Assert.NotNull(subnet); + Assert.Equal(subnetId, subnet.Id); + } + } + } +} diff --git a/src/OpenStack.UnitTests/OpenStack.UnitTests.csproj b/src/OpenStack.UnitTests/OpenStack.UnitTests.csproj new file mode 100644 index 000000000..3b747568f --- /dev/null +++ b/src/OpenStack.UnitTests/OpenStack.UnitTests.csproj @@ -0,0 +1,29 @@ + + + + net452 + + false + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/OpenStack.UnitTests/OpenStackNetTests.cs b/src/OpenStack.UnitTests/OpenStackNetTests.cs new file mode 100644 index 000000000..e6c2f7674 --- /dev/null +++ b/src/OpenStack.UnitTests/OpenStackNetTests.cs @@ -0,0 +1,141 @@ +using System; +using System.Diagnostics; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Flurl.Extensions; +using Flurl.Http; +using Newtonsoft.Json; +using OpenStack.Serialization; +using OpenStack.Testing; +using Xunit; +using Xunit.Abstractions; +#pragma warning disable 618 // We can remove this once OpenStackNet.Configure() is made internal and obsolete is removed + +namespace OpenStack +{ + public class OpenStackNetTests : IDisposable + { + public OpenStackNetTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + } + + public void Dispose() + { + OpenStackNet.ResetDefaults(); + } + + [Fact] + public void WhenConfigureIsCalled_GlobalFlurlConfiguration_IsNotAltered() + { + // User makes their own tweaks to Flurl + Action customErrorHandler = call => Debug.WriteLine("I saw an error!"); + FlurlHttp.GlobalSettings.OnError = customErrorHandler; + + // We configure openstack.net + OpenStackNet.Configure(); + + // We shouldn't have clobbered their settings + Assert.Null(FlurlHttp.GlobalSettings.AfterCall); + Assert.Null(FlurlHttp.GlobalSettings.AfterCallAsync); + Assert.Null(FlurlHttp.GlobalSettings.BeforeCall); + Assert.Null(FlurlHttp.GlobalSettings.BeforeCallAsync); + Assert.Equal(customErrorHandler, FlurlHttp.GlobalSettings.OnError); + } + + [Fact] + public void WhenResetDefaultsIsCalled_GlobalFlurlConfiguration_IsNotAltered() + { + // User makes their own tweaks to Flurl + Action customErrorHandler = call => Debug.WriteLine("I saw an error!"); + FlurlHttp.GlobalSettings.OnError = customErrorHandler; + + // We configure openstack.net + OpenStackNet.ResetDefaults(); + + // We shouldn't have clobbered their settings + Assert.Null(FlurlHttp.GlobalSettings.AfterCall); + Assert.Null(FlurlHttp.GlobalSettings.AfterCallAsync); + Assert.Null(FlurlHttp.GlobalSettings.BeforeCall); + Assert.Null(FlurlHttp.GlobalSettings.BeforeCallAsync); + Assert.Equal(customErrorHandler, FlurlHttp.GlobalSettings.OnError); + } + + [Fact] + public void WhenResetDefaultsIsCalled_GlobalJsonConfiguration_IsNotAltered() + { + // User makes their own tweaks to the serialization + JsonConvert.DefaultSettings = () => new JsonSerializerSettings(); + + // We configure openstack.net + OpenStackNet.ResetDefaults(); + + // We shouldn't have clobbered their settings + var serializer = JsonSerializer.CreateDefault(); + Assert.IsNotType(serializer.ContractResolver); + } + + [Fact] + public void WhenConfigureIsCalled_GlobalJsonConfiguration_IsNotAltered() + { + // User makes their own tweaks to the serialization + JsonConvert.DefaultSettings = () => new JsonSerializerSettings(); + + // We configure openstack.net + OpenStackNet.Configure(); + + // We shouldn't have clobbered their settings + var serializer = JsonSerializer.CreateDefault(); + Assert.IsNotType(serializer.ContractResolver); + } + + [Fact] + public async Task UserAgentTest() + { + using (var httpTest = new HttpTest()) + { + OpenStackNet.Configure(); + + await "http://api.com".PrepareRequest().GetAsync(); + + var userAgent = httpTest.CallLog[0].Request.Headers.UserAgent.ToString(); + Assert.Contains("openstack.net", userAgent); + } + } + + [Fact] + public async Task UserAgentOnlyListOnceTest() + { + using (var httpTest = new HttpTest()) + { + OpenStackNet.Configure(); + OpenStackNet.Configure(); // Duplicate call to Configure should be ignored + + await "http://api.com".PrepareRequest().GetAsync(); + + var userAgent = httpTest.CallLog[0].Request.Headers.UserAgent.ToString(); + Assert.Contains("openstack.net", userAgent); + } + } + + [Fact] + public async Task UserAgentWithApplicationSuffixTest() + { + using (var httpTest = new HttpTest()) + { + // Apply a custom application user agent + OpenStackNet.Configuring += options => + { + options.UserAgents.Add(new ProductInfoHeaderValue("(unittests)")); + }; + + await "http://api.com".PrepareRequest().GetAsync(); + + var userAgent = httpTest.CallLog[0].Request.Headers.UserAgent.ToString(); + Assert.Contains("openstack.net", userAgent); + Assert.Contains("unittests", userAgent); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Providers/Rackspace/CloudBlockStorageTests.cs b/src/OpenStack.UnitTests/Providers/Rackspace/CloudBlockStorageTests.cs new file mode 100644 index 000000000..9ff5a9aa4 --- /dev/null +++ b/src/OpenStack.UnitTests/Providers/Rackspace/CloudBlockStorageTests.cs @@ -0,0 +1,65 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using net.openstack.Providers.Rackspace.Exceptions; +using net.openstack.Providers.Rackspace.Validators; + +namespace OpenStackNet.Testing.Unit.Providers.Rackspace +{ + [TestClass] + public class CloudBlockStorageTests + { + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Not_Throw_Exception_When_Size_Is_In_Range() + { + const int size = 900; + + try + { + var cloudBlockStorageValidator = CloudBlockStorageValidator.Default; + cloudBlockStorageValidator.ValidateVolumeSize(size); + } + catch (Exception) + { + + Assert.Fail("Exception should not be thrown."); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Throw_Exception_When_Size_Is_Less_Than_1() + { + const int size = 0; + + try + { + var cloudBlockStorageValidator = CloudBlockStorageValidator.Default; + cloudBlockStorageValidator.ValidateVolumeSize(size); + Assert.Fail("Expected exception was not thrown."); + } + catch (Exception exc) + { + Assert.IsTrue(exc is InvalidVolumeSizeException); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Throw_Exception_When_Size_Is_Greater_Than_1000() + { + const int size = 1050; + + try + { + var cloudBlockStorageValidator = CloudBlockStorageValidator.Default; + cloudBlockStorageValidator.ValidateVolumeSize(size); + Assert.Fail("Expected was not thrown."); + } + catch (Exception exc) + { + Assert.IsTrue(exc is InvalidVolumeSizeException); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Providers/Rackspace/CloudNetworksValidatorTests.cs b/src/OpenStack.UnitTests/Providers/Rackspace/CloudNetworksValidatorTests.cs new file mode 100644 index 000000000..db2914af5 --- /dev/null +++ b/src/OpenStack.UnitTests/Providers/Rackspace/CloudNetworksValidatorTests.cs @@ -0,0 +1,198 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using net.openstack.Core; +using net.openstack.Core.Validators; +using net.openstack.Providers.Rackspace.Validators; + +namespace OpenStackNet.Testing.Unit.Providers.Rackspace +{ + [TestClass] + public class CloudNetworksValidatorTests + { + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Fail_When_Empty_Cidr() + { + const string cidr = ""; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + try + { + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + Assert.Fail("Expected CidrFormatException was not thrown"); + } + catch (Exception ex) + { + Assert.AreEqual("cidr cannot be empty", ex.Message); + } + } + + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Fail_When_Null_Cidr() + { + const string cidr = null; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + try + { + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + Assert.Fail("Expected CidrFormatException was not thrown"); + } + catch (Exception ex) + { + Assert.AreEqual("Value cannot be null." + Environment.NewLine + "Parameter name: cidr", ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Fail_When_Cidr_Missing_Slash() + { + const string cidr = "10.0.0.0"; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + try + { + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + Assert.Fail("Expected CidrFormatException was not thrown"); + } + catch (Exception ex) + { + Assert.AreEqual(string.Format("ERROR: CIDR {0} is missing /", cidr), ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Fail_When_Cidr_Has_Two_Ranges() + { + const string cidr = "10.0.0.0/24/24"; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + try + { + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + Assert.Fail("Expected CidrFormatException was not thrown"); + } + catch (Exception ex) + { + Assert.AreEqual(string.Format("ERROR: CIDR {0} must have exactly one / character", cidr), ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Fail_When_Cidr_Has_Invalid_IP_Segment() + { + const string cidr = "10.0.0.256/24"; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + try + { + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + Assert.Fail("Expected CidrFormatException was not thrown"); + } + catch (Exception ex) + { + Assert.AreEqual(string.Format("ERROR: IP address segment ({0}) of CIDR is not a valid IP address", "10.0.0.256"), ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Fail_When_Cidr_Has_Non_Integer_Range() + { + const string cidr = "10.0.0.0/abc"; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + try + { + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + Assert.Fail("Expected CidrFormatException was not thrown"); + } + catch (Exception ex) + { + Assert.AreEqual(string.Format("ERROR: CIDR range segment {0} must be an integer", "abc"), ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Fail_When_Cidr_Has_Invalid_Range() + { + const string cidr = "10.0.0.0/33"; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + try + { + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + Assert.Fail("Expected CidrFormatException was not thrown"); + } + catch (Exception ex) + { + Assert.AreEqual(string.Format("ERROR: CIDR range segment {0} must be between 1 and 32", "33"), ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Fail_When_Cidr_Has_Explicit_Range_Specified() + { + const string cidr = "10.0.0.0 - 10.0.0.255"; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + try + { + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + Assert.Fail("Expected CidrFormatException was not thrown"); + } + catch (Exception ex) + { + Assert.AreEqual(string.Format("ERROR: CIDR {0} is missing /", cidr), ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Pass_When_Cidr_Has_IPV4_IP_Segment() + { + const string cidr = "192.0.2.0/24"; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Pass_When_Cidr_Has_IPV6_IP_Segment() + { + const string cidr = "2001:db8::/32"; + var validatorMock = new Mock(); + validatorMock.Setup(v => v.ValidateCidr(cidr)); + + var cloudNetworksValidator = CloudNetworksValidator.Default; + cloudNetworksValidator.ValidateCidr(cidr); + } + } +} diff --git a/src/OpenStack.UnitTests/Providers/Rackspace/EncodeDecodeProviderTests.cs b/src/OpenStack.UnitTests/Providers/Rackspace/EncodeDecodeProviderTests.cs new file mode 100644 index 000000000..7b56028d0 --- /dev/null +++ b/src/OpenStack.UnitTests/Providers/Rackspace/EncodeDecodeProviderTests.cs @@ -0,0 +1,54 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using net.openstack.Providers.Rackspace; + +namespace OpenStackNet.Testing.Unit.Providers.Rackspace +{ + [TestClass] + public class EncodeDecodeProviderTests + { + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Encode_Spaces() + { + const string stringToBeEncoded = "This is a test with spaces"; + var encodeDecodeProvider = EncodeDecodeProvider.Default; + var result = encodeDecodeProvider.UrlEncode(stringToBeEncoded); + Assert.AreEqual("This%20is%20a%20test%20with%20spaces", result); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Decode_Spaces() + { + const string stringToBeDecoded = "This%20is%20a%20test%20with%20spaces"; + var encodeDecodeProvider = EncodeDecodeProvider.Default; + var result = encodeDecodeProvider.UrlDecode(stringToBeDecoded); + Assert.AreEqual("This is a test with spaces", result); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Encode_Special_Characters() + { + const string stringToBeEncoded = "This $ is & a ? test * with @ spaces"; + var encodeDecodeProvider = EncodeDecodeProvider.Default; + var result = encodeDecodeProvider.UrlEncode(stringToBeEncoded); + Assert.AreEqual("This%20%24%20is%20%26%20a%20%3f%20test%20*%20with%20%40%20spaces", result); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Decode_Special_Characters() + { + const string stringToBeEncoded = "This%20%24%20is%20%26%20a%20%3f%20test%20*%20with%20%40%20spaces"; + var encodeDecodeProvider = EncodeDecodeProvider.Default; + var result = encodeDecodeProvider.UrlDecode(stringToBeEncoded); + Assert.AreEqual("This $ is & a ? test * with @ spaces", result); + } + + } +} diff --git a/src/OpenStack.UnitTests/Providers/Rackspace/IdentityProviderCacheTests.cs b/src/OpenStack.UnitTests/Providers/Rackspace/IdentityProviderCacheTests.cs new file mode 100644 index 000000000..6d8908059 --- /dev/null +++ b/src/OpenStack.UnitTests/Providers/Rackspace/IdentityProviderCacheTests.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Net; +using JSIStudios.SimpleRESTServices.Client; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using net.openstack.Core.Caching; +using net.openstack.Core.Domain; +using net.openstack.Providers.Rackspace; +using net.openstack.Providers.Rackspace.Objects; +using net.openstack.Providers.Rackspace.Objects.Response; + +namespace OpenStackNet.Testing.Unit.Providers.Rackspace +{ + [TestClass] + public class IdentityProviderCacheTests + { + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Not_Hit_Cache_When_Authenticating_The_First_Time() + { + var cacheMock = new Mock>(); + var restServiceMock = new Mock(); + + restServiceMock.Setup(m => m.Execute(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(new Response(HttpStatusCode.OK, "OK", new AuthenticationResponse(), new List(), null)); + restServiceMock.Setup(m => m.Execute(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(new Response(HttpStatusCode.OK, "OK", new AuthenticationResponse(), new List(), null)); + + var identityProvider = new CloudIdentityProvider(restServiceMock.Object, cacheMock.Object); + + identityProvider.Authenticate(new RackspaceCloudIdentity()); + + cacheMock.Verify(m => m.Get(It.IsAny(), It.IsAny>(), true), Times.Once()); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Always_Request_Fresh_Data_From_Cache_When_Authenticating() + { + var cacheMock = new Mock>(); + var restServiceMock = new Mock(); + + restServiceMock.Setup(m => m.Execute(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(new Response(HttpStatusCode.OK, "OK", new AuthenticationResponse(), new List(), null)); + restServiceMock.Setup(m => m.Execute(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(new Response(HttpStatusCode.OK, "OK", new AuthenticationResponse(), new List(), null)); + + var identityProvider = new CloudIdentityProvider(restServiceMock.Object, cacheMock.Object); + + for (int i = 0; i < 100; i++) + { + identityProvider.Authenticate(new RackspaceCloudIdentity()); + } + + cacheMock.Verify(m => m.Get(It.IsAny(), It.IsAny>(), true), Times.Exactly(100)); + } + } +} diff --git a/src/OpenStack.UnitTests/Providers/Rackspace/JsonModelTests.cs b/src/OpenStack.UnitTests/Providers/Rackspace/JsonModelTests.cs new file mode 100644 index 000000000..23353d3ae --- /dev/null +++ b/src/OpenStack.UnitTests/Providers/Rackspace/JsonModelTests.cs @@ -0,0 +1,233 @@ +namespace OpenStackNet.Testing.Unit.Providers.Rackspace +{ + using System; + using System.Net; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using net.openstack.Core.Domain; + using net.openstack.Core.Domain.Converters; + using net.openstack.Providers.Rackspace; + using net.openstack.Providers.Rackspace.Objects.Request; + using net.openstack.Providers.Rackspace.Objects.Response; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using Encoding = System.Text.Encoding; + + [TestClass] + public class JsonModelTests + { + /// + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestPasswordCredential() + { + string json = @"{ ""username"" : ""test_user"", ""password"" : ""mypass"" }"; + PasswordCredential credentials = JsonConvert.DeserializeObject(json); + Assert.IsNotNull(credentials); + Assert.AreEqual("test_user", credentials.Username); + Assert.AreEqual("mypass", credentials.Password); + } + + /// + /// Update User Credentials (OpenStack Identity Service API v2.0 Reference) + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestPasswordCredentialResponse() + { + string json = @"{ ""passwordCredentials"" : { username : ""test_user"", password : ""mypass"" } }"; + PasswordCredentialResponse response = JsonConvert.DeserializeObject(json); + Assert.IsNotNull(response); + Assert.IsNotNull(response.PasswordCredential); + Assert.AreEqual("test_user", response.PasswordCredential.Username); + Assert.AreEqual("mypass", response.PasswordCredential.Password); + } + + /// Update Server (OpenStack Compute API v2 and Extensions Reference) + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestUpdateServerRequest() + { + UpdateServerRequest request = new UpdateServerRequest("new-name", IPAddress.Parse("10.0.0.1"), IPAddress.Parse("2607:f0d0:1002:51::4")); + string expectedJson = @"{""server"":{""name"":""new-name"",""accessIPv4"":""10.0.0.1"",""accessIPv6"":""2607:f0d0:1002:51::4""}}"; + string actual = JsonConvert.SerializeObject(request, Formatting.None); + Assert.AreEqual(expectedJson, actual); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestIPAddressDetailsConverter() + { + IPAddressDetailsConverter converter = new IPAddressDetailsConverter(); + + string json = @"{ ""version"" : 4, ""addr"" : ""10.0.0.1"" }"; + IPAddress address = JsonConvert.DeserializeObject(json, converter); + Assert.AreEqual(IPAddress.Parse("10.0.0.1"), address); + + json = @"{ ""version"" : 6, ""addr"" : ""::babe:4317:0A83"" }"; + address = JsonConvert.DeserializeObject(json, converter); + Assert.AreEqual(IPAddress.Parse("::babe:4317:0A83"), address); + + json = JsonConvert.SerializeObject(IPAddress.Parse("10.0.0.1"), converter); + Assert.AreEqual(@"{""addr"":""10.0.0.1"",""version"":""4""}", json); + + json = JsonConvert.SerializeObject(IPAddress.Parse("::babe:4317:0A83"), converter); + Assert.AreEqual(@"{""addr"":""::babe:4317:a83"",""version"":""6""}", json); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestIPAddressSimpleConverter() + { + IPAddressSimpleConverter converter = new IPAddressSimpleConverter(); + + string json = @"""10.0.0.1"""; + IPAddress address = JsonConvert.DeserializeObject(json, converter); + Assert.AreEqual(IPAddress.Parse("10.0.0.1"), address); + + json = @"""::babe:4317:0A83"""; + address = JsonConvert.DeserializeObject(json, converter); + Assert.AreEqual(IPAddress.Parse("::babe:4317:0A83"), address); + + json = JsonConvert.SerializeObject(IPAddress.Parse("10.0.0.1"), converter); + Assert.AreEqual(@"""10.0.0.1""", json); + + json = JsonConvert.SerializeObject(IPAddress.Parse("::babe:4317:0A83"), converter); + Assert.AreEqual(@"""::babe:4317:a83""", json); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestPersonalityJsonModel() + { + string expectedPath = "/usr/lib/stuff"; + string expectedText = "Example text"; + Personality personality = new Personality(expectedPath, expectedText, Encoding.UTF8); + Assert.AreEqual(expectedPath, personality.Path); + Assert.AreEqual(expectedText, Encoding.UTF8.GetString(personality.Content)); + + string json = JsonConvert.SerializeObject(personality); + Personality personality2 = JsonConvert.DeserializeObject(json); + Assert.AreEqual(expectedPath, personality.Path); + Assert.AreEqual(expectedText, Encoding.UTF8.GetString(personality.Content)); + + // make sure the JSON was Base-64 encoded + JObject personalityObject = JsonConvert.DeserializeObject(json); + Assert.IsInstanceOfType(personalityObject["contents"], typeof(JValue)); + byte[] encodedText = Convert.FromBase64String((string)((JValue)personalityObject["contents"]).Value); + Assert.AreEqual(expectedText, Encoding.UTF8.GetString(encodedText)); + Assert.AreEqual(personality.Content.Length, encodedText.Length); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestImpersonationRequest() + { + CloudIdentityProviderWrapper provider = new CloudIdentityProviderWrapper(); + JObject requestBody = provider.BuildImpersonationRequestJsonAccessor("myUser", 27); + Assert.AreEqual(@"{""RAX-AUTH:impersonation"":{""user"":{""username"":""myUser"",""expire-in-seconds"":27}}}", requestBody.ToString(Formatting.None)); + } + + protected class CloudIdentityProviderWrapper : CloudIdentityProvider + { + public JObject BuildImpersonationRequestJsonAccessor(string userName, int expirationInSeconds) + { + return BuildImpersonationRequestJson(userName, expirationInSeconds); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestDiskConfigurationConversions() + { + TestExtensibleEnumSerialization(DiskConfiguration.Auto, "OTHER", DiskConfiguration.FromName); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestImageState() + { + TestExtensibleEnumSerialization(ImageState.Active, "OTHER", ImageState.FromName); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestImageType() + { + TestExtensibleEnumSerialization(ImageType.Base, "OTHER", ImageType.FromName); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestRebootType() + { + TestExtensibleEnumSerialization(RebootType.Hard, "OTHER", RebootType.FromName); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestServerState() + { + TestExtensibleEnumSerialization(ServerState.Build, "OTHER", ServerState.FromName); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestSnapshotState() + { + TestExtensibleEnumSerialization(SnapshotState.Available, "OTHER", SnapshotState.FromName); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestVolumeState() + { + TestExtensibleEnumSerialization(VolumeState.Creating, "OTHER", VolumeState.FromName); + } + + private void TestExtensibleEnumSerialization(T standardItem, string nonStandardName, Func fromName) + { + if (fromName == null) + throw new ArgumentNullException("fromName"); + + T obj = JsonConvert.DeserializeObject("null"); + Assert.IsNull(obj); + + obj = JsonConvert.DeserializeObject(@""""""); + Assert.IsNull(obj); + + // matching case, predefined value + obj = JsonConvert.DeserializeObject('"' + standardItem.ToString() + '"'); + Assert.AreEqual(standardItem, obj); + + // different case, predefined value + string caseDifference = standardItem.ToString().ToLowerInvariant(); + if (standardItem.ToString() == caseDifference) + { + caseDifference = standardItem.ToString().ToUpperInvariant(); + Assert.AreNotEqual(standardItem.ToString(), caseDifference); + } + + obj = JsonConvert.DeserializeObject('"' + caseDifference + '"'); + Assert.AreEqual(standardItem, obj); + + // new value + obj = JsonConvert.DeserializeObject('"' + nonStandardName + '"'); + Assert.AreEqual(fromName(nonStandardName), obj); + + // different case, same as value encountered before + caseDifference = nonStandardName.ToLowerInvariant(); + if (nonStandardName == caseDifference) + { + caseDifference = nonStandardName.ToUpperInvariant(); + Assert.AreNotEqual(nonStandardName, caseDifference); + } + + Assert.AreNotEqual(nonStandardName, caseDifference); + obj = JsonConvert.DeserializeObject('"' + nonStandardName.ToLowerInvariant() + '"'); + Assert.AreEqual(fromName(nonStandardName), obj); + + string json = JsonConvert.SerializeObject(standardItem); + Assert.AreEqual('"' + standardItem.ToString() + '"', json); + } + } +} diff --git a/src/OpenStack.UnitTests/Providers/Rackspace/ObjectProviderHelperTests.cs b/src/OpenStack.UnitTests/Providers/Rackspace/ObjectProviderHelperTests.cs new file mode 100644 index 000000000..dbe622f24 --- /dev/null +++ b/src/OpenStack.UnitTests/Providers/Rackspace/ObjectProviderHelperTests.cs @@ -0,0 +1,124 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using net.openstack.Core; +using net.openstack.Core.Exceptions; +using net.openstack.Core.Validators; +using net.openstack.Providers.Rackspace; +using net.openstack.Providers.Rackspace.Validators; + +namespace OpenStackNet.Testing.Unit.Providers.Rackspace +{ + [TestClass] + public class ObjectProviderHelperTests + { + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Pass_Validation_For_Container_Name() + { + const string containerName = "DarkKnight"; + var validatorMock = new Mock(); + + validatorMock.Setup(v => v.ValidateContainerName(containerName)); + + var objectStoreValidator = CloudFilesValidator.Default; + objectStoreValidator.ValidateContainerName(containerName); + + } + + //[ExpectedException(typeof(ArgumentNullException),"ERROR: Container Name cannot be Null.")] + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Throw_Exception_When_Passing_Empty_Container_Name() + { + const string containerName = ""; + var validatorMock = new Mock(); + + validatorMock.Setup(v => v.ValidateContainerName(containerName)); + + try + { + var objectStoreValidator = CloudFilesValidator.Default; + objectStoreValidator.ValidateContainerName(containerName); + Assert.Fail("Expected exception was not thrown."); + } + catch (Exception ex) + { + Assert.AreEqual("ERROR: Container Name cannot be empty." + Environment.NewLine + "Parameter name: containerName", ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Throw_Exception_When_Passing_Null_Container_Name() + { + const string containerName = null; + var validatorMock = new Mock(); + + validatorMock.Setup(v => v.ValidateContainerName(containerName)); + + try + { + var objectStoreValidator = CloudFilesValidator.Default; + objectStoreValidator.ValidateContainerName(containerName); + Assert.Fail("Expected exception was not thrown."); + } + catch (Exception ex) + { + Assert.AreEqual("Value cannot be null." + Environment.NewLine + "Parameter name: containerName", ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Throw_Exception_When_Passing_256_Characters_In_Container_Name() + { + string containerName = "AaAaAaAaAa"; + + while (containerName.Length <= 256) + { + containerName += containerName; + } + var validatorMock = new Mock(); + + validatorMock.Setup(v => v.ValidateContainerName(containerName)); + + try + { + var objectStoreValidator = CloudFilesValidator.Default; + objectStoreValidator.ValidateContainerName(containerName); + Assert.Fail("Expected exception was not thrown."); + } + catch (ContainerNameException ex) + { + + Assert.AreEqual(string.Format("ERROR: encoded URL Length greater than 256 char's. Container Name:[{0}]",containerName), ex.Message); + } + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Throw_Exception_When_Passing_Forwar_Slash_In_Container_Name() + { + const string containerName = "/"; + + var validatorMock = new Mock(); + + validatorMock.Setup(v => v.ValidateContainerName(containerName)); + + try + { + var objectStoreValidator = CloudFilesValidator.Default; + objectStoreValidator.ValidateContainerName(containerName); + Assert.Fail("Expected exception was not thrown."); + } + catch (ContainerNameException ex) + { + + Assert.AreEqual(string.Format("ERROR: Container Name contains a /. Container Name:[{0}]", containerName), ex.Message); + } + } + + + } +} diff --git a/src/OpenStack.UnitTests/Providers/Rackspace/ProviderBaseTests.cs b/src/OpenStack.UnitTests/Providers/Rackspace/ProviderBaseTests.cs new file mode 100644 index 000000000..b41429b73 --- /dev/null +++ b/src/OpenStack.UnitTests/Providers/Rackspace/ProviderBaseTests.cs @@ -0,0 +1,310 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using JSIStudios.SimpleRESTServices.Client; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Moq.Protected; +using net.openstack.Core; +using net.openstack.Core.Domain; +using net.openstack.Core.Providers; +using net.openstack.Providers.Rackspace; +using net.openstack.Providers.Rackspace.Objects; +using Newtonsoft.Json; + +namespace OpenStackNet.Testing.Unit.Providers.Rackspace +{ + [TestClass] + public class ProviderBaseTests + { + private const string _testService = "test"; + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_Endpoint_When_Identity_Is_Explicitly_Set_And_Region_Is_Explicitly_Declared() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""DFW""}, {region:""ORD""}]}], user:{""RAX-AUTH:defaultRegion"":""DFW""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(null, identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, "DFW", new CloudIdentity()); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("DFW", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_Endpoint_When_Identity_Is_Explicitly_Set_And_Region_Is_Different_Than_Default_Region() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""DFW""}, {region:""ORD""}]}], user:{""RAX-AUTH:defaultRegion"":""DFW""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(null, identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, "ORD", new CloudIdentity()); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("ORD", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_Endpoint_When_Identity_Set_On_Provider_And_Region_Is_Different_Than_Default_Region() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""DFW""}, {region:""ORD""}]}], user:{""RAX-AUTH:defaultRegion"":""DFW""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(new CloudIdentity(), identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, "ORD", null); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("ORD", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_Endpoint_When_Identity_Is_Explicitly_Set_And_Region_Is_NOT_Explicitly_Declared() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""DFW""}, {region:""ORD""}]}], user:{""RAX-AUTH:defaultRegion"":""DFW""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(null, identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, null, new CloudIdentity()); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("DFW", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_Endpoint_When_Identity_Is_Set_On_Provider_And_Region_Is_Explicitly_Declared() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""DFW""}, {region:""ORD""}]}], user:{""RAX-AUTH:defaultRegion"":""DFW""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(new CloudIdentity(), identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, "DFW", null); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("DFW", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_Endpoint_When_Identity_Is_Set_On_Provider_And_Region_Is_NOT_Explicitly_Declared() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""DFW""}, {region:""ORD""}]}], user:{""RAX-AUTH:defaultRegion"":""DFW""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(new CloudIdentity(), identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, null, null); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("DFW", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_LON_Endpoint_When_Identity_Is_Explicitly_Set_And_Region_Is_Explicitly_Declared() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""LON""}, {region:""LON2""}]}], user:{""RAX-AUTH:defaultRegion"":""LON""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(null, identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, "LON", new RackspaceCloudIdentity()); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("LON", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_LON_Endpoint_When_Identity_Is_Explicitly_Set_And_Region_Is_NOT_Explicitly_Declared() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""LON""}, {region:""LON2""}]}], user:{""RAX-AUTH:defaultRegion"":""LON""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(null, identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, null, new RackspaceCloudIdentity()); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("LON", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_LON_Endpoint_When_Identity_Is_Set_On_Provider_And_Region_Is_Explicitly_Declared() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""LON""}, {region:""LON2""}]}], user:{""RAX-AUTH:defaultRegion"":""LON""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(new RackspaceCloudIdentity(), identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, "LON", null); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("LON", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_LON_Endpoint_When_Identity_Is_Set_On_Provider_And_Region_Is_NOT_Explicitly_Declared() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""LON""}, {region:""LON2""}]}], user:{""RAX-AUTH:defaultRegion"":""LON""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(new RackspaceCloudIdentity(), identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, null, null); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("LON", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Correct_LON_Endpoint_When_Identity_Is_Explicitly_And_Region_Is_Always_Empty() + { + UserAccess userAccess = JsonConvert.DeserializeObject( + @"{ serviceCatalog:[{ type : """ + _testService + @""", endpoints : [{region:""LON""}, {region:""LON2""}]}], user:{""RAX-AUTH:defaultRegion"":""LON""} }"); + + var identityProviderMock = new Mock(); + identityProviderMock.Setup(m => m.GetUserAccess(It.IsAny(), It.IsAny())).Returns(userAccess); + var provider = new MockProvider(null, identityProviderMock.Object, null); + + var endpoint = provider.GetEndpoint(_testService, null, new RackspaceCloudIdentity()); + + Assert.IsNotNull(endpoint); + Assert.AreEqual("LON", endpoint.Region); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Null_While_Building_Optional_Parameter_List_When_A_Null_Value_Is_Passed() + { + var providerBase = new MockProvider(null, null, null); + + var paramList = providerBase.BuildOptionalParameterList(null); + + Assert.IsNull(paramList); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Null_While_Building_Optional_Parameter_List_When_An_Empty_Value_Is_Passed() + { + var providerBase = new MockProvider(null, null, null); + + var paramList = providerBase.BuildOptionalParameterList(new Dictionary()); + + Assert.IsNull(paramList); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Null_While_Building_Optional_Parameter_List_When_All_Values_In_List_Are_InValid() + { + var providerBase = new MockProvider(null, null, null); + + var paramList = providerBase.BuildOptionalParameterList(new Dictionary + { + {"key1", ""}, + {"key2", null}, + {"key3", ""}, + {"key4", null}, + }); + + Assert.IsNull(paramList); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_All_Parameters_While_Building_Optional_Parameter_List_When_All_Values_In_List_Are_Valid() + { + var providerBase = new MockProvider(null, null, null); + + var paramList = providerBase.BuildOptionalParameterList(new Dictionary + { + {"key1", "val1"}, + {"key2", "val2"}, + {"key3", "val3"}, + {"key4", "val4"}, + }); + + Assert.AreEqual(4, paramList.Count); + Assert.IsTrue(paramList.Any(p => p.Key == "key1" && p.Value == "val1")); + Assert.IsTrue(paramList.Any(p => p.Key == "key2" && p.Value == "val2")); + Assert.IsTrue(paramList.Any(p => p.Key == "key3" && p.Value == "val3")); + Assert.IsTrue(paramList.Any(p => p.Key == "key4" && p.Value == "val4")); + } + + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void Should_Return_Only_Valid_Parameters_While_Building_Optional_Parameter_List_When_Some_Values_In_List_Are_Valid() + { + var providerBase = new MockProvider(null, null, null); + + var paramList = providerBase.BuildOptionalParameterList(new Dictionary + { + {"key1", "val1"}, + {"key2", ""}, + {"key3", "val3"}, + {"key4", null}, + }); + + Assert.AreEqual(2, paramList.Count); + Assert.IsTrue(paramList.Any(p => p.Key == "key1" && p.Value == "val1")); + Assert.IsFalse(paramList.Any(p => p.Key == "key2" && p.Value == "val2")); + Assert.IsTrue(paramList.Any(p => p.Key == "key3" && p.Value == "val3")); + Assert.IsFalse(paramList.Any(p => p.Key == "key4" && p.Value == "val4")); + } + + + + public class MockProvider : ProviderBase + { + internal MockProvider(CloudIdentity defaultIdentity, IIdentityProvider identityProvider, IRestService restService) : base(defaultIdentity, null, identityProvider, restService) + { + } + + public Endpoint GetEndpoint(string serviceType, string region, CloudIdentity identity) + { + return base.GetServiceEndpoint(identity, serviceType, null, region); + } + + public new Dictionary BuildOptionalParameterList(Dictionary optionalParameters) + { + return base.BuildOptionalParameterList(optionalParameters); + } + } + } +} diff --git a/src/OpenStack.UnitTests/Providers/Rackspace/SerializationTests.cs b/src/OpenStack.UnitTests/Providers/Rackspace/SerializationTests.cs new file mode 100644 index 000000000..649920ecc --- /dev/null +++ b/src/OpenStack.UnitTests/Providers/Rackspace/SerializationTests.cs @@ -0,0 +1,63 @@ +namespace OpenStackNet.Testing.Unit.Providers.Rackspace +{ + using System.Linq; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using net.openstack.Core.Domain; + using net.openstack.Providers.Rackspace.Exceptions; + using net.openstack.Providers.Rackspace.Objects; + using BinaryFormatter = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter; + using HttpStatusCode = System.Net.HttpStatusCode; + using MemoryStream = System.IO.MemoryStream; + using Stream = System.IO.Stream; + + /// + /// These tests are used to ensure that certain objects can be serialized and deserialized as expected. + /// Many of these cases are due to objects providing additional information for custom exceptions, + /// with exceptions being serializable. + /// + [TestClass] + public class SerializationTests + { + /// + /// This tests verifies the serialization behavior of , + /// which is included as a member of the exception class . + /// + [TestMethod] + [TestCategory(TestCategories.Unit)] + public void TestBulkDeletionResultsSerializable() + { + var successfulObjects = new[] { "/container/object1", "/container/object2" }; + var failedObjects = + new[] + { + new BulkDeletionFailedObject("/badContainer/object3", new Status((int)HttpStatusCode.BadRequest, "invalidContainer")), + new BulkDeletionFailedObject("/container/badObject", new Status((int)HttpStatusCode.BadRequest, "invalidName")) + }; + BulkDeletionResults results = new BulkDeletionResults(successfulObjects, failedObjects); + BinaryFormatter formatter = new BinaryFormatter(); + using (Stream stream = new MemoryStream()) + { + formatter.Serialize(stream, results); + stream.Position = 0; + BulkDeletionResults deserialized = (BulkDeletionResults)formatter.Deserialize(stream); + Assert.IsNotNull(deserialized); + + Assert.IsNotNull(deserialized.SuccessfulObjects); + Assert.AreEqual(successfulObjects.Length, deserialized.SuccessfulObjects.Count()); + for (int i = 0; i < successfulObjects.Length; i++) + Assert.AreEqual(successfulObjects[i], deserialized.SuccessfulObjects.ElementAt(i)); + + Assert.IsNotNull(deserialized.FailedObjects); + Assert.AreEqual(failedObjects.Length, deserialized.FailedObjects.Count()); + for (int i = 0; i < failedObjects.Length; i++) + { + Assert.IsNotNull(deserialized.FailedObjects.ElementAt(i)); + Assert.AreEqual(failedObjects[i].Object, deserialized.FailedObjects.ElementAt(i).Object); + Assert.IsNotNull(deserialized.FailedObjects.ElementAt(i).Status); + Assert.AreEqual(failedObjects[i].Status.Code, deserialized.FailedObjects.ElementAt(i).Status.Code); + Assert.AreEqual(failedObjects[i].Status.Description, deserialized.FailedObjects.ElementAt(i).Status.Description); + } + } + } + } +} diff --git a/src/OpenStack.UnitTests/Serialization/EmptyEnumerableTests.cs b/src/OpenStack.UnitTests/Serialization/EmptyEnumerableTests.cs new file mode 100644 index 000000000..86f10021c --- /dev/null +++ b/src/OpenStack.UnitTests/Serialization/EmptyEnumerableTests.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Xunit; + +namespace OpenStack.Serialization +{ + public class EmptyEnumerableTests + { + private class ExampleThing + { + public ExampleThing() + { + Messages = new List(); + } + + [JsonProperty("messages")] + public IEnumerable Messages { get; set; } + } + + [Fact] + public void WhenDeserializingNullCollection_ItShouldUseAnEmptyCollection() + { + var thing = new ExampleThing{Messages = null}; + string json = OpenStackNet.Serialize(thing); + Assert.DoesNotContain("messages", json); + + var result = OpenStackNet.Deserialize(json); + + Assert.NotNull(result.Messages); + Assert.Empty(result.Messages); + } + + [Fact] + public void WhenSerializingEmptyCollection_ItShouldBeIgnored() + { + var thing = new ExampleThing { Messages = new List() }; + + string json = OpenStackNet.Serialize(thing); + + Assert.DoesNotContain("messages", json); + } + } +} diff --git a/src/OpenStack.UnitTests/Serialization/RootWrapperConverterTests.cs b/src/OpenStack.UnitTests/Serialization/RootWrapperConverterTests.cs new file mode 100644 index 000000000..155a11e1c --- /dev/null +++ b/src/OpenStack.UnitTests/Serialization/RootWrapperConverterTests.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace OpenStack.Serialization +{ + public class RootWrapperConverterTests + { + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "thing")] + class Thing + { + [JsonProperty("id")] + public string Id { get; set; } + } + + [JsonConverterWithConstructor(typeof(RootWrapperConverter), "things")] + class ThingCollection : List + { + } + + [Fact] + public void Serialize() + { + var json = OpenStackNet.Serialize(new Thing()); + + var jsonObj = JObject.Parse(json); + JProperty rootProperty = jsonObj.Properties().FirstOrDefault(); + Assert.NotNull(rootProperty); + Assert.Equal("thing", rootProperty.Name); + } + + [Fact] + public void Deserialize() + { + var json = OpenStackNet.Serialize(new Thing {Id = "thing-id"}); + var thing = OpenStackNet.Deserialize(json); + Assert.Equal("thing-id", thing.Id); + } + + [Fact] + public void SerializeWhenNotRoot() + { + var json = OpenStackNet.Serialize(new List{ new Thing() }); + + Assert.DoesNotContain("\"thing\"", json); + } + + [Fact] + public void SerializeWhenNested() + { + var json = OpenStackNet.Serialize(new ThingCollection { new Thing() }); + + Assert.DoesNotContain("\"thing\"", json); + } + + [Fact] + public void DeserializeWhenNotRoot() + { + var json = JArray.Parse("[{'id':'thing-id'}]").ToString(); + var things = OpenStackNet.Deserialize>(json); + Assert.Equal(1, things.Count); + Assert.Equal("thing-id", things[0].Id); + } + + [Fact] + public void DeserializeWhenNested() + { + var json = JObject.Parse("{'things':[{'id':'thing-id'}]}").ToString(); + var things = OpenStackNet.Deserialize(json); + Assert.NotNull(things); + Assert.Equal(1, things.Count); + Assert.Equal("thing-id", things[0].Id); + } + + [Fact] + public void ShouldIgnoreUnexpectedRootProperties() + { + var json = JObject.Parse("{'links': [{'name': 'next', 'link': 'http://nextlink'}], 'thing': {'id': 'thing-id'}}").ToString(); + var thing = OpenStackNet.Deserialize(json); + Assert.NotNull(thing); + Assert.Equal("thing-id", thing.Id); + } + } +} \ No newline at end of file diff --git a/src/OpenStack.UnitTests/Serialization/TolerantEnumConverterTests.cs b/src/OpenStack.UnitTests/Serialization/TolerantEnumConverterTests.cs new file mode 100644 index 000000000..dc8967f2a --- /dev/null +++ b/src/OpenStack.UnitTests/Serialization/TolerantEnumConverterTests.cs @@ -0,0 +1,65 @@ +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Xunit; + +namespace OpenStack.Serialization +{ + public class TolerantEnumConverterTests + { + [JsonConverter(typeof(TolerantEnumConverter))] + enum ThingStatus + { + Active, + Unknown, + [EnumMember(Value = "REMOVE_FAILED")] + RemoveFailed + } + + [JsonConverter(typeof(TolerantEnumConverter))] + enum StuffStatus + { + Missing, + Present + } + + [Fact] + public void WhenValueIsRecognized_MatchToValue() + { + var result = OpenStackNet.Deserialize("\"ACTIVE\""); + + Assert.Equal(ThingStatus.Active, result); + } + + [Fact] + public void WhenAttributedValueIsRecognized_MatchToValue() + { + var result = OpenStackNet.Deserialize("\"REMOVE_FAILED\""); + + Assert.Equal(ThingStatus.RemoveFailed, result); + } + + [Fact] + public void WhenValueIsUnrecognized_MatchToUnknownValue() + { + var result = OpenStackNet.Deserialize("\"bad-enum-value\""); + + Assert.Equal(ThingStatus.Unknown, result); + } + + [Fact] + public void WhenValueIsUnrecognized_AndUnknownIsNotPresent_MatchToFirstValue() + { + var result = OpenStackNet.Deserialize("\"bad-enum-value\""); + + Assert.Equal(StuffStatus.Missing, result); + } + + [Fact] + public void WhenValueIsUnrecognized_AndDestinationIsNullable_UseNull() + { + var result = OpenStackNet.Deserialize("\"bad-enum-value\""); + + Assert.Null(result); + } + } +} diff --git a/src/OpenStack.UnitTests/Stubs.cs b/src/OpenStack.UnitTests/Stubs.cs new file mode 100644 index 000000000..eeb76461a --- /dev/null +++ b/src/OpenStack.UnitTests/Stubs.cs @@ -0,0 +1,34 @@ +using System.Threading; +using System.Threading.Tasks; +using Moq; +using OpenStack.Authentication; + +namespace OpenStack +{ + /// + /// Default stubs for unit testing + /// + public static class Stubs + { + public static readonly IAuthenticationProvider AuthenticationProvider; + + static Stubs() + { + var authProviderStub = CreateAuthenticationProvider(); + AuthenticationProvider = authProviderStub.Object; + } + + public static Mock CreateAuthenticationProvider() + { + var stub = new Mock(); + + stub.Setup(provider => provider.GetToken(It.IsAny())) + .Returns(Task.FromResult("mock-token")); + + stub.Setup(provider => provider.GetEndpoint(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.FromResult("http://example.com/api")); + + return stub; + } + } +} \ No newline at end of file diff --git a/src/OpenStack.UnitTests/TestCategories.cs b/src/OpenStack.UnitTests/TestCategories.cs new file mode 100644 index 000000000..3d21e218e --- /dev/null +++ b/src/OpenStack.UnitTests/TestCategories.cs @@ -0,0 +1,11 @@ +namespace OpenStackNet.Testing.Unit +{ + internal static class TestCategories + { + /// + /// This test category should be applied to tests which should run in the automated build environment as part of + /// validating a pull request or other change. + /// + public const string Unit = "Unit"; + } +} diff --git a/src/OpenStack.UnitTests/XunitTraceListener.cs b/src/OpenStack.UnitTests/XunitTraceListener.cs new file mode 100644 index 000000000..85bb1a9a2 --- /dev/null +++ b/src/OpenStack.UnitTests/XunitTraceListener.cs @@ -0,0 +1,41 @@ +using System; +using System.Diagnostics; +using Xunit.Abstractions; + +namespace OpenStack +{ + public class XunitTraceListener : TraceListener + { + private readonly ITestOutputHelper _testLog; + + public XunitTraceListener(ITestOutputHelper testLog) + { + _testLog = testLog; + } + + public override void Write(string message) + { + if (message.StartsWith(OpenStackNet.Tracing.Http.Name)) + return; + + TryLog(message); + } + + public override void WriteLine(string message) + { + TryLog(message); + } + + private void TryLog(string message) + { + try + { + _testLog.WriteLine(message); + } + catch (InvalidOperationException) + { + // Unable to log to xunit because it thinks no test is active... + } + } + } +} From adfb1c78859a0b61aca58d4dc0da5d57b64ab875 Mon Sep 17 00:00:00 2001 From: Daryl Walleck Date: Fri, 4 May 2018 23:17:55 -0500 Subject: [PATCH 6/6] Starting work on integration tests --- .../v2/BlockStorageTestDataManager.cs | 64 + .../Bootstrapper.cs | 140 ++ .../Compute/v2_1/ComputeServiceTests.cs | 42 + .../Compute/v2_1/ComputeTestDataManager.cs | 295 ++++ .../Compute/v2_1/FlavorTests.cs | 77 + .../Compute/v2_1/ImageTests.cs | 144 ++ .../Compute/v2_1/KeyPairTests.cs | 96 ++ .../v2_1/Operator/ComputeServiceTests.cs | 47 + .../Compute/v2_1/Operator/ServerTests.cs | 65 + .../Compute/v2_1/SecurityGroupTests.cs | 105 ++ .../Compute/v2_1/ServerGroupTests.cs | 66 + .../Compute/v2_1/ServerTests.cs | 473 ++++++ .../Compute/v2_1/VolumeTests.cs | 117 ++ .../v1/ContentDeliveryNetworkServiceTests.cs | 32 + .../v1/ServiceTests.cs | 150 ++ .../Identity/v2/IdentityTests.cs | 32 + .../v2/Layer3/Layer3ExtensionTests.cs | 106 ++ .../Networking/v2/NetworkingServiceTests.cs | 321 +++++ .../v2/NetworkingTestDataManager.cs | 218 +++ .../ObjectStorage/CloudFilesProviderTests.cs | 86 ++ .../OpenStack.IntegrationsTests.csproj | 23 + src/OpenStack.IntegrationsTests/TestData.cs | 12 + .../TestIdentityProvider.cs | 88 ++ .../XunitTraceListener.cs | 41 + src/corelib/OpenStack.old.csproj | 1265 +++++++++++++++++ src/openstack.net.sln | 14 +- ... => OpenStack.IntegrationTests.old.csproj} | 0 .../unit/OpenStack.UnitTests.old.csproj | 698 +++++++++ 28 files changed, 4815 insertions(+), 2 deletions(-) create mode 100644 src/OpenStack.IntegrationsTests/BlockStorage/v2/BlockStorageTestDataManager.cs create mode 100644 src/OpenStack.IntegrationsTests/Bootstrapper.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/ComputeServiceTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/ComputeTestDataManager.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/FlavorTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/ImageTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/KeyPairTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/Operator/ComputeServiceTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/Operator/ServerTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/SecurityGroupTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/ServerGroupTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/ServerTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Compute/v2_1/VolumeTests.cs create mode 100644 src/OpenStack.IntegrationsTests/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceTests.cs create mode 100644 src/OpenStack.IntegrationsTests/ContentDeliveryNetworks/v1/ServiceTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Identity/v2/IdentityTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Networking/v2/Layer3/Layer3ExtensionTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Networking/v2/NetworkingServiceTests.cs create mode 100644 src/OpenStack.IntegrationsTests/Networking/v2/NetworkingTestDataManager.cs create mode 100644 src/OpenStack.IntegrationsTests/ObjectStorage/CloudFilesProviderTests.cs create mode 100644 src/OpenStack.IntegrationsTests/OpenStack.IntegrationsTests.csproj create mode 100644 src/OpenStack.IntegrationsTests/TestData.cs create mode 100644 src/OpenStack.IntegrationsTests/TestIdentityProvider.cs create mode 100644 src/OpenStack.IntegrationsTests/XunitTraceListener.cs create mode 100644 src/corelib/OpenStack.old.csproj rename src/testing/integration/{OpenStack.IntegrationTests.csproj => OpenStack.IntegrationTests.old.csproj} (100%) create mode 100644 src/testing/unit/OpenStack.UnitTests.old.csproj diff --git a/src/OpenStack.IntegrationsTests/BlockStorage/v2/BlockStorageTestDataManager.cs b/src/OpenStack.IntegrationsTests/BlockStorage/v2/BlockStorageTestDataManager.cs new file mode 100644 index 000000000..807e99a44 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/BlockStorage/v2/BlockStorageTestDataManager.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using net.openstack.Core.Domain; +using net.openstack.Core.Providers; + +namespace OpenStack.BlockStorage.v2 +{ + public class BlockStorageTestDataManager : IDisposable + { + private readonly HashSet _testData; + + public BlockStorageTestDataManager(IBlockStorageProvider storage) + { + StorageProvider = storage; + _testData = new HashSet(); + } + + public IBlockStorageProvider StorageProvider { get; } + + public void Register(IEnumerable testItems) + { + foreach (var testItem in testItems) + { + Register(testItem); + } + } + + public void Register(object testItem) + { + _testData.Add(testItem); + } + + public void Dispose() + { + var errors = new List(); + try + { + DeleteVolumes(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + if (errors.Any()) + throw new AggregateException("Unable to remove all test data!", errors); + } + + #region Volumes + public Volume CreateVolume() + { + var volume = StorageProvider.CreateVolume(1); + Register(volume); + return volume; + } + + public void DeleteVolumes(IEnumerable volumes) + { + foreach (Volume volume in volumes) + { + StorageProvider.DeleteVolume(volume.Id); + } + } + #endregion + } +} diff --git a/src/OpenStack.IntegrationsTests/Bootstrapper.cs b/src/OpenStack.IntegrationsTests/Bootstrapper.cs new file mode 100644 index 000000000..2fc06eb76 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Bootstrapper.cs @@ -0,0 +1,140 @@ +using System; +using System.IO; +using System.Text; +using net.openstack.Core.Domain; +using net.openstack.Core.Providers; +using net.openstack.Providers.Rackspace; +using net.openstack.Providers.Rackspace.Objects; + +namespace Net.OpenStack.Testing.Integration +{ + public class Bootstrapper + { + private static OpenstackNetSetings _settings; + public static OpenstackNetSetings Settings + { + get + { + if(_settings == null) + Initialize(); + + return _settings; + } + } + + public static void Initialize() + { + var homeDir = Environment.ExpandEnvironmentVariables("C:\\"); + + var path = Path.Combine(homeDir, ".openstack_net"); + + var contents = new StringBuilder(); + + using(var stream = File.Open(path, FileMode.Open, FileAccess.Read)) + { + using(var reader = new StreamReader(stream)) + { + while (!reader.EndOfStream) + { + var line = reader.ReadLine(); + if(!line.Trim().StartsWith("//")) + contents.Append(line); + } + } + } + + var appCredentials = Newtonsoft.Json.JsonConvert.DeserializeObject(contents.ToString()); + + _settings = appCredentials; + } + + public static IIdentityProvider CreateIdentityProvider() + { + return CreateIdentityProvider(Bootstrapper.Settings.TestIdentity); + } + + public static IIdentityProvider CreateIdentityProvider(CloudIdentity identity) + { + var provider = new CloudIdentityProvider(identity); + SetUserAgent(provider); + return provider; + } + + public static IComputeProvider CreateComputeProvider() + { + var provider = new CloudServersProvider(Bootstrapper.Settings.TestIdentity, Bootstrapper.Settings.DefaultRegion, CreateIdentityProvider(), null); + SetUserAgent(provider); + return provider; + } + + public static INetworksProvider CreateNetworksProvider() + { + var provider = new CloudNetworksProvider(Bootstrapper.Settings.TestIdentity, Bootstrapper.Settings.DefaultRegion, CreateIdentityProvider(), null); + SetUserAgent(provider); + return provider; + } + + public static IBlockStorageProvider CreateBlockStorageProvider() + { + var provider = new CloudBlockStorageProvider(Bootstrapper.Settings.TestIdentity, Bootstrapper.Settings.DefaultRegion, CreateIdentityProvider(), null); + SetUserAgent(provider); + return provider; + } + + public static IObjectStorageProvider CreateObjectStorageProvider() + { + var provider = new CloudFilesProvider(Bootstrapper.Settings.TestIdentity, Bootstrapper.Settings.DefaultRegion, CreateIdentityProvider(), null); + SetUserAgent(provider); + return provider; + } + + private static void SetUserAgent(ProviderBase provider) + where T : class + { + provider.ApplicationUserAgent = "CI-BOT"; + } + } + + public class OpenstackNetSetings + { + public ExtendedCloudIdentity TestIdentity { get; set; } + + public ExtendedCloudIdentity TestAdminIdentity { get; set; } + + public ExtendedRackspaceCloudIdentity TestDomainIdentity { get; set; } + + public string RackspaceExtendedIdentityUrl { get; set; } + + public string DefaultRegion + { + get; + set; + } + } + + public class ExtendedCloudIdentity : CloudIdentity + { + public string TenantId { get; set; } + + public string Domain { get; set; } + } + + public class ExtendedRackspaceCloudIdentity : RackspaceCloudIdentity + { + public string TenantId { get; set; } + + public ExtendedRackspaceCloudIdentity() + { + + } + + public ExtendedRackspaceCloudIdentity(ExtendedCloudIdentity cloudIdentity) + { + this.APIKey = cloudIdentity.APIKey; + this.Password = cloudIdentity.Password; + this.Username = cloudIdentity.Username; + this.TenantId = cloudIdentity.TenantId; + this.Domain = string.IsNullOrEmpty(cloudIdentity.Domain) ? null : new Domain(cloudIdentity.Domain); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/ComputeServiceTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/ComputeServiceTests.cs new file mode 100644 index 000000000..8ee3e483c --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/ComputeServiceTests.cs @@ -0,0 +1,42 @@ +using System; +using System.Diagnostics; +using OpenStack.Serialization; +using Xunit; +using Xunit.Abstractions; +using System.Threading.Tasks; + +namespace OpenStack.Compute.v2_1 +{ + public class ComputeServiceTests : IDisposable + { + private readonly ComputeService _compute; + + public ComputeServiceTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + } + + public void Dispose() + { + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task GetLimitsTest() + { + var limits = await _compute.GetLimitsAsync(); + Assert.NotNull(limits); + Assert.Empty(limits.RateLimits); + Assert.NotNull(limits.ResourceLimits); + Assert.NotNull(limits.ResourceLimits.ServersMax); + Assert.NotNull(limits.ResourceLimits.ServersUsed); + Assert.Empty(((IHaveExtraData)limits).Data); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/ComputeTestDataManager.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/ComputeTestDataManager.cs new file mode 100644 index 000000000..c3f052567 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/ComputeTestDataManager.cs @@ -0,0 +1,295 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using net.openstack.Providers.Rackspace; +using OpenStack.BlockStorage.v2; + +namespace OpenStack.Compute.v2_1 +{ + public class ComputeTestDataManager : IDisposable + { + private readonly ComputeService _compute; + private readonly HashSet _testData; + + public ComputeTestDataManager(ComputeService compute) + { + _compute = compute; + _testData = new HashSet(); + + var identityProvider = TestIdentityProvider.GetIdentityProvider(); + var blockStorage = new CloudBlockStorageProvider(null, "RegionOne", identityProvider, null); + BlockStorage = new BlockStorageTestDataManager(blockStorage); + } + + public BlockStorageTestDataManager BlockStorage { get; } + + public void Register(IEnumerable testItems) + { + foreach (var testItem in testItems) + { + Register(testItem); + } + } + + public void Register(object testItem) + { + _testData.Add(testItem); + } + + public void Dispose() + { + var errors = new List(); + + try + { + DeleteServers(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteImages(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteSecurityGroups(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteServerGroups(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteVolumeSnapshots(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteVolumes(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteKeyPairs(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + BlockStorage.Dispose(); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + if (errors.Any()) + throw new AggregateException("Unable to remove all test data!", errors); + } + + #region Servers + public ServerCreateDefinition BuildServer() + { + string name = TestData.GenerateName(); + var flavor = GetDefaultFlavor(); + var image = GetDefaultImage(); + Task.WaitAll(flavor, image); + return new ServerCreateDefinition(name, image.Result, flavor.Result); + } + + private Identifier _defaultFlavor; + private async Task GetDefaultFlavor() + { + if (_defaultFlavor == null) + { + var flavors = await _compute.ListFlavorSummariesAsync(); + _defaultFlavor = flavors.First(x => x.Name == "m1.tiny").Id; + } + return _defaultFlavor; + } + + private Identifier _defaultImage; + private async Task GetDefaultImage() + { + if (_defaultImage == null) + { + var images = await _compute.ListImageSummariesAsync(new ImageListOptions {Name = "cirros"}); + _defaultImage = images.First().Id; + } + return _defaultImage; + } + + public async Task CreateServer() + { + var definition = BuildServer(); + return await CreateServer(definition); + } + + public async Task CreateServer(ServerCreateDefinition definition) + { + var server = await _compute.CreateServerAsync(definition); + Register(server); + return server; + } + + public async Task> CreateServers() + { + var definitions = new[] { BuildServer(), BuildServer(), BuildServer() }; + return await CreateServers(definitions); + } + + public async Task> CreateServers(IEnumerable definitions) + { + var creates = definitions.Select(definition => _compute.CreateServerAsync(definition)).ToArray(); + var servers = await Task.WhenAll(creates); + Register(servers); + return servers; + } + + public void DeleteServers(IEnumerable servers) + { + var deletes = servers.Select(x => x.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + } + #endregion + + #region Images + public void DeleteImages(IEnumerable images) + { + var deletes = images.Select(x => x.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + } + #endregion + + #region Security Groups + public SecurityGroupDefinition BuildSecurityGroup() + { + string name = TestData.GenerateName(); + return new SecurityGroupDefinition(name, "ci test data"); + } + + public async Task CreateSecurityGroup() + { + var definition = BuildSecurityGroup(); + return await CreateSecurityGroup(definition); + } + + public async Task CreateSecurityGroup(SecurityGroupDefinition definition) + { + var securityGroup = await _compute.CreateSecurityGroupAsync(definition); + Register(securityGroup); + return securityGroup; + } + + public void DeleteSecurityGroups(IEnumerable securityGroups) + { + var deletes = securityGroups.Select(x => x.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + } + #endregion + + #region Server Groups + public ServerGroupDefinition BuildServerGroup() + { + string name = TestData.GenerateName(); + return new ServerGroupDefinition(name, "affinity"); + } + + public async Task CreateServerGroup() + { + var definition = BuildServerGroup(); + return await CreateServerGroup(definition); + } + + public async Task CreateServerGroup(ServerGroupDefinition definition) + { + var serverGroup = await _compute.CreateServerGroupAsync(definition); + Register(serverGroup); + return serverGroup; + } + + public void DeleteServerGroups(IEnumerable serverGroups) + { + var deletes = serverGroups.Select(x => x.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + } + #endregion + + #region Volumes + public VolumeDefinition BuildVolume() + { + return new VolumeDefinition(1) + { + Name = TestData.GenerateName() + }; + } + + public async Task CreateVolume() + { + var definition = BuildVolume(); + return await CreateVolume(definition); + } + + public async Task CreateVolume(VolumeDefinition definition) + { + var volume = await _compute.CreateVolumeAsync(definition); + Register(volume); + return volume; + } + + public void DeleteVolumes(IEnumerable volumes) + { + var gets = volumes.Select(v => _compute.GetVolumeAsync(v.Id)).ToArray(); + Task.WaitAll(gets); + + var serverDeletes = gets.SelectMany(v => v.Result.Attachments.Select(a => a.ServerId)) + .Select(serverId => _compute.WaitUntilServerIsDeletedAsync(serverId)).ToArray(); + Task.WaitAll(serverDeletes); + + var deletes = volumes.Select(x => x.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + } + + public void DeleteVolumeSnapshots(IEnumerable snapshots) + { + var deletes = snapshots.Select(x => x.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + + // workaround 500 errors when deleting a volume which still has snapshots + var waits = snapshots.Select(x => x.WaitUntilDeletedAsync()).ToArray(); + Task.WaitAll(waits); + } + #endregion + + #region Key Pairs + public KeyPairRequest BuildKeyPairRequest() + { + return new KeyPairRequest(TestData.GenerateName()); + } + + public Task CreateKeyPair() + { + return CreateKeyPair(BuildKeyPairRequest()); + } + + public async Task CreateKeyPair(KeyPairRequest request) + { + var keypair = await _compute.CreateKeyPairAsync(request); + Register(keypair); + return keypair; + } + + public void DeleteKeyPairs(IEnumerable keypairs) + { + var deletes = keypairs.Select(x => x.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + } + #endregion + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/FlavorTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/FlavorTests.cs new file mode 100644 index 000000000..9c0bd71d8 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/FlavorTests.cs @@ -0,0 +1,77 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.Compute.v2_1 +{ + public class FlavorTests : IDisposable + { + private readonly ComputeService _compute; + private readonly ComputeTestDataManager _testData; + + public FlavorTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + + _testData = new ComputeTestDataManager(_compute); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task ListFlavorSummariesTest() + { + var results = await _compute.ListFlavorSummariesAsync(); + + Assert.NotNull(results); + Assert.All(results, result => Assert.NotNull(result.Id)); + Assert.All(results, result => Assert.NotNull(result.Name)); + } + + [Fact] + public async Task GetFlavorTest() + { + var results = await _compute.ListFlavorSummariesAsync(); + + var flavorRef = results.FirstOrDefault(x => x.Name == "m1.tiny"); + var flavor = await flavorRef.GetFlavorAsync(); + Assert.NotNull(flavor); + Assert.Equal(flavorRef.Id, flavor.Id); + Assert.Equal(flavorRef.Name, flavor.Name); + Assert.True(flavor.DiskSize > 0); + Assert.True(flavor.MemorySize > 0); + Assert.True(flavor.VirtualCPUs > 0); + Assert.NotNull(flavor.EphemeralDiskSize); + Assert.Null(flavor.SwapSize); + } + + [Fact] + public async Task ListFlavorsTest() + { + var results = await _compute.ListFlavorsAsync(); + + Assert.NotNull(results); + Assert.True(results.Any()); + + Assert.All(results, result => Assert.NotNull(result.Id)); + Assert.All(results, result => Assert.NotNull(result.Name)); + Assert.All(results, result => Assert.True(result.DiskSize > 0)); + Assert.All(results, result => Assert.True(result.MemorySize > 0)); + Assert.All(results, result => Assert.True(result.VirtualCPUs > 0)); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/ImageTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/ImageTests.cs new file mode 100644 index 000000000..654182645 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/ImageTests.cs @@ -0,0 +1,144 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.Compute.v2_1 +{ + public class ImageTests : IDisposable + { + private readonly ComputeService _compute; + private readonly ComputeTestDataManager _testData; + + public ImageTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + + _testData = new ComputeTestDataManager(_compute); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task ListImageSummariesTest() + { + var results = await _compute.ListImageSummariesAsync(new ImageListOptions {PageSize = 1}); + + while (results.Any()) + { + var result = results.First(); + Assert.NotNull(result.Name); + + Trace.WriteLine("Getting next page..."); + results = await results.GetNextPageAsync(); + } + Assert.NotNull(results); + } + + [Fact] + public async Task FindSnapshotsTest() + { + Trace.WriteLine("Creating a test server..."); + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine("Snapshotting server..."); + var snapshot = await server.SnapshotAsync(new SnapshotServerRequest(server.Name + "SNAPSHOT")); + _testData.Register(snapshot); + + Trace.WriteLine("Getting snapshot details..."); + var results = await _compute.ListImagesAsync(new ImageListOptions {Type = ImageType.Snapshot}); + Assert.NotNull(results); + Assert.All(results, x => Assert.Equal(ImageType.Snapshot, x.Type)); + Assert.Contains(results, image => image.Id == snapshot.Id); + } + + [Fact] + public async Task ListImagesTest() + { + var results = await _compute.ListImagesAsync(new ImageListOptions { PageSize = 1 }); + + while (results.Any()) + { + var result = results.First(); + Assert.NotNull(result.Size); + results = await results.GetNextPageAsync(); + } + Assert.NotNull(results); + } + + [Fact] + public async Task EditImageMetadataTest() + { + Trace.WriteLine("Creating a test server..."); + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine("Snapshotting server..."); + var snapshot = await server.SnapshotAsync(new SnapshotServerRequest(server.Name + "SNAPSHOT") + { + Metadata = + { + ["category"] = "ci_test", + ["bad_key"] = "value" + } + }); + _testData.Register(snapshot); + + Assert.True(snapshot.Metadata.ContainsKey("category")); + + // Edit immediately + Trace.WriteLine("Adding a key..."); + await snapshot.Metadata.CreateAsync("new_key", "value"); + Assert.True(snapshot.Metadata.ContainsKey("new_key")); + + Trace.WriteLine("Removing a key..."); + await snapshot.Metadata.DeleteAsync("bad_key"); + Assert.False(snapshot.Metadata.ContainsKey("bad_key")); + + // Verify edits were persisted + Trace.WriteLine("Retrieving metadata..."); + var metadata = await snapshot.GetMetadataAsync(); + Assert.True(metadata.ContainsKey("category")); + Assert.True(metadata.ContainsKey("new_key")); + Assert.False(metadata.ContainsKey("bad_key")); + + // Batch edit + metadata.Remove("new_key"); + metadata["category"] = "updated"; + Trace.WriteLine("Updating edited metadata..."); + await metadata.UpdateAsync(overwrite: true); + + Assert.Equal("updated", metadata["category"]); + Assert.False(metadata.ContainsKey("new_key")); + } + + [Fact] + public async Task DeleteImageTest() + { + Trace.WriteLine("Creating a server..."); + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + + Trace.WriteLine("Snapshotting the server..."); + var snapshot = await server.SnapshotAsync(new SnapshotServerRequest(server.Name + "SNAPSHOT")); + await snapshot.WaitUntilActiveAsync(); + + Trace.WriteLine($"Deleting snapshot image {snapshot.Name}"); + + await snapshot.DeleteAsync(); + await snapshot.WaitUntilDeletedAsync(); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/KeyPairTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/KeyPairTests.cs new file mode 100644 index 000000000..b6e326596 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/KeyPairTests.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Flurl.Http; +using Xunit; +using Xunit.Abstractions; +using VolumeState = net.openstack.Core.Domain.VolumeState; + +namespace OpenStack.Compute.v2_1 +{ + public class KeyPairTests : IDisposable + { + private readonly ComputeService _compute; + private readonly ComputeTestDataManager _testData; + + public KeyPairTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + + _testData = new ComputeTestDataManager(_compute); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task CreateKeyPairTest() + { + var request = _testData.BuildKeyPairRequest(); + + Trace.WriteLine($"Creating keypair named: {request.Name}"); + var keypair = await _testData.CreateKeyPair(request); + + + Trace.WriteLine("Verifying keypair matches requested definition..."); + Assert.NotNull(keypair); + Assert.Equal(request.Name, keypair.Name); + Assert.NotNull(keypair.PrivateKey); + Assert.NotNull(keypair.PrivateKey); + Assert.NotNull(keypair.Fingerprint); + } + + [Fact] + public async Task ImportKeyPairTest() + { + var definition = new KeyPairDefinition(TestData.GenerateName(), "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDrBzodZLiWO6nIGGy9ZOVeFhbF6EaG8HUqrknNVKynH6+Hc5ToY71gmeQGJ7XZTAlyKKdFmPhNPCQCYqFQxjPKD3xTIAoGChlRHfkjYwjefbqxFswi9S0Fi3Lq8mawUVuPmPnuTr8KhL8ibnBbAxZnrcfTKBIoxhU+kN56CCmLnkJc5ouG/UcF+UpqUso45pYRf0YWANyyuafyCmj6NiDxMCGy/vnKUBLzMg8wQ01xGSGOfyGDIwuTFZpoPzjeqEV8oUGvxYt9Xyzh/pPKoOz1cz0wBDaVDpucTz3UEq65F9HhCmdwwjso8MP1K46LkM2JNQWQ0eTotqFvUJEoP2ff Generated-by-Nova"); + + Trace.WriteLine($"Importing keypair named: {definition.Name}"); + var keypair = await _compute.ImportKeyPairAsync(definition); + _testData.Register(keypair); + + Trace.WriteLine("Verifying keypair matches requested definition..."); + Assert.NotNull(keypair); + Assert.Equal(definition.Name, keypair.Name); + Assert.NotNull(keypair.Fingerprint); + } + + [Fact] + public async Task ListKeypairsTest() + { + Trace.WriteLine("Generating test data..."); + var keypair = await _testData.CreateKeyPair(); + await _testData.CreateKeyPair(); + + Trace.WriteLine("Listing keypairs..."); + var results = await _compute.ListKeyPairsAsync(); + + Assert.NotNull(results); + Assert.Contains(results, x => x.Name == keypair.Name); + } + + [Fact] + public async Task DeleteKeyPairTest() + { + var keypair = await _testData.CreateKeyPair(); + Trace.WriteLine($"Created keypair named: {keypair.Name}"); + + Trace.WriteLine($"Deleting keypair..."); + await keypair.DeleteAsync(); + + await Assert.ThrowsAsync(() => _compute.GetKeyPairAsync(keypair.Name)); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/Operator/ComputeServiceTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/Operator/ComputeServiceTests.cs new file mode 100644 index 000000000..a9fe5b86d --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/Operator/ComputeServiceTests.cs @@ -0,0 +1,47 @@ +using System.Diagnostics; +using OpenStack.Serialization; +using Xunit; +using System.Threading.Tasks; +using Xunit.Abstractions; + +namespace OpenStack.Compute.v2_1.Operator +{ + public class ComputeServiceTests + { + private readonly ComputeService _compute; + + public ComputeServiceTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetOperatorIdentity(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + } + + public void Dispose() + { + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task GetCurrentQuotas() + { + var quotas = await _compute.GetCurrentQuotasAsync(); + Assert.NotNull(quotas); + Assert.Equal("detail", quotas.Id); + Assert.Empty(((IHaveExtraData)quotas).Data); + } + + [Fact] + public async Task GetDefaultQuotas() + { + var quotas = await _compute.GetDefaultQuotasAsync(); + Assert.NotNull(quotas); + Assert.Equal("defaults", quotas.Id); + Assert.Empty(((IHaveExtraData)quotas).Data); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/Operator/ServerTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/Operator/ServerTests.cs new file mode 100644 index 000000000..b29373240 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/Operator/ServerTests.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Flurl.Http; +using Xunit; +using Xunit.Abstractions; +using VolumeState = net.openstack.Core.Domain.VolumeState; + +namespace OpenStack.Compute.v2_1.Operator +{ + public class ServerTests : IDisposable + { + private readonly ComputeService _compute; + private readonly ComputeTestDataManager _testData; + + public ServerTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetOperatorIdentity(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + + _testData = new ComputeTestDataManager(_compute); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + [Trait("ci", "false")] + public async Task EvacuateServerTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + Trace.WriteLine("Evacuating the server to a new host..."); + var request = new EvacuateServerRequest(false) + { + AdminPassword = "top-secret-password" + }; + + // Our service isn't down, so we can't really evacuate. + // Just check that the request would have gone through (i.e. was valid) + // and only was rejected because the compute service is healthy + try + { + await server.EvacuateAsync(request); + } + catch (FlurlHttpException httpError) when (httpError.Call.ErrorResponseBody.Contains("is still in use")) + { + // Hurray! the test passed + } + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/SecurityGroupTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/SecurityGroupTests.cs new file mode 100644 index 000000000..9c4085670 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/SecurityGroupTests.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Flurl.Http; +using Xunit; +using Xunit.Abstractions; +using VolumeState = net.openstack.Core.Domain.VolumeState; + +namespace OpenStack.Compute.v2_1 +{ + public class SecurityGroupTests : IDisposable + { + private readonly ComputeService _compute; + private readonly ComputeTestDataManager _testData; + + public SecurityGroupTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + + _testData = new ComputeTestDataManager(_compute); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task SecurityGroupTest() + { + var definition = _testData.BuildSecurityGroup(); + Trace.WriteLine($"Creating security group named: {definition.Name}"); + var securityGroup = await _testData.CreateSecurityGroup(definition); + + Trace.WriteLine("Verifying security group matches requested definition..."); + Assert.NotNull(securityGroup); + Assert.Equal(definition.Name, securityGroup.Name); + Assert.Equal(definition.Description, securityGroup.Description); + + Trace.WriteLine("Creatinga server associated with the security group..."); + var serverDefinition = _testData.BuildServer(); + serverDefinition.SecurityGroups.Add(new SecurityGroupReference()); + Trace.WriteLine("Updating the security group..."); + string updatedName = securityGroup.Name + "UPDATED"; + securityGroup.Name = updatedName; + await securityGroup.UpdateAsync(); + Assert.Equal(updatedName, securityGroup.Name); + + Trace.WriteLine("Verifying the updated security group matches..."); + securityGroup = await _compute.GetSecurityGroupAsync(securityGroup.Id); + Assert.NotNull(securityGroup); + Assert.Equal(updatedName, securityGroup.Name); + Assert.Equal(definition.Description, securityGroup.Description); + + Trace.WriteLine("Deleting the security group..."); + await securityGroup.DeleteAsync(); + + await Assert.ThrowsAsync(() => _compute.GetSecurityGroupAsync(securityGroup.Id)); + + } + + [Fact] + public async Task ListSecurityGroupsTest() + { + var groups = await _compute.ListSecurityGroupsAsync(); + Assert.NotEmpty(groups); + Assert.Contains(groups, x => x.Name == "default"); + } + + [Fact] + public async Task SecurityGroupRuleTest() + { + Trace.WriteLine("Creating security group..."); + var securityGroup = await _testData.CreateSecurityGroup(); + + Trace.WriteLine("Adding a rule..."); + var ruleDefinition = new SecurityGroupRuleDefinition(IPProtocol.TCP, 22, 22, "0.0.0.0/24"); + var rule = await securityGroup.AddRuleAsync(ruleDefinition); + + Trace.WriteLine("Verifying rule matches requested definition..."); + Assert.NotNull(rule); + Assert.Equal(ruleDefinition.Protocol, rule.Protocol); + Assert.Equal(ruleDefinition.ToPort, rule.ToPort); + Assert.Equal(ruleDefinition.FromPort, rule.FromPort); + Assert.Equal(ruleDefinition.CIDR, rule.CIDR); + Assert.Equal(securityGroup.Id, rule.GroupId); + + Trace.WriteLine("Deleting the rule..."); + await rule.DeleteAsync(); + + securityGroup = await _compute.GetSecurityGroupAsync(securityGroup.Id); + Assert.DoesNotContain(securityGroup.Rules, x => x.Id == rule.Id); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/ServerGroupTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/ServerGroupTests.cs new file mode 100644 index 000000000..481106065 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/ServerGroupTests.cs @@ -0,0 +1,66 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Flurl.Http; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.Compute.v2_1 +{ + public class ServerGroupTests : IDisposable + { + private readonly ComputeService _compute; + private readonly ComputeTestDataManager _testData; + + public ServerGroupTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + + _testData = new ComputeTestDataManager(_compute); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task CreateServerGroup_AndAssociateAServerTest() + { + ServerGroupDefinition definition = _testData.BuildServerGroup(); + Trace.WriteLine($"Creating server group named: {definition.Name}"); + ServerGroup serverGroup = await _testData.CreateServerGroup(definition); + + Trace.WriteLine("Verifying server group matches requested definition..."); + Assert.NotNull(serverGroup); + Assert.Equal(definition.Name, serverGroup.Name); + Assert.Equal(definition.Policies, serverGroup.Policies); + + Trace.WriteLine("Creating a server associated with the group..."); + ServerCreateDefinition serverDefinition = _testData.BuildServer(); + serverDefinition.SchedulerHints = new SchedulerHints(); + serverDefinition.SchedulerHints.Add("group", serverGroup.Id); + var server = await _testData.CreateServer(serverDefinition); + await server.WaitUntilActiveAsync(); + + Trace.WriteLine("Verifying the server is a member of the group..."); + serverGroup = await _compute.GetServerGroupAsync(serverGroup.Id); + Assert.Contains(server.Id, serverGroup.Members); + + Trace.WriteLine("Deleting the server group..."); + await serverGroup.DeleteAsync(); + + var groups = await _compute.ListServerGroupsAsync(); + Assert.DoesNotContain(serverGroup.Id, groups.Select(x => x.Id)); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/ServerTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/ServerTests.cs new file mode 100644 index 000000000..1098a2dc7 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/ServerTests.cs @@ -0,0 +1,473 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Flurl.Http; +using Xunit; +using Xunit.Abstractions; +using VolumeState = net.openstack.Core.Domain.VolumeState; + +namespace OpenStack.Compute.v2_1 +{ + public class ServerTests : IDisposable + { + private readonly ComputeService _compute; + private readonly ComputeTestDataManager _testData; + + public ServerTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + + _testData = new ComputeTestDataManager(_compute); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task CreateServerTest() + { + var definition = _testData.BuildServer(); + + Trace.WriteLine($"Creating server named: {definition.Name}"); + var server = await _testData.CreateServer(definition); + await server.WaitUntilActiveAsync(); + + Trace.WriteLine("Verifying server matches requested definition..."); + Assert.NotNull(server); + Assert.Equal(definition.Name, server.Name); + Assert.NotNull(server.Flavor); + Assert.Equal(definition.FlavorId, server.Flavor.Id); + Assert.NotNull(server.AdminPassword); + Assert.NotNull(server.Image); + Assert.Equal(definition.ImageId, server.Image.Id); + Assert.Equal(server.Status, ServerStatus.Active); + Assert.NotNull(server.AvailabilityZone); + Assert.NotNull(server.Created); + Assert.NotNull(server.LastModified); + Assert.NotNull(server.Launched); + Assert.NotNull(server.DiskConfig); + Assert.NotNull(server.HostId); + Assert.NotNull(server.PowerState); + Assert.NotNull(server.VMState); + Assert.NotNull(server.SecurityGroups); + + var history = await server.ListActionSummariesAsync(); + Assert.NotNull(history); + var createRef = history.FirstOrDefault(a => a.Name == "create"); + Assert.NotNull(createRef); + Assert.NotNull(createRef.Id); + Assert.NotNull(createRef.Name); + Assert.NotNull(createRef.ServerId); + Assert.NotNull(createRef.UserId); + + var createAction = await createRef.GetActionAsync(); + Assert.NotNull(createAction); + Assert.NotNull(createAction.Id); + Assert.NotNull(createAction.Name); + Assert.NotNull(createAction.Events); + } + + [Fact] + [Trait("ci", "false")] // TODO: Run with CI tests once we've implemented cinder + public async Task BootFromVolume() + { + var definition = _testData.BuildServer(); + definition.ConfigureBootFromVolume("30ca5d77-c519-48ea-a56c-7c4e0ca0894d"); + + Trace.WriteLine("Booting new server from volume..."); + var server = await _testData.CreateServer(definition); + await server.WaitUntilActiveAsync(); + + Assert.NotEmpty(server.AttachedVolumes); + Assert.Contains(server.AttachedVolumes, x => x.Id == definition.BlockDeviceMapping[0].SourceId); + } + + [Fact] + [Trait("ci", "false")] // TODO: Run with CI tests once we've implemented cinder + public async Task BootFromVolumeCopy() + { + var definition = _testData.BuildServer(); + definition.ConfigureBootFromNewVolume("30ca5d77-c519-48ea-a56c-7c4e0ca0894d", volumeSize: 1, deleteVolumeWithServer: true); + + Trace.WriteLine("Booting new server from a new volume created from an existing volume..."); + var server = await _testData.CreateServer(definition); + await server.WaitUntilActiveAsync(); + + Assert.NotEmpty(server.AttachedVolumes); + Assert.Contains(server.AttachedVolumes, x => x.Id == definition.BlockDeviceMapping[0].SourceId); + } + + [Fact] + public async Task BootFromImageCopy() + { + var definition = _testData.BuildServer(); + definition.ConfigureBootFromNewVolume(volumeSize: 1, deleteVolumeWithServer: true); + Trace.WriteLine("Booting new server from a new volume created from an existing image..."); + var server = await _testData.CreateServer(definition); + await server.WaitUntilActiveAsync(); + + Assert.NotEmpty(server.AttachedVolumes); + Assert.Contains(server.AttachedVolumes, x => x.Id != definition.BlockDeviceMapping[0].SourceId); + } + + [Fact] + public async Task ListServerReferencesTest() + { + var results = await _compute.ListServerSummariesAsync(new ServerListOptions {PageSize = 1}); + + while (results.Any()) + { + var result = results.First(); + Assert.NotNull(result.Name); + results = await results.GetNextPageAsync(); + } + Assert.NotNull(results); + } + + [Fact] + public async Task FindServersTest() + { + var servers = await _testData.CreateServers(); + await Task.WhenAll(servers.Select(x => x.WaitUntilActiveAsync())); + + var serverWithMetadata = servers.First(); + var fooValue = Guid.NewGuid().ToString(); + await serverWithMetadata.Metadata.CreateAsync("foo", fooValue); + + var serversNames = new HashSet(servers.Select(s => s.Name)); + + var results = await _compute.ListServerSummariesAsync(new ServerListOptions {Name = "ci-*"}); + var resultNames = new HashSet(results.Select(s => s.Name)); + + Assert.Subset(resultNames, serversNames); + + Trace.WriteLine("Filtering servers by their metadata..."); + results = await _compute.ListServerSummariesAsync(new ServerListOptions + { + Metadata = + { + {"foo", fooValue} + } + }); + Assert.Contains(serverWithMetadata.Id, results.Select(x => x.Id)); + } + + [Fact] + public async Task ListServersTest() + { + var results = await _compute.ListServersAsync(new ServerListOptions { PageSize = 1 }); + + while (results.Any()) + { + var result = results.First(); + Assert.NotNull(result.Image); + results = await results.GetNextPageAsync(); + } + Assert.NotNull(results); + } + + [Fact] + public async Task UpdateServerTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + var desiredName = server.Name + "UPDATED"; + server.Name = desiredName; + Trace.WriteLine($"Updating server name to: {server.Name}..."); + await server.UpdateAsync(); + + Trace.WriteLine("Verifying server instance was updated..."); + Assert.NotNull(server); + Assert.Equal(desiredName, server.Name); + + Trace.WriteLine("Verifying server matches updated definition..."); + server = await _compute.GetServerAsync(server.Id); + Assert.Equal(desiredName, server.Name); + } + + [Fact] + public async Task EditServerMetadataTest() + { + Trace.WriteLine("Creating a test server..."); + var definition = _testData.BuildServer(); + definition.Metadata = new ServerMetadata + { + ["category"] = "ci_test", + ["bad_key"] = "value" + }; + var server = await _testData.CreateServer(definition); + await server.WaitUntilActiveAsync(); + + Assert.True(server.Metadata.ContainsKey("category")); + + // Edit immediately + Trace.WriteLine("Adding a key..."); + await server.Metadata.CreateAsync("new_key", "value"); + Assert.True(server.Metadata.ContainsKey("new_key")); + + Trace.WriteLine("Removing a key..."); + await server.Metadata.DeleteAsync("bad_key"); + Assert.False(server.Metadata.ContainsKey("bad_key")); + + // Verify edits were persisted + Trace.WriteLine("Retrieving metadata..."); + var metadata = await server.GetMetadataAsync(); + Assert.True(metadata.ContainsKey("category")); + Assert.True(metadata.ContainsKey("new_key")); + Assert.False(metadata.ContainsKey("bad_key")); + + // Batch edit + metadata.Remove("new_key"); + metadata["category"] = "updated"; + Trace.WriteLine("Updating edited metadata..."); + await metadata.UpdateAsync(overwrite: true); + + Assert.Equal("updated", metadata["category"]); + Assert.False(metadata.ContainsKey("new_key")); + } + + [Fact] + public async Task DeleteServerTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + await server.DeleteAsync(); + await server.WaitUntilDeletedAsync(); + + await Assert.ThrowsAsync(() => _compute.GetServerAsync(server.Id)); + } + + [Fact] + public async Task LookupServerAddressesTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + var results = await server.ListAddressesAsync(); + Assert.NotEmpty(results); + + var networkLabel = results.First().Key; + var result = (await server.GetAddressAsync(networkLabel)).First(); + Assert.NotNull(result.IP); + } + + [Fact] + public async Task SnapshotServerTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + var request = new SnapshotServerRequest(server.Name + "-SNAPSHOT") + { + Metadata = + { + ["category"] = "ci" + } + }; + + Trace.WriteLine("Taking a snapshot of the server..."); + var image = await server.SnapshotAsync(request); + _testData.Register(image); + await image.WaitUntilActiveAsync(); + + Assert.NotNull(image); + Assert.Equal(request.Name, image.Name); + Assert.True(image.Metadata["category"] == "ci"); + } + + [Fact] + public async Task RestartServerTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + Trace.WriteLine("Stopping the server..."); + await server.StopAsync(); + await server.WaitForStatusAsync(ServerStatus.Stopped); + Assert.Equal(server.Status, ServerStatus.Stopped); + + Trace.WriteLine("Starting the server..."); + await server.StartAsync(); + await server.WaitUntilActiveAsync(); + Assert.Equal(server.Status, ServerStatus.Active); + } + + [Fact] + public async Task RebootServerTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + Trace.WriteLine("Rebooting the server..."); + await server.RebootAsync(); + await server.WaitForStatusAsync(ServerStatus.Reboot); + await server.WaitUntilActiveAsync(); + } + + [Fact] + public async Task ResumeServerTest() + { + Trace.WriteLine("Creating server..."); + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + + Trace.WriteLine("Suspending the server..."); + await server.SuspendAsync(); + await server.WaitForStatusAsync(ServerStatus.Suspended); + + Trace.WriteLine("Resuming the server..."); + await server.ResumeAsync(); + await server.WaitUntilActiveAsync(); + } + + [Fact] + public async Task ServerVolumesTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + Trace.WriteLine("Creating a test volume..."); + var volume = await _testData.CreateVolume(); + Identifier volumeId = volume.Id; + _testData.BlockStorage.StorageProvider.WaitForVolumeAvailable(volumeId); + + Trace.WriteLine("Attaching the volume..."); + await server.AttachVolumeAsync(new ServerVolumeDefinition(volumeId)); + _testData.BlockStorage.StorageProvider.WaitForVolumeState(volumeId, VolumeState.InUse, new[] { VolumeState.Error }); + + var volumeRef = server.AttachedVolumes.FirstOrDefault(); + Assert.NotNull(volumeRef); + + Trace.WriteLine("Verifying volume was attached successfully..."); + var attachedVolumes = await server.ListVolumesAsync(); + var attachedVolume = attachedVolumes.FirstOrDefault(v => v.Id == volumeId); + Assert.NotNull(attachedVolume); + + Trace.WriteLine("Retrieving attached volume details..."); + var serverVolume = await volumeRef.GetServerVolumeAsync(); + Assert.Equal(volumeId, serverVolume.VolumeId); + Assert.Equal(server.Id, serverVolume.ServerId); + + Trace.WriteLine("Detaching the volume..."); + await volumeRef.DetachAsync(); + Assert.False(server.AttachedVolumes.Any(v => v.Id == volumeId)); + _testData.BlockStorage.StorageProvider.WaitForVolumeAvailable(volumeId); + } + + [Fact] + public async Task GetConsoleTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + Trace.WriteLine("Getting a VNC console..."); + // This is a silly hack to verify that our message passed validation + // Since we don't have VNC setup, it won't actually pass + try + { + await server.GetVncConsoleAsync(RemoteConsoleType.NoVnc); + } + catch (FlurlHttpException httpError) when (httpError.Call.ErrorResponseBody.Contains("Unavailable console type novnc")) + { + } + + Trace.WriteLine("Getting a SPICE console..."); + var spiceConsole = await server.GetSpiceConsoleAsync(); + Assert.NotNull(spiceConsole); + Assert.NotNull(spiceConsole.Url); + Assert.Equal(RemoteConsoleType.SpiceHtml5, spiceConsole.Type); + + Trace.WriteLine("Getting a Serial console..."); + // This is a silly hack to verify that our message passed validation + // Since we don't have serial setup, it won't actually pass + try + { + await server.GetSerialConsoleAsync(); + } + catch (FlurlHttpException httpError) when (httpError.Call.ErrorResponseBody.Contains("Unavailable console type serial")) + { + } + + Trace.WriteLine("Getting a RDP console..."); + // This is a silly hack to verify that our message passed validation + // Since we don't have windows/RDP setup, it won't actually pass + try + { + await server.GetRdpConsoleAsync(); + } + catch (FlurlHttpException httpError) when (httpError.Call.ErrorResponseBody.Contains("Unavailable console type rdp-html5")) + { + } + + // Not testing GetConsoleOutput because it only returns a 404 on my OpenStack installation... + } + + [Fact] + public async Task RescueServerTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + Trace.WriteLine("Rescuing the server..."); + await server.RescueAsync(); + await server.WaitForStatusAsync(ServerStatus.Rescue); + + Trace.WriteLine("Unrescuing the server..."); + await server.UnrescueAsync(); + await server.WaitUntilActiveAsync(); + } + + [Fact] + [Trait("ci", "false")] + public async Task ResizeServerTest() + { + var flavors = await _compute.ListFlavorSummariesAsync(); + var small = flavors.First(f => f.Name.Contains("small")).Id; + var medium = flavors.First(f => f.Name.Contains("medium")).Id; + + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + Trace.WriteLine($"Created server named: {server.Name}"); + + Trace.WriteLine("Resizing the server to medium..."); + await server.ResizeAsync(medium); + await server.WaitForStatusAsync(ServerStatus.VerifyResize); + + Trace.WriteLine("Canceling the resize of the server..."); + await server.CancelResizeAsync(); + await server.WaitUntilActiveAsync(); + + Trace.WriteLine("Resizing the server to small..."); + await server.ResizeAsync(small); + await server.WaitForStatusAsync(ServerStatus.VerifyResize); + + Trace.WriteLine("Confirming the resize of the server..."); + await server.ConfirmResizeAsync(); + await server.WaitForStatusAsync(new [] {ServerStatus.Resizing, ServerStatus.Active}); // resizing is quick, or maybe doesn't happen at all, so wait for either + await server.WaitUntilActiveAsync(); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Compute/v2_1/VolumeTests.cs b/src/OpenStack.IntegrationsTests/Compute/v2_1/VolumeTests.cs new file mode 100644 index 000000000..7b4af2661 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Compute/v2_1/VolumeTests.cs @@ -0,0 +1,117 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Flurl.Http; +using OpenStack.BlockStorage.v2; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.Compute.v2_1 +{ + public class VolumeTests : IDisposable + { + private readonly ComputeService _compute; + private readonly ComputeTestDataManager _testData; + + public VolumeTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _compute = new ComputeService(authenticationProvider, "RegionOne"); + + _testData = new ComputeTestDataManager(_compute); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + // Endpoint is documented but doesn't exist + //[Fact] + //public async Task ListVolumeTypes() + //{ + // var types = await _compute.ListVolumeTypesAsync(); + // Assert.NotNull(types); + // Assert.Contains("lvm", types.Select(x => x.Name)); + //} + + [Fact] + public async Task VolumesTest() + { + var volume = await _testData.CreateVolume(); + await volume.WaitUntilAvailableAsync(); + Assert.NotNull(volume.Id); + Assert.NotNull(volume.Name); + Assert.Null(volume.Description); + Assert.Null(volume.SourceSnapshotId); + Assert.Empty(volume.Attachments); + + var volumeDetails = await _compute.GetVolumeAsync(volume.Id); + Assert.Equal(volume.Id, volumeDetails.Id); + Assert.Equal(volume.Name, volumeDetails.Name); + Assert.Equal(volume.Description, volumeDetails.Description); + Assert.Equal(volumeDetails.SourceSnapshotId, volumeDetails.SourceSnapshotId); + Assert.Empty(volumeDetails.Attachments); + + var results = await _compute.ListVolumesAsync(); + + Assert.NotNull(results); + Assert.Contains(volume.Id, results.Select(x => x.Id)); + } + + [Fact] + public async Task AttachVolumeTest() + { + var server = await _testData.CreateServer(); + await server.WaitUntilActiveAsync(); + + var volume = await _testData.CreateVolume(); + await volume.WaitUntilAvailableAsync(); + + var serverVolume = await server.AttachVolumeAsync(new ServerVolumeDefinition(volume.Id)); + _testData.Register(serverVolume); + await volume.WaitForStatusAsync(VolumeStatus.InUse); + + volume = await _compute.GetVolumeAsync(volume.Id); + serverVolume = volume.Attachments.FirstOrDefault(); + + Assert.NotNull(serverVolume); + Assert.Equal(server.Id, serverVolume.ServerId); + Assert.Equal(volume.Id, serverVolume.VolumeId); + } + + [Fact] + public async Task SnapshotsTest() + { + var volume = await _testData.CreateVolume(); + await volume.WaitUntilAvailableAsync(); + + var snapshot = await volume.SnapshotAsync(); + _testData.Register(snapshot); + await snapshot.WaitUntilAvailableAsync(); + Assert.NotNull(snapshot.Id); + Assert.Equal(volume.Id, snapshot.VolumeId); + Assert.Null(snapshot.Name); + Assert.Null(snapshot.Description); + + var snapshotDetails = await _compute.GetVolumeSnapshotAsync(snapshot.Id); + Assert.Equal(snapshot.Id, snapshotDetails.Id); + Assert.Equal(snapshot.Name, snapshotDetails.Name); + Assert.Equal(snapshot.Description, snapshotDetails.Description); + Assert.Equal(snapshot.VolumeId, snapshotDetails.VolumeId); + + var results = await _compute.ListVolumeSnapshotsAsync(); + + Assert.NotNull(results); + Assert.Contains(snapshot.Id, results.Select(x => x.Id)); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceTests.cs b/src/OpenStack.IntegrationsTests/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceTests.cs new file mode 100644 index 000000000..ade119efa --- /dev/null +++ b/src/OpenStack.IntegrationsTests/ContentDeliveryNetworks/v1/ContentDeliveryNetworkServiceTests.cs @@ -0,0 +1,32 @@ +using System; +using OpenStack.Synchronous; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + [Trait("ci","false")] // TODO: Run these with the CI tests once Poppy is installed on our environment + public class ContentDeliveryNetworkServiceTests : IDisposable + { + private readonly ContentDeliveryNetworkService _cdnService; + + public ContentDeliveryNetworkServiceTests(ITestOutputHelper testLog) + { + OpenStackNet.Tracing.Http.Listeners.Add(new XunitTraceListener(testLog)); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _cdnService = new ContentDeliveryNetworkService(authenticationProvider, "DFW"); + } + + public void Dispose() + { + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public void Ping() + { + _cdnService.Ping(); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/ContentDeliveryNetworks/v1/ServiceTests.cs b/src/OpenStack.IntegrationsTests/ContentDeliveryNetworks/v1/ServiceTests.cs new file mode 100644 index 000000000..58384b15c --- /dev/null +++ b/src/OpenStack.IntegrationsTests/ContentDeliveryNetworks/v1/ServiceTests.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Marvin.JsonPatch; +using Newtonsoft.Json; +using OpenStack.Synchronous; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.ContentDeliveryNetworks.v1 +{ + [Trait("ci","false")] + public class ServiceTests : IDisposable + { + private readonly ContentDeliveryNetworkService _cdnService; + + public ServiceTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + Trace.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _cdnService = new ContentDeliveryNetworkService(authenticationProvider, "DFW"); + } + + public void Dispose() + { + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task CreateAServiceOnAkamai_UsingDefaults() + { + Trace.WriteLine("Looking for a CDN flavor provided by Akamai..."); + var flavors = await _cdnService.ListFlavorsAsync(); + var flavor = flavors.FirstOrDefault(x => x.Providers.Any(p => string.Equals(p.Name, "Akamai", StringComparison.OrdinalIgnoreCase))); + Assert.NotNull(flavor); + var akamaiFlavor = flavor.Id; + Trace.WriteLine(string.Format("Found the {0} flavor", akamaiFlavor)); + + Trace.WriteLine("Creating a CDN service using defaults for anything I can omit..."); + var domains = new[] {new ServiceDomain("mirror.example.com")}; + var origins = new[] {new ServiceOrigin("example.com")}; + var serviceDefinition = new ServiceDefinition("ci-test", akamaiFlavor, domains, origins); + var serviceId = await _cdnService.CreateServiceAsync(serviceDefinition); + Trace.WriteLine(string.Format("Service was created: {0}", serviceId)); + + try + { + Trace.WriteLine("Waiting for the service to be deployed..."); + var service = await _cdnService.WaitForServiceDeployedAsync(serviceId, progress: new Progress(x => Trace.WriteLine("..."))); + + Trace.WriteLine("Verifying service matches the requested definition..."); + Assert.Equal("ci-test", service.Name); + Assert.Equal(serviceDefinition.FlavorId, service.FlavorId); + + Assert.Equal(serviceDefinition.Origins.Count, service.Origins.Count()); + Assert.Equal(serviceDefinition.Origins.First().Origin, service.Origins.First().Origin); + + Assert.Equal(serviceDefinition.Domains.Count, service.Domains.Count()); + Assert.Equal(serviceDefinition.Domains.First().Domain, service.Domains.First().Domain); + + Trace.WriteLine("Updating the service..."); + var patch = new JsonPatchDocument(); + patch.Replace(x => x.Name, "ci-test2"); + var intranetOnly = new ServiceRestriction("intranet", new[] {new ServiceRestrictionRule("intranet", "intranet.example.com")}); + patch.Add(x => x.Restrictions, intranetOnly, 0); + await _cdnService.UpdateServiceAsync(serviceId, patch); + + Trace.WriteLine("Waiting for the service changes to be deployed..."); + service = await _cdnService.WaitForServiceDeployedAsync(serviceId, progress: new Progress(x => Trace.WriteLine("..."))); + + Trace.WriteLine("Verifying service matches updated definition..."); + Assert.Equal("ci-test2", service.Name); + Assert.Equal(JsonConvert.SerializeObject(intranetOnly), JsonConvert.SerializeObject(service.Restrictions.First())); + + Trace.WriteLine("Purging all assets on service"); + await _cdnService.PurgeCachedAssetsAsync(serviceId); + } + finally + { + Trace.WriteLine("Cleaning up any test data..."); + + Trace.WriteLine("Removing the service..."); + _cdnService.DeleteService(serviceId); + _cdnService.WaitForServiceDeleted(serviceId); + Trace.WriteLine("The service was cleaned up sucessfully."); + } + } + + [Fact] + public async Task FindServiceOnAPage() + { + var serviceIds = new List(); + try + { + var create1 = CreateService("ci-test1", "mirror.example1.com", "example1.com").ContinueWith(t => serviceIds.Add(t.Result)); + var create2 = CreateService("ci-test2", "mirror.example2.com", "example2.com").ContinueWith(t => serviceIds.Add(t.Result)); + var create3 = CreateService("ci-test3", "mirror.example3.com", "example3.com").ContinueWith(t => serviceIds.Add(t.Result)); + + await Task.WhenAll(create1, create2, create3); + + var currentPage = await _cdnService.ListServicesAsync(pageSize: 1); + while (currentPage.Any()) + { + if (currentPage.Any(x => x.Name == "ci-test3")) + { + Trace.WriteLine("Found the desired service"); + break; + } + + currentPage = await currentPage.GetNextPageAsync(); + } + } + finally + { + Trace.WriteLine("Cleaning up any test data..."); + + Trace.WriteLine("Removing the services..."); + var deletes = serviceIds.Select(serviceId => _cdnService + .DeleteServiceAsync(serviceId) + .ContinueWith(t => _cdnService.WaitForServiceDeletedAsync(serviceId)) + .ContinueWith(t => Trace.WriteLine(string.Format("Service was deleted: {0}", serviceId)))) + .ToArray(); + + Task.WaitAll(deletes); + Trace.WriteLine("The services were cleaned up sucessfully."); + + } + } + + private async Task CreateService(string name, string domain, string origin) + { + var flavors = await _cdnService.ListFlavorsAsync(); + var flavor = flavors.First(); + + Trace.WriteLine(string.Format("Creating CDN Service: {0} for {1} originating from {2}", name, domain, origin)); + var domains = new[] { new ServiceDomain(domain) }; + var origins = new[] { new ServiceOrigin(origin) }; + var serviceDefinition = new ServiceDefinition(name, flavor.Id, domains, origins); + var serviceId = await _cdnService.CreateServiceAsync(serviceDefinition); + Trace.WriteLine("Service was created: {0}", serviceId); + return serviceId; + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Identity/v2/IdentityTests.cs b/src/OpenStack.IntegrationsTests/Identity/v2/IdentityTests.cs new file mode 100644 index 000000000..e0091db07 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Identity/v2/IdentityTests.cs @@ -0,0 +1,32 @@ +using System.Diagnostics; +using net.openstack.Core.Providers; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.Identity.v2 +{ + public class IdentityTests + { + private readonly OpenStackIdentityProvider _identityService; + + public IdentityTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + _identityService = (OpenStackIdentityProvider) TestIdentityProvider.GetIdentityProvider(); + } + + [Fact] + public void AuthenticateTest() + { + var userAccess = _identityService.Authenticate(); + Assert.NotNull(userAccess); + Assert.NotNull(userAccess.Token); + Assert.NotNull(userAccess.Token.Id); + Assert.NotNull(userAccess.ServiceCatalog); + Assert.NotEmpty(userAccess.ServiceCatalog); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/Networking/v2/Layer3/Layer3ExtensionTests.cs b/src/OpenStack.IntegrationsTests/Networking/v2/Layer3/Layer3ExtensionTests.cs new file mode 100644 index 000000000..c86fcd2eb --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Networking/v2/Layer3/Layer3ExtensionTests.cs @@ -0,0 +1,106 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using OpenStack.Compute.v2_1; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.Networking.v2.Layer3 +{ + public class Layer3ExtensionTests : IDisposable + { + private readonly NetworkingService _networkingService; + private readonly NetworkingTestDataManager _testData; + private readonly ComputeTestDataManager _computeTestData; + + public Layer3ExtensionTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + // The operator identity is necessary to create external networks + var authenticationProvider = TestIdentityProvider.GetOperatorIdentity(); + _networkingService = new NetworkingService(authenticationProvider, "RegionOne"); + + _testData = new NetworkingTestDataManager(_networkingService); + var compute = new ComputeService(authenticationProvider, "RegionOne"); + _computeTestData = new ComputeTestDataManager(compute); + } + + public void Dispose() + { + _computeTestData.Dispose(); + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public async Task AssignFloatingIP() + { + // 1. Make an internal network and subnet. + var internalNetwork = await _testData.CreateNetwork(); + var internalSubnet = await _testData.CreateSubnet(internalNetwork); + + // 2. Make an external network and subnet. + Operator.NetworkDefinition externalNetworkDefinition = _testData.BuildNetwork(); + externalNetworkDefinition.IsExternal = true; + var externalNetwork = await _testData.CreateNetwork(externalNetworkDefinition); + var externalSubnet = await _testData.CreateSubnet(externalNetwork); + + // 3. Make a router on the external network. + var routerDefinition = new RouterCreateDefinition + { + Name = TestData.GenerateName(), + ExternalGateway = new ExternalGatewayDefinition(externalNetwork.Id) + }; + var router = await _networkingService.CreateRouterAsync(routerDefinition); + _testData.Register(router); + + // 4. Attach the router to the internal network. + var internalPortId = await router.AttachSubnetAsync(internalSubnet.Id); + _testData.Register(new Port {Id = internalPortId}); + + // 5. Make a floating ip on the external network. + var floatingIPDefinition = new FloatingIPCreateDefinition(externalNetwork.Id); + var floatingIP = await _networkingService.CreateFloatingIPAsync(floatingIPDefinition); + _testData.Register(floatingIP); + + // 6. Make a server on the internal network. + var serverDefinition = _computeTestData.BuildServer(); + serverDefinition.Networks.Add(new ServerNetworkDefinition {NetworkId = internalNetwork.Id }); + var server = await _computeTestData.CreateServer(serverDefinition); + await server.WaitUntilActiveAsync(); + + // 7.Associate the floating ip to the server. + await server.AssociateFloatingIPAsync(new AssociateFloatingIPRequest(floatingIP.FloatingIPAddress)); + + // 8. Disassociate the floating ip from the server + await server.DisassociateFloatingIPAsync(floatingIP.FloatingIPAddress); + } + + [Fact] + public async Task ListSecurityGroups() + { + var groups = await _networkingService.ListSecurityGroupsAsync(new SecurityGroupListOptions {Name = "default"}); + + Assert.NotEmpty(groups); + + var defaultGroup = groups.First(); + Assert.NotNull(defaultGroup); + Assert.NotNull(defaultGroup.Name); + Assert.NotNull(defaultGroup.Description); + Assert.NotNull(defaultGroup.Id); + Assert.NotEmpty(defaultGroup.SecurityGroupRules); + + var defaultRule = defaultGroup.SecurityGroupRules.First(); + Assert.NotNull(defaultRule.Id); + Assert.NotNull(defaultRule.Direction); + Assert.NotNull(defaultRule.Ethertype); + Assert.NotNull(defaultRule.SecurityGroupId); + } + } +} \ No newline at end of file diff --git a/src/OpenStack.IntegrationsTests/Networking/v2/NetworkingServiceTests.cs b/src/OpenStack.IntegrationsTests/Networking/v2/NetworkingServiceTests.cs new file mode 100644 index 000000000..7ab333d94 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Networking/v2/NetworkingServiceTests.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace OpenStack.Networking.v2 +{ + public class NetworkingServiceTests : IDisposable + { + private readonly NetworkingService _networkingService; + private readonly NetworkingTestDataManager _testData; + + public NetworkingServiceTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + _networkingService = new NetworkingService(authenticationProvider, "RegionOne"); + + _testData = new NetworkingTestDataManager(_networkingService); + } + + public void Dispose() + { + _testData.Dispose(); + + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + #region Networks + + [Fact] + public async Task CreateNetworkTest() + { + var definition = _testData.BuildNetwork(); + + Trace.WriteLine(string.Format("Creating network named: {0}", definition.Name)); + var network = await _testData.CreateNetwork(definition); + + Trace.WriteLine("Verifying network matches requested definition..."); + Assert.NotNull(network); + Assert.Equal(definition.Name, network.Name); + Assert.True(network.IsUp); + Assert.False(network.IsShared); + Assert.Equal(NetworkStatus.Active, network.Status); + } + + [Fact] + public async Task BulkCreateNetworksTest() + { + var definitions = new[] { _testData.BuildNetwork(), _testData.BuildNetwork(), _testData.BuildNetwork() }; + + Trace.WriteLine(string.Format("Creating networks: {0}", string.Join(", ", definitions.Select(d => d.Name)))); + var networks = await _testData.CreateNetworks(definitions); + + Trace.WriteLine("Verifying networks matches requested definitions..."); + + Assert.NotNull(networks); + Assert.Equal(3, networks.Count()); + Assert.All(networks, n => Assert.True(n.IsUp)); + Assert.All(networks, n => Assert.Equal(NetworkStatus.Active, n.Status)); + } + + [Fact] + public async Task UpdateNetworkTest() + { + Network network = await _testData.CreateNetwork(); + + var networkUpdate = new NetworkDefinition + { + Name = string.Format("{0}-updated", network.Name) + }; + + Trace.WriteLine("Updating the network..."); + network = await _networkingService.UpdateNetworkAsync(network.Id, networkUpdate); + + Trace.WriteLine("Verifying network was updated as requested..."); + Assert.NotNull(network); + Assert.Equal(networkUpdate.Name, network.Name); + } + + [Fact] + public async Task ListNetworksTest() + { + var networks = await _testData.CreateNetworks(); + + Trace.WriteLine("Listing networks..."); + var results = await _networkingService.ListNetworksAsync(); + + Trace.WriteLine("Verifying list of networks..."); + Assert.NotNull(results); + Assert.All(networks, network => Assert.True(results.Any(x => x.Id == network.Id))); + } + + [Fact] + public async Task GetNetworkTest() + { + var network = await _testData.CreateNetwork(); + + Trace.WriteLine("Retrieving network..."); + var result = await _networkingService.GetNetworkAsync(network.Id); + + Trace.WriteLine("Verifying network..."); + Assert.NotNull(result); + Assert.Equal(network.Id, result.Id); + } + #endregion + + #region Subnets + [Fact] + public async Task CreateSubnetTest() + { + var network = await _testData.CreateNetwork(); + var definition = new SubnetCreateDefinition(network.Id, IPVersion.IPv4, "192.168.3.0/24") + { + Name = TestData.GenerateName(), + IsDHCPEnabled = true, + GatewayIP = "192.168.3.1", + AllocationPools = + { + new AllocationPool("192.168.3.10", "192.168.3.50") + }, + Nameservers = + { + "8.8.8.8" + }, + HostRoutes = + { + new HostRoute("1.2.3.4/24", "10.0.0.1") + } + }; + + Trace.WriteLine(string.Format("Creating subnet named: {0}", definition.Name)); + var subnet = await _testData.CreateSubnet(definition); + + Trace.WriteLine("Verifying subnet matches requested definition..."); + Assert.NotNull(subnet); + Assert.Equal(definition.NetworkId, subnet.NetworkId); + Assert.Equal(definition.Name, subnet.Name); + Assert.Equal(definition.CIDR, subnet.CIDR); + Assert.Equal(definition.IPVersion, subnet.IPVersion); + Assert.Equal(definition.IsDHCPEnabled, subnet.IsDHCPEnabled); + Assert.Equal(definition.GatewayIP, subnet.GatewayIP); + Assert.Equal(definition.AllocationPools, subnet.AllocationPools); + Assert.Equal(definition.Nameservers, subnet.Nameservers); + Assert.Equal(definition.HostRoutes, subnet.HostRoutes); + } + + [Fact] + public async Task BulkCreateSubnetsTest() + { + var network = await _testData.CreateNetwork(); + var definitions = new[] {_testData.BuildSubnet(network), _testData.BuildSubnet(network), _testData.BuildSubnet(network) }; + + Trace.WriteLine(string.Format("Creating subnets: {0}", string.Join(", ", definitions.Select(d => d.Name)))); + var subnets = await _testData.CreateSubnets(definitions); + + Trace.WriteLine("Verifying subnets matches requested definitions..."); + Assert.NotNull(subnets); + Assert.Equal(3, subnets.Count()); + } + + [Fact] + public async Task UpdateSubnetTest() + { + Network network = await _testData.CreateNetwork(); + Subnet subnet = await _testData.CreateSubnet(network); + + var networkUpdate = new SubnetUpdateDefinition + { + Name = string.Format("{0}-updated", subnet.Name) + }; + + Trace.WriteLine("Updating the subnet..."); + subnet = await _networkingService.UpdateSubnetAsync(subnet.Id, networkUpdate); + + Trace.WriteLine("Verifying subnet was updated as requested..."); + Assert.NotNull(subnet); + Assert.Equal(networkUpdate.Name, subnet.Name); + } + + [Fact] + public async Task ListSubnetsTest() + { + var network = await _testData.CreateNetwork(); + var subnets = await _testData.CreateSubnets(network); + + Trace.WriteLine("Listing subnets..."); + var results = await _networkingService.ListSubnetsAsync(); + + Trace.WriteLine("Verifying list of subnets..."); + Assert.NotNull(results); + Assert.All(subnets, subnet => Assert.True(results.Any(x => x.Id == subnet.Id))); + } + + [Fact] + public async Task GetSubnetTest() + { + var network = await _testData.CreateNetwork(); + var subnet = await _testData.CreateSubnet(network); + + Trace.WriteLine("Retrieving subnet..."); + var result = await _networkingService.GetSubnetAsync(subnet.Id); + + Trace.WriteLine("Verifying subnet..."); + Assert.NotNull(result); + Assert.Equal(subnet.Id, result.Id); + + } + #endregion + + #region Ports + [Fact] + public async Task CreatePortTest() + { + var network = await _testData.CreateNetwork(); + var subnet = await _testData.CreateSubnet(network); + + var portIdAddress = subnet.CIDR.Replace("0/24", "2"); + var definition = new PortCreateDefinition(network.Id) + { + Name = TestData.GenerateName(), + DHCPOptions = + { + {"server-ip-address", "192.168.1.1"} + }, + AllowedAddresses = + { + new AllowedAddress("10.0.0.1") { MACAddress = "24:a0:74:f0:1c:66" } + }, + MACAddress = "24:a0:74:f0:1c:66", + FixedIPs = + { + new IPAddressAssociation(subnet.Id, portIdAddress) + } + }; + + Trace.WriteLine(string.Format("Creating port named: {0}", definition.Name)); + var port = await _testData.CreatePort(definition); + + Trace.WriteLine("Verifying port matches requested definition..."); + Assert.NotNull(port); + Assert.NotNull(port.Id); + Assert.Equal(definition.Name, port.Name); + Assert.Equal(definition.NetworkId, port.NetworkId); + Assert.Equal(definition.DHCPOptions, port.DHCPOptions); + Assert.Equal(definition.AllowedAddresses, port.AllowedAddresses); + Assert.Equal(subnet.Id, port.FixedIPs.Single().SubnetId); + Assert.Equal(portIdAddress, port.FixedIPs.Single().IPAddress); + } + + [Fact] + public async Task BulkCreatePortsTest() + { + var network = await _testData.CreateNetwork(); + var definitions = new[] { _testData.BuildPort(network), _testData.BuildPort(network), _testData.BuildPort(network) }; + + Trace.WriteLine(string.Format("Creating ports: {0}", string.Join(", ", definitions.Select(d => d.Name)))); + var subnets = await _testData.CreatePorts(definitions); + + Trace.WriteLine("Verifying ports matches requested definitions..."); + Assert.NotNull(subnets); + Assert.Equal(3, subnets.Count()); + } + + [Fact] + public async Task UpdatePortTest() + { + Network network = await _testData.CreateNetwork(); + Port port = await _testData.CreatePort(network); + + var portUpdate = new PortUpdateDefinition + { + Name = string.Format("{0}-updated", port.Name) + }; + + Trace.WriteLine("Updating the port..."); + port = await _networkingService.UpdatePortAsync(port.Id, portUpdate); + + Trace.WriteLine("Verifying port was updated as requested..."); + Assert.NotNull(port); + Assert.Equal(portUpdate.Name, port.Name); + } + + [Fact] + public async Task ListPortsTest() + { + var network = await _testData.CreateNetwork(); + var ports = await _testData.CreatePorts(network); + + Trace.WriteLine("Listing ports..."); + var results = await _networkingService.ListPortsAsync(); + + Trace.WriteLine("Verifying list of ports..."); + Assert.NotNull(results); + Assert.All(ports, port => Assert.True(results.Any(x => x.Id == port.Id))); + } + + [Fact] + public async Task GetPortTest() + { + var network = await _testData.CreateNetwork(); + var port = await _testData.CreatePort(network); + + Trace.WriteLine("Retrieving port..."); + var result = await _networkingService.GetPortAsync(port.Id); + + Trace.WriteLine("Verifying port..."); + Assert.NotNull(result); + Assert.Equal(port.Id, result.Id); + + } + #endregion + } +} diff --git a/src/OpenStack.IntegrationsTests/Networking/v2/NetworkingTestDataManager.cs b/src/OpenStack.IntegrationsTests/Networking/v2/NetworkingTestDataManager.cs new file mode 100644 index 000000000..34fbb2887 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/Networking/v2/NetworkingTestDataManager.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using OpenStack.Networking.v2.Layer3; + +namespace OpenStack.Networking.v2 +{ + public class NetworkingTestDataManager : IDisposable + { + private readonly NetworkingService _networkingService; + private readonly HashSet _testData; + + public NetworkingTestDataManager(NetworkingService networkingService) + { + _networkingService = networkingService; + _testData = new HashSet(); + } + + public void Register(IEnumerable testItems) + { + foreach (var testItem in testItems) + { + Register(testItem); + } + } + + public void Register(object testItem) + { + _testData.Add(testItem); + } + + public void Dispose() + { + var errors = new List(); + + try + { + DeleteFloatingIPs(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteRouters(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeletePorts(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteSubnets(_testData.OfType()); + } + catch (AggregateException ex) { errors.AddRange(ex.InnerExceptions); } + + try + { + DeleteNetworks(_testData.OfType()); + } + catch (AggregateException ex){ errors.AddRange(ex.InnerExceptions); } + + if (errors.Any()) + throw new AggregateException("Unable to remove all test data!", errors); + } + + #region Networks + public Operator.NetworkDefinition BuildNetwork() + { + return new Operator.NetworkDefinition + { + Name = TestData.GenerateName() + }; + } + + public async Task CreateNetwork() + { + var definition = BuildNetwork(); + return await CreateNetwork(definition); + } + + public async Task CreateNetwork(NetworkDefinition definition) + { + var network = await _networkingService.CreateNetworkAsync(definition); + Register(network); + return network; + } + + public async Task> CreateNetworks() + { + var definitions = new[] { BuildNetwork(), BuildNetwork(), BuildNetwork() }; + return await CreateNetworks(definitions); + } + + public async Task> CreateNetworks(IEnumerable definitions) + { + var networks = await _networkingService.CreateNetworksAsync(definitions); + Register(networks); + return networks; + } + + public void DeleteNetworks(IEnumerable networks) + { + var deletes = networks.Select(x => _networkingService.DeleteNetworkAsync(x.Id)).ToArray(); + Task.WaitAll(deletes); + } + #endregion + + #region Subnets + private static int _subnetCounter; + + public SubnetCreateDefinition BuildSubnet(Network network) + { + var cidr = $"192.168.{_subnetCounter++}.0/24"; + return new SubnetCreateDefinition(network.Id, IPVersion.IPv4, cidr) + { + Name = TestData.GenerateName() + }; + } + + public async Task CreateSubnet(Network network) + { + var definition = BuildSubnet(network); + return await CreateSubnet(definition); + } + + public async Task> CreateSubnets(Network network) + { + var definitions = new[] {BuildSubnet(network), BuildSubnet(network), BuildSubnet(network) }; + return await CreateSubnets(definitions); + } + + public async Task CreateSubnet(SubnetCreateDefinition definition) + { + var subnet = await _networkingService.CreateSubnetAsync(definition); + Register(subnet); + return subnet; + } + + public async Task> CreateSubnets(IEnumerable definitions) + { + var subnets = await _networkingService.CreateSubnetsAsync(definitions); + Register(subnets); + return subnets; + } + + public void DeleteSubnets(IEnumerable networks) + { + Task[] deletes = networks.Select(n => _networkingService.DeleteSubnetAsync(n.Id)).ToArray(); + Task.WaitAll(deletes); + } + #endregion + + #region Ports + public PortCreateDefinition BuildPort(Network network) + { + return new PortCreateDefinition(network.Id) + { + Name = TestData.GenerateName() + }; + } + + public async Task CreatePort(Network network) + { + var definition = BuildPort(network); + return await CreatePort(definition); + } + + public async Task CreatePort(PortCreateDefinition definition) + { + var port = await _networkingService.CreatePortAsync(definition); + Register(port); + return port; + } + + public async Task> CreatePorts(Network network) + { + var definitions = new[] { BuildPort(network), BuildPort(network), BuildPort(network) }; + return await CreatePorts(definitions); + } + + public async Task> CreatePorts(IEnumerable definitions) + { + var ports = await _networkingService.CreatePortsAsync(definitions); + Register(ports); + return ports; + } + + public void DeletePorts(IEnumerable ports) + { + Task[] deletes = ports.Select(x => _networkingService.DeletePortAsync(x.Id)).ToArray(); + Task.WaitAll(deletes); + } + #endregion + + #region Routers + + public void DeleteRouters(IEnumerable routers) + { + Task[] deletes = routers.Select(router => router.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + } + #endregion + + #region Floating IPs + + public void DeleteFloatingIPs(IEnumerable floatingIPs) + { + Task[] deletes = floatingIPs.Select(ip => ip.DeleteAsync()).ToArray(); + Task.WaitAll(deletes); + } + #endregion + } +} diff --git a/src/OpenStack.IntegrationsTests/ObjectStorage/CloudFilesProviderTests.cs b/src/OpenStack.IntegrationsTests/ObjectStorage/CloudFilesProviderTests.cs new file mode 100644 index 000000000..19034fd33 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/ObjectStorage/CloudFilesProviderTests.cs @@ -0,0 +1,86 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.Remoting; +using System.Text; +using net.openstack.Core.Exceptions.Response; +using OpenStack; +using Xunit; +using Xunit.Abstractions; + +namespace net.openstack.Providers.Rackspace +{ + public class CloudFilesTests + { + private const string region = "RegionOne"; + private readonly CloudFilesProvider _cloudFiles; + + public CloudFilesTests(ITestOutputHelper testLog) + { + var testOutput = new XunitTraceListener(testLog); + Trace.Listeners.Add(testOutput); + OpenStackNet.Tracing.Http.Listeners.Add(testOutput); + + var authenticationProvider = TestIdentityProvider.GetIdentityProvider(); + authenticationProvider.Authenticate(); + + _cloudFiles = new CloudFilesProvider(null, authenticationProvider); + } + + public void Dispose() + { + Trace.Listeners.Clear(); + OpenStackNet.Tracing.Http.Listeners.Clear(); + } + + [Fact] + public void MoveObject() + { + const string container = "test"; + const string fileName = "helloworld.html"; + const string backupName = "helloworld.bak"; + + // Remove old test data + try + { + _cloudFiles.DeleteObject(container, backupName, region: region); + } + catch (ItemNotFoundException) + { + } + + // Create test data + _cloudFiles.CreateContainer(container, region: region); + var testObject = new MemoryStream(Encoding.UTF8.GetBytes("hello world")); + _cloudFiles.CreateObject(container, testObject, fileName, region: region); + + // Backup the file + _cloudFiles.MoveObject(container, fileName, container, backupName, region: region); + + // Verify the file moved + var files = _cloudFiles.ListObjects(container, region: region); + Assert.False(files.Any(f => f.Name == fileName)); + Assert.True(files.Any(f => f.Name == backupName)); + } + + [Fact] + public void MoveObject_ShouldDoNothing_WhenSourceAndDestinationAreTheSame() + { + const string container = "test"; + const string filename = "helloworld.html"; + + // Create test data + _cloudFiles.CreateContainer(container, region: region); + var testObject = new MemoryStream(Encoding.UTF8.GetBytes("hello world")); + _cloudFiles.CreateObject(container, testObject, filename, region: region); + + // Move the file to the same location + _cloudFiles.MoveObject(container, filename, container, filename, region: region); + + // Verify the file wasn't removed + var files = _cloudFiles.ListObjects(container, region: region); + Assert.True(files.Any(f => f.Name == filename)); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/OpenStack.IntegrationsTests.csproj b/src/OpenStack.IntegrationsTests/OpenStack.IntegrationsTests.csproj new file mode 100644 index 000000000..bf8d5a8c5 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/OpenStack.IntegrationsTests.csproj @@ -0,0 +1,23 @@ + + + + net452 + + false + + + + + + + + + + + + + + + + + diff --git a/src/OpenStack.IntegrationsTests/TestData.cs b/src/OpenStack.IntegrationsTests/TestData.cs new file mode 100644 index 000000000..d59f20ee4 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/TestData.cs @@ -0,0 +1,12 @@ +using System; + +namespace OpenStack +{ + public static class TestData + { + public static string GenerateName() + { + return string.Format("ci-test-{0}", Guid.NewGuid()); + } + } +} diff --git a/src/OpenStack.IntegrationsTests/TestIdentityProvider.cs b/src/OpenStack.IntegrationsTests/TestIdentityProvider.cs new file mode 100644 index 000000000..44b7c4e49 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/TestIdentityProvider.cs @@ -0,0 +1,88 @@ +using System; +using System.Net.Http.Headers; +using net.openstack.Core.Domain; +using net.openstack.Core.Providers; + +namespace OpenStack +{ + public class TestIdentityProvider + { + private static readonly string EnvironmentVariablesNotFoundErrorMessage = + "No identity environment variables found. Make sure the following environment variables exist: " + Environment.NewLine + + "OPENSTACKNET_IDENTITY_URL" + Environment.NewLine + + "OPENSTACKNET_{0}USER" + Environment.NewLine + + "OPENSTACKNET_{0}PASSWORD" + Environment.NewLine + + "OPENSTACKNET_{0}PROJECT"; + + public static IIdentityProvider GetOperatorIdentity() + { + return GetIdentityProvider("OPERATOR"); + } + + public static IIdentityProvider GetIdentityProvider(string role = null) + { + var identity = GetIdentityFromEnvironment(role); + var identityEndpoint = GetIdentityEndpointFromEnvironment(); + return new OpenStackIdentityProvider(identityEndpoint, identity) + { + ApplicationUserAgent = new ProductInfoHeaderValue("(CI-BOT)").ToString() + }; + } + + public static Uri GetIdentityEndpointFromEnvironment() + { + var identityUrl = Environment.GetEnvironmentVariable("OPENSTACKNET_IDENTITY_URL"); + if(!string.IsNullOrEmpty(identityUrl)) + return new Uri(identityUrl); + + identityUrl = Environment.GetEnvironmentVariable("BAMBOO_OPENSTACKNET_IDENTITY_URL"); + if (!string.IsNullOrEmpty(identityUrl)) + return new Uri(identityUrl); + + throw new Exception(EnvironmentVariablesNotFoundErrorMessage); + } + + public static CloudIdentity GetIdentityFromEnvironment(string role = null) + { + string roleSuffix = null; + if (role != null) + roleSuffix = role + "_"; + + var user = Environment.GetEnvironmentVariable($"OPENSTACKNET_{roleSuffix}USER"); + if (!string.IsNullOrEmpty(user)) + { + var password = Environment.GetEnvironmentVariable($"OPENSTACKNET_{roleSuffix}PASSWORD"); + var projectName = Environment.GetEnvironmentVariable($"OPENSTACKNET_{roleSuffix}PROJECT"); + + if (!string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(projectName)) + { + return new CloudIdentityWithProject + { + Username = user, + Password = password, + ProjectName = projectName + }; + } + } + + user = Environment.GetEnvironmentVariable($"BAMBOO_OPENSTACKNET_{roleSuffix}USER"); + if (!string.IsNullOrEmpty(user)) + { + var password = Environment.GetEnvironmentVariable($"BAMBOO_OPENSTACKNET_{roleSuffix}PASSWORD"); + var projectName = Environment.GetEnvironmentVariable($"BAMBOO_OPENSTACKNET_{roleSuffix}PROJECT"); + + if (!string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(projectName)) + { + return new CloudIdentityWithProject + { + Username = user, + Password = password, + ProjectName = projectName + }; + } + } + + throw new Exception(string.Format(EnvironmentVariablesNotFoundErrorMessage, roleSuffix)); + } + } +} \ No newline at end of file diff --git a/src/OpenStack.IntegrationsTests/XunitTraceListener.cs b/src/OpenStack.IntegrationsTests/XunitTraceListener.cs new file mode 100644 index 000000000..85bb1a9a2 --- /dev/null +++ b/src/OpenStack.IntegrationsTests/XunitTraceListener.cs @@ -0,0 +1,41 @@ +using System; +using System.Diagnostics; +using Xunit.Abstractions; + +namespace OpenStack +{ + public class XunitTraceListener : TraceListener + { + private readonly ITestOutputHelper _testLog; + + public XunitTraceListener(ITestOutputHelper testLog) + { + _testLog = testLog; + } + + public override void Write(string message) + { + if (message.StartsWith(OpenStackNet.Tracing.Http.Name)) + return; + + TryLog(message); + } + + public override void WriteLine(string message) + { + TryLog(message); + } + + private void TryLog(string message) + { + try + { + _testLog.WriteLine(message); + } + catch (InvalidOperationException) + { + // Unable to log to xunit because it thinks no test is active... + } + } + } +} diff --git a/src/corelib/OpenStack.old.csproj b/src/corelib/OpenStack.old.csproj new file mode 100644 index 000000000..557b01642 --- /dev/null +++ b/src/corelib/OpenStack.old.csproj @@ -0,0 +1,1265 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {1A4FB67F-8642-4402-B931-118955AE7538} + Library + Properties + OpenStack + openstacknet + v4.5 + 512 + obj\v4.0\ + ..\ + + + + true + full + false + bin\v4.0\Debug\ + DEBUG;TRACE + prompt + 4 + bin\v4.0\Debug\openstacknet.xml + false + true + 612,618 + + + pdbonly + true + bin\v4.0\Release\ + TRACE + prompt + 4 + bin\v4.0\Release\openstacknet.xml + false + true + + + true + + + ..\..\build\keys\OpenStackNetV1.snk + ..\..\build\keys\OpenStackNetV1.dev.snk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OpenStackNetV1.dev.snk + + + OpenStackNetV1.snk + + + + + + + + + + + + + + + + ..\..\packages\Flurl.Http.Signed\lib\net45\Flurl.Http.dll + True + True + + + + + + + ..\..\packages\Flurl.Http.Signed\lib\portable-net45+sl50+win+wpa81+wp80\Flurl.Http.dll + True + True + + + + + + + + + ..\..\packages\Flurl.Signed\lib\portable-net40+sl50+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Flurl.dll + True + True + + + + + + + True + + + + + + + ..\..\packages\Marvin.JsonPatch.Signed\lib\portable-net40+win+wpa81\Marvin.JsonPatch.dll + True + True + + + + + + + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.IO.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.Runtime.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.IO.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.Runtime.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.IO.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.Runtime.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.IO.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.Runtime.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.IO.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.Runtime.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.IO.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.Runtime.dll + True + True + + + ..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.Threading.Tasks.dll + True + True + + + + + + + + + ..\..\packages\Microsoft.Bcl.Async\lib\portable-net40+sl4+win8+wp71+wpa81\Microsoft.Threading.Tasks.dll + True + True + + + ..\..\packages\Microsoft.Bcl.Async\lib\portable-net40+sl4+win8+wp71+wpa81\Microsoft.Threading.Tasks.Extensions.dll + True + True + + + + + + + ..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.dll + True + True + + + ..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.Extensions.dll + True + True + + + + + + + ..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wpa81\Microsoft.Threading.Tasks.dll + True + True + + + ..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wpa81\Microsoft.Threading.Tasks.Extensions.dll + True + True + + + + + + + + + ..\..\packages\Microsoft.Net.Http\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Extensions.dll + True + True + + + ..\..\packages\Microsoft.Net.Http\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Primitives.dll + True + True + + + + + + + ..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8\System.Net.Http.Extensions.dll + True + True + + + ..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8\System.Net.Http.Primitives.dll + True + True + + + + + + + ..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8+wpa81\System.Net.Http.Extensions.dll + True + True + + + ..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8+wpa81\System.Net.Http.Primitives.dll + True + True + + + + + + + + + ..\..\packages\Newtonsoft.Json\lib\net20\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\net35\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\netcore45\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Newtonsoft.Json.dll + True + True + + + + + + + + + ..\..\packages\PCLStorage\lib\portable-net45+sl5+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll + True + True + + + ..\..\packages\PCLStorage\lib\portable-net45+sl5+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll + True + True + + + + + + + ..\..\packages\PCLStorage\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll + True + True + + + ..\..\packages\PCLStorage\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll + True + True + + + + + + + ..\..\packages\PCLStorage\lib\portable-win8+wpa81\PCLStorage.dll + True + True + + + ..\..\packages\PCLStorage\lib\portable-win8+wpa81\PCLStorage.Abstractions.dll + True + True + + + + + + + + + ..\..\packages\SimpleRESTServices\lib\net35\SimpleRESTServices.dll + True + True + + + + + + + ..\..\packages\SimpleRESTServices\lib\net40\SimpleRESTServices.dll + True + True + + + + + \ No newline at end of file diff --git a/src/openstack.net.sln b/src/openstack.net.sln index 28e7467ee..4ead482ae 100644 --- a/src/openstack.net.sln +++ b/src/openstack.net.sln @@ -27,11 +27,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.old", "corelib\Op EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.UnitTests.old", "testing\unit\OpenStack.UnitTests.old.csproj", "{AC3D4496-F18B-4907-9FEB-E87F9C6CB7E4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.IntegrationTests", "testing\integration\OpenStack.IntegrationTests.csproj", "{0C731980-8780-4F9B-9D14-DED790FD649A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.IntegrationTests.old", "testing\integration\OpenStack.IntegrationTests.old.csproj", "{0C731980-8780-4F9B-9D14-DED790FD649A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenStack", "OpenStack\OpenStack.csproj", "{DD4A67AA-32F0-4FB4-A230-C37ED8CF57B7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.UnitTests", "OpenStack.UnitTests\OpenStack.UnitTests.csproj", "{010E0D43-1B48-447E-8DBD-FDC1F1197AE3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenStack.UnitTests", "OpenStack.UnitTests\OpenStack.UnitTests.csproj", "{010E0D43-1B48-447E-8DBD-FDC1F1197AE3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenStack.IntegrationsTests", "OpenStack.IntegrationsTests\OpenStack.IntegrationsTests.csproj", "{8C7859AA-FBDA-443F-9501-08B476CBB320}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -81,6 +83,14 @@ Global {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Release|Any CPU.Build.0 = Release|Any CPU {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {010E0D43-1B48-447E-8DBD-FDC1F1197AE3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8C7859AA-FBDA-443F-9501-08B476CBB320}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C7859AA-FBDA-443F-9501-08B476CBB320}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C7859AA-FBDA-443F-9501-08B476CBB320}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8C7859AA-FBDA-443F-9501-08B476CBB320}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8C7859AA-FBDA-443F-9501-08B476CBB320}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C7859AA-FBDA-443F-9501-08B476CBB320}.Release|Any CPU.Build.0 = Release|Any CPU + {8C7859AA-FBDA-443F-9501-08B476CBB320}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8C7859AA-FBDA-443F-9501-08B476CBB320}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/testing/integration/OpenStack.IntegrationTests.csproj b/src/testing/integration/OpenStack.IntegrationTests.old.csproj similarity index 100% rename from src/testing/integration/OpenStack.IntegrationTests.csproj rename to src/testing/integration/OpenStack.IntegrationTests.old.csproj diff --git a/src/testing/unit/OpenStack.UnitTests.old.csproj b/src/testing/unit/OpenStack.UnitTests.old.csproj new file mode 100644 index 000000000..fd33d1592 --- /dev/null +++ b/src/testing/unit/OpenStack.UnitTests.old.csproj @@ -0,0 +1,698 @@ + + + + Debug + AnyCPU + + + 2.0 + {AC3D4496-F18B-4907-9FEB-E87F9C6CB7E4} + Library + Properties + OpenStack + OpenStackNet.Testing.Unit + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + 73bfe604 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + true + + + ..\..\..\build\keys\SDKTestingKey.snk + + + + + + + 3.5 + + + + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SDKTestingKey.snk + + + + + + + {dd4a67aa-32f0-4fb4-a230-c37ed8cf57b7} + OpenStack + + + + + + + <__paket__xunit_runner_visualstudio_props>net20\xunit.runner.visualstudio + + + + + <__paket__xunit_runner_visualstudio_props>portable-net45+win8+wp8+wpa81\xunit.runner.visualstudio + + + + + <__paket__xunit_runner_visualstudio_props>uap10.0\xunit.runner.visualstudio + <__paket__xunit_runner_visualstudio_targets>uap10.0\xunit.runner.visualstudio + + + + + <__paket__xunit_runner_visualstudio_props>win81\xunit.runner.visualstudio + <__paket__xunit_runner_visualstudio_targets>win81\xunit.runner.visualstudio + + + + + <__paket__xunit_runner_visualstudio_props>wpa81\xunit.runner.visualstudio + <__paket__xunit_runner_visualstudio_targets>wpa81\xunit.runner.visualstudio + + + + + + + + <__paket__xunit_core_props>portable-net45+win8+wp8+wpa81\xunit.core + + + + + <__paket__xunit_core_props>win81\xunit.core + + + + + <__paket__xunit_core_props>wpa81\xunit.core + + + + + + + + + + + ..\..\..\packages\Flurl.Http.Signed\lib\net45\Flurl.Http.dll + True + True + + + + + + + ..\..\..\packages\Flurl.Http.Signed\lib\portable-net45+sl50+win+wpa81+wp80\Flurl.Http.dll + True + True + + + + + + + + + ..\..\..\packages\Flurl.Signed\lib\portable-net40+sl50+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Flurl.dll + True + True + + + + + + + + + ..\..\..\packages\Marvin.JsonPatch.Signed\lib\portable-net40+win+wpa81\Marvin.JsonPatch.dll + True + True + + + + + + + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.IO.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.Runtime.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.IO.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.Runtime.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp71+wpa81\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.IO.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.Runtime.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl4+win8+wp8+wpa81\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.IO.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.Runtime.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8+wpa81\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.IO.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.Runtime.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8\System.Threading.Tasks.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.IO.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.Runtime.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl\lib\portable-net40+win8+wp8+wpa81\System.Threading.Tasks.dll + True + True + + + + + + + + + ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net40+sl4+win8+wp71+wpa81\Microsoft.Threading.Tasks.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net40+sl4+win8+wp71+wpa81\Microsoft.Threading.Tasks.Extensions.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.Extensions.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wpa81\Microsoft.Threading.Tasks.dll + True + True + + + ..\..\..\packages\Microsoft.Bcl.Async\lib\portable-net45+win8+wpa81\Microsoft.Threading.Tasks.Extensions.dll + True + True + + + + + + + + + ..\..\..\packages\Microsoft.Net.Http\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Extensions.dll + True + True + + + ..\..\..\packages\Microsoft.Net.Http\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Primitives.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8\System.Net.Http.Extensions.dll + True + True + + + ..\..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8\System.Net.Http.Primitives.dll + True + True + + + + + + + ..\..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8+wpa81\System.Net.Http.Extensions.dll + True + True + + + ..\..\..\packages\Microsoft.Net.Http\lib\portable-net45+win8+wpa81\System.Net.Http.Primitives.dll + True + True + + + + + + + + + ..\..\..\packages\Moq\lib\net35\Moq.dll + True + True + + + + + + + ..\..\..\packages\Moq\lib\net40\Moq.dll + True + True + + + + + + + ..\..\..\packages\Moq\lib\sl5\Moq.Silverlight.dll + True + True + + + + + + + + + ..\..\..\packages\Newtonsoft.Json\lib\net20\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\..\packages\Newtonsoft.Json\lib\net35\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\..\packages\Newtonsoft.Json\lib\netcore45\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\..\packages\Newtonsoft.Json\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\..\packages\Newtonsoft.Json\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Newtonsoft.Json.dll + True + True + + + + + + + + + ..\..\..\packages\PCLStorage\lib\portable-net45+sl5+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll + True + True + + + ..\..\..\packages\PCLStorage\lib\portable-net45+sl5+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll + True + True + + + + + + + ..\..\..\packages\PCLStorage\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll + True + True + + + ..\..\..\packages\PCLStorage\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll + True + True + + + + + + + ..\..\..\packages\PCLStorage\lib\portable-win8+wpa81\PCLStorage.dll + True + True + + + ..\..\..\packages\PCLStorage\lib\portable-win8+wpa81\PCLStorage.Abstractions.dll + True + True + + + + + + + + + ..\..\..\packages\SimpleRESTServices\lib\net35\SimpleRESTServices.dll + True + True + + + + + + + ..\..\..\packages\SimpleRESTServices\lib\net40\SimpleRESTServices.dll + True + True + + + + + + + + + ..\..\..\packages\xunit.abstractions\lib\net35\xunit.abstractions.dll + True + True + + + + + + + ..\..\..\packages\xunit.abstractions\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.abstractions.dll + True + True + + + + + + + + + ..\..\..\packages\xunit.assert\lib\portable-net45+win8+wp8+wpa81\xunit.assert.dll + True + True + + + + + + + + + ..\..\..\packages\xunit.extensibility.core\lib\portable-net45+win8+wp8+wpa81\xunit.core.dll + True + True + + + + + + + + + ..\..\..\packages\xunit.extensibility.execution\lib\monoandroid\xunit.execution.dotnet.dll + True + True + + + + + + + ..\..\..\packages\xunit.extensibility.execution\lib\monotouch\xunit.execution.dotnet.dll + True + True + + + + + + + ..\..\..\packages\xunit.extensibility.execution\lib\net45\xunit.execution.desktop.dll + True + True + + + + + + + ..\..\..\packages\xunit.extensibility.execution\lib\portable-net45+win8+wp8+wpa81\xunit.execution.dotnet.dll + True + True + + + + + + + ..\..\..\packages\xunit.extensibility.execution\lib\win8\xunit.execution.dotnet.dll + True + True + + + + + + + ..\..\..\packages\xunit.extensibility.execution\lib\wp8\xunit.execution.dotnet.dll + True + True + + + + + + + ..\..\..\packages\xunit.extensibility.execution\lib\wpa81\xunit.execution.dotnet.dll + True + True + + + + + + + ..\..\..\packages\xunit.extensibility.execution\lib\xamarinios\xunit.execution.dotnet.dll + True + True + + + + + + \ No newline at end of file