1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package gatewaykcp
import (
"context"
"fmt"
"log/slog"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"github.com/johnandersen777/socialweb-computer-kcp/internal/kcpserver"
"github.com/johnandersen777/socialweb-computer-kcp/internal/lease/local"
)
const MemberKubeconfig = "members.kubeconfig"
func memberRestConfig(path string) (*rest.Config, error) {
cfg, err := clientcmd.BuildConfigFromFlags("", path)
if err != nil {
return nil, err
}
cfg.Host, _, _ = strings.Cut(strings.TrimSuffix(cfg.Host, "/"), "/clusters/")
return kcpserver.FollowTokenFile(cfg), nil
}
const (
MemberToken = kcpserver.MemberTokenFile
kcpAdminUser = kcpserver.KcpAdminUser
memberTokenGap = 5 * time.Second
)
func followMemberToken(ctx context.Context, slotRoot func() string, slotsFile, tokenFile string, log *slog.Logger) {
for ctx.Err() == nil {
root := slotRoot()
wctx, cancel := context.WithCancel(ctx)
changes, err := local.Watch(wctx, slotsFile, filepath.Join(root, "admin.kubeconfig"), tokenFile)
if err != nil {
cancel()
log.Warn("the members' kcp-admin token files could not be watched", "err", err.Error())
again := time.NewTimer(memberTokenGap)
select {
case <-ctx.Done():
again.Stop()
return
case <-again.C:
}
continue
}
changed, err := kcpserver.RefreshMemberToken(root, tokenFile)
if err != nil {
log.Warn("the members' kcp-admin token could not be read from the active slot", "err", err.Error())
} else if changed {
log.Warn("the members' kcp-admin token lagged the active kcp slot; the fallback check rewrote it, not the roll at its flip", "slotRoot", root, "tokenFile", tokenFile)
}
select {
case <-ctx.Done():
case <-changes:
}
cancel()
}
}
func writeMemberKubeconfig(slotRoot, frontURL, out string) error {
cfg, err := clientcmd.LoadFromFile(filepath.Join(slotRoot, "admin.kubeconfig"))
if err != nil {
return err
}
tokenFile := filepath.Join(filepath.Dir(out), MemberToken)
if _, err := kcpserver.RefreshMemberToken(slotRoot, tokenFile); err != nil {
return err
}
if u, ok := cfg.AuthInfos[kcpAdminUser]; ok {
u.Token, u.TokenFile = "", tokenFile
}
front, err := url.Parse(frontURL)
if err != nil {
return err
}
for name, c := range cfg.Clusters {
u, err := url.Parse(c.Server)
if err != nil {
return fmt.Errorf("gatewaykcp: cluster %s server %q: %w", name, c.Server, err)
}
u.Scheme, u.Host = front.Scheme, front.Host
c.Server = u.String()
c.TLSServerName = "127.0.0.1"
}
tmp := out + ".tmp"
if err := clientcmd.WriteToFile(*cfg, tmp); err != nil {
return err
}
if err := os.Chmod(tmp, 0o600); err != nil {
return err
}
return os.Rename(tmp, out)
}