github.com/hernad/nomad@v1.6.112/nomad/structs/extensions.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package structs
     5  
     6  import (
     7  	"reflect"
     8  )
     9  
    10  var (
    11  	// extendedTypes is a mapping of extended types to their extension function
    12  	// TODO: the duplicates could be simplified by looking up the base type in the case of a pointer type in ConvertExt
    13  	extendedTypes = map[reflect.Type]extendFunc{
    14  		reflect.TypeOf(Node{}):       nodeExt,
    15  		reflect.TypeOf(&Node{}):      nodeExt,
    16  		reflect.TypeOf(CSIVolume{}):  csiVolumeExt,
    17  		reflect.TypeOf(&CSIVolume{}): csiVolumeExt,
    18  	}
    19  )
    20  
    21  // nodeExt ensures the node is sanitized and adds the legacy field .Drain back to encoded Node objects
    22  func nodeExt(v interface{}) interface{} {
    23  	node := v.(*Node).Sanitize()
    24  	// transform to a struct with inlined Node fields plus the Drain field
    25  	// - using defined type (not an alias!) EmbeddedNode gives us free conversion to a distinct type
    26  	// - distinct type prevents this encoding extension from being called recursively/infinitely on the embedding
    27  	// - pointers mean the conversion function doesn't have to make a copy during conversion
    28  	type EmbeddedNode Node
    29  	return &struct {
    30  		*EmbeddedNode
    31  		Drain bool
    32  	}{
    33  		EmbeddedNode: (*EmbeddedNode)(node),
    34  		Drain:        node != nil && node.DrainStrategy != nil,
    35  	}
    36  }
    37  
    38  func csiVolumeExt(v interface{}) interface{} {
    39  	vol := v.(*CSIVolume)
    40  	type EmbeddedCSIVolume CSIVolume
    41  
    42  	allocCount := len(vol.ReadAllocs) + len(vol.WriteAllocs)
    43  
    44  	apiVol := &struct {
    45  		*EmbeddedCSIVolume
    46  		Allocations []*AllocListStub
    47  	}{
    48  		EmbeddedCSIVolume: (*EmbeddedCSIVolume)(vol),
    49  		Allocations:       make([]*AllocListStub, 0, allocCount),
    50  	}
    51  
    52  	// WriteAllocs and ReadAllocs will only ever contain the Allocation ID,
    53  	// with a null value for the Allocation; these IDs are mapped to
    54  	// allocation stubs in the Allocations field. This indirection is so the
    55  	// API can support both the UI and CLI consumer in a safely backwards
    56  	// compatible way
    57  	for _, a := range vol.ReadAllocs {
    58  		if a != nil {
    59  			apiVol.ReadAllocs[a.ID] = nil
    60  			apiVol.Allocations = append(apiVol.Allocations, a.Stub(nil))
    61  		}
    62  	}
    63  	for _, a := range vol.WriteAllocs {
    64  		if a != nil {
    65  			apiVol.WriteAllocs[a.ID] = nil
    66  			apiVol.Allocations = append(apiVol.Allocations, a.Stub(nil))
    67  		}
    68  	}
    69  
    70  	// MountFlags can contain secrets, so we always redact it but want
    71  	// to show the user that we have the value
    72  	if vol.MountOptions != nil && len(vol.MountOptions.MountFlags) > 0 {
    73  		apiVol.MountOptions.MountFlags = []string{"[REDACTED]"}
    74  	}
    75  
    76  	// would be better not to have at all but left in and redacted for
    77  	// backwards compatibility with the existing API
    78  	apiVol.Secrets = nil
    79  
    80  	return apiVol
    81  }