Skip to content

Commit 1a16c2d

Browse files
authored
Merge pull request kubernetes#128487 from neolit123/1.32-fix-get-node-from-ssr-bug
kubeadm: ensure proper parsing of SSR username
2 parents d87bf75 + fceb39e commit 1a16c2d

File tree

3 files changed

+96
-15
lines changed

3 files changed

+96
-15
lines changed

cmd/kubeadm/app/cmd/upgrade/common.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ import (
2626
"github.com/pkg/errors"
2727
"github.com/spf13/pflag"
2828

29-
apierrors "k8s.io/apimachinery/pkg/api/errors"
30-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3129
"k8s.io/apimachinery/pkg/util/sets"
3230
fakediscovery "k8s.io/client-go/discovery/fake"
3331
clientset "k8s.io/client-go/kubernetes"
@@ -96,11 +94,6 @@ func enforceRequirements(flagSet *pflag.FlagSet, flags *applyPlanFlags, args []s
9694

9795
initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, "upgrade/config", false, false)
9896
if err != nil {
99-
if apierrors.IsNotFound(err) {
100-
_, _ = printer.Printf("[upgrade/config] In order to upgrade, a ConfigMap called %q in the %q namespace must exist.\n", constants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
101-
_, _ = printer.Printf("[upgrade/config] Use 'kubeadm init phase upload-config --config your-config.yaml' to re-upload it.\n")
102-
err = errors.Errorf("the ConfigMap %q in the %q namespace was not found", constants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
103-
}
10497
return nil, nil, nil, nil, errors.Wrap(err, "[upgrade/init config] FATAL")
10598
}
10699

cmd/kubeadm/app/util/config/cluster.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ func FetchInitConfigurationFromCluster(client clientset.Interface, printer outpu
5353
if printer == nil {
5454
printer = &output.TextPrinter{}
5555
}
56-
printer.Printf("[%s] Reading configuration from the cluster...\n", logPrefix)
57-
printer.Printf("[%s] FYI: You can look at this config file with 'kubectl -n %s get cm %s -o yaml'\n", logPrefix, metav1.NamespaceSystem, constants.KubeadmConfigConfigMap)
56+
_, _ = printer.Printf("[%s] Reading configuration from the %q ConfigMap in namespace %q...\n",
57+
logPrefix, constants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
58+
_, _ = printer.Printf("[%s] Use 'kubeadm init phase upload-config --config your-config.yaml' to re-upload it.\n", logPrefix)
5859

5960
// Fetch the actual config from cluster
6061
cfg, err := getInitConfigurationFromCluster(constants.KubernetesDir, client, newControlPlane, skipComponentConfigs)
@@ -139,11 +140,9 @@ func GetNodeName(kubeconfigFile string) (string, error) {
139140
if kubeconfigFile != "" {
140141
client, err := kubeconfig.ClientSetFromFile(kubeconfigFile)
141142
if err == nil {
142-
ssr, err := client.AuthenticationV1().SelfSubjectReviews().
143-
Create(context.Background(), &authv1.SelfSubjectReview{}, metav1.CreateOptions{})
144-
145-
if err == nil && ssr.Status.UserInfo.Username != "" {
146-
return ssr.Status.UserInfo.Username, nil
143+
nodeName, err = getNodeNameFromSSR(client)
144+
if err == nil {
145+
return nodeName, nil
147146
}
148147
}
149148
nodeName, err = getNodeNameFromKubeletConfig(kubeconfigFile)
@@ -167,7 +166,7 @@ func GetNodeRegistration(kubeconfigFile string, client clientset.Interface, node
167166
}
168167

169168
// gets the corresponding node and retrieves attributes stored there.
170-
node, err := client.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{})
169+
node, err := client.CoreV1().Nodes().Get(context.Background(), nodeName, metav1.GetOptions{})
171170
if err != nil {
172171
return errors.Wrap(err, "failed to get corresponding node")
173172
}
@@ -231,6 +230,22 @@ func getNodeNameFromKubeletConfig(fileName string) (string, error) {
231230
return strings.TrimPrefix(cert.Subject.CommonName, constants.NodesUserPrefix), nil
232231
}
233232

233+
// getNodeNameFromSSR reads the node name from the SelfSubjectReview for a given client.
234+
// If the kubelet.conf is passed as fileName it can be used to retrieve the node name.
235+
func getNodeNameFromSSR(client clientset.Interface) (string, error) {
236+
ssr, err := client.AuthenticationV1().SelfSubjectReviews().
237+
Create(context.Background(), &authv1.SelfSubjectReview{}, metav1.CreateOptions{})
238+
if err != nil {
239+
return "", err
240+
}
241+
user := ssr.Status.UserInfo.Username
242+
if !strings.HasPrefix(user, constants.NodesUserPrefix) {
243+
return "", errors.Errorf("%q is not a node client, must have %q prefix in the name",
244+
user, constants.NodesUserPrefix)
245+
}
246+
return strings.TrimPrefix(user, constants.NodesUserPrefix), nil
247+
}
248+
234249
func getAPIEndpoint(client clientset.Interface, nodeName string, apiEndpoint *kubeadmapi.APIEndpoint) error {
235250
return getAPIEndpointWithRetry(client, nodeName, apiEndpoint,
236251
constants.KubernetesAPICallRetryInterval, kubeadmapi.GetActiveTimeouts().KubernetesAPICall.Duration)

cmd/kubeadm/app/util/config/cluster_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929

3030
"github.com/pkg/errors"
3131

32+
authv1 "k8s.io/api/authentication/v1"
3233
v1 "k8s.io/api/core/v1"
3334
apierrors "k8s.io/apimachinery/pkg/api/errors"
3435
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -860,3 +861,75 @@ func TestGetRawAPIEndpointFromPodAnnotationWithoutRetry(t *testing.T) {
860861
})
861862
}
862863
}
864+
865+
func TestGetNodeNameFromSSR(t *testing.T) {
866+
var tests = []struct {
867+
name string
868+
clientSetup func(*clientsetfake.Clientset)
869+
expectedNodeName string
870+
expectedError bool
871+
}{
872+
{
873+
name: "valid node name",
874+
clientSetup: func(clientset *clientsetfake.Clientset) {
875+
clientset.PrependReactor("create", "selfsubjectreviews",
876+
func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
877+
obj := &authv1.SelfSubjectReview{
878+
Status: authv1.SelfSubjectReviewStatus{
879+
UserInfo: authv1.UserInfo{
880+
Username: kubeadmconstants.NodesUserPrefix + "foo",
881+
},
882+
},
883+
}
884+
return true, obj, nil
885+
})
886+
},
887+
expectedNodeName: "foo",
888+
expectedError: false,
889+
},
890+
{
891+
name: "SSR created but client is not a node",
892+
clientSetup: func(clientset *clientsetfake.Clientset) {
893+
clientset.PrependReactor("create", "selfsubjectreviews",
894+
func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
895+
obj := &authv1.SelfSubjectReview{
896+
Status: authv1.SelfSubjectReviewStatus{
897+
UserInfo: authv1.UserInfo{
898+
Username: "foo",
899+
},
900+
},
901+
}
902+
return true, obj, nil
903+
})
904+
},
905+
expectedNodeName: "",
906+
expectedError: true,
907+
},
908+
{
909+
name: "error creating SSR",
910+
clientSetup: func(clientset *clientsetfake.Clientset) {
911+
clientset.PrependReactor("create", "selfsubjectreviews",
912+
func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
913+
return true, nil, errors.New("")
914+
})
915+
},
916+
expectedNodeName: "",
917+
expectedError: true,
918+
},
919+
}
920+
for _, rt := range tests {
921+
t.Run(rt.name, func(t *testing.T) {
922+
client := clientsetfake.NewSimpleClientset()
923+
rt.clientSetup(client)
924+
925+
nodeName, err := getNodeNameFromSSR(client)
926+
927+
if (err != nil) != rt.expectedError {
928+
t.Fatalf("expected error: %+v, got: %+v", rt.expectedError, err)
929+
}
930+
if rt.expectedNodeName != nodeName {
931+
t.Fatalf("expected nodeName: %s, got: %s", rt.expectedNodeName, nodeName)
932+
}
933+
})
934+
}
935+
}

0 commit comments

Comments
 (0)