Skip to content

Commit 50f9994

Browse files
committed
Merge pull request #602 from carolynvs/missing-userlevel-server-actions
Support Suspend/Resume Server
2 parents d2093d0 + dfcba0c commit 50f9994

9 files changed

Lines changed: 115 additions & 35 deletions

File tree

src/corelib/Compute/v2_1/Actions/StartServerRequest.cs

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/corelib/Compute/v2_1/Actions/StopServerRequest.cs

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/corelib/Compute/v2_1/ComputeService.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ public ComputeService(IAuthenticationProvider authenticationProvider, string reg
134134
return _computeApi.StopServerAsync(serverId, cancellationToken);
135135
}
136136

137+
/// <inheritdoc cref="ComputeApi.SuspendServerAsync" />
138+
public Task SuspendServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken))
139+
{
140+
return _computeApi.SuspendServerAsync(serverId, cancellationToken);
141+
}
142+
143+
/// <inheritdoc cref="ComputeApi.ResumeServerAsync" />
144+
public Task ResumeServerAsync(Identifier serverId, CancellationToken cancellationToken = default(CancellationToken))
145+
{
146+
return _computeApi.ResumeServerAsync(serverId, cancellationToken);
147+
}
148+
137149
/// <inheritdoc cref="ComputeApi.RebootServerAsync{TRequest}" />
138150
public Task RebootServerAsync(Identifier serverId, RebootServerRequest request = null, CancellationToken cancellationToken = default(CancellationToken))
139151
{

src/corelib/Compute/v2_1/Serialization/ComputeApi.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ protected ComputeApi(IServiceType serviceType, IAuthenticationProvider authentic
539539
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
540540
public virtual Task StartServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken))
541541
{
542-
var request = new StartServerRequest();
542+
var request = new Dictionary<string, object> {["os-start"] = "" };
543543
return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync();
544544
}
545545

@@ -550,7 +550,29 @@ protected ComputeApi(IServiceType serviceType, IAuthenticationProvider authentic
550550
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
551551
public virtual Task StopServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken))
552552
{
553-
var request = new StopServerRequest();
553+
var request = new Dictionary<string, object> {["os-stop"] = "" };
554+
return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync();
555+
}
556+
557+
/// <summary>
558+
/// Suspends a server and changes its status to SUSPENDED.
559+
/// </summary>
560+
/// <param name="serverId">The server identifier.</param>
561+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
562+
public virtual Task SuspendServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken))
563+
{
564+
var request = new Dictionary<string, object> {["suspend"] = "" };
565+
return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync();
566+
}
567+
568+
/// <summary>
569+
/// Resumes a suspended server and changes its status to ACTIVE.
570+
/// </summary>
571+
/// <param name="serverId">The server identifier.</param>
572+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
573+
public virtual Task ResumeServerAsync(string serverId, CancellationToken cancellationToken = default(CancellationToken))
574+
{
575+
var request = new Dictionary<string, object> {["resume"] = "" };
554576
return BuildServerActionRequest(serverId, request, cancellationToken).SendAsync();
555577
}
556578

src/corelib/Compute/v2_1/ServerExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ public static void Stop(this ServerReference server)
9595
server.StopAsync().ForceSynchronous();
9696
}
9797

98+
/// <inheritdoc cref="ServerReference.SuspendAsync"/>
99+
public static void Suspend(this ServerReference server)
100+
{
101+
server.SuspendAsync().ForceSynchronous();
102+
}
103+
104+
/// <inheritdoc cref="ServerReference.ResumeAsync"/>
105+
public static void Resume(this ServerReference server)
106+
{
107+
server.ResumeAsync().ForceSynchronous();
108+
}
109+
98110
/// <inheritdoc cref="ServerReference.RebootAsync"/>
99111
public static void Reboot(this ServerReference server, RebootServerRequest request = null)
100112
{

src/corelib/Compute/v2_1/ServerReference.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ public class ServerReference : IHaveExtraData, IServiceResource
103103
await compute.StopServerAsync(Id, cancellationToken).ConfigureAwait(false);
104104
}
105105

