Skip to content

Commit 0b833cc

Browse files
Merge pull request microsoft#2220 from katiewasnothere/kabaldau/guest_caps
Refactor guest defined capabilities
2 parents e55a82b + 89620dc commit 0b833cc

9 files changed

+143
-27
lines changed

internal/gcs/guestcaps.go

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//go:build windows
2+
3+
package gcs
4+
5+
import (
6+
"encoding/json"
7+
"fmt"
8+
9+
"github.com/Microsoft/hcsshim/internal/guest/prot"
10+
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
11+
)
12+
13+
// GuestDefinedCapabilities is an interface for different guest defined capabilities.
14+
// This allows us to define different capabilities by OS.
15+
//
16+
// When adding new fields to the implementations of type GuestDefinedCapabilities, a
17+
// new interface function should only be added if that capability describes a feature
18+
// available for both WCOW and LCOW. Otherwise, you can use the helper functions
19+
// GetWCOWCapabilities or GetLCOWCapabilities to check for capabilities specific to
20+
// one implementation.
21+
type GuestDefinedCapabilities interface {
22+
IsSignalProcessSupported() bool
23+
IsDeleteContainerStateSupported() bool
24+
IsDumpStacksSupported() bool
25+
IsNamespaceAddRequestSupported() bool
26+
}
27+
28+
func GetWCOWCapabilities(gdc GuestDefinedCapabilities) *WCOWGuestDefinedCapabilities {
29+
g, ok := gdc.(*WCOWGuestDefinedCapabilities)
30+
if !ok {
31+
return nil
32+
}
33+
return g
34+
}
35+
36+
func GetLCOWCapabilities(gdc GuestDefinedCapabilities) *LCOWGuestDefinedCapabilities {
37+
g, ok := gdc.(*LCOWGuestDefinedCapabilities)
38+
if !ok {
39+
return nil
40+
}
41+
return g
42+
}
43+
44+
func unmarshalGuestCapabilities(os string, data json.RawMessage) (GuestDefinedCapabilities, error) {
45+
if os == "windows" {
46+
gdc := &WCOWGuestDefinedCapabilities{}
47+
if err := json.Unmarshal(data, gdc); err != nil {
48+
return nil, fmt.Errorf("unmarshal returned GuestDefinedCapabilities for windows: %w", err)
49+
}
50+
return gdc, nil
51+
}
52+
// linux
53+
gdc := &LCOWGuestDefinedCapabilities{}
54+
if err := json.Unmarshal(data, gdc); err != nil {
55+
return nil, fmt.Errorf("unmarshal returned GuestDefinedCapabilities for lcow: %w", err)
56+
}
57+
return gdc, nil
58+
}
59+
60+
var _ GuestDefinedCapabilities = &LCOWGuestDefinedCapabilities{}
61+
62+
type LCOWGuestDefinedCapabilities struct {
63+
prot.GcsGuestCapabilities
64+
}
65+
66+
func (l *LCOWGuestDefinedCapabilities) IsNamespaceAddRequestSupported() bool {
67+
return l.NamespaceAddRequestSupported
68+
}
69+
70+
func (l *LCOWGuestDefinedCapabilities) IsSignalProcessSupported() bool {
71+
return l.SignalProcessSupported
72+
}
73+
74+
func (l *LCOWGuestDefinedCapabilities) IsDumpStacksSupported() bool {
75+
return l.DumpStacksSupported
76+
}
77+
78+
func (l *LCOWGuestDefinedCapabilities) IsDeleteContainerStateSupported() bool {
79+
return l.DeleteContainerStateSupported
80+
}
81+
82+
var _ GuestDefinedCapabilities = &WCOWGuestDefinedCapabilities{}
83+
84+
type WCOWGuestDefinedCapabilities struct {
85+
schema1.GuestDefinedCapabilities
86+
}
87+
88+
func (w *WCOWGuestDefinedCapabilities) IsNamespaceAddRequestSupported() bool {
89+
return w.NamespaceAddRequestSupported
90+
}
91+
92+
func (w *WCOWGuestDefinedCapabilities) IsSignalProcessSupported() bool {
93+
return w.SignalProcessSupported
94+
}
95+
96+
func (w *WCOWGuestDefinedCapabilities) IsDumpStacksSupported() bool {
97+
return w.DumpStacksSupported
98+
}
99+
100+
func (w *WCOWGuestDefinedCapabilities) IsDeleteContainerStateSupported() bool {
101+
return w.DeleteContainerStateSupported
102+
}

