Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
f55f0967
Commit
f55f0967
authored
Feb 16, 2022
by
Brad Davidson
Committed by
Brad Davidson
Mar 15, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix adding etcd-only node to existing cluster
Signed-off-by:
Brad Davidson
<
brad.davidson@rancher.com
>
(cherry picked from commit
5014c9e0
)
parent
ee4c209d
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
164 additions
and
93 deletions
+164
-93
loadbalancer.go
pkg/agent/loadbalancer/loadbalancer.go
+33
-26
servers.go
pkg/agent/loadbalancer/servers.go
+2
-2
apiproxy.go
pkg/agent/proxy/apiproxy.go
+23
-0
run.go
pkg/agent/run.go
+27
-12
agent.go
pkg/cli/cmds/agent.go
+1
-1
server.go
pkg/cli/server/server.go
+17
-32
bootstrap.go
pkg/cluster/bootstrap.go
+1
-0
server.go
pkg/daemons/control/server.go
+5
-3
etcd.go
pkg/etcd/etcd.go
+25
-14
etcd.go
pkg/server/etcd.go
+2
-1
router.go
pkg/server/router.go
+16
-1
server.go
pkg/server/server.go
+7
-1
api.go
pkg/util/api.go
+5
-0
No files found.
pkg/agent/loadbalancer/loadbalancer.go
View file @
f55f0967
...
@@ -19,16 +19,17 @@ type LoadBalancer struct {
...
@@ -19,16 +19,17 @@ type LoadBalancer struct {
dialer
*
net
.
Dialer
dialer
*
net
.
Dialer
proxy
*
tcpproxy
.
Proxy
proxy
*
tcpproxy
.
Proxy
configFile
string
serviceName
string
localAddress
string
configFile
string
localServerURL
string
localAddress
string
originalServerAddress
string
localServerURL
string
ServerURL
string
defaultServerAddress
string
ServerAddresses
[]
string
ServerURL
string
randomServers
[]
string
ServerAddresses
[]
string
currentServerAddress
string
randomServers
[]
string
nextServerIndex
int
currentServerAddress
string
Listener
net
.
Listener
nextServerIndex
int
Listener
net
.
Listener
}
}
const
RandomPort
=
0
const
RandomPort
=
0
...
@@ -55,26 +56,27 @@ func New(ctx context.Context, dataDir, serviceName, serverURL string, lbServerPo
...
@@ -55,26 +56,27 @@ func New(ctx context.Context, dataDir, serviceName, serverURL string, lbServerPo
}
}
localAddress
:=
listener
.
Addr
()
.
String
()
localAddress
:=
listener
.
Addr
()
.
String
()
original
ServerAddress
,
localServerURL
,
err
:=
parseURL
(
serverURL
,
localAddress
)
default
ServerAddress
,
localServerURL
,
err
:=
parseURL
(
serverURL
,
localAddress
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
if
serverURL
==
localServerURL
{
if
serverURL
==
localServerURL
{
logrus
.
Debugf
(
"Initial server URL for load balancer
points at local server URL - starting with empty original server address"
)
logrus
.
Debugf
(
"Initial server URL for load balancer
%s points at local server URL - starting with empty default server address"
,
serviceName
)
original
ServerAddress
=
""
default
ServerAddress
=
""
}
}
lb
:=
&
LoadBalancer
{
lb
:=
&
LoadBalancer
{
dialer
:
&
net
.
Dialer
{},
serviceName
:
serviceName
,
configFile
:
filepath
.
Join
(
dataDir
,
"etc"
,
serviceName
+
".json"
),
dialer
:
&
net
.
Dialer
{},
localAddress
:
localAddress
,
configFile
:
filepath
.
Join
(
dataDir
,
"etc"
,
serviceName
+
".json"
),
localServerURL
:
localServerURL
,
localAddress
:
localAddress
,
originalServerAddress
:
originalServerAddress
,
localServerURL
:
localServerURL
,
ServerURL
:
serverURL
,
defaultServerAddress
:
defaultServerAddress
,
ServerURL
:
serverURL
,
}
}
lb
.
setServers
([]
string
{
lb
.
original
ServerAddress
})
lb
.
setServers
([]
string
{
lb
.
default
ServerAddress
})
lb
.
proxy
=
&
tcpproxy
.
Proxy
{
lb
.
proxy
=
&
tcpproxy
.
Proxy
{
ListenFunc
:
func
(
string
,
string
)
(
net
.
Listener
,
error
)
{
ListenFunc
:
func
(
string
,
string
)
(
net
.
Listener
,
error
)
{
...
@@ -93,11 +95,16 @@ func New(ctx context.Context, dataDir, serviceName, serverURL string, lbServerPo
...
@@ -93,11 +95,16 @@ func New(ctx context.Context, dataDir, serviceName, serverURL string, lbServerPo
if
err
:=
lb
.
proxy
.
Start
();
err
!=
nil
{
if
err
:=
lb
.
proxy
.
Start
();
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
logrus
.
Infof
(
"Running load balancer %s
-> %v"
,
lb
.
localAddress
,
lb
.
randomServers
)
logrus
.
Infof
(
"Running load balancer %s
%s -> %v"
,
serviceName
,
lb
.
localAddress
,
lb
.
randomServers
)
return
lb
,
nil
return
lb
,
nil
}
}
func
(
lb
*
LoadBalancer
)
SetDefault
(
serverAddress
string
)
{
logrus
.
Infof
(
"Updating load balancer %s default server address -> %s"
,
lb
.
serviceName
,
serverAddress
)
lb
.
defaultServerAddress
=
serverAddress
}
func
(
lb
*
LoadBalancer
)
Update
(
serverAddresses
[]
string
)
{
func
(
lb
*
LoadBalancer
)
Update
(
serverAddresses
[]
string
)
{
if
lb
==
nil
{
if
lb
==
nil
{
return
return
...
@@ -105,10 +112,10 @@ func (lb *LoadBalancer) Update(serverAddresses []string) {
...
@@ -105,10 +112,10 @@ func (lb *LoadBalancer) Update(serverAddresses []string) {
if
!
lb
.
setServers
(
serverAddresses
)
{
if
!
lb
.
setServers
(
serverAddresses
)
{
return
return
}
}
logrus
.
Infof
(
"Updating load balancer
server addresses -> %v"
,
lb
.
randomServers
)
logrus
.
Infof
(
"Updating load balancer
%s server addresses -> %v"
,
lb
.
serviceName
,
lb
.
randomServers
)
if
err
:=
lb
.
writeConfig
();
err
!=
nil
{
if
err
:=
lb
.
writeConfig
();
err
!=
nil
{
logrus
.
Warnf
(
"Error updating load balancer
config: %s"
,
err
)
logrus
.
Warnf
(
"Error updating load balancer
%s config: %s"
,
lb
.
serviceName
,
err
)
}
}
}
}
...
@@ -128,14 +135,14 @@ func (lb *LoadBalancer) dialContext(ctx context.Context, network, address string
...
@@ -128,14 +135,14 @@ func (lb *LoadBalancer) dialContext(ctx context.Context, network, address string
if
err
==
nil
{
if
err
==
nil
{
return
conn
,
nil
return
conn
,
nil
}
}
logrus
.
Debugf
(
"Dial error from load balancer
: %s"
,
err
)
logrus
.
Debugf
(
"Dial error from load balancer
%s: %s"
,
lb
.
serviceName
,
err
)
newServer
,
err
:=
lb
.
nextServer
(
targetServer
)
newServer
,
err
:=
lb
.
nextServer
(
targetServer
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
if
targetServer
!=
newServer
{
if
targetServer
!=
newServer
{
logrus
.
Debugf
(
"Dial server in load balancer
failed over to %s"
,
newServer
)
logrus
.
Debugf
(
"Dial server in load balancer
%s failed over to %s"
,
lb
.
serviceName
,
newServer
)
}
}
if
ctx
.
Err
()
!=
nil
{
if
ctx
.
Err
()
!=
nil
{
return
nil
,
ctx
.
Err
()
return
nil
,
ctx
.
Err
()
...
@@ -156,7 +163,7 @@ func onDialError(src net.Conn, dstDialErr error) {
...
@@ -156,7 +163,7 @@ func onDialError(src net.Conn, dstDialErr error) {
src
.
Close
()
src
.
Close
()
}
}
// ResetLoadBalancer will delete the local state file for the load bala
cn
er on disk
// ResetLoadBalancer will delete the local state file for the load bala
nc
er on disk
func
ResetLoadBalancer
(
dataDir
,
serviceName
string
)
error
{
func
ResetLoadBalancer
(
dataDir
,
serviceName
string
)
error
{
stateFile
:=
filepath
.
Join
(
dataDir
,
"etc"
,
serviceName
+
".json"
)
stateFile
:=
filepath
.
Join
(
dataDir
,
"etc"
,
serviceName
+
".json"
)
if
err
:=
os
.
Remove
(
stateFile
);
err
!=
nil
{
if
err
:=
os
.
Remove
(
stateFile
);
err
!=
nil
{
...
...
pkg/agent/loadbalancer/servers.go
View file @
f55f0967
...
@@ -7,7 +7,7 @@ import (
...
@@ -7,7 +7,7 @@ import (
)
)
func
(
lb
*
LoadBalancer
)
setServers
(
serverAddresses
[]
string
)
bool
{
func
(
lb
*
LoadBalancer
)
setServers
(
serverAddresses
[]
string
)
bool
{
serverAddresses
,
hasOriginalServer
:=
sortServers
(
serverAddresses
,
lb
.
original
ServerAddress
)
serverAddresses
,
hasOriginalServer
:=
sortServers
(
serverAddresses
,
lb
.
default
ServerAddress
)
if
len
(
serverAddresses
)
==
0
{
if
len
(
serverAddresses
)
==
0
{
return
false
return
false
}
}
...
@@ -25,7 +25,7 @@ func (lb *LoadBalancer) setServers(serverAddresses []string) bool {
...
@@ -25,7 +25,7 @@ func (lb *LoadBalancer) setServers(serverAddresses []string) bool {
lb
.
randomServers
[
i
],
lb
.
randomServers
[
j
]
=
lb
.
randomServers
[
j
],
lb
.
randomServers
[
i
]
lb
.
randomServers
[
i
],
lb
.
randomServers
[
j
]
=
lb
.
randomServers
[
j
],
lb
.
randomServers
[
i
]
})
})
if
!
hasOriginalServer
{
if
!
hasOriginalServer
{
lb
.
randomServers
=
append
(
lb
.
randomServers
,
lb
.
original
ServerAddress
)
lb
.
randomServers
=
append
(
lb
.
randomServers
,
lb
.
default
ServerAddress
)
}
}
lb
.
currentServerAddress
=
lb
.
randomServers
[
0
]
lb
.
currentServerAddress
=
lb
.
randomServers
[
0
]
lb
.
nextServerIndex
=
1
lb
.
nextServerIndex
=
1
...
...
pkg/agent/proxy/apiproxy.go
View file @
f55f0967
...
@@ -15,6 +15,7 @@ import (
...
@@ -15,6 +15,7 @@ import (
type
Proxy
interface
{
type
Proxy
interface
{
Update
(
addresses
[]
string
)
Update
(
addresses
[]
string
)
SetAPIServerPort
(
ctx
context
.
Context
,
port
int
)
error
SetAPIServerPort
(
ctx
context
.
Context
,
port
int
)
error
SetSupervisorDefault
(
address
string
)
SupervisorURL
()
string
SupervisorURL
()
string
SupervisorAddresses
()
[]
string
SupervisorAddresses
()
[]
string
APIServerURL
()
string
APIServerURL
()
string
...
@@ -135,6 +136,28 @@ func (p *proxy) SetAPIServerPort(ctx context.Context, port int) error {
...
@@ -135,6 +136,28 @@ func (p *proxy) SetAPIServerPort(ctx context.Context, port int) error {
return
nil
return
nil
}
}
// SetSupervisorDefault updates the default (fallback) address for the connection to the
// supervisor. This is most useful on k3s nodes without apiservers, where the local
// supervisor must be used to bootstrap the agent config, but then switched over to
// another node running an apiserver once one is available.
func
(
p
*
proxy
)
SetSupervisorDefault
(
address
string
)
{
host
,
port
,
err
:=
sysnet
.
SplitHostPort
(
address
)
if
err
!=
nil
{
logrus
.
Errorf
(
"Failed to parse address %s, dropping: %v"
,
address
,
err
)
return
}
if
p
.
apiServerEnabled
{
port
=
p
.
supervisorPort
address
=
sysnet
.
JoinHostPort
(
host
,
port
)
}
p
.
fallbackSupervisorAddress
=
address
if
p
.
supervisorLB
==
nil
{
p
.
supervisorURL
=
"https://"
+
address
}
else
{
p
.
supervisorLB
.
SetDefault
(
address
)
}
}
func
(
p
*
proxy
)
SupervisorURL
()
string
{
func
(
p
*
proxy
)
SupervisorURL
()
string
{
return
p
.
supervisorURL
return
p
.
supervisorURL
}
}
...
...
pkg/agent/run.go
View file @
f55f0967
...
@@ -3,9 +3,10 @@ package agent
...
@@ -3,9 +3,10 @@ package agent
import
(
import
(
"context"
"context"
"fmt"
"fmt"
"net
/url
"
"net"
"os"
"os"
"path/filepath"
"path/filepath"
"strconv"
"strings"
"strings"
"time"
"time"
...
@@ -350,17 +351,8 @@ func setupTunnelAndRunAgent(ctx context.Context, nodeConfig *daemonconfig.Node,
...
@@ -350,17 +351,8 @@ func setupTunnelAndRunAgent(ctx context.Context, nodeConfig *daemonconfig.Node,
}
}
agentRan
=
true
agentRan
=
true
}
}
if
err
:=
waitForAPIServerAddresses
(
ctx
,
nodeConfig
,
cfg
,
proxy
);
err
!=
nil
{
select
{
return
err
case
address
:=
<-
cfg
.
APIAddressCh
:
cfg
.
ServerURL
=
address
u
,
err
:=
url
.
Parse
(
cfg
.
ServerURL
)
if
err
!=
nil
{
logrus
.
Warn
(
err
)
}
proxy
.
Update
([]
string
{
fmt
.
Sprintf
(
"%s:%d"
,
u
.
Hostname
(),
nodeConfig
.
ServerHTTPSPort
)})
case
<-
ctx
.
Done
()
:
return
ctx
.
Err
()
}
}
}
else
if
cfg
.
ClusterReset
&&
proxy
.
IsAPIServerLBEnabled
()
{
}
else
if
cfg
.
ClusterReset
&&
proxy
.
IsAPIServerLBEnabled
()
{
// If we're doing a cluster-reset on RKE2, the kubelet needs to be started early to clean
// If we're doing a cluster-reset on RKE2, the kubelet needs to be started early to clean
...
@@ -379,3 +371,26 @@ func setupTunnelAndRunAgent(ctx context.Context, nodeConfig *daemonconfig.Node,
...
@@ -379,3 +371,26 @@ func setupTunnelAndRunAgent(ctx context.Context, nodeConfig *daemonconfig.Node,
}
}
return
nil
return
nil
}
}
func
waitForAPIServerAddresses
(
ctx
context
.
Context
,
nodeConfig
*
daemonconfig
.
Node
,
cfg
cmds
.
Agent
,
proxy
proxy
.
Proxy
)
error
{
for
{
select
{
case
<-
time
.
After
(
5
*
time
.
Second
)
:
logrus
.
Info
(
"Waiting for apiserver addresses"
)
case
addresses
:=
<-
cfg
.
APIAddressCh
:
for
i
,
a
:=
range
addresses
{
host
,
_
,
err
:=
net
.
SplitHostPort
(
a
)
if
err
==
nil
{
addresses
[
i
]
=
net
.
JoinHostPort
(
host
,
strconv
.
Itoa
(
nodeConfig
.
ServerHTTPSPort
))
if
i
==
0
{
proxy
.
SetSupervisorDefault
(
addresses
[
i
])
}
}
}
proxy
.
Update
(
addresses
)
return
nil
case
<-
ctx
.
Done
()
:
return
ctx
.
Err
()
}
}
}
pkg/cli/cmds/agent.go
View file @
f55f0967
...
@@ -14,7 +14,7 @@ type Agent struct {
...
@@ -14,7 +14,7 @@ type Agent struct {
TokenFile
string
TokenFile
string
ClusterSecret
string
ClusterSecret
string
ServerURL
string
ServerURL
string
APIAddressCh
chan
string
APIAddressCh
chan
[]
string
DisableLoadBalancer
bool
DisableLoadBalancer
bool
DisableServiceLB
bool
DisableServiceLB
bool
ETCDAgent
bool
ETCDAgent
bool
...
...
pkg/cli/server/server.go
View file @
f55f0967
...
@@ -393,13 +393,6 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont
...
@@ -393,13 +393,6 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont
serverConfig
.
ControlConfig
.
DisableScheduler
=
true
serverConfig
.
ControlConfig
.
DisableScheduler
=
true
serverConfig
.
ControlConfig
.
DisableCCM
=
true
serverConfig
.
ControlConfig
.
DisableCCM
=
true
// only close the agentReady channel in case of k3s restoration, because k3s does not start
// the agent until server returns successfully, unlike rke2's agent which starts in parallel
// with the server
if
serverConfig
.
ControlConfig
.
SupervisorPort
==
serverConfig
.
ControlConfig
.
HTTPSPort
{
close
(
agentReady
)
}
dataDir
,
err
:=
datadir
.
LocalHome
(
cfg
.
DataDir
,
false
)
dataDir
,
err
:=
datadir
.
LocalHome
(
cfg
.
DataDir
,
false
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
...
@@ -483,10 +476,12 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont
...
@@ -483,10 +476,12 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont
}
}
if
serverConfig
.
ControlConfig
.
DisableAPIServer
{
if
serverConfig
.
ControlConfig
.
DisableAPIServer
{
if
cfg
.
ServerURL
!=
""
{
agentConfig
.
ServerURL
=
cfg
.
ServerURL
}
// initialize the apiAddress Channel for receiving the api address from etcd
// initialize the apiAddress Channel for receiving the api address from etcd
agentConfig
.
APIAddressCh
=
make
(
chan
string
,
1
)
agentConfig
.
APIAddressCh
=
make
(
chan
[]
string
)
setAPIAddressChannel
(
ctx
,
&
serverConfig
,
&
agentConfig
)
go
getAPIAddressFromEtcd
(
ctx
,
serverConfig
,
agentConfig
)
defer
close
(
agentConfig
.
APIAddressCh
)
}
}
return
agent
.
Run
(
ctx
,
agentConfig
)
return
agent
.
Run
(
ctx
,
agentConfig
)
}
}
...
@@ -532,29 +527,19 @@ func getArgValueFromList(searchArg string, argList []string) string {
...
@@ -532,29 +527,19 @@ func getArgValueFromList(searchArg string, argList []string) string {
return
value
return
value
}
}
// setAPIAddressChannel will try to get the api address key from etcd and when it succeed it will
func
getAPIAddressFromEtcd
(
ctx
context
.
Context
,
serverConfig
server
.
Config
,
agentConfig
cmds
.
Agent
)
{
// set the APIAddressCh channel with its value, the function works for both k3s and rke2 in case
defer
close
(
agentConfig
.
APIAddressCh
)
// of k3s we block returning back to the agent.Run until we get the api address, however in rke2
for
{
// the code will not block operation and will run the operation in a goroutine
toCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
5
*
time
.
Second
)
func
setAPIAddressChannel
(
ctx
context
.
Context
,
serverConfig
*
server
.
Config
,
agentConfig
*
cmds
.
Agent
)
{
defer
cancel
()
// start a goroutine to check for the server ip if set from etcd in case of rke2
serverAddresses
,
err
:=
etcd
.
GetAPIServerURLsFromETCD
(
toCtx
,
&
serverConfig
.
ControlConfig
)
if
serverConfig
.
ControlConfig
.
HTTPSPort
!=
serverConfig
.
ControlConfig
.
SupervisorPort
{
if
err
==
nil
&&
len
(
serverAddresses
)
>
0
{
go
getAPIAddressFromEtcd
(
ctx
,
serverConfig
,
agentConfig
)
agentConfig
.
APIAddressCh
<-
serverAddresses
return
}
getAPIAddressFromEtcd
(
ctx
,
serverConfig
,
agentConfig
)
}
func
getAPIAddressFromEtcd
(
ctx
context
.
Context
,
serverConfig
*
server
.
Config
,
agentConfig
*
cmds
.
Agent
)
{
t
:=
time
.
NewTicker
(
5
*
time
.
Second
)
defer
t
.
Stop
()
for
range
t
.
C
{
serverAddress
,
err
:=
etcd
.
GetAPIServerURLFromETCD
(
ctx
,
&
serverConfig
.
ControlConfig
)
if
err
==
nil
{
agentConfig
.
ServerURL
=
"https://"
+
serverAddress
agentConfig
.
APIAddressCh
<-
agentConfig
.
ServerURL
break
break
}
}
logrus
.
Warn
(
err
)
if
!
errors
.
Is
(
err
,
etcd
.
ErrAddressNotSet
)
{
logrus
.
Warnf
(
"Failed to get apiserver address from etcd: %v"
,
err
)
}
<-
toCtx
.
Done
()
}
}
}
}
pkg/cluster/bootstrap.go
View file @
f55f0967
...
@@ -356,6 +356,7 @@ func (c *Cluster) ReconcileBootstrapData(ctx context.Context, buf io.ReadSeeker,
...
@@ -356,6 +356,7 @@ func (c *Cluster) ReconcileBootstrapData(ctx context.Context, buf io.ReadSeeker,
buf
.
Seek
(
0
,
0
)
buf
.
Seek
(
0
,
0
)
}
}
logrus
.
Debugf
(
"One or more certificate directories do not exist; writing data to disk from datastore"
)
return
bootstrap
.
WriteToDiskFromStorage
(
files
,
crb
)
return
bootstrap
.
WriteToDiskFromStorage
(
files
,
crb
)
}
}
...
...
pkg/daemons/control/server.go
View file @
f55f0967
...
@@ -55,10 +55,12 @@ func Server(ctx context.Context, cfg *config.Control) error {
...
@@ -55,10 +55,12 @@ func Server(ctx context.Context, cfg *config.Control) error {
if
err
:=
apiServer
(
ctx
,
cfg
);
err
!=
nil
{
if
err
:=
apiServer
(
ctx
,
cfg
);
err
!=
nil
{
return
err
return
err
}
}
}
if
err
:=
waitForAPIServerInBackground
(
ctx
,
cfg
.
Runtime
);
err
!=
nil
{
// Wait for an apiserver to become available before starting additional controllers,
return
err
// even if we're not running an apiserver locally.
}
if
err
:=
waitForAPIServerInBackground
(
ctx
,
cfg
.
Runtime
);
err
!=
nil
{
return
err
}
}
if
!
cfg
.
DisableScheduler
{
if
!
cfg
.
DisableScheduler
{
...
...
pkg/etcd/etcd.go
View file @
f55f0967
...
@@ -74,6 +74,8 @@ var (
...
@@ -74,6 +74,8 @@ var (
NodeNameAnnotation
=
"etcd."
+
version
.
Program
+
".cattle.io/node-name"
NodeNameAnnotation
=
"etcd."
+
version
.
Program
+
".cattle.io/node-name"
NodeAddressAnnotation
=
"etcd."
+
version
.
Program
+
".cattle.io/node-address"
NodeAddressAnnotation
=
"etcd."
+
version
.
Program
+
".cattle.io/node-address"
ErrAddressNotSet
=
errors
.
New
(
"apiserver addresses not yet set"
)
)
)
type
NodeControllerGetter
func
()
controllerv1
.
NodeController
type
NodeControllerGetter
func
()
controllerv1
.
NodeController
...
@@ -277,7 +279,7 @@ func (e *ETCD) Reset(ctx context.Context, rebootstrap func() error) error {
...
@@ -277,7 +279,7 @@ func (e *ETCD) Reset(ctx context.Context, rebootstrap func() error) error {
// Start starts the datastore
// Start starts the datastore
func
(
e
*
ETCD
)
Start
(
ctx
context
.
Context
,
clientAccessInfo
*
clientaccess
.
Info
)
error
{
func
(
e
*
ETCD
)
Start
(
ctx
context
.
Context
,
clientAccessInfo
*
clientaccess
.
Info
)
error
{
existingCluster
,
err
:=
e
.
IsInitialized
(
ctx
,
e
.
config
)
isInitialized
,
err
:=
e
.
IsInitialized
(
ctx
,
e
.
config
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errors
.
Wrapf
(
err
,
"configuration validation failed"
)
return
errors
.
Wrapf
(
err
,
"configuration validation failed"
)
}
}
...
@@ -289,7 +291,7 @@ func (e *ETCD) Start(ctx context.Context, clientAccessInfo *clientaccess.Info) e
...
@@ -289,7 +291,7 @@ func (e *ETCD) Start(ctx context.Context, clientAccessInfo *clientaccess.Info) e
go
e
.
manageLearners
(
ctx
)
go
e
.
manageLearners
(
ctx
)
if
existingCluster
{
if
isInitialized
{
//check etcd dir permission
//check etcd dir permission
etcdDir
:=
DBDir
(
e
.
config
)
etcdDir
:=
DBDir
(
e
.
config
)
info
,
err
:=
os
.
Stat
(
etcdDir
)
info
,
err
:=
os
.
Stat
(
etcdDir
)
...
@@ -313,9 +315,18 @@ func (e *ETCD) Start(ctx context.Context, clientAccessInfo *clientaccess.Info) e
...
@@ -313,9 +315,18 @@ func (e *ETCD) Start(ctx context.Context, clientAccessInfo *clientaccess.Info) e
}
}
go
func
()
{
go
func
()
{
<-
e
.
config
.
Runtime
.
AgentReady
for
{
if
err
:=
e
.
join
(
ctx
,
clientAccessInfo
);
err
!=
nil
{
select
{
logrus
.
Fatalf
(
"ETCD join failed: %v"
,
err
)
case
<-
time
.
After
(
30
*
time
.
Second
)
:
logrus
.
Infof
(
"Waiting for agent to become ready before joining ETCD cluster"
)
case
<-
e
.
config
.
Runtime
.
AgentReady
:
if
err
:=
e
.
join
(
ctx
,
clientAccessInfo
);
err
!=
nil
{
logrus
.
Fatalf
(
"ETCD join failed: %v"
,
err
)
}
return
case
<-
ctx
.
Done
()
:
return
}
}
}
}()
}()
...
@@ -1725,27 +1736,27 @@ func backupDirWithRetention(dir string, maxBackupRetention int) (string, error)
...
@@ -1725,27 +1736,27 @@ func backupDirWithRetention(dir string, maxBackupRetention int) (string, error)
return
backupDir
,
nil
return
backupDir
,
nil
}
}
// GetAPIServerURLFromETCD will try to fetch the version.Program/apiaddresses key from etcd
// GetAPIServerURLsFromETCD will try to fetch the version.Program/apiaddresses key from etcd
// when it succeed it will parse the first address in the list and return back an address
func
GetAPIServerURLsFromETCD
(
ctx
context
.
Context
,
cfg
*
config
.
Control
)
([]
string
,
error
)
{
func
GetAPIServerURLFromETCD
(
ctx
context
.
Context
,
cfg
*
config
.
Control
)
(
string
,
error
)
{
cl
,
err
:=
GetClient
(
ctx
,
cfg
.
Runtime
,
endpoint
)
cl
,
err
:=
GetClient
(
ctx
,
cfg
.
Runtime
,
endpoint
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
nil
,
err
}
}
etcdResp
,
err
:=
cl
.
KV
.
Get
(
ctx
,
AddressKey
)
etcdResp
,
err
:=
cl
.
KV
.
Get
(
ctx
,
AddressKey
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
nil
,
err
}
}
if
etcdResp
.
Count
<
1
{
if
etcdResp
.
Count
==
0
||
len
(
etcdResp
.
Kvs
[
0
]
.
Value
)
==
0
{
return
""
,
fmt
.
Errorf
(
"servers addresses are not yet set"
)
return
nil
,
ErrAddressNotSet
}
}
var
addresses
[]
string
var
addresses
[]
string
if
err
:=
json
.
Unmarshal
(
etcdResp
.
Kvs
[
0
]
.
Value
,
&
addresses
);
err
!=
nil
{
if
err
:=
json
.
Unmarshal
(
etcdResp
.
Kvs
[
0
]
.
Value
,
&
addresses
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to unmarshal etcd key
: %v"
,
err
)
return
nil
,
fmt
.
Errorf
(
"failed to unmarshal apiserver addresses from etcd
: %v"
,
err
)
}
}
return
addresses
[
0
]
,
nil
return
addresses
,
nil
}
}
// GetMembersClientURLs will list through the member lists in etcd and return
// GetMembersClientURLs will list through the member lists in etcd and return
...
...
pkg/server/etcd.go
View file @
f55f0967
...
@@ -13,10 +13,11 @@ import (
...
@@ -13,10 +13,11 @@ import (
)
)
// setETCDLabelsAndAnnotations will set the etcd role label if not exists also it
// setETCDLabelsAndAnnotations will set the etcd role label if not exists also it
// sets special annota
it
ons on the node object which are etcd node id and etcd node
// sets special annota
ti
ons on the node object which are etcd node id and etcd node
// address, the function will also remove the controlplane and master role labels if
// address, the function will also remove the controlplane and master role labels if
// they exist on the node
// they exist on the node
func
setETCDLabelsAndAnnotations
(
ctx
context
.
Context
,
config
*
Config
)
error
{
func
setETCDLabelsAndAnnotations
(
ctx
context
.
Context
,
config
*
Config
)
error
{
<-
config
.
ControlConfig
.
Runtime
.
APIServerReady
t
:=
time
.
NewTicker
(
5
*
time
.
Second
)
t
:=
time
.
NewTicker
(
5
*
time
.
Second
)
defer
t
.
Stop
()
defer
t
.
Stop
()
for
range
t
.
C
{
for
range
t
.
C
{
...
...
pkg/server/router.go
View file @
f55f0967
...
@@ -39,7 +39,6 @@ func router(ctx context.Context, config *Config, cfg *cmds.Server) http.Handler
...
@@ -39,7 +39,6 @@ func router(ctx context.Context, config *Config, cfg *cmds.Server) http.Handler
prefix
:=
"/v1-"
+
version
.
Program
prefix
:=
"/v1-"
+
version
.
Program
authed
:=
mux
.
NewRouter
()
authed
:=
mux
.
NewRouter
()
authed
.
Use
(
authMiddleware
(
serverConfig
,
version
.
Program
+
":agent"
))
authed
.
Use
(
authMiddleware
(
serverConfig
,
version
.
Program
+
":agent"
))
authed
.
NotFoundHandler
=
apiserver
(
serverConfig
.
Runtime
)
authed
.
Path
(
prefix
+
"/serving-kubelet.crt"
)
.
Handler
(
servingKubeletCert
(
serverConfig
,
serverConfig
.
Runtime
.
ServingKubeletKey
,
nodeAuth
))
authed
.
Path
(
prefix
+
"/serving-kubelet.crt"
)
.
Handler
(
servingKubeletCert
(
serverConfig
,
serverConfig
.
Runtime
.
ServingKubeletKey
,
nodeAuth
))
authed
.
Path
(
prefix
+
"/client-kubelet.crt"
)
.
Handler
(
clientKubeletCert
(
serverConfig
,
serverConfig
.
Runtime
.
ClientKubeletKey
,
nodeAuth
))
authed
.
Path
(
prefix
+
"/client-kubelet.crt"
)
.
Handler
(
clientKubeletCert
(
serverConfig
,
serverConfig
.
Runtime
.
ClientKubeletKey
,
nodeAuth
))
authed
.
Path
(
prefix
+
"/client-kube-proxy.crt"
)
.
Handler
(
fileHandler
(
serverConfig
.
Runtime
.
ClientKubeProxyCert
,
serverConfig
.
Runtime
.
ClientKubeProxyKey
))
authed
.
Path
(
prefix
+
"/client-kube-proxy.crt"
)
.
Handler
(
fileHandler
(
serverConfig
.
Runtime
.
ClientKubeProxyCert
,
serverConfig
.
Runtime
.
ClientKubeProxyKey
))
...
@@ -49,6 +48,12 @@ func router(ctx context.Context, config *Config, cfg *cmds.Server) http.Handler
...
@@ -49,6 +48,12 @@ func router(ctx context.Context, config *Config, cfg *cmds.Server) http.Handler
authed
.
Path
(
prefix
+
"/config"
)
.
Handler
(
configHandler
(
serverConfig
,
cfg
))
authed
.
Path
(
prefix
+
"/config"
)
.
Handler
(
configHandler
(
serverConfig
,
cfg
))
authed
.
Path
(
prefix
+
"/readyz"
)
.
Handler
(
readyzHandler
(
serverConfig
))
authed
.
Path
(
prefix
+
"/readyz"
)
.
Handler
(
readyzHandler
(
serverConfig
))
if
cfg
.
DisableAPIServer
{
authed
.
NotFoundHandler
=
apiserverDisabled
()
}
else
{
authed
.
NotFoundHandler
=
apiserver
(
serverConfig
.
Runtime
)
}
nodeAuthed
:=
mux
.
NewRouter
()
nodeAuthed
:=
mux
.
NewRouter
()
nodeAuthed
.
Use
(
authMiddleware
(
serverConfig
,
"system:nodes"
))
nodeAuthed
.
Use
(
authMiddleware
(
serverConfig
,
"system:nodes"
))
nodeAuthed
.
Path
(
prefix
+
"/connect"
)
.
Handler
(
serverConfig
.
Runtime
.
Tunnel
)
nodeAuthed
.
Path
(
prefix
+
"/connect"
)
.
Handler
(
serverConfig
.
Runtime
.
Tunnel
)
...
@@ -88,6 +93,16 @@ func apiserver(runtime *config.ControlRuntime) http.Handler {
...
@@ -88,6 +93,16 @@ func apiserver(runtime *config.ControlRuntime) http.Handler {
})
})
}
}
func
apiserverDisabled
()
http
.
Handler
{
return
http
.
HandlerFunc
(
func
(
resp
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
data
:=
[]
byte
(
"apiserver disabled"
)
resp
.
WriteHeader
(
http
.
StatusServiceUnavailable
)
resp
.
Header
()
.
Set
(
"Content-Type"
,
"text/plain"
)
resp
.
Header
()
.
Set
(
"Content-length"
,
strconv
.
Itoa
(
len
(
data
)))
resp
.
Write
(
data
)
})
}
func
cacerts
(
serverCA
string
)
http
.
Handler
{
func
cacerts
(
serverCA
string
)
http
.
Handler
{
var
ca
[]
byte
var
ca
[]
byte
return
http
.
HandlerFunc
(
func
(
resp
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
return
http
.
HandlerFunc
(
func
(
resp
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
...
...
pkg/server/server.go
View file @
f55f0967
...
@@ -366,7 +366,13 @@ func writeKubeConfig(certs string, config *Config) error {
...
@@ -366,7 +366,13 @@ func writeKubeConfig(certs string, config *Config) error {
if
ip
==
""
{
if
ip
==
""
{
ip
=
"127.0.0.1"
ip
=
"127.0.0.1"
}
}
url
:=
fmt
.
Sprintf
(
"https://%s:%d"
,
ip
,
config
.
ControlConfig
.
HTTPSPort
)
port
:=
config
.
ControlConfig
.
HTTPSPort
// on servers without a local apiserver, tunnel access via the loadbalancer
if
config
.
ControlConfig
.
DisableAPIServer
{
ip
=
"127.0.0.1"
port
=
config
.
ControlConfig
.
APIServerPort
}
url
:=
fmt
.
Sprintf
(
"https://%s:%d"
,
ip
,
port
)
kubeConfig
,
err
:=
HomeKubeConfig
(
true
,
config
.
Rootless
)
kubeConfig
,
err
:=
HomeKubeConfig
(
true
,
config
.
Rootless
)
def
:=
true
def
:=
true
if
err
!=
nil
{
if
err
!=
nil
{
...
...
pkg/util/api.go
View file @
f55f0967
...
@@ -18,6 +18,7 @@ import (
...
@@ -18,6 +18,7 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/util/wait"
clientset
"k8s.io/client-go/kubernetes"
clientset
"k8s.io/client-go/kubernetes"
coregetter
"k8s.io/client-go/kubernetes/typed/core/v1"
coregetter
"k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/tools/record"
)
)
...
@@ -56,6 +57,10 @@ func WaitForAPIServerReady(ctx context.Context, client clientset.Interface, time
...
@@ -56,6 +57,10 @@ func WaitForAPIServerReady(ctx context.Context, client clientset.Interface, time
err
:=
wait
.
PollImmediate
(
time
.
Second
,
timeout
,
func
()
(
bool
,
error
)
{
err
:=
wait
.
PollImmediate
(
time
.
Second
,
timeout
,
func
()
(
bool
,
error
)
{
healthStatus
:=
0
healthStatus
:=
0
// Idle connections to the apiserver are returned to a global pool between requests. Explicitly
// close these idle connections so that we re-connect through the loadbalancer in case the endpoints
// have changed.
restClient
.
(
*
rest
.
RESTClient
)
.
Client
.
CloseIdleConnections
()
result
:=
restClient
.
Get
()
.
AbsPath
(
"/readyz"
)
.
Do
(
ctx
)
.
StatusCode
(
&
healthStatus
)
result
:=
restClient
.
Get
()
.
AbsPath
(
"/readyz"
)
.
Do
(
ctx
)
.
StatusCode
(
&
healthStatus
)
if
rerr
:=
result
.
Error
();
rerr
!=
nil
{
if
rerr
:=
result
.
Error
();
rerr
!=
nil
{
if
errors
.
Is
(
rerr
,
context
.
Canceled
)
{
if
errors
.
Is
(
rerr
,
context
.
Canceled
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment