Skip to content

Commit 58955a3

Browse files
committed
Implement support and tests for load balancer health monitors
1 parent 9fd7319 commit 58955a3

7 files changed

Lines changed: 342 additions & 26 deletions

File tree

src/corelib/Providers/Rackspace/CloudLoadBalancerProvider.cs

Lines changed: 93 additions & 3 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

@@ -1337,19 +1338,108 @@ public Task ClearAccessListAsync(LoadBalancerId loadBalancerId, AsyncCompletionO
13371338
/// <inheritdoc/>
13381339
public Task<HealthMonitor> GetHealthMonitorAsync(LoadBalancerId loadBalancerId, CancellationToken cancellationToken)
13391340
{
1340-
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);
13411373
}
13421374

13431375
/// <inheritdoc/>
13441376
public Task SetHealthMonitorAsync(LoadBalancerId loadBalancerId, HealthMonitor monitor, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress<LoadBalancer> progress)
13451377
{
1346-
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();
13471409
}
13481410

13491411
/// <inheritdoc/>
13501412
public Task RemoveHealthMonitorAsync(LoadBalancerId loadBalancerId, AsyncCompletionOption completionOption, CancellationToken cancellationToken, IProgress<LoadBalancer> progress)
13511413
{
1352-
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();
13531443
}
13541444

13551445
/// <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

src/corelib/corelib.v3.5.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@
236236
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\AccessType.cs" />
237237
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\ConnectionHealthMonitor.cs" />
238238
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\ConnectionThrottles.cs" />
239+
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\CustomHealthMonitor.cs" />
239240
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\HealthMonitor.cs" />
240241
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\HealthMonitorType.cs" />
241242
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\LoadBalancer.cs" />

src/corelib/corelib.v4.0.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@
227227
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\AccessType.cs" />
228228
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\ConnectionHealthMonitor.cs" />
229229
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\ConnectionThrottles.cs" />
230+
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\CustomHealthMonitor.cs" />
230231
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\HealthMonitor.cs" />
231232
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\HealthMonitorType.cs" />
232233
<Compile Include="Providers\Rackspace\Objects\LoadBalancers\LoadBalancer.cs" />

0 commit comments

Comments
 (0)