Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ require (

replace (
github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2
github.com/microsoft/moc => github.com/arg5739/moc v0.37.1-0.20251030202049-256cd7317066
github.com/miekg/dns => github.com/miekg/dns v1.1.25
golang.org/x/crypto => golang.org/x/crypto v0.37.0
golang.org/x/image => golang.org/x/image v0.23.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ code.cloudfoundry.org/bytefmt v0.53.0/go.mod h1:q/Fu9SYbYx4sZLJSrJxipQYJUsyx8wpF
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/arg5739/moc v0.37.1-0.20251030202049-256cd7317066 h1:8y05U5bVlk8l0ev/N97p5/t6f0SVOTkZ8NPFamFf1ok=
github.com/arg5739/moc v0.37.1-0.20251030202049-256cd7317066/go.mod h1:ZCe9fB0fehR5q+xKWVq7uNhvx+mAuHKFz4srsUVp/P8=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
Expand Down Expand Up @@ -72,8 +74,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/microsoft/moc v0.35.5 h1:3Kl83HXK0iAP6B1SMSSypBK75S+pwbuzJPrjUqwzkUk=
github.com/microsoft/moc v0.35.5/go.mod h1:lF4GKU8OLgqWmOCmu7qLXc/CAqY1Svr5TNsSRLqbt+U=
github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw=
github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
Expand Down
10 changes: 10 additions & 0 deletions services/compute/virtualmachine/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Service interface {
Hydrate(context.Context, string, string, *compute.VirtualMachine) (*compute.VirtualMachine, error)
Start(context.Context, string, string) error
Stop(context.Context, string, string) error
Poweroff(context.Context, string, string, bool) error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should align the naming. If we are going to call it Stop_Graceful in the protobuf, we should call it StopGraceful in the interface.

I realize this is inconsistent with the naming in the upstream arm api but we can do something like

PowerOff arm api -> StopGraceful MOC api
PowerOff SkipShutdown arm api -> Stop MOC api

but naming should be consistent in the moc bubble.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't even think we need to expand the interface, just add a flag to Stop to indicate for skipshutdown.

we are doing a bit of a slow rollout api replacement in the arm api where poweroff will replace stop but it is not necessary in the MOC api's where we can just outright modify the behavior of the stop api because we control the call pattern.

i.e. all arm STOP calls STOP with skip shutdown to true.
all arm poweroff calls STOP and can toggle skipshutdown based on their paramaterization.

Pause(context.Context, string, string) error
Save(context.Context, string, string) error
RemoveIsoDisk(context.Context, string, string) error
Expand Down Expand Up @@ -74,6 +75,15 @@ func (c *VirtualMachineClient) Stop(ctx context.Context, group string, name stri
err = c.internal.Stop(ctx, group, name)
return
}

// Poweroff initiates a VM shutdown operation
// skipShutdown: false (default/recommended) = graceful shutdown with guest OS notification
//
// true = force immediate shutdown (not recommended, may cause data loss)
func (c *VirtualMachineClient) Poweroff(ctx context.Context, group string, name string, skipShutdown bool) (err error) {
err = c.internal.Poweroff(ctx, group, name, skipShutdown)
return
}
func (c *VirtualMachineClient) Restart(ctx context.Context, group string, name string) (err error) {
err = c.internal.Stop(ctx, group, name)
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions services/compute/virtualmachine/internal/wssd.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ func (c *client) Stop(ctx context.Context, group, name string) (err error) {
return
}

// Poweroff performs a graceful shutdown of the VM
// skipShutdown: false (default) = graceful shutdown, true = force immediate shutdown
func (c *client) Poweroff(ctx context.Context, group, name string, skipShutdown bool) (err error) {
request, err := c.getVirtualMachineOperationRequestForPowerOff(ctx, wssdcommonproto.VirtualMachineOperation_STOP_GRACEFUL, name, skipShutdown)
if err != nil {
return
}
_, err = c.VirtualMachineAgentClient.Operate(ctx, request)
return
}

func (c *client) Pause(ctx context.Context, group, name string) (err error) {
request, err := c.getVirtualMachineOperationRequest(ctx, wssdcommonproto.VirtualMachineOperation_PAUSE, name)
if err != nil {
Expand Down Expand Up @@ -240,6 +251,23 @@ func (c *client) getVirtualMachineOperationRequest(ctx context.Context, opType w
return
}

func (c *client) getVirtualMachineOperationRequestForPowerOff(ctx context.Context, opType wssdcommonproto.VirtualMachineOperation, name string, skipShutdown bool) (request *wssdcompute.VirtualMachineOperationRequest, err error) {
vms, err := c.get(ctx, "", name)
if err != nil {
return
}

// skipShutdown = false (default): graceful shutdown with guest OS notification
// skipShutdown = true: immediate force shutdown
request = &wssdcompute.VirtualMachineOperationRequest{
OperationType: opType,
VirtualMachines: vms,
SkipShutdown: skipShutdown, // Defaults to false when not explicitly set
}

return
}

func (c *client) getVirtualMachineRunCommandRequest(ctx context.Context, group, name string, request *compute.VirtualMachineRunCommandRequest) (mocRequest *wssdcompute.VirtualMachineRunCommandRequest, err error) {
vms, err := c.get(ctx, group, name)
if err != nil {
Expand Down
Loading