uploadconfig.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. )
  27. const (
  28. // NodesKubeadmConfigClusterRoleName sets the name for the ClusterRole that allows
  29. // the bootstrap tokens to access the kubeadm-config ConfigMap during the node bootstrap/discovery
  30. // or during upgrade nodes
  31. NodesKubeadmConfigClusterRoleName = "kubeadm:nodes-kubeadm-config"
  32. )
  33. // ResetClusterStatusForNode removes the APIEndpoint of a given control-plane node
  34. // from the ClusterStatus and updates the kubeadm ConfigMap
  35. func ResetClusterStatusForNode(nodeName string, client clientset.Interface) error {
  36. fmt.Printf("[reset] Removing info for node %q from the ConfigMap %q in the %q Namespace\n",
  37. nodeName, kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
  38. return apiclient.MutateConfigMap(client, metav1.ObjectMeta{
  39. Name: kubeadmconstants.KubeadmConfigConfigMap,
  40. Namespace: metav1.NamespaceSystem,
  41. }, func(cm *v1.ConfigMap) error {
  42. return mutateClusterStatus(cm, func(cs *kubeadmapi.ClusterStatus) error {
  43. // Handle a nil APIEndpoints map. Should only happen if someone manually
  44. // interacted with the ConfigMap.
  45. if cs.APIEndpoints == nil {
  46. return errors.Errorf("APIEndpoints from ConfigMap %q in the %q Namespace is nil",
  47. kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
  48. }
  49. klog.V(2).Infof("Removing APIEndpoint for Node %q", nodeName)
  50. delete(cs.APIEndpoints, nodeName)
  51. return nil
  52. })
  53. })
  54. }
  55. // UploadConfiguration saves the InitConfiguration used for later reference (when upgrading for instance)
  56. func UploadConfiguration(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
  57. fmt.Printf("[upload-config] Storing the configuration used in ConfigMap %q in the %q Namespace\n", kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
  58. // Prepare the ClusterConfiguration for upload
  59. // The components store their config in their own ConfigMaps, then reset the .ComponentConfig struct;
  60. // We don't want to mutate the cfg itself, so create a copy of it using .DeepCopy of it first
  61. clusterConfigurationToUpload := cfg.ClusterConfiguration.DeepCopy()
  62. clusterConfigurationToUpload.ComponentConfigs = kubeadmapi.ComponentConfigMap{}
  63. // Marshal the ClusterConfiguration into YAML
  64. clusterConfigurationYaml, err := configutil.MarshalKubeadmConfigObject(clusterConfigurationToUpload)
  65. if err != nil {
  66. return err
  67. }
  68. // Prepare the ClusterStatus for upload
  69. clusterStatus := &kubeadmapi.ClusterStatus{
  70. APIEndpoints: map[string]kubeadmapi.APIEndpoint{
  71. cfg.NodeRegistration.Name: cfg.LocalAPIEndpoint,
  72. },
  73. }
  74. // Marshal the ClusterStatus into YAML
  75. clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
  76. if err != nil {
  77. return err
  78. }
  79. err = apiclient.CreateOrMutateConfigMap(client, &v1.ConfigMap{
  80. ObjectMeta: metav1.ObjectMeta{
  81. Name: kubeadmconstants.KubeadmConfigConfigMap,
  82. Namespace: metav1.NamespaceSystem,
  83. },
  84. Data: map[string]string{
  85. kubeadmconstants.ClusterConfigurationConfigMapKey: string(clusterConfigurationYaml),
  86. kubeadmconstants.ClusterStatusConfigMapKey: string(clusterStatusYaml),
  87. },
  88. }, func(cm *v1.ConfigMap) error {
  89. // Upgrade will call to UploadConfiguration with a modified KubernetesVersion reflecting the new
  90. // Kubernetes version. In that case, the mutation path will take place.
  91. cm.Data[kubeadmconstants.ClusterConfigurationConfigMapKey] = string(clusterConfigurationYaml)
  92. // Mutate the ClusterStatus now
  93. return mutateClusterStatus(cm, func(cs *kubeadmapi.ClusterStatus) error {
  94. // Handle a nil APIEndpoints map. Should only happen if someone manually
  95. // interacted with the ConfigMap.
  96. if cs.APIEndpoints == nil {
  97. return errors.Errorf("APIEndpoints from ConfigMap %q in the %q Namespace is nil",
  98. kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
  99. }
  100. cs.APIEndpoints[cfg.NodeRegistration.Name] = cfg.LocalAPIEndpoint
  101. return nil
  102. })
  103. })
  104. if err != nil {
  105. return err
  106. }
  107. // Ensure that the NodesKubeadmConfigClusterRoleName exists
  108. err = apiclient.CreateOrUpdateRole(client, &rbac.Role{
  109. ObjectMeta: metav1.ObjectMeta{
  110. Name: NodesKubeadmConfigClusterRoleName,
  111. Namespace: metav1.NamespaceSystem,
  112. },
  113. Rules: []rbac.PolicyRule{
  114. {
  115. Verbs: []string{"get"},
  116. APIGroups: []string{""},
  117. Resources: []string{"configmaps"},
  118. ResourceNames: []string{kubeadmconstants.KubeadmConfigConfigMap},
  119. },
  120. },
  121. })
  122. if err != nil {
  123. return err
  124. }
  125. // Binds the NodesKubeadmConfigClusterRoleName to all the bootstrap tokens
  126. // that are members of the system:bootstrappers:kubeadm:default-node-token group
  127. // and to all nodes
  128. return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
  129. ObjectMeta: metav1.ObjectMeta{
  130. Name: NodesKubeadmConfigClusterRoleName,
  131. Namespace: metav1.NamespaceSystem,
  132. },
  133. RoleRef: rbac.RoleRef{
  134. APIGroup: rbac.GroupName,
  135. Kind: "Role",
  136. Name: NodesKubeadmConfigClusterRoleName,
  137. },
  138. Subjects: []rbac.Subject{
  139. {
  140. Kind: rbac.GroupKind,
  141. Name: kubeadmconstants.NodeBootstrapTokenAuthGroup,
  142. },
  143. {
  144. Kind: rbac.GroupKind,
  145. Name: kubeadmconstants.NodesGroup,
  146. },
  147. },
  148. })
  149. }
  150. func mutateClusterStatus(cm *v1.ConfigMap, mutator func(*kubeadmapi.ClusterStatus) error) error {
  151. // Obtain the existing ClusterStatus object
  152. clusterStatus, err := configutil.UnmarshalClusterStatus(cm.Data)
  153. if err != nil {
  154. return err
  155. }
  156. // Mutate the ClusterStatus
  157. if err := mutator(clusterStatus); err != nil {
  158. return err
  159. }
  160. // Marshal the ClusterStatus back into YAML
  161. clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
  162. if err != nil {
  163. return err
  164. }
  165. // Write the marshaled mutated cluster status back to the ConfigMap
  166. cm.Data[kubeadmconstants.ClusterStatusConfigMapKey] = string(clusterStatusYaml)
  167. return nil
  168. }