106+
/// <inheritdoc cref="ComputeApi.SuspendServerAsync" />
107+
/// <exception cref="InvalidOperationException">When this instance was not constructed by the <see cref="ComputeService"/>, as it is missing the appropriate internal state to execute service calls.</exception>
108+
public async Task SuspendAsync(CancellationToken cancellationToken = default(CancellationToken))
109+
{
110+
var compute = this.GetOwnerOrThrow<ComputeApi>();
111+
await compute.SuspendServerAsync(Id, cancellationToken).ConfigureAwait(false);
112+
}
113+
114+
/// <inheritdoc cref="ComputeApi.ResumeServerAsync" />
115+
/// <exception cref="InvalidOperationException">When this instance was not constructed by the <see cref="ComputeService"/>, as it is missing the appropriate internal state to execute service calls.</exception>
116+
public async Task ResumeAsync(CancellationToken cancellationToken = default(CancellationToken))
117+
{
118+
var compute = this.GetOwnerOrThrow<ComputeApi>();
119+
await compute.ResumeServerAsync(Id, cancellationToken).ConfigureAwait(false);
120+
}
121+
106122
/// <inheritdoc cref="ComputeApi.RebootServerAsync{T}" />
107123
/// <exception cref="InvalidOperationException">When this instance was not constructed by the <see cref="ComputeService"/>, as it is missing the appropriate internal state to execute service calls.</exception>
108124
public async Task RebootAsync(RebootServerRequest request = null, CancellationToken cancellationToken = default(CancellationToken))

src/corelib/OpenStack.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@
9292
<Compile Include="Compute\v2_1\Actions\RebootServerRequest.cs" />
9393
<Compile Include="Compute\v2_1\Actions\RebootType.cs" />
9494
<Compile Include="Compute\v2_1\Actions\SnapshotServerRequest.cs" />
95-
<Compile Include="Compute\v2_1\Actions\StartServerRequest.cs" />
96-
<Compile Include="Compute\v2_1\Actions\StopServerRequest.cs" />
9795
<Compile Include="Compute\v2_1\AddressType.cs" />
9896
<Compile Include="Compute\v2_1\Flavor.cs" />
9997
<Compile Include="Compute\v2_1\FlavorReference.cs" />

src/testing/integration/Compute/v2_1/ServerTests.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,23 @@ public async Task RebootServerTest()
323323
await server.WaitForStatusAsync(ServerStatus.Reboot);
324324
await server.WaitUntilActiveAsync();
325325
}
326-
326+
327+
[Fact]
328+
public async Task ResumeServerTest()
329+
{
330+
Trace.WriteLine("Creating server...");
331+
var server = await _testData.CreateServer();
332+
await server.WaitUntilActiveAsync();
333+
334+
Trace.WriteLine("Suspending the server...");
335+
await server.SuspendAsync();
336+
await server.WaitForStatusAsync(ServerStatus.Suspended);
337+
338+
Trace.WriteLine("Resuming the server...");
339+
await server.ResumeAsync();
340+
await server.WaitUntilActiveAsync();
341+
}
342+
327343
[Fact]
328344
public async Task ServerVolumesTest()
329345
{

src/testing/unit/Compute/v2_1/ServerTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,40 @@ public void StopServer()
484484
}
485485
}
486486

487+
[Fact]
488+
public void SuspendServer()
489+
{
490+
using (var httpTest = new HttpTest())
491+
{
492+
Identifier serverId = Guid.NewGuid();
493+
httpTest.RespondWithJson(new Server { Id = serverId });
494+
httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss");
495+
496+
var server = _compute.GetServer(serverId);
497+
server.Suspend();
498+
499+
httpTest.ShouldHaveCalled($"*/servers/{serverId}/action");
500+
Assert.True(httpTest.CallLog.Last().RequestBody.Contains("suspend"));
501+
}
502+
}
503+
504+
[Fact]
505+
public void ResumeServer()
506+
{
507+
using (var httpTest = new HttpTest())
508+
{
509+
Identifier serverId = Guid.NewGuid();
510+
httpTest.RespondWithJson(new Server { Id = serverId });
511+
httpTest.RespondWith((int)HttpStatusCode.Accepted, "Roger that, boss");
512+
513+
var server = _compute.GetServer(serverId);
514+
server.Resume();
515+
516+
httpTest.ShouldHaveCalled($"*/servers/{serverId}/action");
517+
Assert.True(httpTest.CallLog.Last().RequestBody.Contains("resume"));
518+
}
519+
}
520+
487521
[Fact]
488522
public void RebootServer()
489523
{

0 commit comments

Comments
 (0)