github.com/ilhicas/nomad@v0.11.8/drivers/docker/fingerprint.go (about) 1 package docker 2 3 import ( 4 "context" 5 "runtime" 6 "sort" 7 "strings" 8 "time" 9 10 "github.com/hashicorp/nomad/helper" 11 "github.com/hashicorp/nomad/plugins/drivers" 12 pstructs "github.com/hashicorp/nomad/plugins/shared/structs" 13 ) 14 15 func (d *Driver) Fingerprint(ctx context.Context) (<-chan *drivers.Fingerprint, error) { 16 // start reconciler when we start fingerprinting 17 // this is the only method called when driver is launched properly 18 d.reconciler.Start() 19 20 ch := make(chan *drivers.Fingerprint) 21 go d.handleFingerprint(ctx, ch) 22 return ch, nil 23 } 24 25 func (d *Driver) previouslyDetected() bool { 26 d.detectedLock.RLock() 27 defer d.detectedLock.RUnlock() 28 29 return d.detected 30 } 31 32 func (d *Driver) setDetected(detected bool) { 33 d.detectedLock.Lock() 34 defer d.detectedLock.Unlock() 35 36 d.detected = detected 37 } 38 39 // setFingerprintSuccess marks the driver as having fingerprinted successfully 40 func (d *Driver) setFingerprintSuccess() { 41 d.fingerprintLock.Lock() 42 d.fingerprintSuccess = helper.BoolToPtr(true) 43 d.fingerprintLock.Unlock() 44 } 45 46 // setFingerprintFailure marks the driver as having failed fingerprinting 47 func (d *Driver) setFingerprintFailure() { 48 d.fingerprintLock.Lock() 49 d.fingerprintSuccess = helper.BoolToPtr(false) 50 d.fingerprintLock.Unlock() 51 } 52 53 // fingerprintSuccessful returns true if the driver has 54 // never fingerprinted or has successfully fingerprinted 55 func (d *Driver) fingerprintSuccessful() bool { 56 d.fingerprintLock.Lock() 57 defer d.fingerprintLock.Unlock() 58 return d.fingerprintSuccess == nil || *d.fingerprintSuccess 59 } 60 61 func (d *Driver) handleFingerprint(ctx context.Context, ch chan *drivers.Fingerprint) { 62 defer close(ch) 63 64 ticker := time.NewTimer(0) 65 defer ticker.Stop() 66 67 for { 68 select { 69 case <-ctx.Done(): 70 return 71 case <-d.ctx.Done(): 72 return 73 case <-ticker.C: 74 ticker.Reset(fingerprintPeriod) 75 ch <- d.buildFingerprint() 76 } 77 } 78 } 79 80 func (d *Driver) buildFingerprint() *drivers.Fingerprint { 81 fp := &drivers.Fingerprint{ 82 Attributes: map[string]*pstructs.Attribute{}, 83 Health: drivers.HealthStateHealthy, 84 HealthDescription: drivers.DriverHealthy, 85 } 86 client, _, err := d.dockerClients() 87 if err != nil { 88 if d.fingerprintSuccessful() { 89 d.logger.Info("failed to initialize client", "error", err) 90 } 91 d.setFingerprintFailure() 92 return &drivers.Fingerprint{ 93 Health: drivers.HealthStateUndetected, 94 HealthDescription: "Failed to initialize docker client", 95 } 96 } 97 98 env, err := client.Version() 99 if err != nil { 100 if d.fingerprintSuccessful() { 101 d.logger.Debug("could not connect to docker daemon", "endpoint", client.Endpoint(), "error", err) 102 } 103 d.setFingerprintFailure() 104 105 result := drivers.HealthStateUndetected 106 if d.previouslyDetected() { 107 result = drivers.HealthStateUnhealthy 108 } 109 110 return &drivers.Fingerprint{ 111 Health: result, 112 HealthDescription: "Failed to connect to docker daemon", 113 } 114 } 115 116 d.setDetected(true) 117 fp.Attributes["driver.docker"] = pstructs.NewBoolAttribute(true) 118 fp.Attributes["driver.docker.version"] = pstructs.NewStringAttribute(env.Get("Version")) 119 if d.config.AllowPrivileged { 120 fp.Attributes["driver.docker.privileged.enabled"] = pstructs.NewBoolAttribute(true) 121 } 122 123 if d.config.Volumes.Enabled { 124 fp.Attributes["driver.docker.volumes.enabled"] = pstructs.NewBoolAttribute(true) 125 } 126 127 if nets, err := client.ListNetworks(); err != nil { 128 d.logger.Warn("error discovering bridge IP", "error", err) 129 } else { 130 for _, n := range nets { 131 if n.Name != "bridge" { 132 continue 133 } 134 135 if len(n.IPAM.Config) == 0 { 136 d.logger.Warn("no IPAM config for bridge network") 137 break 138 } 139 140 if n.IPAM.Config[0].Gateway != "" { 141 fp.Attributes["driver.docker.bridge_ip"] = pstructs.NewStringAttribute(n.IPAM.Config[0].Gateway) 142 } else { 143 // Docker 17.09.0-ce dropped the Gateway IP from the bridge network 144 // See https://github.com/moby/moby/issues/32648 145 if d.fingerprintSuccess == nil { 146 d.logger.Debug("bridge_ip could not be discovered") 147 } 148 } 149 break 150 } 151 } 152 153 if dockerInfo, err := client.Info(); err != nil { 154 d.logger.Warn("failed to get Docker system info", "error", err) 155 } else { 156 runtimeNames := make([]string, 0, len(dockerInfo.Runtimes)) 157 for name := range dockerInfo.Runtimes { 158 if d.config.GPURuntimeName == name { 159 // Nvidia runtime is detected by Docker. 160 // It makes possible to run GPU workloads using Docker driver on this host. 161 d.gpuRuntime = true 162 } 163 runtimeNames = append(runtimeNames, name) 164 } 165 sort.Strings(runtimeNames) 166 167 fp.Attributes["driver.docker.runtimes"] = pstructs.NewStringAttribute( 168 strings.Join(runtimeNames, ",")) 169 fp.Attributes["driver.docker.os_type"] = pstructs.NewStringAttribute(dockerInfo.OSType) 170 171 // If this situations arises, we are running in Windows 10 with Linux Containers enabled via VM 172 if runtime.GOOS == "windows" && dockerInfo.OSType == "linux" { 173 if d.fingerprintSuccessful() { 174 d.logger.Warn("Docker is configured with Linux containers; switch to Windows Containers") 175 } 176 177 d.setFingerprintFailure() 178 return &drivers.Fingerprint{ 179 Health: drivers.HealthStateUnhealthy, 180 HealthDescription: "Docker is configured with Linux containers; switch to Windows Containers", 181 } 182 } 183 } 184 185 d.setFingerprintSuccess() 186 187 return fp 188 }