Skip to content

Commit 9843d4c

Browse files
committed
Merge pull request #252 from sharwell/fix-240
Implement support and add remaining tests for load balancers features
2 parents 01c4163 + 58955a3 commit 9843d4c

8 files changed

Lines changed: 618 additions & 39 deletions

File tree

src/corelib/Providers/Rackspace/CloudLoadBalancerProvider.cs

Lines changed: 192 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using net.openstack.Providers.Rackspace.Objects.LoadBalancers.Request;
1515
using net.openstack.Providers.Rackspace.Objects.LoadBalancers.Response;
1616
using net.openstack.Providers.Rackspace.Validators;
17+
using Newtonsoft.Json.Linq;
1718
using CancellationToken = System.Threading.CancellationToken;
1819
using JsonRestServices = JSIStudios.SimpleRESTServices.Client.Json.JsonRestServices;
1920

@@ -945,25 +946,119 @@ public Task<IEnumerable<string>> ListAllowedDomainsAsync(CancellationToken cance
945946
/// <inheritdoc/>
946947
public Task<IEnumerable<LoadBalancer>> ListBillableLoadBalancersAsync(DateTimeOffset? startTime, DateTimeOffset? endTime, int? offset, int? limit, CancellationToken cancellationToken)
947948
{
948-
throw new NotImplementedException();
949+
if (endTime < startTime)
950+
throw new ArgumentOutOfRangeException("endTime");
951+
if (offset < 0)
952+
throw new ArgumentOutOfRangeException("offset");
953+
if (limit <= 0)
954+
throw new ArgumentOutOfRangeException("limit");
955+
956+
UriTemplate template = new UriTemplate("/loadbalancers/billable?startTime={startTime}&endTime={endTime}&offset={offset}&limit={limit}");
957+
var parameters = new Dictionary<string, string>();
958+
if (startTime != null)
959+
parameters.Add("startTime", startTime.Value.ToString("yyyy-MM-dd"));
960+
if (endTime != null)
961+
parameters.Add("endTime", endTime.Value.ToString("yyyy-MM-dd"));
962+
if (offset != null)
963+
parameters.Add("offset", offset.ToString());
964+
if (limit != null)
965+
parameters.Add("limit", limit.ToString());
966+
967+
Func<Task<Tuple<IdentityToken, Uri>>, HttpWebRequest> prepareRequest =
968+
PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters);
969+
970+
Func<Task<HttpWebRequest>, Task<ListLoadBalancersResponse>> requestResource =
971+
GetResponseAsyncFunc<ListLoadBalancersResponse>(cancellationToken);
972+
973+
Func<Task<ListLoadBalancersResponse>, IEnumerable<LoadBalancer>> resultSelector =
974+
task => (task.Result != null ? task.Result.LoadBalancers : null) ?? Enumerable.Empty<LoadBalancer>();
975+
976+
return AuthenticateServiceAsync(cancellationToken)
977+
.ContinueWith(prepareRequest)
978+
.ContinueWith(requestResource).Unwrap()
979+
.ContinueWith(resultSelector);
949980
}
950981

951982
/// <inheritdoc/>
952983
public Task<IEnumerable<LoadBalancerUsage>> ListAccountLevelUsageAsync(DateTimeOffset? startTime, DateTimeOffset? endTime, CancellationToken cancellationToken)
953984
{
954-
throw new NotImplementedException();
985+
if (endTime < startTime)
986+
throw new ArgumentOutOfRangeException("endTime");
987+
988+
UriTemplate template = new UriTemplate("/loadbalancers/usage?startTime={startTime}&endTime={endTime}");
989+
var parameters = new Dictionary<string, string>();
990+
if (startTime != null)
991+
parameters.Add("startTime", startTime.Value.ToString("yyyy-MM-dd"));
992+
if (endTime != null)
993+
parameters.Add("endTime", endTime.Value.ToString("yyyy-MM-dd"));
994+
995+
Func<Task<Tuple<IdentityToken, Uri>>, HttpWebRequest> prepareRequest =
996+
PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters);
997+
998+
Func<Task<HttpWebRequest>, Task<ListLoadBalancerUsageResponse>> requestResource =
999+
GetResponseAsyncFunc<ListLoadBalancerUsageResponse>(cancellationToken);
1000+
1001+
Func<Task<ListLoadBalancerUsageResponse>, IEnumerable<LoadBalancerUsage>> resultSelector =
1002+
task => (task.Result != null ? task.Result.UsageRecords : null) ?? Enumerable.Empty<LoadBalancerUsage>();
1003+
1004+
return AuthenticateServiceAsync(cancellationToken)
1005+
.ContinueWith(prepareRequest)
1006+
.ContinueWith(requestResource).Unwrap()
1007+
.ContinueWith(resultSelector);
9551008
}
9561009

9571010
/// <inheritdoc/>
958-
public Task<IEnumerable<LoadBalancerUsage>> ListHistoricalUsageAsync(LoadBalancerId loadBalancerId, DateTimeOffset? startTime, DateTimeOffset? endTime, CancellationToken cancellationToken1)
1011+
public Task<IEnumerable<LoadBalancerUsage>> ListHistoricalUsageAsync(LoadBalancerId loadBalancerId, DateTimeOffset? startTime, DateTimeOffset? endTime, CancellationToken cancellationToken)
9591012
{
960-
throw new NotImplementedException();
1013+
if (loadBalancerId == null)
1014+
throw new ArgumentNullException("loadBalancerId");
1015+
if (endTime < startTime)
1016+
throw new ArgumentOutOfRangeException("endTime");
1017+
1018+
UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/usage?startTime={startTime}&endTime={endTime}");
1019+
var parameters = new Dictionary<string, string> { { "loadBalancerId", loadBalancerId.Value } };
1020+
if (startTime != null)
1021+
parameters.Add("startTime", startTime.Value.ToString("yyyy-MM-dd"));
1022+
if (endTime != null)
1023+
parameters.Add("endTime", endTime.Value.ToString("yyyy-MM-dd"));
1024+
1025+
Func<Task<Tuple<IdentityToken, Uri>>, HttpWebRequest> prepareRequest =
1026+
PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters);
1027+
1028+
Func<Task<HttpWebRequest>, Task<ListLoadBalancerUsageResponse>> requestResource =
1029+
GetResponseAsyncFunc<ListLoadBalancerUsageResponse>(cancellationToken);
1030+
1031+
Func<Task<ListLoadBalancerUsageResponse>, IEnumerable<LoadBalancerUsage>> resultSelector =
1032+
task => (task.Result != null ? task.Result.UsageRecords : null) ?? Enumerable.Empty<LoadBalancerUsage>();
1033+
1034+
return AuthenticateServiceAsync(cancellationToken)
1035+
.ContinueWith(prepareRequest)
1036+
.ContinueWith(requestResource).Unwrap()
1037+
.ContinueWith(resultSelector);
9611038
}
9621039

9631040
/// <inheritdoc/>
9641041
public Task<IEnumerable<LoadBalancerUsage>> ListCurrentUsageAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken)
9651042
{
966-
throw new NotImplementedException();
1043+
if (loadBalancerId == null)
1044+
throw new ArgumentNullException("loadBalancerId");
1045+
1046+
UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/usage/current");
1047+
var parameters = new Dictionary<string, string> { { "loadBalancerId", loadBalancerId.Value } };
1048+
1049+
Func<Task<Tuple<IdentityToken, Uri>>, HttpWebRequest> prepareRequest =
1050+
PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters);
1051+
1052+
Func<Task<HttpWebRequest>, Task<ListLoadBalancerUsageResponse>> requestResource =
1053+
GetResponseAsyncFunc<ListLoadBalancerUsageResponse>(cancellationToken);
1054+
1055+
Func<Task<ListLoadBalancerUsageResponse>, IEnumerable<LoadBalancerUsage>> resultSelector =
1056+
task => (task.Result != null ? task.Result.UsageRecords : null) ?? Enumerable.Empty<LoadBalancerUsage>();
1057+
1058+
return AuthenticateServiceAsync(cancellationToken)
1059+
.ContinueWith(prepareRequest)
1060+
.ContinueWith(requestResource).Unwrap()
1061+
.ContinueWith(resultSelector);
9671062
}
9681063

9691064
/// <inheritdoc/>
@@ -1243,19 +1338,108 @@ public Task ClearAccessListAsync(LoadBalancerId loadBalancerId, AsyncCompletionO
12431338
/// <inheritdoc/>
12441339
public Task<HealthMonitor> GetHealthMonitorAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken)
12451340
{
1246-
throw new NotImplementedException();
1341+
if (loadBalancerId == null)
1342+
throw new ArgumentNullException("loadBalancerId");
1343+
1344+
UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/healthmonitor");
1345+
var parameters = new Dictionary<string, string>()
1346+
{
1347+
{ "loadBalancerId", loadBalancerId.Value }
1348+
};
1349+
1350+
Func<Task<Tuple<IdentityToken, Uri>>, HttpWebRequest> prepareRequest =
1351+
PrepareRequestAsyncFunc(HttpMethod.GET, template, parameters);
1352+
1353+
Func<Task<HttpWebRequest>, Task<JObject>> requestResource =
1354+
GetResponseAsyncFunc<JObject>(cancellationToken);
1355+
1356+
Func<Task<JObject>, HealthMonitor> resultSelector =
1357+
task =>
1358+
{
1359+
if (task.Result == null)
1360+
return null;
1361+
1362+
JObject healthMonitorObject = task.Result["healthMonitor"] as JObject;
1363+
if (healthMonitorObject == null)
1364+
return null;
1365+
1366+
return HealthMonitor.FromJObject(healthMonitorObject);
1367+
};
1368+
1369+
return AuthenticateServiceAsync(cancellationToken)
1370+
.ContinueWith(prepareRequest)
1371+
.ContinueWith(requestResource).Unwrap()
1372+
.ContinueWith(resultSelector);
12471373
}
12481374

