1
16
17 package kubelet
18
19 import (
20 "fmt"
21 "io"
22 "os"
23 "path/filepath"
24
25 "github.com/pkg/errors"
26
27 v1 "k8s.io/api/core/v1"
28 rbac "k8s.io/api/rbac/v1"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 clientset "k8s.io/client-go/kubernetes"
31 kubeletconfig "k8s.io/kubelet/config/v1beta1"
32 "sigs.k8s.io/yaml"
33
34 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
35 "k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
36 kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
37 "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
38 "k8s.io/kubernetes/cmd/kubeadm/app/util/patches"
39 )
40
41
42
43 func WriteConfigToDisk(cfg *kubeadmapi.ClusterConfiguration, kubeletDir, patchesDir string, output io.Writer) error {
44 kubeletCfg, ok := cfg.ComponentConfigs[componentconfigs.KubeletGroup]
45 if !ok {
46 return errors.New("no kubelet component config found")
47 }
48
49 if err := kubeletCfg.Mutate(); err != nil {
50 return err
51 }
52
53 kubeletBytes, err := kubeletCfg.Marshal()
54 if err != nil {
55 return err
56 }
57
58
59 if len(patchesDir) != 0 {
60 kubeletBytes, err = applyKubeletConfigPatches(kubeletBytes, patchesDir, output)
61 if err != nil {
62 return errors.Wrap(err, "could not apply patches to the KubeletConfiguration")
63 }
64 }
65
66 return writeConfigBytesToDisk(kubeletBytes, kubeletDir)
67 }
68
69
70
71 func CreateConfigMap(cfg *kubeadmapi.ClusterConfiguration, client clientset.Interface) error {
72 configMapName := kubeadmconstants.KubeletBaseConfigurationConfigMap
73 fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem)
74
75 kubeletCfg, ok := cfg.ComponentConfigs[componentconfigs.KubeletGroup]
76 if !ok {
77 return errors.New("no kubelet component config found in the active component config set")
78 }
79
80 kubeletBytes, err := kubeletCfg.Marshal()
81 if err != nil {
82 return err
83 }
84
85 configMap := &v1.ConfigMap{
86 ObjectMeta: metav1.ObjectMeta{
87 Name: configMapName,
88 Namespace: metav1.NamespaceSystem,
89 },
90 Data: map[string]string{
91 kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(kubeletBytes),
92 },
93 }
94
95 if !kubeletCfg.IsUserSupplied() {
96 componentconfigs.SignConfigMap(configMap)
97 }
98
99 if err := apiclient.CreateOrUpdateConfigMap(client, configMap); err != nil {
100 return err
101 }
102
103 if err := createConfigMapRBACRules(client); err != nil {
104 return errors.Wrap(err, "error creating kubelet configuration configmap RBAC rules")
105 }
106 return nil
107 }
108
109
110 func createConfigMapRBACRules(client clientset.Interface) error {
111 if err := apiclient.CreateOrUpdateRole(client, &rbac.Role{
112 ObjectMeta: metav1.ObjectMeta{
113 Name: kubeadmconstants.KubeletBaseConfigMapRole,
114 Namespace: metav1.NamespaceSystem,
115 },
116 Rules: []rbac.PolicyRule{
117 {
118 Verbs: []string{"get"},
119 APIGroups: []string{""},
120 Resources: []string{"configmaps"},
121 ResourceNames: []string{kubeadmconstants.KubeletBaseConfigurationConfigMap},
122 },
123 },
124 }); err != nil {
125 return err
126 }
127
128 return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
129 ObjectMeta: metav1.ObjectMeta{
130 Name: kubeadmconstants.KubeletBaseConfigMapRole,
131 Namespace: metav1.NamespaceSystem,
132 },
133 RoleRef: rbac.RoleRef{
134 APIGroup: rbac.GroupName,
135 Kind: "Role",
136 Name: kubeadmconstants.KubeletBaseConfigMapRole,
137 },
138 Subjects: []rbac.Subject{
139 {
140 Kind: rbac.GroupKind,
141 Name: kubeadmconstants.NodesGroup,
142 },
143 {
144 Kind: rbac.GroupKind,
145 Name: kubeadmconstants.NodeBootstrapTokenAuthGroup,
146 },
147 },
148 })
149 }
150
151
152 func writeConfigBytesToDisk(b []byte, kubeletDir string) error {
153 configFile := filepath.Join(kubeletDir, kubeadmconstants.KubeletConfigurationFileName)
154 fmt.Printf("[kubelet-start] Writing kubelet configuration to file %q\n", configFile)
155
156
157 if err := os.MkdirAll(kubeletDir, 0700); err != nil {
158 return errors.Wrapf(err, "failed to create directory %q", kubeletDir)
159 }
160
161 if err := os.WriteFile(configFile, b, 0644); err != nil {
162 return errors.Wrapf(err, "failed to write kubelet configuration to the file %q", configFile)
163 }
164 return nil
165 }
166
167
168 func applyKubeletConfigPatches(kubeletBytes []byte, patchesDir string, output io.Writer) ([]byte, error) {
169 patchManager, err := patches.GetPatchManagerForPath(patchesDir, patches.KnownTargets(), output)
170 if err != nil {
171 return nil, err
172 }
173
174 patchTarget := &patches.PatchTarget{
175 Name: patches.KubeletConfiguration,
176 StrategicMergePatchObject: kubeletconfig.KubeletConfiguration{},
177 Data: kubeletBytes,
178 }
179 if err := patchManager.ApplyPatchesToTarget(patchTarget); err != nil {
180 return nil, err
181 }
182
183 kubeletBytes, err = yaml.JSONToYAML(patchTarget.Data)
184 if err != nil {
185 return nil, err
186 }
187 return kubeletBytes, nil
188 }
189
View as plain text