Files
docker-cli/cli/command/swarm/progress/root_rotation.go
Kir Kolyshkin 6f8070deb2 Switch from x/net/context to context
Since go 1.7, "context" is a standard package. Since go 1.9,
x/net/context merely provides some types aliased to those in
the standard context package.

The changes were performed by the following script:

for f in $(git ls-files \*.go | grep -v ^vendor/); do
	sed -i 's|golang.org/x/net/context|context|' $f
	goimports -w $f
	for i in 1 2; do
		awk '/^$/ {e=1; next;}
			/\t"context"$/ {e=0;}
			{if (e) {print ""; e=0}; print;}' < $f > $f.new && \
				mv $f.new $f
		goimports -w $f
	done
done

[v2: do awk/goimports fixup twice]
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2018-05-11 16:49:43 -07:00

121 lines
3.4 KiB
Go

package progress
import (
"bytes"
"context"
"io"
"os"
"os/signal"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/progress"
"github.com/docker/docker/pkg/streamformatter"
"github.com/opencontainers/go-digest"
)
const (
certsRotatedStr = " rotated TLS certificates"
rootsRotatedStr = " rotated CA certificates"
// rootsAction has a single space because rootsRotatedStr is one character shorter than certsRotatedStr.
// This makes sure the progress bar are aligned.
certsAction = ""
rootsAction = " "
)
// RootRotationProgress outputs progress information for convergence of a root rotation.
func RootRotationProgress(ctx context.Context, dclient client.APIClient, progressWriter io.WriteCloser) error {
defer progressWriter.Close()
progressOut := streamformatter.NewJSONProgressOutput(progressWriter, false)
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, os.Interrupt)
defer signal.Stop(sigint)
// draw 2 progress bars, 1 for nodes with the correct cert, 1 for nodes with the correct trust root
progress.Update(progressOut, "desired root digest", "")
progress.Update(progressOut, certsRotatedStr, certsAction)
progress.Update(progressOut, rootsRotatedStr, rootsAction)
var done bool
for {
info, err := dclient.SwarmInspect(ctx)
if err != nil {
return err
}
if done {
return nil
}
nodes, err := dclient.NodeList(ctx, types.NodeListOptions{})
if err != nil {
return err
}
done = updateProgress(progressOut, info.ClusterInfo.TLSInfo, nodes, info.ClusterInfo.RootRotationInProgress)
select {
case <-time.After(200 * time.Millisecond):
case <-sigint:
if !done {
progress.Message(progressOut, "", "Operation continuing in background.")
progress.Message(progressOut, "", "Use `swarmctl cluster inspect default` to check progress.")
}
return nil
}
}
}
func updateProgress(progressOut progress.Output, desiredTLSInfo swarm.TLSInfo, nodes []swarm.Node, rootRotationInProgress bool) bool {
// write the current desired root cert's digest, because the desired root certs might be too long
progressOut.WriteProgress(progress.Progress{
ID: "desired root digest",
Action: digest.FromBytes([]byte(desiredTLSInfo.TrustRoot)).String(),
})
// If we had reached a converged state, check if we are still converged.
var certsRight, trustRootsRight int64
for _, n := range nodes {
if bytes.Equal(n.Description.TLSInfo.CertIssuerPublicKey, desiredTLSInfo.CertIssuerPublicKey) &&
bytes.Equal(n.Description.TLSInfo.CertIssuerSubject, desiredTLSInfo.CertIssuerSubject) {
certsRight++
}
if n.Description.TLSInfo.TrustRoot == desiredTLSInfo.TrustRoot {
trustRootsRight++
}
}
total := int64(len(nodes))
progressOut.WriteProgress(progress.Progress{
ID: certsRotatedStr,
Action: certsAction,
Current: certsRight,
Total: total,
Units: "nodes",
})
rootsProgress := progress.Progress{
ID: rootsRotatedStr,
Action: rootsAction,
Current: trustRootsRight,
Total: total,
Units: "nodes",
}
if certsRight == total && !rootRotationInProgress {
progressOut.WriteProgress(rootsProgress)
return certsRight == total && trustRootsRight == total
}
// we still have certs that need renewing, so display that there are zero roots rotated yet
rootsProgress.Current = 0
progressOut.WriteProgress(rootsProgress)
return false
}