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  }