github.com/hspak/nomad@v0.7.2-0.20180309000617-bc4ae22a39a5/client/fingerprint_manager.go (about) 1 package client 2 3 import ( 4 "log" 5 "sync" 6 "time" 7 8 "github.com/hashicorp/nomad/client/config" 9 "github.com/hashicorp/nomad/client/driver" 10 "github.com/hashicorp/nomad/client/fingerprint" 11 cstructs "github.com/hashicorp/nomad/client/structs" 12 "github.com/hashicorp/nomad/nomad/structs" 13 ) 14 15 // FingerprintManager runs a client fingerprinters on a continuous basis, and 16 // updates the client when the node has changed 17 type FingerprintManager struct { 18 getConfig func() *config.Config 19 node *structs.Node 20 nodeLock sync.Mutex 21 shutdownCh chan struct{} 22 23 // updateNode is a callback to the client to update the state of its 24 // associated node 25 updateNode func(*cstructs.FingerprintResponse) *structs.Node 26 logger *log.Logger 27 } 28 29 // NewFingerprintManager is a constructor that creates and returns an instance 30 // of FingerprintManager 31 func NewFingerprintManager(getConfig func() *config.Config, 32 node *structs.Node, 33 shutdownCh chan struct{}, 34 updateNode func(*cstructs.FingerprintResponse) *structs.Node, 35 logger *log.Logger) *FingerprintManager { 36 return &FingerprintManager{ 37 getConfig: getConfig, 38 updateNode: updateNode, 39 node: node, 40 shutdownCh: shutdownCh, 41 logger: logger, 42 } 43 } 44 45 // run runs each fingerprinter individually on an ongoing basis 46 func (fm *FingerprintManager) run(f fingerprint.Fingerprint, period time.Duration, name string) { 47 fm.logger.Printf("[DEBUG] client.fingerprint_manager: fingerprinting %s every %v", name, period) 48 49 for { 50 select { 51 case <-time.After(period): 52 _, err := fm.fingerprint(name, f) 53 if err != nil { 54 fm.logger.Printf("[DEBUG] client.fingerprint_manager: periodic fingerprinting for %v failed: %+v", name, err) 55 continue 56 } 57 58 case <-fm.shutdownCh: 59 return 60 } 61 } 62 } 63 64 // setupDrivers is used to fingerprint the node to see if these drivers are 65 // supported 66 func (fm *FingerprintManager) setupDrivers(drivers []string) error { 67 var availDrivers []string 68 driverCtx := driver.NewDriverContext("", "", fm.getConfig(), fm.node, fm.logger, nil) 69 for _, name := range drivers { 70 71 d, err := driver.NewDriver(name, driverCtx) 72 if err != nil { 73 return err 74 } 75 76 detected, err := fm.fingerprint(name, d) 77 if err != nil { 78 fm.logger.Printf("[DEBUG] client.fingerprint_manager: fingerprinting for %v failed: %+v", name, err) 79 return err 80 } 81 82 // log the fingerprinters which have been applied 83 if detected { 84 availDrivers = append(availDrivers, name) 85 } 86 87 p, period := d.Periodic() 88 if p { 89 go fm.run(d, period, name) 90 } 91 } 92 93 fm.logger.Printf("[DEBUG] client.fingerprint_manager: detected drivers %v", availDrivers) 94 return nil 95 } 96 97 // fingerprint does an initial fingerprint of the client. If the fingerprinter 98 // is meant to be run continuously, a process is launched to perform this 99 // fingerprint on an ongoing basis in the background. 100 func (fm *FingerprintManager) fingerprint(name string, f fingerprint.Fingerprint) (bool, error) { 101 request := &cstructs.FingerprintRequest{Config: fm.getConfig(), Node: fm.node} 102 var response cstructs.FingerprintResponse 103 104 fm.nodeLock.Lock() 105 err := f.Fingerprint(request, &response) 106 fm.nodeLock.Unlock() 107 108 if err != nil { 109 return false, err 110 } 111 112 if node := fm.updateNode(&response); node != nil { 113 fm.nodeLock.Lock() 114 fm.node = node 115 fm.nodeLock.Unlock() 116 } 117 118 return response.Detected, nil 119 } 120 121 // setupFingerprints is used to fingerprint the node to see if these attributes are 122 // supported 123 func (fm *FingerprintManager) setupFingerprinters(fingerprints []string) error { 124 var appliedFingerprints []string 125 126 for _, name := range fingerprints { 127 f, err := fingerprint.NewFingerprint(name, fm.logger) 128 129 if err != nil { 130 fm.logger.Printf("[DEBUG] client.fingerprint_manager: fingerprinting for %v failed: %+v", name, err) 131 return err 132 } 133 134 detected, err := fm.fingerprint(name, f) 135 if err != nil { 136 return err 137 } 138 139 // log the fingerprinters which have been applied 140 if detected { 141 appliedFingerprints = append(appliedFingerprints, name) 142 } 143 144 p, period := f.Periodic() 145 if p { 146 go fm.run(f, period, name) 147 } 148 } 149 150 fm.logger.Printf("[DEBUG] client.fingerprint_manager: detected fingerprints %v", appliedFingerprints) 151 return nil 152 } 153 154 // Run starts the process of fingerprinting the node. It does an initial pass, 155 // identifying whitelisted and blacklisted fingerprints/drivers. Then, for 156 // those which require periotic checking, it starts a periodic process for 157 // each. 158 func (fp *FingerprintManager) Run() error { 159 // first, set up all fingerprints 160 cfg := fp.getConfig() 161 whitelistFingerprints := cfg.ReadStringListToMap("fingerprint.whitelist") 162 whitelistFingerprintsEnabled := len(whitelistFingerprints) > 0 163 blacklistFingerprints := cfg.ReadStringListToMap("fingerprint.blacklist") 164 165 fp.logger.Printf("[DEBUG] client.fingerprint_manager: built-in fingerprints: %v", fingerprint.BuiltinFingerprints()) 166 167 var availableFingerprints []string 168 var skippedFingerprints []string 169 for _, name := range fingerprint.BuiltinFingerprints() { 170 // Skip modules that are not in the whitelist if it is enabled. 171 if _, ok := whitelistFingerprints[name]; whitelistFingerprintsEnabled && !ok { 172 skippedFingerprints = append(skippedFingerprints, name) 173 continue 174 } 175 // Skip modules that are in the blacklist 176 if _, ok := blacklistFingerprints[name]; ok { 177 skippedFingerprints = append(skippedFingerprints, name) 178 continue 179 } 180 181 availableFingerprints = append(availableFingerprints, name) 182 } 183 184 if err := fp.setupFingerprinters(availableFingerprints); err != nil { 185 return err 186 } 187 188 if len(skippedFingerprints) != 0 { 189 fp.logger.Printf("[DEBUG] client.fingerprint_manager: fingerprint modules skipped due to white/blacklist: %v", skippedFingerprints) 190 } 191 192 // next, set up drivers 193 // Build the white/blacklists of drivers. 194 whitelistDrivers := cfg.ReadStringListToMap("driver.whitelist") 195 whitelistDriversEnabled := len(whitelistDrivers) > 0 196 blacklistDrivers := cfg.ReadStringListToMap("driver.blacklist") 197 198 var availDrivers []string 199 var skippedDrivers []string 200 201 for name := range driver.BuiltinDrivers { 202 // Skip fingerprinting drivers that are not in the whitelist if it is 203 // enabled. 204 if _, ok := whitelistDrivers[name]; whitelistDriversEnabled && !ok { 205 skippedDrivers = append(skippedDrivers, name) 206 continue 207 } 208 // Skip fingerprinting drivers that are in the blacklist 209 if _, ok := blacklistDrivers[name]; ok { 210 skippedDrivers = append(skippedDrivers, name) 211 continue 212 } 213 214 availDrivers = append(availDrivers, name) 215 } 216 217 if err := fp.setupDrivers(availDrivers); err != nil { 218 return err 219 } 220 221 if len(skippedDrivers) > 0 { 222 fp.logger.Printf("[DEBUG] client.fingerprint_manager: drivers skipped due to white/blacklist: %v", skippedDrivers) 223 } 224 return nil 225 }