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
026a23ca
Commit
026a23ca
authored
Apr 17, 2018
by
Jason DeTiberus
Committed by
leigh schrandt
Apr 24, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add etcd L7 check on upgrade
- Adds L7 check for kubeadm etcd static pod upgrade
parent
acd0894f
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
221 additions
and
128 deletions
+221
-128
apply.go
cmd/kubeadm/app/cmd/upgrade/apply.go
+3
-17
plan.go
cmd/kubeadm/app/cmd/upgrade/plan.go
+9
-5
BUILD
cmd/kubeadm/app/phases/upgrade/BUILD
+1
-0
compute.go
cmd/kubeadm/app/phases/upgrade/compute.go
+2
-2
compute_test.go
cmd/kubeadm/app/phases/upgrade/compute_test.go
+9
-3
staticpods.go
cmd/kubeadm/app/phases/upgrade/staticpods.go
+87
-33
staticpods_test.go
cmd/kubeadm/app/phases/upgrade/staticpods_test.go
+29
-11
BUILD
cmd/kubeadm/app/util/etcd/BUILD
+1
-4
etcd.go
cmd/kubeadm/app/util/etcd/etcd.go
+79
-50
etcd_test.go
cmd/kubeadm/app/util/etcd/etcd_test.go
+1
-3
No files found.
cmd/kubeadm/app/cmd/upgrade/apply.go
View file @
026a23ca
...
@@ -269,23 +269,9 @@ func PerformStaticPodUpgrade(client clientset.Interface, waiter apiclient.Waiter
...
@@ -269,23 +269,9 @@ func PerformStaticPodUpgrade(client clientset.Interface, waiter apiclient.Waiter
return
err
return
err
}
}
// These are the same because kubeadm currently does not support reconciling a new config against an older one.
// These are uninitialized because passing in the clients allow for mocking the client during testing
// For instance, currently, changing CertificatesDir or EtcdDataDir breaks the upgrade, because oldcfg is not fetchable.
var
oldEtcdClient
,
newEtdClient
etcdutil
.
Client
// There would need to be additional upgrade code to handle copying the certs/data over to the new filepaths.
return
upgrade
.
StaticPodControlPlane
(
waiter
,
pathManager
,
internalcfg
,
etcdUpgrade
,
oldEtcdClient
,
newEtdClient
)
// It's still useful to have these parameterized as separate clusters though, because it allows us to mock these
// interfaces for tests.
oldEtcdCluster
:=
etcdutil
.
StaticPodCluster
{
Endpoints
:
[]
string
{
"localhost:2379"
},
ManifestDir
:
constants
.
GetStaticPodDirectory
(),
CertificatesDir
:
internalcfg
.
CertificatesDir
,
}
newEtcdCluster
:=
etcdutil
.
StaticPodCluster
{
Endpoints
:
[]
string
{
"localhost:2379"
},
ManifestDir
:
constants
.
GetStaticPodDirectory
(),
CertificatesDir
:
internalcfg
.
CertificatesDir
,
}
return
upgrade
.
StaticPodControlPlane
(
waiter
,
pathManager
,
internalcfg
,
etcdUpgrade
,
oldEtcdCluster
,
newEtcdCluster
)
}
}
// DryRunStaticPodUpgrade fakes an upgrade of the control plane
// DryRunStaticPodUpgrade fakes an upgrade of the control plane
...
...
cmd/kubeadm/app/cmd/upgrade/plan.go
View file @
026a23ca
...
@@ -63,14 +63,18 @@ func RunPlan(parentFlags *cmdUpgradeFlags) error {
...
@@ -63,14 +63,18 @@ func RunPlan(parentFlags *cmdUpgradeFlags) error {
}
}
// Define Local Etcd cluster to be able to retrieve information
// Define Local Etcd cluster to be able to retrieve information
etcdCluster
:=
etcdutil
.
StaticPodCluster
{
etcdClient
,
err
:=
etcdutil
.
NewStaticPodClient
(
Endpoints
:
[]
string
{
"localhost:2379"
},
[]
string
{
"localhost:2379"
},
ManifestDir
:
constants
.
GetStaticPodDirectory
(),
constants
.
GetStaticPodDirectory
(),
CertificatesDir
:
upgradeVars
.
cfg
.
CertificatesDir
,
upgradeVars
.
cfg
.
CertificatesDir
,
)
if
err
!=
nil
{
return
err
}
}
// Compute which upgrade possibilities there are
// Compute which upgrade possibilities there are
availUpgrades
,
err
:=
upgrade
.
GetAvailableUpgrades
(
upgradeVars
.
versionGetter
,
parentFlags
.
allowExperimentalUpgrades
,
parentFlags
.
allowRCUpgrades
,
etcdCluster
,
upgradeVars
.
cfg
.
FeatureGates
)
fmt
.
Println
(
"[upgrade/plan] computing upgrade possibilities"
)
availUpgrades
,
err
:=
upgrade
.
GetAvailableUpgrades
(
upgradeVars
.
versionGetter
,
parentFlags
.
allowExperimentalUpgrades
,
parentFlags
.
allowRCUpgrades
,
etcdClient
,
upgradeVars
.
cfg
.
FeatureGates
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"[upgrade/versions] FATAL: %v"
,
err
)
return
fmt
.
Errorf
(
"[upgrade/versions] FATAL: %v"
,
err
)
}
}
...
...
cmd/kubeadm/app/phases/upgrade/BUILD
View file @
026a23ca
...
@@ -90,6 +90,7 @@ go_test(
...
@@ -90,6 +90,7 @@ go_test(
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/util/version:go_default_library",
"//pkg/util/version:go_default_library",
"//vendor/github.com/coreos/etcd/clientv3:go_default_library",
"//vendor/github.com/coreos/etcd/clientv3:go_default_library",
"//vendor/github.com/coreos/etcd/pkg/transport:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
],
],
)
)
cmd/kubeadm/app/phases/upgrade/compute.go
View file @
026a23ca
...
@@ -74,7 +74,7 @@ type ClusterState struct {
...
@@ -74,7 +74,7 @@ type ClusterState struct {
// GetAvailableUpgrades fetches all versions from the specified VersionGetter and computes which
// GetAvailableUpgrades fetches all versions from the specified VersionGetter and computes which
// kinds of upgrades can be performed
// kinds of upgrades can be performed
func
GetAvailableUpgrades
(
versionGetterImpl
VersionGetter
,
experimentalUpgradesAllowed
,
rcUpgradesAllowed
bool
,
etcdCl
uster
etcdutil
.
Cluster
,
featureGates
map
[
string
]
bool
)
([]
Upgrade
,
error
)
{
func
GetAvailableUpgrades
(
versionGetterImpl
VersionGetter
,
experimentalUpgradesAllowed
,
rcUpgradesAllowed
bool
,
etcdCl
ient
etcdutil
.
Client
,
featureGates
map
[
string
]
bool
)
([]
Upgrade
,
error
)
{
fmt
.
Println
(
"[upgrade] Fetching available versions to upgrade to"
)
fmt
.
Println
(
"[upgrade] Fetching available versions to upgrade to"
)
// Collect the upgrades kubeadm can do in this list
// Collect the upgrades kubeadm can do in this list
...
@@ -107,7 +107,7 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
...
@@ -107,7 +107,7 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
}
}
// Get current etcd version
// Get current etcd version
etcdStatus
,
err
:=
etcdCl
uster
.
GetStatus
()
etcdStatus
,
err
:=
etcdCl
ient
.
GetStatus
()
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
...
cmd/kubeadm/app/phases/upgrade/compute_test.go
View file @
026a23ca
...
@@ -17,10 +17,12 @@ limitations under the License.
...
@@ -17,10 +17,12 @@ limitations under the License.
package
upgrade
package
upgrade
import
(
import
(
"github.com/coreos/etcd/clientv3"
versionutil
"k8s.io/kubernetes/pkg/util/version"
"reflect"
"reflect"
"testing"
"testing"
"time"
"github.com/coreos/etcd/clientv3"
versionutil
"k8s.io/kubernetes/pkg/util/version"
)
)
type
fakeVersionGetter
struct
{
type
fakeVersionGetter
struct
{
...
@@ -62,7 +64,7 @@ func (f *fakeVersionGetter) KubeletVersions() (map[string]uint16, error) {
...
@@ -62,7 +64,7 @@ func (f *fakeVersionGetter) KubeletVersions() (map[string]uint16, error) {
type
fakeEtcdCluster
struct
{
TLS
bool
}
type
fakeEtcdCluster
struct
{
TLS
bool
}
func
(
f
fakeEtcdCluster
)
HasTLS
()
(
bool
,
error
)
{
return
f
.
TLS
,
nil
}
func
(
f
fakeEtcdCluster
)
HasTLS
()
bool
{
return
f
.
TLS
}
func
(
f
fakeEtcdCluster
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
{
func
(
f
fakeEtcdCluster
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
{
client
:=
&
clientv3
.
StatusResponse
{}
client
:=
&
clientv3
.
StatusResponse
{}
...
@@ -70,6 +72,10 @@ func (f fakeEtcdCluster) GetStatus() (*clientv3.StatusResponse, error) {
...
@@ -70,6 +72,10 @@ func (f fakeEtcdCluster) GetStatus() (*clientv3.StatusResponse, error) {
return
client
,
nil
return
client
,
nil
}
}
func
(
f
fakeEtcdCluster
)
WaitForStatus
(
delay
time
.
Duration
,
retries
int
,
retryInterval
time
.
Duration
)
(
*
clientv3
.
StatusResponse
,
error
)
{
return
f
.
GetStatus
()
}
func
TestGetAvailableUpgrades
(
t
*
testing
.
T
)
{
func
TestGetAvailableUpgrades
(
t
*
testing
.
T
)
{
featureGates
:=
make
(
map
[
string
]
bool
)
featureGates
:=
make
(
map
[
string
]
bool
)
tests
:=
[]
struct
{
tests
:=
[]
struct
{
...
...
cmd/kubeadm/app/phases/upgrade/staticpods.go
View file @
026a23ca
...
@@ -20,6 +20,7 @@ import (
...
@@ -20,6 +20,7 @@ import (
"fmt"
"fmt"
"os"
"os"
"strings"
"strings"
"time"
kubeadmapi
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapi
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
...
@@ -224,13 +225,14 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
...
@@ -224,13 +225,14 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
}
}
// performEtcdStaticPodUpgrade performs upgrade of etcd, it returns bool which indicates fatal error or not and the actual error.
// performEtcdStaticPodUpgrade performs upgrade of etcd, it returns bool which indicates fatal error or not and the actual error.
func
performEtcdStaticPodUpgrade
(
waiter
apiclient
.
Waiter
,
pathMgr
StaticPodPathManager
,
cfg
*
kubeadmapi
.
MasterConfiguration
,
recoverManifests
map
[
string
]
string
,
isTLSUpgrade
bool
,
oldEtcdCl
uster
,
newEtcdCluster
etcdutil
.
Cluster
)
(
bool
,
error
)
{
func
performEtcdStaticPodUpgrade
(
waiter
apiclient
.
Waiter
,
pathMgr
StaticPodPathManager
,
cfg
*
kubeadmapi
.
MasterConfiguration
,
recoverManifests
map
[
string
]
string
,
isTLSUpgrade
bool
,
oldEtcdCl
ient
,
newEtcdClient
etcdutil
.
Client
)
(
bool
,
error
)
{
// Add etcd static pod spec only if external etcd is not configured
// Add etcd static pod spec only if external etcd is not configured
if
len
(
cfg
.
Etcd
.
Endpoints
)
!=
0
{
if
len
(
cfg
.
Etcd
.
Endpoints
)
!=
0
{
return
false
,
fmt
.
Errorf
(
"external etcd detected, won't try to change any etcd state"
)
return
false
,
fmt
.
Errorf
(
"external etcd detected, won't try to change any etcd state"
)
}
}
// Checking health state of etcd before proceeding with the upgrade
// Checking health state of etcd before proceeding with the upgrade
etcdStatus
,
err
:=
oldEtcdCl
uster
.
GetStatus
()
etcdStatus
,
err
:=
oldEtcdCl
ient
.
GetStatus
()
if
err
!=
nil
{
if
err
!=
nil
{
return
true
,
fmt
.
Errorf
(
"etcd cluster is not healthy: %v"
,
err
)
return
true
,
fmt
.
Errorf
(
"etcd cluster is not healthy: %v"
,
err
)
}
}
...
@@ -276,7 +278,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
...
@@ -276,7 +278,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
if
err
:=
upgradeComponent
(
constants
.
Etcd
,
waiter
,
pathMgr
,
cfg
,
beforeEtcdPodHash
,
recoverManifests
,
isTLSUpgrade
);
err
!=
nil
{
if
err
:=
upgradeComponent
(
constants
.
Etcd
,
waiter
,
pathMgr
,
cfg
,
beforeEtcdPodHash
,
recoverManifests
,
isTLSUpgrade
);
err
!=
nil
{
// Since etcd upgrade component failed, the old manifest has been restored
// Since etcd upgrade component failed, the old manifest has been restored
// now we need to check the health of etcd cluster if it came back up with old manifest
// now we need to check the health of etcd cluster if it came back up with old manifest
if
_
,
err
:=
oldEtcdCl
uster
.
GetStatus
();
err
!=
nil
{
if
_
,
err
:=
oldEtcdCl
ient
.
GetStatus
();
err
!=
nil
{
// At this point we know that etcd cluster is dead and it is safe to copy backup datastore and to rollback old etcd manifest
// At this point we know that etcd cluster is dead and it is safe to copy backup datastore and to rollback old etcd manifest
if
err
:=
rollbackEtcdData
(
cfg
,
fmt
.
Errorf
(
"etcd cluster is not healthy after upgrade: %v rolling back"
,
err
),
pathMgr
);
err
!=
nil
{
if
err
:=
rollbackEtcdData
(
cfg
,
fmt
.
Errorf
(
"etcd cluster is not healthy after upgrade: %v rolling back"
,
err
),
pathMgr
);
err
!=
nil
{
// Even copying back datastore failed, no options for recovery left, bailing out
// Even copying back datastore failed, no options for recovery left, bailing out
...
@@ -288,7 +290,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
...
@@ -288,7 +290,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
}
}
// Since rollback of the old etcd manifest was successful, checking again the status of etcd cluster
// Since rollback of the old etcd manifest was successful, checking again the status of etcd cluster
if
_
,
err
:=
oldEtcdCl
uster
.
GetStatus
();
err
!=
nil
{
if
_
,
err
:=
oldEtcdCl
ient
.
GetStatus
();
err
!=
nil
{
// Nothing else left to try to recover etcd cluster
// Nothing else left to try to recover etcd cluster
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
}
}
...
@@ -299,51 +301,103 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
...
@@ -299,51 +301,103 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
return
true
,
fmt
.
Errorf
(
"fatal error when trying to upgrade the etcd cluster: %v, rolled the state back to pre-upgrade state"
,
err
)
return
true
,
fmt
.
Errorf
(
"fatal error when trying to upgrade the etcd cluster: %v, rolled the state back to pre-upgrade state"
,
err
)
}
}
if
isTLSUpgrade
{
fmt
.
Println
(
"[upgrade/etcd] waiting for etcd to become available"
)
fmt
.
Printf
(
"[upgrade/etcd] Skipping L7 health-check for %s (as well as data rollback on failure)
\n
"
,
constants
.
Etcd
)
}
else
{
// Checking health state of etcd after the upgrade
if
_
,
err
=
newEtcdCluster
.
GetStatus
();
err
!=
nil
{
// Despite the fact that upgradeComponent was successful, there is something wrong with etcd cluster
// First step is to restore back up of datastore
if
err
:=
rollbackEtcdData
(
cfg
,
fmt
.
Errorf
(
"etcd cluster is not healthy after upgrade: %v rolling back"
,
err
),
pathMgr
);
err
!=
nil
{
// Even copying back datastore failed, no options for recovery left, bailing out
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
}
// Old datastore has been copied, rolling back old manifests
if
err
:=
rollbackOldManifests
(
recoverManifests
,
err
,
pathMgr
,
true
);
err
!=
nil
{
// Rolling back to old manifests failed, no options for recovery left, bailing out
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
}
// Since rollback of the old etcd manifest was successful, checking again the status of etcd cluster
if
_
,
err
:=
oldEtcdCluster
.
GetStatus
();
err
!=
nil
{
// Nothing else left to try to recover etcd cluster
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
}
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, rolled the state back to pre-upgrade state"
,
err
)
// Initialize the new etcd client if it wasn't pre-initialized
if
newEtcdClient
==
nil
{
client
,
err
:=
etcdutil
.
NewStaticPodClient
(
[]
string
{
"localhost:2379"
},
constants
.
GetStaticPodDirectory
(),
cfg
.
CertificatesDir
,
)
if
err
!=
nil
{
return
true
,
fmt
.
Errorf
(
"fatal error creating etcd client: %v"
,
err
)
}
}
newEtcdClient
=
client
}
// Checking health state of etcd after the upgrade
delay
:=
0
*
time
.
Second
if
isTLSUpgrade
{
// If we are upgrading TLS we need to wait for old static pod to be removed.
// This is needed because we are not able to currently verify that the static pod
// has been updated through the apiserver across an etcd TLS upgrade.
delay
=
30
*
time
.
Second
}
// The intial delay is required to ensure that the old static etcd pod
// has stopped prior to polling for status.
retries
:=
10
retryInterval
:=
15
*
time
.
Second
if
_
,
err
=
newEtcdClient
.
WaitForStatus
(
delay
,
retries
,
retryInterval
);
err
!=
nil
{
// Despite the fact that upgradeComponent was successful, there is something wrong with etcd cluster
// First step is to restore back up of datastore
if
err
:=
rollbackEtcdData
(
cfg
,
fmt
.
Errorf
(
"etcd cluster is not healthy after upgrade: %v rolling back"
,
err
),
pathMgr
);
err
!=
nil
{
// Even copying back datastore failed, no options for recovery left, bailing out
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
}
// Old datastore has been copied, rolling back old manifests
if
err
:=
rollbackOldManifests
(
recoverManifests
,
err
,
pathMgr
,
true
);
err
!=
nil
{
// Rolling back to old manifests failed, no options for recovery left, bailing out
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
}
// Since rollback of the old etcd manifest was successful, checking again the status of etcd cluster
if
_
,
err
:=
oldEtcdClient
.
GetStatus
();
err
!=
nil
{
// Nothing else left to try to recover etcd cluster
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, the backup of etcd database is stored here:(%s)"
,
err
,
backupEtcdDir
)
}
return
true
,
fmt
.
Errorf
(
"fatal error upgrading local etcd cluster: %v, rolled the state back to pre-upgrade state"
,
err
)
}
}
return
false
,
nil
return
false
,
nil
}
}
// StaticPodControlPlane upgrades a static pod-hosted control plane
// StaticPodControlPlane upgrades a static pod-hosted control plane
func
StaticPodControlPlane
(
waiter
apiclient
.
Waiter
,
pathMgr
StaticPodPathManager
,
cfg
*
kubeadmapi
.
MasterConfiguration
,
etcdUpgrade
bool
,
oldEtcdCl
uster
,
newEtcdCluster
etcdutil
.
Cluster
)
error
{
func
StaticPodControlPlane
(
waiter
apiclient
.
Waiter
,
pathMgr
StaticPodPathManager
,
cfg
*
kubeadmapi
.
MasterConfiguration
,
etcdUpgrade
bool
,
oldEtcdCl
ient
,
newEtcdClient
etcdutil
.
Client
)
error
{
recoverManifests
:=
map
[
string
]
string
{}
recoverManifests
:=
map
[
string
]
string
{}
var
isTLSUpgrade
bool
var
isTLSUpgrade
bool
var
isExternalEtcd
bool
beforePodHashMap
,
err
:=
waiter
.
WaitForStaticPodControlPlaneHashes
(
cfg
.
NodeName
)
beforePodHashMap
,
err
:=
waiter
.
WaitForStaticPodControlPlaneHashes
(
cfg
.
NodeName
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
// etcd upgrade is done prior to other control plane components
if
oldEtcdClient
==
nil
{
if
etcdUpgrade
{
if
len
(
cfg
.
Etcd
.
Endpoints
)
>
0
{
previousEtcdHasTLS
,
err
:=
oldEtcdCluster
.
HasTLS
()
// External etcd
if
err
!=
nil
{
isExternalEtcd
=
true
return
fmt
.
Errorf
(
"failed to determine if previous etcd was using TLS: %v"
,
err
)
client
,
err
:=
etcdutil
.
NewClient
(
cfg
.
Etcd
.
Endpoints
,
cfg
.
Etcd
.
CAFile
,
cfg
.
Etcd
.
CertFile
,
cfg
.
Etcd
.
KeyFile
,
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to create etcd client for external etcd: %v"
,
err
)
}
oldEtcdClient
=
client
// Since etcd is managed externally, the new etcd client will be the same as the old client
if
newEtcdClient
==
nil
{
newEtcdClient
=
client
}
}
else
{
// etcd Static Pod
client
,
err
:=
etcdutil
.
NewStaticPodClient
(
[]
string
{
"localhost:2379"
},
constants
.
GetStaticPodDirectory
(),
cfg
.
CertificatesDir
,
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to create etcd client: %v"
,
err
)
}
oldEtcdClient
=
client
}
}
}
// etcd upgrade is done prior to other control plane components
if
!
isExternalEtcd
&&
etcdUpgrade
{
previousEtcdHasTLS
:=
oldEtcdClient
.
HasTLS
()
// set the TLS upgrade flag for all components
// set the TLS upgrade flag for all components
isTLSUpgrade
=
!
previousEtcdHasTLS
isTLSUpgrade
=
!
previousEtcdHasTLS
...
@@ -352,7 +406,7 @@ func StaticPodControlPlane(waiter apiclient.Waiter, pathMgr StaticPodPathManager
...
@@ -352,7 +406,7 @@ func StaticPodControlPlane(waiter apiclient.Waiter, pathMgr StaticPodPathManager
}
}
// Perform etcd upgrade using common to all control plane components function
// Perform etcd upgrade using common to all control plane components function
fatal
,
err
:=
performEtcdStaticPodUpgrade
(
waiter
,
pathMgr
,
cfg
,
recoverManifests
,
isTLSUpgrade
,
oldEtcdCl
uster
,
newEtcdCluster
)
fatal
,
err
:=
performEtcdStaticPodUpgrade
(
waiter
,
pathMgr
,
cfg
,
recoverManifests
,
isTLSUpgrade
,
oldEtcdCl
ient
,
newEtcdClient
)
if
err
!=
nil
{
if
err
!=
nil
{
if
fatal
{
if
fatal
{
return
err
return
err
...
...
cmd/kubeadm/app/phases/upgrade/staticpods_test.go
View file @
026a23ca
...
@@ -27,6 +27,7 @@ import (
...
@@ -27,6 +27,7 @@ import (
"time"
"time"
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/pkg/transport"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime"
kubeadmapi
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapi
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiext
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
kubeadmapiext
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
...
@@ -208,33 +209,50 @@ func (spm *fakeStaticPodPathManager) BackupEtcdDir() string {
...
@@ -208,33 +209,50 @@ func (spm *fakeStaticPodPathManager) BackupEtcdDir() string {
return
spm
.
backupEtcdDir
return
spm
.
backupEtcdDir
}
}
type
fakeTLSEtcdCl
uster
struct
{
TLS
bool
}
type
fakeTLSEtcdCl
ient
struct
{
TLS
bool
}
func
(
c
luster
fakeTLSEtcdCluster
)
HasTLS
()
(
bool
,
error
)
{
func
(
c
fakeTLSEtcdClient
)
HasTLS
()
bool
{
return
c
luster
.
TLS
,
nil
return
c
.
TLS
}
}
func
(
c
luster
fakeTLSEtcdCluster
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
{
func
(
c
fakeTLSEtcdClient
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
{
client
:=
&
clientv3
.
StatusResponse
{}
client
:=
&
clientv3
.
StatusResponse
{}
client
.
Version
=
"3.1.12"
client
.
Version
=
"3.1.12"
return
client
,
nil
return
client
,
nil
}
}
type
fakePodManifestEtcdCluster
struct
{
ManifestDir
,
CertificatesDir
string
}
func
(
c
fakeTLSEtcdClient
)
WaitForStatus
(
delay
time
.
Duration
,
retries
int
,
retryInterval
time
.
Duration
)
(
*
clientv3
.
StatusResponse
,
error
)
{
return
c
.
GetStatus
()
}
type
fakePodManifestEtcdClient
struct
{
ManifestDir
,
CertificatesDir
string
}
func
(
cluster
fakePodManifestEtcdCluster
)
HasTLS
()
(
bool
,
error
)
{
func
(
c
fakePodManifestEtcdClient
)
HasTLS
()
bool
{
return
etcdutil
.
PodManifestsHaveTLS
(
cluster
.
ManifestDir
)
hasTLS
,
_
:=
etcdutil
.
PodManifestsHaveTLS
(
c
.
ManifestDir
)
return
hasTLS
}
}
func
(
c
luster
fakePodManifestEtcdCluster
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
{
func
(
c
fakePodManifestEtcdClient
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
{
// Make sure the certificates generated from the upgrade are readable from disk
// Make sure the certificates generated from the upgrade are readable from disk
etcdutil
.
NewTLSConfig
(
cluster
.
CertificatesDir
)
tlsInfo
:=
transport
.
TLSInfo
{
CertFile
:
filepath
.
Join
(
c
.
CertificatesDir
,
constants
.
EtcdCACertName
),
KeyFile
:
filepath
.
Join
(
c
.
CertificatesDir
,
constants
.
EtcdHealthcheckClientCertName
),
TrustedCAFile
:
filepath
.
Join
(
c
.
CertificatesDir
,
constants
.
EtcdHealthcheckClientKeyName
),
}
_
,
err
:=
tlsInfo
.
ClientConfig
()
if
err
!=
nil
{
return
nil
,
err
}
client
:=
&
clientv3
.
StatusResponse
{}
client
:=
&
clientv3
.
StatusResponse
{}
client
.
Version
=
"3.1.12"
client
.
Version
=
"3.1.12"
return
client
,
nil
return
client
,
nil
}
}
func
(
c
fakePodManifestEtcdClient
)
WaitForStatus
(
delay
time
.
Duration
,
retries
int
,
retryInterval
time
.
Duration
)
(
*
clientv3
.
StatusResponse
,
error
)
{
return
c
.
GetStatus
()
}
func
TestStaticPodControlPlane
(
t
*
testing
.
T
)
{
func
TestStaticPodControlPlane
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
tests
:=
[]
struct
{
description
string
description
string
...
@@ -420,10 +438,10 @@ func TestStaticPodControlPlane(t *testing.T) {
...
@@ -420,10 +438,10 @@ func TestStaticPodControlPlane(t *testing.T) {
pathMgr
,
pathMgr
,
newcfg
,
newcfg
,
true
,
true
,
fakeTLSEtcdCl
uster
{
fakeTLSEtcdCl
ient
{
TLS
:
false
,
TLS
:
false
,
},
},
fakePodManifestEtcdCl
uster
{
fakePodManifestEtcdCl
ient
{
ManifestDir
:
pathMgr
.
RealManifestDir
(),
ManifestDir
:
pathMgr
.
RealManifestDir
(),
CertificatesDir
:
newcfg
.
CertificatesDir
,
CertificatesDir
:
newcfg
.
CertificatesDir
,
},
},
...
...
cmd/kubeadm/app/util/etcd/BUILD
View file @
026a23ca
...
@@ -17,10 +17,7 @@ go_test(
...
@@ -17,10 +17,7 @@ go_test(
name = "go_default_test",
name = "go_default_test",
srcs = ["etcd_test.go"],
srcs = ["etcd_test.go"],
embed = [":go_default_library"],
embed = [":go_default_library"],
deps = [
deps = ["//cmd/kubeadm/test:go_default_library"],
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/test:go_default_library",
],
)
)
filegroup(
filegroup(
...
...
cmd/kubeadm/app/util/etcd/etcd.go
View file @
026a23ca
...
@@ -30,25 +30,22 @@ import (
...
@@ -30,25 +30,22 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
"k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
)
)
// Cluster is an interface to get etcd cluster related information
// Client is an interface to get etcd cluster related information
type
Cluster
interface
{
type
Client
interface
{
HasTLS
()
(
bool
,
error
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
WaitForStatus
(
delay
time
.
Duration
,
retries
int
,
retryInterval
time
.
Duration
)
(
*
clientv3
.
StatusResponse
,
error
)
HasTLS
()
bool
}
}
// StaticPodCluster represents an instance of a static pod etcd cluster.
// GenericClient is a common etcd client for supported etcd servers
// CertificatesDir should contain the etcd CA and healthcheck client TLS identity.
type
GenericClient
struct
{
// ManifestDir should contain the etcd static pod manifest.
Endpoints
[]
string
type
StaticPodCluster
struct
{
TLSConfig
*
tls
.
Config
Endpoints
[]
string
CertificatesDir
string
ManifestDir
string
}
}
// HasTLS returns a boolean representing whether the static pod etcd cluster implements TLS.
// HasTLS returns true if etcd is configured for TLS
// It may return an error for file I/O issues.
func
(
c
GenericClient
)
HasTLS
()
bool
{
func
(
cluster
StaticPodCluster
)
HasTLS
()
(
bool
,
error
)
{
return
c
.
TLSConfig
!=
nil
return
PodManifestsHaveTLS
(
cluster
.
ManifestDir
)
}
}
// PodManifestsHaveTLS reads the etcd staticpod manifest from disk and returns false if the TLS flags
// PodManifestsHaveTLS reads the etcd staticpod manifest from disk and returns false if the TLS flags
...
@@ -86,55 +83,87 @@ FlagLoop:
...
@@ -86,55 +83,87 @@ FlagLoop:
return
true
,
nil
return
true
,
nil
}
}
// GetStatus invokes the proper protocol check based off of whether the cluster HasTLS() to get the cluster's status
// GetStatus gets server status
func
(
cluster
StaticPodCluster
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
{
func
(
c
GenericClient
)
GetStatus
()
(
*
clientv3
.
StatusResponse
,
error
)
{
hasTLS
,
err
:=
cluster
.
HasTLS
()
const
dialTimeout
=
5
*
time
.
Second
cli
,
err
:=
clientv3
.
New
(
clientv3
.
Config
{
Endpoints
:
c
.
Endpoints
,
DialTimeout
:
dialTimeout
,
TLS
:
c
.
TLSConfig
,
})
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to determine if current etcd static pod is using TLS: %v"
,
err
)
return
nil
,
err
}
}
defer
cli
.
Close
()
var
tlsConfig
*
tls
.
Config
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
if
hasTLS
{
resp
,
err
:=
cli
.
Status
(
ctx
,
c
.
Endpoints
[
0
])
tlsConfig
,
err
=
NewTLSConfig
(
cluster
.
CertificatesDir
)
cancel
()
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to create a TLS Config using the cluster.CertificatesDir: %v"
,
err
)
return
nil
,
err
}
}
}
return
GetClusterStatus
(
cluster
.
Endpoints
,
tlsConfig
)
return
resp
,
nil
}
}
// NewTLSConfig generates a tlsConfig using credentials from the default sub-paths of the certificates directory
// WaitForStatus returns a StatusResponse after an initial delay and retry attempts
func
NewTLSConfig
(
certificatesDir
string
)
(
*
tls
.
Config
,
error
)
{
func
(
c
GenericClient
)
WaitForStatus
(
delay
time
.
Duration
,
retries
int
,
retryInterval
time
.
Duration
)
(
*
clientv3
.
StatusResponse
,
error
)
{
tlsInfo
:=
transport
.
TLSInfo
{
fmt
.
Printf
(
"[util/etcd] Waiting %v for initial delay
\n
"
,
delay
)
CertFile
:
filepath
.
Join
(
certificatesDir
,
constants
.
EtcdHealthcheckClientCertName
),
time
.
Sleep
(
delay
)
KeyFile
:
filepath
.
Join
(
certificatesDir
,
constants
.
EtcdHealthcheckClientKeyName
),
for
i
:=
0
;
i
<
retries
;
i
++
{
TrustedCAFile
:
filepath
.
Join
(
certificatesDir
,
constants
.
EtcdCACertName
),
if
i
>
0
{
fmt
.
Printf
(
"[util/etcd] Waiting %v until next retry
\n
"
,
retryInterval
)
time
.
Sleep
(
retryInterval
)
}
fmt
.
Printf
(
"[util/etcd] Attempting to get etcd status %d/%d
\n
"
,
i
+
1
,
retries
)
resp
,
err
:=
c
.
GetStatus
()
if
err
!=
nil
{
switch
err
{
case
context
.
DeadlineExceeded
:
fmt
.
Println
(
"[util/etcd] Attempt timed out"
)
default
:
fmt
.
Printf
(
"[util/etcd] Attempt failed with error: %v
\n
"
,
err
)
}
continue
}
return
resp
,
nil
}
}
tlsConfig
,
err
:=
tlsInfo
.
ClientConfig
()
return
nil
,
fmt
.
Errorf
(
"timeout waiting for etcd cluster status"
)
if
err
!=
nil
{
}
return
nil
,
err
// NewClient creates a new EtcdCluster client
func
NewClient
(
endpoints
[]
string
,
caFile
string
,
certFile
string
,
keyFile
string
)
(
*
GenericClient
,
error
)
{
client
:=
GenericClient
{
Endpoints
:
endpoints
}
if
caFile
!=
""
||
certFile
!=
""
||
keyFile
!=
""
{
tlsInfo
:=
transport
.
TLSInfo
{
CertFile
:
certFile
,
KeyFile
:
keyFile
,
TrustedCAFile
:
caFile
,
}
tlsConfig
,
err
:=
tlsInfo
.
ClientConfig
()
if
err
!=
nil
{
return
nil
,
err
}
client
.
TLSConfig
=
tlsConfig
}
}
return
tlsConfig
,
nil
return
&
client
,
nil
}
}
// GetClusterStatus returns nil for status Up or error for status Down
// NewStaticPodClient creates a GenericClient from the given endpoints, manifestDir, and certificatesDir
func
GetClusterStatus
(
endpoints
[]
string
,
tlsConfig
*
tls
.
Config
)
(
*
clientv3
.
StatusResponse
,
error
)
{
func
NewStaticPodClient
(
endpoints
[]
string
,
manifestDir
string
,
certificatesDir
string
)
(
*
GenericClient
,
error
)
{
cli
,
err
:=
clientv3
.
New
(
clientv3
.
Config
{
hasTLS
,
err
:=
PodManifestsHaveTLS
(
manifestDir
)
Endpoints
:
endpoints
,
DialTimeout
:
5
*
time
.
Second
,
TLS
:
tlsConfig
,
})
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
fmt
.
Errorf
(
"could not read manifests from: %s, error: %v"
,
manifestDir
,
err
)
}
}
defer
cli
.
Close
()
if
hasTLS
{
return
NewClient
(
resp
,
err
:=
cli
.
Status
(
context
.
Background
(),
endpoints
[
0
])
endpoints
,
if
err
!=
nil
{
filepath
.
Join
(
certificatesDir
,
constants
.
EtcdCACertName
),
return
nil
,
err
filepath
.
Join
(
certificatesDir
,
constants
.
EtcdHealthcheckClientCertName
),
filepath
.
Join
(
certificatesDir
,
constants
.
EtcdHealthcheckClientKeyName
),
)
}
}
return
NewClient
(
endpoints
,
""
,
""
,
""
)
return
resp
,
nil
}
}
cmd/kubeadm/app/util/etcd/etcd_test.go
View file @
026a23ca
...
@@ -179,9 +179,7 @@ func TestPodManifestHasTLS(t *testing.T) {
...
@@ -179,9 +179,7 @@ func TestPodManifestHasTLS(t *testing.T) {
}
}
}
}
tmpEtcdCluster
:=
StaticPodCluster
{
ManifestDir
:
tmpdir
}
hasTLS
,
actualErr
:=
PodManifestsHaveTLS
(
tmpdir
)
hasTLS
,
actualErr
:=
tmpEtcdCluster
.
HasTLS
()
if
(
actualErr
!=
nil
)
!=
rt
.
expectErr
{
if
(
actualErr
!=
nil
)
!=
rt
.
expectErr
{
t
.
Errorf
(
t
.
Errorf
(
"PodManifestHasTLS failed
\n
%s
\n\t
expected error: %t
\n\t
got: %t
\n\t
actual error: %v"
,
"PodManifestHasTLS failed
\n
%s
\n\t
expected error: %t
\n\t
got: %t
\n\t
actual error: %v"
,
...
...
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