uploadconfig.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package uploadconfig
  14. import (
  15. "fmt"
  16. "github.com/pkg/errors"
  17. v1 "k8s.io/api/core/v1"
  18. rbac "k8s.io/api/rbac/v1"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. clientset "k8s.io/client-go/kubernetes"
  21. "k8s.io/klog"
  22. kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
  23. kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
  24. "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
  25. configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
  26. rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
  27. )
  28. const (
  29. // NodesKubeadmConfigClusterRoleName sets the name for the ClusterRole that allows
  30. // the bootstrap tokens to access the kubeadm-config ConfigMap during the node bootstrap/discovery
  31. // or during upgrade nodes
  32. NodesKubeadmConfigClusterRoleName = "kubeadm:nodes-kubeadm-config"
  33. )
  34. // ResetClusterStatusForNode removes the APIEndpoint of a given control-plane node
  35. // from the ClusterStatus and updates the kubeadm ConfigMap
  36. func ResetClusterStatusForNode(nodeName string, client clientset.Interface) error {
  37. fmt.Printf("[reset] Removing info for node %q from the ConfigMap %q in the %q Namespace\n",
  38. nodeName, kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
  39. return apiclient.MutateConfigMap(client, metav1.ObjectMeta{
  40. Name: kubeadmconstants.KubeadmConfigConfigMap,
  41. Namespace: metav1.NamespaceSystem,
  42. }, func(cm *v1.ConfigMap) error {
  43. return mutateClusterStatus(cm, func(cs *kubeadmapi.ClusterStatus) error {
  44. // Handle a nil APIEndpoints map. Should only happen if someone manually
  45. // interacted with the ConfigMap.
  46. if cs.APIEndpoints == nil {
  47. return errors.Errorf("APIEndpoints from ConfigMap %q in the %q Namespace is nil",
  48. kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
  49. }
  50. klog.V(2).Infof("Removing APIEndpoint for Node %q", nodeName)
  51. delete(cs.APIEndpoints, nodeName)
  52. return nil
  53. })
  54. })
  55. }
  56. // UploadConfiguration saves the InitConfiguration used for later reference (when upgrading for instance)
  57. func UploadConfiguration(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
  58. fmt.Printf("[upload-config] Storing the configuration used in ConfigMap %q in the %q Namespace\n", kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
  59. // Prepare the ClusterConfiguration for upload
  60. // The components store their config in their own ConfigMaps, then reset the .ComponentConfig struct;
  61. // We don't want to mutate the cfg itself, so create a copy of it using .DeepCopy of it first
  62. clusterConfigurationToUpload := cfg.ClusterConfiguration.DeepCopy()
  63. clusterConfigurationToUpload.ComponentConfigs = kubeadmapi.ComponentConfigs{}
  64. // Marshal the ClusterConfiguration into YAML
  65. clusterConfigurationYaml, err := configutil.MarshalKubeadmConfigObject(clusterConfigurationToUpload)
  66. if err != nil {
  67. return err
  68. }
  69. // Prepare the ClusterStatus for upload
  70. clusterStatus := &kubeadmapi.ClusterStatus{
  71. APIEndpoints: map[string]kubeadmapi.APIEndpoint{
  72. cfg.NodeRegistration.Name: cfg.LocalAPIEndpoint,
  73. },
  74. }
  75. // Marshal the ClusterStatus into YAML
  76. clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
  77. if err != nil {
  78. return err
  79. }
  80. err = apiclient.CreateOrMutateConfigMap(client, &v1.ConfigMap{
  81. ObjectMeta: metav1.ObjectMeta{
  82. Name: kubeadmconstants.KubeadmConfigConfigMap,
  83. Namespace: metav1.NamespaceSystem,
  84. },
  85. Data: map[string]string{
  86. kubeadmconstants.ClusterConfigurationConfigMapKey: string(clusterConfigurationYaml),
  87. kubeadmconstants.ClusterStatusConfigMapKey: string(clusterStatusYaml),
  88. },
  89. }, func(cm *v1.ConfigMap) error {
  90. // Upgrade will call to UploadConfiguration with a modified KubernetesVersion reflecting the new
  91. // Kubernetes version. In that case, the mutation path will take place.
  92. cm.Data[kubeadmconstants.ClusterConfigurationConfigMapKey] = string(clusterConfigurationYaml)
  93. // Mutate the ClusterStatus now
  94. return mutateClusterStatus(cm, func(cs *kubeadmapi.ClusterStatus) error {
  95. // Handle a nil APIEndpoints map. Should only happen if someone manually
  96. // interacted with the ConfigMap.
  97. if cs.APIEndpoints == nil {
  98. return errors.Errorf("APIEndpoints from ConfigMap %q in the %q Namespace is nil",
  99. kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
  100. }
  101. cs.APIEndpoints[cfg.NodeRegistration.Name] = cfg.LocalAPIEndpoint
  102. return nil
  103. })
  104. })
  105. if err != nil {
  106. return err
  107. }
  108. // Ensure that the NodesKubeadmConfigClusterRoleName exists
  109. err = apiclient.CreateOrUpdateRole(client, &rbac.Role{
  110. ObjectMeta: metav1.ObjectMeta{
  111. Name: NodesKubeadmConfigClusterRoleName,
  112. Namespace: metav1.NamespaceSystem,
  113. },
  114. Rules: []rbac.PolicyRule{
  115. rbachelper.NewRule("get").Groups("").Resources("configmaps").Names(kubeadmconstants.KubeadmConfigConfigMap).RuleOrDie(),
  116. },
  117. })
  118. if err != nil {
  119. return err
  120. }
  121. // Binds the NodesKubeadmConfigClusterRoleName to all the bootstrap tokens
  122. // that are members of the system:bootstrappers:kubeadm:default-node-token group
  123. // and to all nodes
  124. return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
  125. ObjectMeta: metav1.ObjectMeta{
  126. Name: NodesKubeadmConfigClusterRoleName,
  127. Namespace: metav1.NamespaceSystem,
  128. },
  129. RoleRef: rbac.RoleRef{
  130. APIGroup: rbac.GroupName,
  131. Kind: "Role",
  132. Name: NodesKubeadmConfigClusterRoleName,
  133. },
  134. Subjects: []rbac.Subject{
  135. {
  136. Kind: rbac.GroupKind,
  137. Name: kubeadmconstants.NodeBootstrapTokenAuthGroup,
  138. },
  139. {
  140. Kind: rbac.GroupKind,
  141. Name: kubeadmconstants.NodesGroup,
  142. },
  143. },
  144. })
  145. }
  146. func mutateClusterStatus(cm *v1.ConfigMap, mutator func(*kubeadmapi.ClusterStatus) error) error {
  147. // Obtain the existing ClusterStatus object
  148. clusterStatus, err := configutil.UnmarshalClusterStatus(cm.Data)
  149. if err != nil {
  150. return err
  151. }
  152. // Mutate the ClusterStatus
  153. if err := mutator(clusterStatus); err != nil {
  154. return err
  155. }
  156. // Marshal the ClusterStatus back into YAML
  157. clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
  158. if err != nil {
  159. return err
  160. }
  161. // Write the marshaled mutated cluster status back to the ConfigMap
  162. cm.Data[kubeadmconstants.ClusterStatusConfigMapKey] = string(clusterStatusYaml)
  163. return nil
  164. }