internal/gcs/guestconnection.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"github.com/Microsoft/go-winio"
1717
"github.com/Microsoft/go-winio/pkg/guid"
1818
"github.com/Microsoft/hcsshim/internal/cow"
19-
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
2019
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
2120
"github.com/Microsoft/hcsshim/internal/log"
2221
"github.com/Microsoft/hcsshim/internal/logfields"
@@ -98,15 +97,15 @@ type GuestConnection struct {
9897
mu sync.Mutex
9998
nextPort uint32
10099
notifyChs map[string]chan struct{}
101-
caps schema1.GuestDefinedCapabilities
100+
caps GuestDefinedCapabilities
102101
os string
103102
}
104103

105104
var _ cow.ProcessHost = &GuestConnection{}
106105

107106
// Capabilities returns the guest's declared capabilities.
108-
func (gc *GuestConnection) Capabilities() *schema1.GuestDefinedCapabilities {
109-
return &gc.caps
107+
func (gc *GuestConnection) Capabilities() GuestDefinedCapabilities {
108+
return gc.caps
110109
}
111110

112111
// Protocol returns the protocol version that is in use.
@@ -123,18 +122,24 @@ func (gc *GuestConnection) connect(ctx context.Context, isColdStart bool, initGu
123122
MaximumVersion: protocolVersion,
124123
}
125124
var resp negotiateProtocolResponse
126-
resp.Capabilities.GuestDefinedCapabilities = &gc.caps
127125
err = gc.brdg.RPC(ctx, rpcNegotiateProtocol, &req, &resp, true)
128126
if err != nil {
129127
return err
130128
}
131129
if resp.Version != protocolVersion {
132130
return fmt.Errorf("unexpected version %d returned", resp.Version)
133131
}
132+
134133
gc.os = strings.ToLower(resp.Capabilities.RuntimeOsType)
135134
if gc.os == "" {
136135
gc.os = "windows"
137136
}
137+
138+
gc.caps, err = unmarshalGuestCapabilities(gc.os, resp.Capabilities.GuestDefinedCapabilities)
139+
if err != nil {
140+
return fmt.Errorf("unmarshalGuestCapabilities: %w", err)
141+
}
142+
138143
if isColdStart && resp.Capabilities.SendHostCreateMessage {
139144
conf := &uvmConfig{
140145
SystemType: "Container",

internal/gcs/protocol.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ type gcsCapabilities struct {
323323
SendLifecycleNotifications bool
324324
SupportedSchemaVersions []hcsschema.Version
325325
RuntimeOsType string
326-
GuestDefinedCapabilities interface{}
326+
GuestDefinedCapabilities json.RawMessage
327327
}
328328

329329
type containerCreateResponse struct {

internal/uvm/capabilities.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,27 @@
22

33
package uvm
44

5-
import "github.com/Microsoft/hcsshim/internal/hcs/schema1"
5+
import (
6+
"github.com/Microsoft/hcsshim/internal/gcs"
7+
)
68

79
// SignalProcessSupported returns `true` if the guest supports the capability to
810
// signal a process.
911
//
1012
// This support was added RS5+ guests.
1113
func (uvm *UtilityVM) SignalProcessSupported() bool {
12-
return uvm.guestCaps.SignalProcessSupported
14+
return uvm.guestCaps.IsSignalProcessSupported()
1315
}
1416

1517
func (uvm *UtilityVM) DeleteContainerStateSupported() bool {
1618
if uvm.gc == nil {
1719
return false
1820
}
19-
return uvm.guestCaps.DeleteContainerStateSupported
21+
return uvm.guestCaps.IsDeleteContainerStateSupported()
2022
}
2123

2224
// Capabilities returns the protocol version and the guest defined capabilities.
2325
// This should only be used for testing.
24-
func (uvm *UtilityVM) Capabilities() (uint32, schema1.GuestDefinedCapabilities) {
26+
func (uvm *UtilityVM) Capabilities() (uint32, gcs.GuestDefinedCapabilities) {
2527
return uvm.protocol, uvm.guestCaps
2628
}

internal/uvm/dumpstacks.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
func (uvm *UtilityVM) DumpStacks(ctx context.Context) (string, error) {
10-
if uvm.gc == nil || !uvm.guestCaps.DumpStacksSupported {
10+
if uvm.gc == nil || !uvm.guestCaps.IsDumpStacksSupported() {
1111
return "", nil
1212
}
1313

internal/uvm/network.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ func (uvm *UtilityVM) RemoveEndpointFromNS(ctx context.Context, id string, endpo
529529

530530
// IsNetworkNamespaceSupported returns bool value specifying if network namespace is supported inside the guest
531531
func (uvm *UtilityVM) isNetworkNamespaceSupported() bool {
532-
return uvm.guestCaps.NamespaceAddRequestSupported
532+
return uvm.guestCaps.IsNamespaceAddRequestSupported()
533533
}
534534

535535
func getNetworkModifyRequest(adapterID string, requestType guestrequest.RequestType, settings interface{}) interface{} {

internal/uvm/start.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ func (uvm *UtilityVM) Start(ctx context.Context) (err error) {
282282
if err != nil {
283283
return err
284284
}
285-
uvm.guestCaps = *uvm.gc.Capabilities()
285+
uvm.guestCaps = uvm.gc.Capabilities()
286286
uvm.protocol = uvm.gc.Protocol()
287287

288288
// initial setup required for external GCS connection
@@ -295,7 +295,7 @@ func (uvm *UtilityVM) Start(ctx context.Context) (err error) {
295295
if err != nil {
296296
return err
297297
}
298-
uvm.guestCaps = properties.GuestConnectionInfo.GuestDefinedCapabilities
298+
uvm.guestCaps = &gcs.WCOWGuestDefinedCapabilities{GuestDefinedCapabilities: properties.GuestConnectionInfo.GuestDefinedCapabilities}
299299
uvm.protocol = properties.GuestConnectionInfo.ProtocolVersion
300300
}
301301

internal/uvm/types.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313

1414
"github.com/Microsoft/hcsshim/internal/gcs"
1515
"github.com/Microsoft/hcsshim/internal/hcs"
16-
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
1716
"github.com/Microsoft/hcsshim/internal/hns"
1817
"github.com/Microsoft/hcsshim/internal/uvm/scsi"
1918
)
@@ -55,7 +54,7 @@ type UtilityVM struct {
5554

5655
// GCS bridge protocol and capabilities
5756
protocol uint32
58-
guestCaps schema1.GuestDefinedCapabilities
57+
guestCaps gcs.GuestDefinedCapabilities
5958

6059
// containerCounter is the current number of containers that have been created.
6160
// This is never decremented in the life of the UVM.

test/functional/uvm_properties_test.go

+19-11
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,52 @@ import (
99

1010
"github.com/Microsoft/hcsshim/osversion"
1111

12+
"github.com/Microsoft/hcsshim/internal/gcs"
1213
"github.com/Microsoft/hcsshim/test/internal/util"
1314
"github.com/Microsoft/hcsshim/test/pkg/require"
1415
testuvm "github.com/Microsoft/hcsshim/test/pkg/uvm"
1516
)
1617

1718
func TestPropertiesGuestConnection_LCOW(t *testing.T) {
18-
t.Skip("not yet updated")
19-
2019
require.Build(t, osversion.RS5)
2120
requireFeatures(t, featureLCOW, featureUVM)
2221

2322
ctx := util.Context(context.Background(), t)
24-
uvm := testuvm.CreateAndStartLCOWFromOpts(ctx, t, defaultLCOWOptions(ctx, t))
23+
uvm := testuvm.CreateAndStart(ctx, t, defaultLCOWOptions(ctx, t))
2524
defer uvm.Close()
2625

2726
p, gc := uvm.Capabilities()
28-
if gc.NamespaceAddRequestSupported ||
29-
!gc.SignalProcessSupported ||
27+
if !gc.IsNamespaceAddRequestSupported() ||
28+
!gc.IsSignalProcessSupported() ||
3029
p < 4 {
3130
t.Fatalf("unexpected values: %d %+v", p, gc)
3231
}
32+
33+
// check the type of the capabilities
34+
gdc := gcs.GetLCOWCapabilities(gc)
35+
if gdc == nil {
36+
t.Fatal("capabilities are unexpected type")
37+
}
3338
}
3439

3540
func TestPropertiesGuestConnection_WCOW(t *testing.T) {
36-
t.Skip("not yet updated")
37-
3841
require.Build(t, osversion.RS5)
3942
requireFeatures(t, featureWCOW, featureUVM)
4043

4144
ctx := util.Context(context.Background(), t)
42-
//nolint:staticcheck // SA1019: deprecated; will be replaced when test is updated
43-
uvm, _, _ := testuvm.CreateWCOWUVM(ctx, t, t.Name(), "microsoft/nanoserver")
45+
uvm := testuvm.CreateAndStart(ctx, t, defaultWCOWOptions(ctx, t))
4446
defer uvm.Close()
4547

4648
p, gc := uvm.Capabilities()
47-
if !gc.NamespaceAddRequestSupported ||
48-
!gc.SignalProcessSupported ||
49+
if !gc.IsNamespaceAddRequestSupported() ||
50+
!gc.IsSignalProcessSupported() ||
4951
p < 4 {
5052
t.Fatalf("unexpected values: %d %+v", p, gc)
5153
}
54+
55+
// check the type of the capabilities
56+
gdc := gcs.GetWCOWCapabilities(gc)
57+
if gdc == nil {
58+
t.Fatal("capabilities are unexpected type")
59+
}
5260
}

0 commit comments

Comments
 (0)