github.com/uchennaokeke444/nomad@v0.11.8/nomad/structs/node.go (about) 1 package structs 2 3 import ( 4 "reflect" 5 "time" 6 7 "github.com/hashicorp/nomad/helper" 8 ) 9 10 // CSITopology is a map of topological domains to topological segments. 11 // A topological domain is a sub-division of a cluster, like "region", 12 // "zone", "rack", etc. 13 // 14 // According to CSI, there are a few requirements for the keys within this map: 15 // - Valid keys have two segments: an OPTIONAL prefix and name, separated 16 // by a slash (/), for example: "com.company.example/zone". 17 // - The key name segment is REQUIRED. The prefix is OPTIONAL. 18 // - The key name MUST be 63 characters or less, begin and end with an 19 // alphanumeric character ([a-z0-9A-Z]), and contain only dashes (-), 20 // underscores (_), dots (.), or alphanumerics in between, for example 21 // "zone". 22 // - The key prefix MUST be 63 characters or less, begin and end with a 23 // lower-case alphanumeric character ([a-z0-9]), contain only 24 // dashes (-), dots (.), or lower-case alphanumerics in between, and 25 // follow domain name notation format 26 // (https://tools.ietf.org/html/rfc1035#section-2.3.1). 27 // - The key prefix SHOULD include the plugin's host company name and/or 28 // the plugin name, to minimize the possibility of collisions with keys 29 // from other plugins. 30 // - If a key prefix is specified, it MUST be identical across all 31 // topology keys returned by the SP (across all RPCs). 32 // - Keys MUST be case-insensitive. Meaning the keys "Zone" and "zone" 33 // MUST not both exist. 34 // - Each value (topological segment) MUST contain 1 or more strings. 35 // - Each string MUST be 63 characters or less and begin and end with an 36 // alphanumeric character with '-', '_', '.', or alphanumerics in 37 // between. 38 // 39 // However, Nomad applies lighter restrictions to these, as they are already 40 // only referenced by plugin within the scheduler and as such collisions and 41 // related concerns are less of an issue. We may implement these restrictions 42 // in the future. 43 type CSITopology struct { 44 Segments map[string]string 45 } 46 47 func (t *CSITopology) Copy() *CSITopology { 48 if t == nil { 49 return nil 50 } 51 52 return &CSITopology{ 53 Segments: helper.CopyMapStringString(t.Segments), 54 } 55 } 56 57 func (t *CSITopology) Equal(o *CSITopology) bool { 58 if t == nil || o == nil { 59 return t == o 60 } 61 62 return helper.CompareMapStringString(t.Segments, o.Segments) 63 } 64 65 // CSINodeInfo is the fingerprinted data from a CSI Plugin that is specific to 66 // the Node API. 67 type CSINodeInfo struct { 68 // ID is the identity of a given nomad client as observed by the storage 69 // provider. 70 ID string 71 72 // MaxVolumes is the maximum number of volumes that can be attached to the 73 // current host via this provider. 74 // If 0 then unlimited volumes may be attached. 75 MaxVolumes int64 76 77 // AccessibleTopology specifies where (regions, zones, racks, etc.) the node is 78 // accessible from within the storage provider. 79 // 80 // A plugin that returns this field MUST also set the `RequiresTopologies` 81 // property. 82 // 83 // This field is OPTIONAL. If it is not specified, then we assume that the 84 // the node is not subject to any topological constraint, and MAY 85 // schedule workloads that reference any volume V, such that there are 86 // no topological constraints declared for V. 87 // 88 // Example 1: 89 // accessible_topology = 90 // {"region": "R1", "zone": "Z2"} 91 // Indicates the node exists within the "region" "R1" and the "zone" 92 // "Z2" within the storage provider. 93 AccessibleTopology *CSITopology 94 95 // RequiresNodeStageVolume indicates whether the client should Stage/Unstage 96 // volumes on this node. 97 RequiresNodeStageVolume bool 98 } 99 100 func (n *CSINodeInfo) Copy() *CSINodeInfo { 101 if n == nil { 102 return nil 103 } 104 105 nc := new(CSINodeInfo) 106 *nc = *n 107 nc.AccessibleTopology = n.AccessibleTopology.Copy() 108 109 return nc 110 } 111 112 // CSIControllerInfo is the fingerprinted data from a CSI Plugin that is specific to 113 // the Controller API. 114 type CSIControllerInfo struct { 115 // SupportsReadOnlyAttach is set to true when the controller returns the 116 // ATTACH_READONLY capability. 117 SupportsReadOnlyAttach bool 118 119 // SupportsPublishVolume is true when the controller implements the methods 120 // required to attach and detach volumes. If this is false Nomad should skip 121 // the controller attachment flow. 122 SupportsAttachDetach bool 123 124 // SupportsListVolumes is true when the controller implements the ListVolumes 125 // RPC. NOTE: This does not guaruntee that attached nodes will be returned 126 // unless SupportsListVolumesAttachedNodes is also true. 127 SupportsListVolumes bool 128 129 // SupportsListVolumesAttachedNodes indicates whether the plugin will return 130 // attached nodes data when making ListVolume RPCs 131 SupportsListVolumesAttachedNodes bool 132 } 133 134 func (c *CSIControllerInfo) Copy() *CSIControllerInfo { 135 if c == nil { 136 return nil 137 } 138 139 nc := new(CSIControllerInfo) 140 *nc = *c 141 142 return nc 143 } 144 145 // CSIInfo is the current state of a single CSI Plugin. This is updated regularly 146 // as plugin health changes on the node. 147 type CSIInfo struct { 148 PluginID string 149 AllocID string 150 Healthy bool 151 HealthDescription string 152 UpdateTime time.Time 153 154 Provider string // vendor name from CSI GetPluginInfoResponse 155 ProviderVersion string // vendor version from CSI GetPluginInfoResponse 156 157 // RequiresControllerPlugin is set when the CSI Plugin returns the 158 // CONTROLLER_SERVICE capability. When this is true, the volumes should not be 159 // scheduled on this client until a matching controller plugin is available. 160 RequiresControllerPlugin bool 161 162 // RequiresTopologies is set when the CSI Plugin returns the 163 // VOLUME_ACCESSIBLE_CONSTRAINTS capability. When this is true, we must 164 // respect the Volume and Node Topology information. 165 RequiresTopologies bool 166 167 // CSI Specific metadata 168 ControllerInfo *CSIControllerInfo `json:",omitempty"` 169 NodeInfo *CSINodeInfo `json:",omitempty"` 170 } 171 172 func (c *CSIInfo) Copy() *CSIInfo { 173 if c == nil { 174 return nil 175 } 176 177 nc := new(CSIInfo) 178 *nc = *c 179 nc.ControllerInfo = c.ControllerInfo.Copy() 180 nc.NodeInfo = c.NodeInfo.Copy() 181 182 return nc 183 } 184 185 func (c *CSIInfo) SetHealthy(hs bool) { 186 c.Healthy = hs 187 if hs { 188 c.HealthDescription = "healthy" 189 } else { 190 c.HealthDescription = "unhealthy" 191 } 192 } 193 194 func (c *CSIInfo) Equal(o *CSIInfo) bool { 195 if c == nil && o == nil { 196 return c == o 197 } 198 199 nc := *c 200 nc.UpdateTime = time.Time{} 201 no := *o 202 no.UpdateTime = time.Time{} 203 204 return reflect.DeepEqual(nc, no) 205 } 206 207 func (c *CSIInfo) IsController() bool { 208 if c == nil || c.ControllerInfo == nil { 209 return false 210 } 211 return true 212 } 213 214 func (c *CSIInfo) IsNode() bool { 215 if c == nil || c.NodeInfo == nil { 216 return false 217 } 218 return true 219 } 220 221 // DriverInfo is the current state of a single driver. This is updated 222 // regularly as driver health changes on the node. 223 type DriverInfo struct { 224 Attributes map[string]string 225 Detected bool 226 Healthy bool 227 HealthDescription string 228 UpdateTime time.Time 229 } 230 231 func (di *DriverInfo) Copy() *DriverInfo { 232 if di == nil { 233 return nil 234 } 235 236 cdi := new(DriverInfo) 237 *cdi = *di 238 cdi.Attributes = helper.CopyMapStringString(di.Attributes) 239 return cdi 240 } 241 242 // MergeHealthCheck merges information from a health check for a drier into a 243 // node's driver info 244 func (di *DriverInfo) MergeHealthCheck(other *DriverInfo) { 245 di.Healthy = other.Healthy 246 di.HealthDescription = other.HealthDescription 247 di.UpdateTime = other.UpdateTime 248 } 249 250 // MergeFingerprint merges information from fingerprinting a node for a driver 251 // into a node's driver info for that driver. 252 func (di *DriverInfo) MergeFingerprintInfo(other *DriverInfo) { 253 di.Detected = other.Detected 254 di.Attributes = other.Attributes 255 } 256 257 // DriverInfo determines if two driver info objects are equal..As this is used 258 // in the process of health checking, we only check the fields that are 259 // computed by the health checker. In the future, this will be merged. 260 func (di *DriverInfo) HealthCheckEquals(other *DriverInfo) bool { 261 if di == nil && other == nil { 262 return true 263 } 264 265 if di.Healthy != other.Healthy { 266 return false 267 } 268 269 if di.HealthDescription != other.HealthDescription { 270 return false 271 } 272 273 return true 274 }