@@ -21,6 +21,7 @@ import (
21
21
"bytes"
22
22
"fmt"
23
23
"io"
24
+ "io/ioutil"
24
25
"os"
25
26
"strings"
26
27
"time"
@@ -36,16 +37,89 @@ import (
36
37
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
37
38
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
38
39
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
40
+ "k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
39
41
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
40
42
"k8s.io/kubernetes/cmd/kubeadm/app/features"
41
43
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
42
44
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
45
+ kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
43
46
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
44
47
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
45
48
dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
46
49
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
47
50
)
48
51
52
+ // isKubeadmConfigPresent checks if a kubeadm config type is found in the provided document map
53
+ func isKubeadmConfigPresent (docmap kubeadmapi.DocumentMap ) bool {
54
+ for gvk := range docmap {
55
+ if gvk .Group == kubeadmapi .GroupName {
56
+ return true
57
+ }
58
+ }
59
+ return false
60
+ }
61
+
62
+ // loadConfig loads configuration from a file and/or the cluster. InitConfiguration, ClusterConfiguration and (optionally) component configs
63
+ // are loaded. This function allows the component configs to be loaded from a file that contains only them. If the file contains any kubeadm types
64
+ // in it (API group "kubeadm.kubernetes.io" present), then the supplied file is treaded as a legacy reconfiguration style "--config" use and the
65
+ // returned bool value is set to true (the only case to be done so).
66
+ func loadConfig (cfgPath string , client clientset.Interface , skipComponentConfigs bool ) (* kubeadmapi.InitConfiguration , bool , error ) {
67
+ // Used for info logs here
68
+ const logPrefix = "upgrade/config"
69
+
70
+ // The usual case here is to not have a config file, but rather load the config from the cluster.
71
+ // This is probably 90% of the time. So we handle it first.
72
+ if cfgPath == "" {
73
+ cfg , err := configutil .FetchInitConfigurationFromCluster (client , os .Stdout , logPrefix , false , skipComponentConfigs )
74
+ return cfg , false , err
75
+ }
76
+
77
+ // Otherwise, we have a config file. Let's load it.
78
+ configBytes , err := ioutil .ReadFile (cfgPath )
79
+ if err != nil {
80
+ return nil , false , errors .Wrapf (err , "unable to load config from file %q" , cfgPath )
81
+ }
82
+
83
+ // Split the YAML documents in the file into a DocumentMap
84
+ docmap , err := kubeadmutil .SplitYAMLDocuments (configBytes )
85
+ if err != nil {
86
+ return nil , false , err
87
+ }
88
+
89
+ // If there are kubeadm types (API group kubeadm.kubernetes.io) present, we need to keep the existing behavior
90
+ // here. Basically, we have to load all of the configs from the file and none from the cluster. Configs that are
91
+ // missing from the file will be automatically regenerated by kubeadm even if they are present in the cluster.
92
+ // The resulting configs overwrite the existing cluster ones at the end of a successful upgrade apply operation.
93
+ if isKubeadmConfigPresent (docmap ) {
94
+ klog .Warning ("WARNING: Usage of the --config flag with kubeadm config types for reconfiguring the cluster during upgrade is not recommended!" )
95
+ cfg , err := configutil .BytesToInitConfiguration (configBytes )
96
+ return cfg , true , err
97
+ }
98
+
99
+ // If no kubeadm config types are present, we assume that there are manually upgraded component configs in the file.
100
+ // Hence, we load the kubeadm types from the cluster.
101
+ initCfg , err := configutil .FetchInitConfigurationFromCluster (client , os .Stdout , logPrefix , false , true )
102
+ if err != nil {
103
+ return nil , false , err
104
+ }
105
+
106
+ // Stop here if the caller does not want us to load the component configs
107
+ if ! skipComponentConfigs {
108
+ // Load the component configs with upgrades
109
+ if err := componentconfigs .FetchFromClusterWithLocalOverwrites (& initCfg .ClusterConfiguration , client , docmap ); err != nil {
110
+ return nil , false , err
111
+ }
112
+
113
+ // Now default and validate the configs
114
+ componentconfigs .Default (& initCfg .ClusterConfiguration , & initCfg .LocalAPIEndpoint , & initCfg .NodeRegistration )
115
+ if errs := componentconfigs .Validate (& initCfg .ClusterConfiguration ); len (errs ) != 0 {
116
+ return nil , false , errs .ToAggregate ()
117
+ }
118
+ }
119
+
120
+ return initCfg , false , nil
121
+ }
122
+
49
123
// enforceRequirements verifies that it's okay to upgrade and then returns the variables needed for the rest of the procedure
50
124
func enforceRequirements (flags * applyPlanFlags , args []string , dryRun bool , upgradeApply bool ) (clientset.Interface , upgrade.VersionGetter , * kubeadmapi.InitConfiguration , error ) {
51
125
client , err := getClient (flags .kubeConfigPath , dryRun )
@@ -62,21 +136,7 @@ func enforceRequirements(flags *applyPlanFlags, args []string, dryRun bool, upgr
62
136
fmt .Println ("[upgrade/config] Making sure the configuration is correct:" )
63
137
64
138
var newK8sVersion string
65
- var cfg * kubeadmapi.InitConfiguration
66
-
67
- if flags .cfgPath != "" {
68
- klog .Warning ("WARNING: Usage of the --config flag for reconfiguring the cluster during upgrade is not recommended!" )
69
- cfg , err = configutil .LoadInitConfigurationFromFile (flags .cfgPath )
70
-
71
- // Initialize newK8sVersion to the value in the ClusterConfiguration. This is done, so that users who use the --config option
72
- // don't have to specify the Kubernetes version twice if they don't want to upgrade, but just change a setting.
73
- if err != nil {
74
- newK8sVersion = cfg .KubernetesVersion
75
- }
76
- } else {
77
- cfg , err = configutil .FetchInitConfigurationFromCluster (client , os .Stdout , "upgrade/config" , false , ! upgradeApply )
78
- }
79
-
139
+ cfg , legacyReconfigure , err := loadConfig (flags .cfgPath , client , ! upgradeApply )
80
140
if err != nil {
81
141
if apierrors .IsNotFound (err ) {
82
142
fmt .Printf ("[upgrade/config] In order to upgrade, a ConfigMap called %q in the %s namespace must exist.\n " , constants .KubeadmConfigConfigMap , metav1 .NamespaceSystem )
@@ -90,6 +150,11 @@ func enforceRequirements(flags *applyPlanFlags, args []string, dryRun bool, upgr
90
150
err = errors .Errorf ("the ConfigMap %q in the %s namespace used for getting configuration information was not found" , constants .KubeadmConfigConfigMap , metav1 .NamespaceSystem )
91
151
}
92
152
return nil , nil , nil , errors .Wrap (err , "[upgrade/config] FATAL" )
153
+ } else if legacyReconfigure {
154
+ // Set the newK8sVersion to the value in the ClusterConfiguration. This is done, so that users who use the --config option
155
+ // to supply a new ClusterConfiguration don't have to specify the Kubernetes version twice,
156
+ // if they don't want to upgrade but just change a setting.
157
+ newK8sVersion = cfg .KubernetesVersion
93
158
}
94
159
95
160
ignorePreflightErrorsSet , err := validation .ValidateIgnorePreflightErrors (flags .ignorePreflightErrors , cfg .NodeRegistration .IgnorePreflightErrors )
0 commit comments