12491375
/// <inheritdoc/>
12501376
public Task SetHealthMonitorAsync(LoadBalancerId loadBalancerId, HealthMonitor monitor, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress<LoadBalancer> progress)
12511377
{
1252-
throw new NotImplementedException();
1378+
if (loadBalancerId == null)
1379+
throw new ArgumentNullException("loadBalancerId");
1380+
if (monitor == null)
1381+
throw new ArgumentNullException("monitor");
1382+
1383+
UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/healthmonitor");
1384+
var parameters = new Dictionary<string, string>()
1385+
{
1386+
{ "loadBalancerId", loadBalancerId.Value }
1387+
};
1388+
1389+
Func<Task<Tuple<IdentityToken, Uri>>, Task<HttpWebRequest>> prepareRequest =
1390+
PrepareRequestAsyncFunc(HttpMethod.PUT, template, parameters, monitor);
1391+
1392+
Func<Task<HttpWebRequest>, Task<string>> requestResource =
1393+
GetResponseAsyncFunc(cancellationToken);
1394+
1395+
Func<Task<string>, Task<LoadBalancer>> resultSelector =
1396+
task =>
1397+
{
1398+
task.PropagateExceptions();
1399+
if (completionOption == AsyncCompletionOption.RequestCompleted)
1400+
return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress);
1401+
1402+
return InternalTaskExtensions.CompletedTask(default(LoadBalancer));
1403+
};
1404+
1405+
return AuthenticateServiceAsync(cancellationToken)
1406+
.ContinueWith(prepareRequest).Unwrap()
1407+
.ContinueWith(requestResource).Unwrap()
1408+
.ContinueWith(resultSelector).Unwrap();
12531409
}
12541410

12551411
/// <inheritdoc/>
12561412
public Task RemoveHealthMonitorAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress<LoadBalancer> progress)
12571413
{
1258-
throw new NotImplementedException();
1414+
if (loadBalancerId == null)
1415+
throw new ArgumentNullException("loadBalancerId");
1416+
1417+
UriTemplate template = new UriTemplate("/loadbalancers/{loadBalancerId}/healthmonitor");
1418+
var parameters = new Dictionary<string, string>()
1419+
{
1420+
{ "loadBalancerId", loadBalancerId.Value },
1421+
};
1422+
1423+
Func<Task<Tuple<IdentityToken, Uri>>, HttpWebRequest> prepareRequest =
1424+
PrepareRequestAsyncFunc(HttpMethod.DELETE, template, parameters);
1425+
1426+
Func<Task<HttpWebRequest>, Task<string>> requestResource =
1427+
GetResponseAsyncFunc(cancellationToken);
1428+
1429+
Func<Task<string>, Task<LoadBalancer>> resultSelector =
1430+
task =>
1431+
{
1432+
task.PropagateExceptions();
1433+
if (completionOption == AsyncCompletionOption.RequestCompleted)
1434+
return WaitForLoadBalancerToLeaveStateAsync(loadBalancerId, LoadBalancerStatus.PendingUpdate, cancellationToken, progress);
1435+
1436+
return InternalTaskExtensions.CompletedTask(default(LoadBalancer));
1437+
};
1438+
1439+
return AuthenticateServiceAsync(cancellationToken)
1440+
.ContinueWith(prepareRequest)
1441+
.ContinueWith(requestResource).Unwrap()
1442+
.ContinueWith(resultSelector).Unwrap();
12591443
}
12601444

12611445
/// <inheritdoc/>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace net.openstack.Providers.Rackspace.Objects.LoadBalancers
2+
{
3+
using Newtonsoft.Json;
4+
5+
/// <summary>
6+
/// This class models the JSON object used to represent a custom <see cref="HealthMonitor"/>.
7+
/// </summary>
8+
/// <threadsafety static="true" instance="false"/>
9+
/// <preliminary/>
10+
[JsonObject(MemberSerialization.OptIn)]
11+
public class CustomHealthMonitor : HealthMonitor
12+
{
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="CustomHealthMonitor"/> class
15+
/// during JSON deserialization.
16+
/// </summary>
17+
[JsonConstructor]
18+
protected CustomHealthMonitor()
19+
{
20+
}
21+
}
22+
}

