Repository: k3s-io/k3s
File: pkg/cluster/managed.go (Go)

Code before:
			return err
		}
		if ok, err := driver.IsInitialized(); err != nil {
			return err
		} else if ok {
			c.managedDB = driver
			return nil
		}
	}

	// If we have been asked to initialize or join a cluster, do so using the default managed database.
	if c.config.Datastore.Endpoint == "" && (c.config.ClusterInit || (c.config.Token != "" && c.config.JoinURL != "")) {
		c.managedDB = managed.Default()
	}

	return nil
}

// setupEtcdProxy starts a goroutine to periodically update the etcd proxy with the current list of
// cluster client URLs, as retrieved from etcd.
func (c *Cluster) setupEtcdProxy(ctx context.Context, etcdProxy etcd.Proxy) {
	if c.managedDB == nil {
		return
	}
	// We use Poll here instead of Until because we want to wait the interval before running the function.
	go wait.PollUntilContextCancel(ctx, 30*time.Second, true, func(ctx context.Context) (bool, error) {
		clientURLs, err := c.managedDB.GetMembersClientURLs(ctx)
		if err != nil {
			logrus.Warnf("Failed to get etcd ClientURLs: %v", err)
			return false, nil
		}
		// client URLs are a full URI, but the proxy only wants host:port
		for i, c := range clientURLs {
			u, err := url.Parse(c)
			if err != nil {
				logrus.Warnf("Failed to parse etcd ClientURL: %v", err)
				return false, nil
			}
			clientURLs[i] = u.Host
		}
		etcdProxy.Update(clientURLs)
		return false, nil
	})
}

// deleteNodePasswdSecret wipes out the node password secret after restoration
func (c *Cluster) deleteNodePasswdSecret(ctx context.Context) {
	nodeName := os.Getenv("NODE_NAME")
	secretsClient := c.config.Runtime.Core.Core().V1().Secret()
	if err := nodepassword.Delete(secretsClient, nodeName); err != nil {
		if apierrors.IsNotFound(err) {

Review comment (suggestion):
We explicitly want to wait for the 30s before calling the function. This "may" be the source of the split role error. 
```suggestion
	go wait.PollUntilContextCancel(ctx, 30*time.Second, false, func(ctx context.Context) (bool, error) {
```

Code after:
			return err
		}
		if ok, err := driver.IsInitialized(); err != nil {
			return err
		} else if ok {
			c.managedDB = driver
			return nil
		}
	}

	// If we have been asked to initialize or join a cluster, do so using the default managed database.
	if c.config.Datastore.Endpoint == "" && (c.config.ClusterInit || (c.config.Token != "" && c.config.JoinURL != "")) {
		c.managedDB = managed.Default()
	}

	return nil
}

// setupEtcdProxy starts a goroutine to periodically update the etcd proxy with the current list of
// cluster client URLs, as retrieved from etcd.
func (c *Cluster) setupEtcdProxy(ctx context.Context, etcdProxy etcd.Proxy) {
	if c.managedDB == nil {
		return
	}
	// We use Poll here instead of Until because we want to wait the interval before running the function.
	go wait.PollUntilContextCancel(ctx, 30*time.Second, false, func(ctx context.Context) (bool, error) {
		clientURLs, err := c.managedDB.GetMembersClientURLs(ctx)
		if err != nil {
			logrus.Warnf("Failed to get etcd ClientURLs: %v", err)
			return false, nil
		}
		// client URLs are a full URI, but the proxy only wants host:port
		for i, c := range clientURLs {
			u, err := url.Parse(c)
			if err != nil {
				logrus.Warnf("Failed to parse etcd ClientURL: %v", err)
				return false, nil
			}
			clientURLs[i] = u.Host
		}
		etcdProxy.Update(clientURLs)
		return false, nil
	})
}

// deleteNodePasswdSecret wipes out the node password secret after restoration
func (c *Cluster) deleteNodePasswdSecret(ctx context.Context) {
	nodeName := os.Getenv("NODE_NAME")
	secretsClient := c.config.Runtime.Core.Core().V1().Secret()
	if err := nodepassword.Delete(secretsClient, nodeName); err != nil {
		if apierrors.IsNotFound(err) {