Skip to content

Commit

Permalink
VM, NIC and disk hydration (#225)
Browse files Browse the repository at this point in the history
* Hydration changes

---------

Co-authored-by: Katlyn Ho <[email protected]>
Co-authored-by: Katlyn Ho <[email protected]>
Co-authored-by: Neeraj Dixit <[email protected]>
Co-authored-by: neerajdixit-msft2 <[email protected]>
Co-authored-by: Yingxin Zhang <[email protected]>
  • Loading branch information
6 people authored Dec 14, 2024
1 parent b7681c6 commit a1f10af
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 20 deletions.
11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ require (
code.cloudfoundry.org/bytefmt v0.0.0-20210608160410-67692ebc98de
github.com/Azure/go-autorest/autorest v0.11.29
github.com/Azure/go-autorest/autorest/date v0.3.0
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
github.com/microsoft/moc v0.24.3
github.com/microsoft/moc v0.25.1
google.golang.org/grpc v1.62.1
k8s.io/klog v1.0.0
)
Expand Down Expand Up @@ -35,9 +36,9 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/text v0.20.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f // indirect
golang.org/x/net v0.32.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand All @@ -52,7 +53,7 @@ require (
github.com/stretchr/testify v1.9.0
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/sys v0.28.0 // indirect
google.golang.org/protobuf v1.35.2
)

Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/microsoft/moc v0.24.3 h1:t9J/Es0Fd9WTEKwy8boTwe5mwnxzxXgEOQorOCm3VCQ=
github.com/microsoft/moc v0.24.3/go.mod h1:nvYz7yZT6x+rRx/aEkswVTI2sa8AyAG9mZmWvXHk8cw=
github.com/microsoft/moc v0.25.1 h1:rhrP2f7VvqUxZKVMbDPFD9wprQtRKuF+zX93Ew7Zjl4=
github.com/microsoft/moc v0.25.1/go.mod h1:5C1DJUUtlOEw8AxWuVrUbge2z2oqkyvqmWi9PYzIo5g=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
Expand Down Expand Up @@ -155,8 +155,8 @@ golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
Expand All @@ -167,8 +167,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:C1QccEa9kUwvMgEUORqQD9S17QesQijxjZ84sO82mfo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
Expand Down
6 changes: 6 additions & 0 deletions services/compute/virtualmachine/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
type Service interface {
Get(context.Context, string, string) (*[]compute.VirtualMachine, error)
CreateOrUpdate(context.Context, string, string, *compute.VirtualMachine) (*compute.VirtualMachine, error)
Hydrate(context.Context, string, string, *compute.VirtualMachine) (*compute.VirtualMachine, error)
Delete(context.Context, string, string) error
Query(context.Context, string, string) (*[]compute.VirtualMachine, error)
Start(context.Context, string, string) error
Expand Down Expand Up @@ -60,6 +61,11 @@ func (c *VirtualMachineClient) CreateOrUpdate(ctx context.Context, group, name s
return c.internal.CreateOrUpdate(ctx, group, name, compute)
}

// Hydrate methods creates MOC representation of the VM resource
func (c *VirtualMachineClient) Hydrate(ctx context.Context, group, name string, compute *compute.VirtualMachine) (*compute.VirtualMachine, error) {
return c.internal.Hydrate(ctx, group, name, compute)
}

// Delete methods invokes delete of the compute resource
func (c *VirtualMachineClient) Delete(ctx context.Context, group string, name string) error {
return c.internal.Delete(ctx, group, name)
Expand Down
35 changes: 29 additions & 6 deletions services/compute/virtualmachine/virtualmachine.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package virtualmachine

import (
"github.com/google/go-cmp/cmp"
"github.com/microsoft/moc-sdk-for-go/services/compute"
"github.com/microsoft/moc/pkg/convert"
"github.com/microsoft/moc/pkg/errors"
Expand Down Expand Up @@ -559,13 +560,23 @@ func (c *client) getWssdVirtualMachineProxyConfiguration(proxyConfig *compute.Pr

// Conversion functions from wssdcloudcompute to compute

func (c *client) getVirtualMachine(vm *wssdcloudcompute.VirtualMachine, group string) *compute.VirtualMachine {
func (c *client) getVirtualMachine(vm *wssdcloudcompute.VirtualMachine) *compute.VirtualMachine {
if vm == nil {
return &compute.VirtualMachine{}
}

vmtype := compute.Tenant
if vm.VmType == wssdcloudcompute.VMType_LOADBALANCER {
vmtype = compute.LoadBalancer
} else if vm.VmType == wssdcloudcompute.VMType_STACKEDCONTROLPLANE {
vmtype = compute.StackedControlPlane
}

version := ""
if vm.Status != nil && vm.Status.Version != nil {
version = vm.Status.Version.Number
}

return &compute.VirtualMachine{
Name: &vm.Name,
ID: &vm.Id,
Expand All @@ -589,7 +600,7 @@ func (c *client) getVirtualMachine(vm *wssdcloudcompute.VirtualMachine, group st
PlacementGroupProfile: c.getPlacementGroupReference(vm.PlacementGroup),
Priority: vm.Priority,
},
Version: &vm.Status.Version.Number,
Version: &version,
Location: &vm.LocationName,
}
}
Expand Down Expand Up @@ -750,6 +761,10 @@ func (c *client) getVirtualMachineNetworkProfile(n *wssdcloudcompute.NetworkConf
NetworkInterfaces: &[]compute.NetworkInterfaceReference{},
}

if n == nil {
return np
}

for _, nic := range n.Interfaces {
if nic == nil {
continue
Expand Down Expand Up @@ -799,12 +814,12 @@ func (c *client) getVirtualMachineGuestInstanceView(g *wssdcommon.VirtualMachine
}

func (c *client) getVirtualMachineWindowsConfiguration(windowsConfiguration *wssdcloudcompute.WindowsConfiguration) *compute.WindowsConfiguration {
wc := &compute.WindowsConfiguration{
RDP: &compute.RDPConfiguration{},
if windowsConfiguration == nil || cmp.Equal(windowsConfiguration, wssdcloudcompute.WindowsConfiguration{}) {
return nil
}

if windowsConfiguration == nil {
return wc
wc := &compute.WindowsConfiguration{
RDP: &compute.RDPConfiguration{},
}

if windowsConfiguration.WinRMConfiguration != nil && len(windowsConfiguration.WinRMConfiguration.Listeners) >= 1 {
Expand Down Expand Up @@ -836,6 +851,10 @@ func (c *client) getVirtualMachineWindowsConfiguration(windowsConfiguration *wss
}

func (c *client) getVirtualMachineLinuxConfiguration(linuxConfiguration *wssdcloudcompute.LinuxConfiguration) *compute.LinuxConfiguration {
if linuxConfiguration == nil || cmp.Equal(linuxConfiguration, wssdcloudcompute.LinuxConfiguration{}) {
return nil
}

lc := &compute.LinuxConfiguration{}

if linuxConfiguration != nil {
Expand Down Expand Up @@ -866,6 +885,10 @@ func (c *client) getInstanceViewStatus(status *wssdcommon.InstanceViewStatus) *c
}

func (c *client) getVirtualMachineOSProfile(o *wssdcloudcompute.OperatingSystemConfiguration) *compute.OSProfile {
if o == nil {
return &compute.OSProfile{}
}

osType := compute.Windows
switch o.Ostype {
case wssdcommon.OperatingSystemType_LINUX:
Expand Down
20 changes: 19 additions & 1 deletion services/compute/virtualmachine/wssd.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,24 @@ func (c *client) CreateOrUpdate(ctx context.Context, group, name string, sg *com
return &(*vms)[0], nil
}

// Hydrate
func (c *client) Hydrate(ctx context.Context, group, name string, sg *compute.VirtualMachine) (*compute.VirtualMachine, error) {
request, err := c.getVirtualMachineRequest(wssdcloudproto.Operation_HYDRATE, group, name, sg)
if err != nil {
return nil, err
}
response, err := c.VirtualMachineAgentClient.Invoke(ctx, request)
if err != nil {
return nil, err
}
vms := c.getVirtualMachineFromResponse(response, group)
if len(*vms) == 0 {
return nil, fmt.Errorf("hydration of Virtual Machine failed to unknown reason")
}

return &(*vms)[0], nil
}

// Delete methods invokes create or update on the client
func (c *client) Delete(ctx context.Context, group, name string) error {
vm, err := c.Get(ctx, group, name)
Expand Down Expand Up @@ -327,7 +345,7 @@ func (c *client) getVirtualMachineRunCommandResponse(mocResponse *wssdcloudcompu
func (c *client) getVirtualMachineFromResponse(response *wssdcloudcompute.VirtualMachineResponse, group string) *[]compute.VirtualMachine {
vms := []compute.VirtualMachine{}
for _, vm := range response.GetVirtualMachines() {
vms = append(vms, *(c.getVirtualMachine(vm, group)))
vms = append(vms, *(c.getVirtualMachine(vm)))
}

return &vms
Expand Down
6 changes: 6 additions & 0 deletions services/network/networkinterface/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
type Service interface {
Get(context.Context, string, string) (*[]network.Interface, error)
CreateOrUpdate(context.Context, string, string, *network.Interface) (*network.Interface, error)
Hydrate(context.Context, string, string, *network.Interface) (*network.Interface, error)
Delete(context.Context, string, string) error
Precheck(ctx context.Context, group string, networkInterfaces []*network.Interface) (bool, error)
}
Expand Down Expand Up @@ -44,6 +45,11 @@ func (c *InterfaceClient) CreateOrUpdate(ctx context.Context, group, name string
return c.internal.CreateOrUpdate(ctx, group, name, networkInterface)
}

// Hydrate methods invokes hydrate on the client
func (c *InterfaceClient) Hydrate(ctx context.Context, group, name string, networkInterface *network.Interface) (*network.Interface, error) {
return c.internal.Hydrate(ctx, group, name, networkInterface)
}

// Delete methods invokes delete of the network interface resource
func (c *InterfaceClient) Delete(ctx context.Context, group, name string) error {
return c.internal.Delete(ctx, group, name)
Expand Down
11 changes: 10 additions & 1 deletion services/network/networkinterface/networkinterface.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,24 @@ func getWssdNetworkInterfaceIPConfig(ipConfig *network.InterfaceIPConfiguration,

// Conversion function from wssdcloud network interface to network interface
func getNetworkInterface(server, group string, c *wssdcloudnetwork.NetworkInterface) (*network.Interface, error) {
if c == nil {
return &network.Interface{}, nil
}

ipConfigs := []network.InterfaceIPConfiguration{}
for _, wssdipconfig := range c.IpConfigurations {
ipConfigs = append(ipConfigs, *(getNetworkIpConfig(wssdipconfig)))
}

version := ""
if c.Status != nil && c.Status.Version != nil {
version = c.Status.Version.Number
}

vnetIntf := &network.Interface{
Name: &c.Name,
ID: &c.Id,
Version: &c.Status.Version.Number,
Version: &version,
InterfacePropertiesFormat: &network.InterfacePropertiesFormat{
MacAddress: &c.Macaddress,
// TODO: Type
Expand Down
18 changes: 18 additions & 0 deletions services/network/networkinterface/wssd.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,24 @@ func (c *client) CreateOrUpdate(ctx context.Context, group, name string, vnetInt
return &(*vnets)[0], nil
}

// Hydrate
func (c *client) Hydrate(ctx context.Context, group, name string, networkInterface *network.Interface) (*network.Interface, error) {
request, err := c.getNetworkInterfaceRequest(wssdcloudcommon.Operation_HYDRATE, group, name, networkInterface)
if err != nil {
return nil, err
}
response, err := c.NetworkInterfaceAgentClient.Invoke(ctx, request)
if err != nil {
return nil, err
}
vnics, err := c.getInterfacesFromResponse(group, response)
if err != nil {
return nil, err
}

return &(*vnics)[0], nil
}

// Delete methods invokes create or update on the client
func (c *client) Delete(ctx context.Context, group, name string) error {
vnetInterface, err := c.Get(ctx, group, name)
Expand Down
8 changes: 8 additions & 0 deletions services/storage/virtualharddisk/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
// Service interface
type Service interface {
Get(context.Context, string, string, string) (*[]storage.VirtualHardDisk, error)
Hydrate(context.Context, string, string, string, *storage.VirtualHardDisk) (*storage.VirtualHardDisk, error)
CreateOrUpdate(context.Context, string, string, string, *storage.VirtualHardDisk, string, common.ImageSource) (*storage.VirtualHardDisk, error)
Delete(context.Context, string, string, string) error
Precheck(context.Context, string, string, []*storage.VirtualHardDisk) (bool, error)
Expand Down Expand Up @@ -48,6 +49,13 @@ func (c *VirtualHardDiskClient) CreateOrUpdate(ctx context.Context, group, conta
return c.internal.CreateOrUpdate(ctx, group, container, name, storage, "", common.ImageSource_LOCAL_SOURCE)
}

// The entry point for the hydrate call takes the group name, container name and the name of the disk file. The group is standard input for every call.
// Ultimately, we need the full path on disk to the disk file which we assemble from the path of the container plus the file name of the disk.
// (e.g. "C:\ClusterStorage\Userdata_1\abc123" for the container path and "my_disk.vhd" for the disk name)
func (c *VirtualHardDiskClient) Hydrate(ctx context.Context, group, container, name string, storage *storage.VirtualHardDisk) (*storage.VirtualHardDisk, error) {
return c.internal.Hydrate(ctx, group, container, name, storage)
}

// Delete methods invokes delete of the storage resource
func (c *VirtualHardDiskClient) Delete(ctx context.Context, group, container, name string) error {
return c.internal.Delete(ctx, group, container, name)
Expand Down
23 changes: 22 additions & 1 deletion services/storage/virtualharddisk/wssd.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,35 @@ func (c *client) CreateOrUpdate(ctx context.Context, group, container, name stri
return &((*vhds)[0]), nil
}

// The hydrate call takes the group name, container name and the name of the disk file. The group is standard input for every call.
// Ultimately, we need the full path on disk to the disk file which we assemble from the path of the container plus the file name of the disk.
// (e.g. "C:\ClusterStorage\Userdata_1\abc123" for the container path and "my_disk.vhd" for the disk name)
func (c *client) Hydrate(ctx context.Context, group, container, name string, vhd *storage.VirtualHardDisk) (*storage.VirtualHardDisk, error) {
request, err := getVirtualHardDiskRequest(wssdcloudcommon.Operation_HYDRATE, group, container, name, vhd, "", common.ImageSource_LOCAL_SOURCE)
if err != nil {
return nil, err
}
response, err := c.VirtualHardDiskAgentClient.Invoke(ctx, request)
if err != nil {
return nil, err
}
vhds := getVirtualHardDisksFromResponse(response, group)

if len(*vhds) == 0 {
return nil, fmt.Errorf("[VirtualHardDisk][Hydrate] Unexpected error: Hydrating a storage interface returned no result")
}

return &((*vhds)[0]), nil
}

// Delete methods invokes create or update on the client
func (c *client) Delete(ctx context.Context, group, container, name string) error {
vhd, err := c.Get(ctx, group, container, name)
if err != nil {
return err
}
if len(*vhd) == 0 {
return fmt.Errorf("Virtual Network [%s] not found", name)
return fmt.Errorf("[VirtualHardDisk][Delete] %s: not found", name)
}

request, err := getVirtualHardDiskRequest(wssdcloudcommon.Operation_DELETE, group, container, name, &(*vhd)[0], "", common.ImageSource_LOCAL_SOURCE)
Expand Down

0 comments on commit a1f10af

Please sign in to comment.