src/corelib/Providers/Rackspace/Objects/LoadBalancers/HealthMonitor.cs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
using System;
44
using Newtonsoft.Json;
5+
using Newtonsoft.Json.Linq;
56

67
/// <summary>
78
/// This is the base class for load balancer health monitoring configurations.
@@ -13,7 +14,6 @@
1314
/// <threadsafety static="true" instance="false"/>
1415
/// <preliminary/>
1516
[JsonObject(MemberSerialization.OptIn)]
16-
[JsonConverter(typeof(HealthMonitor.Converter))]
1717
public abstract class HealthMonitor
1818
{
1919
/// <summary>
@@ -131,26 +131,28 @@ public int? AttemptsBeforeDeactivation
131131
}
132132
}
133133

134-
/// <inheritdoc/>
135-
protected class Converter : JsonConverter
134+
/// <summary>
135+
/// Deserializes a JSON object to a <see cref="HealthMonitor"/> instance of the proper type.
136+
/// </summary>
137+
/// <param name="jsonObject">The JSON object representing the health monitor.</param>
138+
/// <returns>A <see cref="HealthMonitor"/> object corresponding to the JSON object.</returns>
139+
/// <exception cref="ArgumentNullException">If <paramref name="jsonObject"/> is <c>null</c>.</exception>
140+
public static HealthMonitor FromJObject(JObject jsonObject)
136141
{
137-
/// <inheritdoc/>
138-
public override bool CanConvert(Type objectType)
139-
{
140-
throw new NotImplementedException();
141-
}
142-
143-
/// <inheritdoc/>
144-
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
145-
{
146-
throw new NotImplementedException();
147-
}
148-
149-
/// <inheritdoc/>
150-
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
151-
{
152-
throw new NotImplementedException();
153-
}
142+
if (jsonObject == null)
143+
throw new ArgumentNullException("jsonObject");
144+
145+
JValue typeValue = jsonObject["type"] as JValue;
146+
if (typeValue == null)
147+
return null;
148+
149+
HealthMonitorType type = typeValue.ToObject<HealthMonitorType>();
150+
if (type == HealthMonitorType.Connect)
151+
return jsonObject.ToObject<ConnectionHealthMonitor>();
152+
else if (type == HealthMonitorType.Http || type == HealthMonitorType.Https)
153+
return jsonObject.ToObject<WebServerHealthMonitor>();
154+
else
155+
return jsonObject.ToObject<CustomHealthMonitor>();
154156
}
155157
}
156158
}

src/corelib/Providers/Rackspace/Objects/LoadBalancers/LoadBalancerConfiguration`1.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.ObjectModel;
66
using System.Linq;
77
using Newtonsoft.Json;
8+
using Newtonsoft.Json.Linq;
89

910
/// <summary>
1011
/// Represents a load balancer configuration.
@@ -86,7 +87,7 @@ public class LoadBalancerConfiguration<TNodeConfiguration>
8687
/// This is the backing field for the <see cref="HealthMonitor"/> property.
8788
/// </summary>
8889
[JsonProperty("healthMonitor", DefaultValueHandling = DefaultValueHandling.Ignore)]
89-
private HealthMonitor _healthMonitor;
90+
private JObject _healthMonitor;
9091

9192
/// <summary>
9293
/// This is the backing field for the <see cref="Metadata"/> property.
@@ -190,7 +191,7 @@ public LoadBalancerConfiguration(string name, LoadBalancingProtocol protocol, IE
190191
if (contentCaching.HasValue)
191192
_contentCaching = contentCaching.Value ? LoadBalancerEnabledFlag.True : LoadBalancerEnabledFlag.False;
192193
_connectionThrottle = connectionThrottle;
193-
_healthMonitor = healthMonitor;
194+
_healthMonitor = healthMonitor != null ? JObject.FromObject(healthMonitor) : null;
194195
_metadata = metadata != null ? metadata.ToArray() : null;
195196
_timeout = timeout != null ? (int?)timeout.Value.TotalSeconds : null;
196197
_sessionPersistence = sessionPersistence;
@@ -340,7 +341,10 @@ public HealthMonitor HealthMonitor
340341
{
341342
get
342343
{
343-
return _healthMonitor;
344+
if (_healthMonitor == null)
345+
return null;
346+
347+
return HealthMonitor.FromJObject(_healthMonitor);
344348
}
345349
}
346350

0 commit comments

Comments
 (0)