github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/structs/extensions.go (about)

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