@@ -4,13 +4,15 @@ import (
44 "context"
55 "encoding/json"
66 "errors"
7+ "fmt"
78 "slices"
89 "strconv"
910 "strings"
1011
1112 "github.com/opencontainers/runtime-spec/specs-go"
1213 "github.com/sirupsen/logrus"
1314
15+ "github.com/Microsoft/go-winio/pkg/guid"
1416 iannotations "github.com/Microsoft/hcsshim/internal/annotations"
1517 hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
1618 "github.com/Microsoft/hcsshim/internal/log"
@@ -66,6 +68,7 @@ func ParseAnnotationsDisableGMSA(ctx context.Context, s *specs.Spec) bool {
6668}
6769
6870// parseAdditionalRegistryValues extracts the additional registry values to set from annotations.
71+ //
6972// Like the [parseAnnotation*] functions, this logs errors but does not return them.
7073func parseAdditionalRegistryValues (ctx context.Context , a map [string ]string ) []hcsschema.RegistryValue {
7174 // rather than have users deal with nil vs []hcsschema.RegistryValue as returns, always
@@ -81,7 +84,7 @@ func parseAdditionalRegistryValues(ctx context.Context, a map[string]string) []h
8184
8285 t := []hcsschema.RegistryValue {}
8386 if err := json .Unmarshal ([]byte (v ), & t ); err != nil {
84- logAnnotationParseError (ctx , k , v , "JSON string" , err )
87+ logAnnotationValueParseError (ctx , k , v , fmt . Sprintf ( "%T" , t ) , err )
8588 return []hcsschema.RegistryValue {}
8689 }
8790
@@ -182,20 +185,63 @@ func parseAdditionalRegistryValues(ctx context.Context, a map[string]string) []h
182185 return slices .Clip (rvs )
183186}
184187
188+ // parseHVSocketServiceTable extracts any additional Hyper-V socket service configurations from annotations.
189+ //
190+ // Like the [parseAnnotation*] functions, this logs errors but does not return them.
191+ func parseHVSocketServiceTable (ctx context.Context , a map [string ]string ) map [string ]hcsschema.HvSocketServiceConfig {
192+ sc := make (map [string ]hcsschema.HvSocketServiceConfig )
193+ // TODO(go1.23) use range over functions to implement a functional `filter | map $ a`
194+ for k , v := range a {
195+ sGUID , found := strings .CutPrefix (k , iannotations .UVMHyperVSocketConfigPrefix )
196+ if ! found {
197+ continue
198+ }
199+
200+ entry := log .G (ctx ).WithFields (logrus.Fields {
201+ logfields .OCIAnnotation : k ,
202+ logfields .Value : v ,
203+ "guid" : sGUID ,
204+ })
205+
206+ g , err := guid .FromString (sGUID )
207+ if err != nil {
208+ entry .WithError (err ).Warn ("invalid GUID string for Hyper-V socket service configuration annotation" )
209+ continue
210+ }
211+ sGUID = g .String () // overwrite the GUID string to standardize format (capitalization)
212+
213+ conf := hcsschema.HvSocketServiceConfig {}
214+ if err := json .Unmarshal ([]byte (v ), & conf ); err != nil {
215+ logAnnotationValueParseError (ctx , k , v , fmt .Sprintf ("%T" , conf ), err )
216+ continue
217+ }
218+
219+ if _ , found := sc [sGUID ]; found {
220+ entry .WithFields (logrus.Fields {
221+ "guid" : sGUID ,
222+ }).Warn ("overwritting existing Hyper-V socket service configuration" )
223+ }
224+
225+ if entry .Logger .IsLevelEnabled (logrus .TraceLevel ) {
226+ entry .WithField ("configuration" , log .Format (ctx , conf )).Trace ("found Hyper-V socket service configuration annotation" )
227+ }
228+ sc [sGUID ] = conf
229+ }
230+
231+ return sc
232+ }
233+
185234// general annotation parsing
186235
187236// ParseAnnotationsBool searches `a` for `key` and if found verifies that the
188237// value is `true` or `false` in any case. If `key` is not found returns `def`.
189238func ParseAnnotationsBool (ctx context.Context , a map [string ]string , key string , def bool ) bool {
190239 if v , ok := a [key ]; ok {
191- switch strings .ToLower (v ) {
192- case "true" :
193- return true
194- case "false" :
195- return false
196- default :
197- logAnnotationParseError (ctx , key , v , logfields .Bool , nil )
240+ b , err := strconv .ParseBool (v )
241+ if err == nil {
242+ return b
198243 }
244+ logAnnotationValueParseError (ctx , key , v , logfields .Bool , err )
199245 }
200246 return def
201247}
@@ -206,17 +252,11 @@ func ParseAnnotationsBool(ctx context.Context, a map[string]string, key string,
206252// the value they point at.
207253func ParseAnnotationsNullableBool (ctx context.Context , a map [string ]string , key string ) * bool {
208254 if v , ok := a [key ]; ok {
209- switch strings .ToLower (v ) {
210- case "true" :
211- _bool := true
212- return & _bool
213- case "false" :
214- _bool := false
215- return & _bool
216- default :
217- err := errors .New ("boolean fields must be 'true', 'false', or not set" )
218- logAnnotationParseError (ctx , key , v , logfields .Bool , err )
255+ b , err := strconv .ParseBool (v )
256+ if err == nil {
257+ return & b
219258 }
259+ logAnnotationValueParseError (ctx , key , v , logfields .Bool , err )
220260 }
221261 return nil
222262}
@@ -230,7 +270,7 @@ func ParseAnnotationsInt32(ctx context.Context, a map[string]string, key string,
230270 v := int32 (countu )
231271 return v
232272 }
233- logAnnotationParseError (ctx , key , v , logfields .Int32 , err )
273+ logAnnotationValueParseError (ctx , key , v , logfields .Int32 , err )
234274 }
235275 return def
236276}
@@ -244,7 +284,7 @@ func ParseAnnotationsUint32(ctx context.Context, a map[string]string, key string
244284 v := uint32 (countu )
245285 return v
246286 }
247- logAnnotationParseError (ctx , key , v , logfields .Uint32 , err )
287+ logAnnotationValueParseError (ctx , key , v , logfields .Uint32 , err )
248288 }
249289 return def
250290}
@@ -257,15 +297,15 @@ func ParseAnnotationsUint64(ctx context.Context, a map[string]string, key string
257297 if err == nil {
258298 return countu
259299 }
260- logAnnotationParseError (ctx , key , v , logfields .Uint64 , err )
300+ logAnnotationValueParseError (ctx , key , v , logfields .Uint64 , err )
261301 }
262302 return def
263303}
264304
265- // ParseAnnotationCommaSeparated searches `annotations ` for `annotation` corresponding to a
266- // list of comma separated strings
267- func ParseAnnotationCommaSeparatedUint32 (ctx context.Context , annotations map [string ]string , annotation string , def []uint32 ) []uint32 {
268- cs , ok := annotations [ annotation ]
305+ // ParseAnnotationCommaSeparated searches `a ` for `annotation` corresponding to a
306+ // list of comma separated strings.
307+ func ParseAnnotationCommaSeparatedUint32 (_ context.Context , a map [string ]string , key string , def []uint32 ) []uint32 {
308+ cs , ok := a [ key ]
269309 if ! ok || cs == "" {
270310 return def
271311 }
@@ -289,18 +329,18 @@ func ParseAnnotationsString(a map[string]string, key string, def string) string
289329 return def
290330}
291331
292- // ParseAnnotationCommaSeparated searches `annotations ` for `annotation ` corresponding to a
293- // list of comma separated strings
294- func ParseAnnotationCommaSeparated (annotation string , annotations map [string ]string ) []string {
295- cs , ok := annotations [ annotation ]
332+ // ParseAnnotationCommaSeparated searches `a ` for `key ` corresponding to a
333+ // list of comma separated strings.
334+ func ParseAnnotationCommaSeparated (key string , a map [string ]string ) []string {
335+ cs , ok := a [ key ]
296336 if ! ok || cs == "" {
297337 return nil
298338 }
299339 results := strings .Split (cs , "," )
300340 return results
301341}
302342
303- func logAnnotationParseError (ctx context.Context , k , v , et string , err error ) {
343+ func logAnnotationValueParseError (ctx context.Context , k , v , et string , err error ) {
304344 entry := log .G (ctx ).WithFields (logrus.Fields {
305345 logfields .OCIAnnotation : k ,
306346 logfields .Value : v ,
@@ -309,5 +349,5 @@ func logAnnotationParseError(ctx context.Context, k, v, et string, err error) {
309349 if err != nil {
310350 entry = entry .WithError (err )
311351 }
312- entry .Warning ("annotation could not be parsed" )
352+ entry .Warning ("annotation value could not be parsed" )
313353}
0 commit comments