// validatePendingEngine connects to the engine, func (c *Cluster) validatePendingEngine(engine *cluster.Engine) bool { // Attempt a connection to the engine. Since this is slow, don't get a hold // of the lock yet. if err := engine.Connect(c.TLSConfig); err != nil { log.WithFields(log.Fields{"Addr": engine.Addr}).Debugf("Failed to validate pending node: %s", err) return false } // The following is critical and fast. Grab a lock. c.Lock() defer c.Unlock() // Only validate engines from pendingEngines list if _, exists := c.pendingEngines[engine.Addr]; !exists { return false } // Make sure the engine ID is unique. if old, exists := c.engines[engine.ID]; exists { if old.Addr != engine.Addr { log.Errorf("ID duplicated. %s shared by %s and %s", engine.ID, old.Addr, engine.Addr) // Keep this engine in pendingEngines table and show its error. // If it's ID duplication from VM clone, user see this message and can fix it. // If the engine is rebooted and get new IP from DHCP, previous address will be removed // from discovery after a while. // In both cases, retry may fix the problem. engine.HandleIDConflict(old.Addr) } else { log.Debugf("node %q (name: %q) with address %q is already registered", engine.ID, engine.Name, engine.Addr) engine.Disconnect() // Remove it from pendingEngines table delete(c.pendingEngines, engine.Addr) } return false } // Engine validated, move from pendingEngines table to engines table delete(c.pendingEngines, engine.Addr) // set engine state to healthy, and start refresh loop engine.ValidationComplete() c.engines[engine.ID] = engine log.Infof("Registered Engine %s at %s", engine.Name, engine.Addr) return true }