-
Notifications
You must be signed in to change notification settings - Fork 40k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kubeadm upload and fetch of kubeam config v1alpha3 #67944
Kubeadm upload and fetch of kubeam config v1alpha3 #67944
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @fabriziopandini
added minor comments but also commented on the usage of ChooseBindAddress that we talked about last time. we might need something more unique here, unless i'm mistaken.
|
||
apiEndpoint, ok := status.APIEndpoints[machineID] | ||
if !ok { | ||
return nil, fmt.Errorf("failed to retry APIEndpoint information for this node") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to retry
-> to get
?
func GetMachineID() (string, error) { | ||
// the IP of the host default network interface as a machine unique id | ||
ip, err := netutil.ChooseBindAddress(nil) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so if we have the following scenario:
- machine A is a master node and
ChooseBindAddress
returned192.168.0.1
for it. - machine B in a different network want to join the cluster but
ChooseBindAddress
also returns192.168.0.1
for it. - both nodes have the same ID/local IP, even if technically for node B to join node A it needs it's external IP.
hostnames suffer from the same problem.
i think we might have to do UUIDs, but this needs platform specific code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@neolit123 how frequent is this case?
However, If there is a library already vendored in kubernetes for getting UUIDs I can try to switch...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think it's a general issue when nodes are not on the same sub-network?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think generating some UUID is pretty useful when folks are changing nodes in a virutual infra will be useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i can't find a vendored "system" uuid lib in k8s - i.e. a library for returning the uuid of the machine.
there is this, but this library is just for generating a RFC compliant random uuid:
https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/util/uuid/uuid.go
we need something like:
https://github.com/denisbrodbeck/machineid
the methods that the library uses are outlined here:
https://github.com/denisbrodbeck/machineid#snippets
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of UUIDs here. IP change can cause issues.
On the other hand, the machineid library queries OS maintained IDs. These are usually generated upon first boot, install or regenerated if missing on boot. They can be the same if a VM is created from a template and these are not taken care of correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meanwhile, in our own documentation:
https://kubernetes.io/docs/setup/independent/install-kubeadm/#verify-the-mac-address-and-product-uuid-are-unique-for-every-node
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabriziopandini we talked about this at the kubeadm office hours today.
Jason reminded us that the node name should be unique for a cluster to work anyway so we can use that as the key for the status map:
from @detiber
More specifically, this should be "node name" being either the user-supplied override in the kubeadm config or the default detected node name (generally the hostname here)
@@ -0,0 +1,107 @@ | |||
/* | |||
Copyright 2016 The Kubernetes Authors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2018
// Create temp folder for the test case | ||
tmpdir, err := ioutil.TempDir("", "") | ||
if err != nil { | ||
t.Fatalf("Couldn't create tmpdir") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't
-> couldn't
} | ||
|
||
if obj == nil { | ||
t.Errorf("Unexpected nil return value") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected
-> unexpected
k8sVersion := version.MustParseGeneric("v1.12.0") | ||
obj, err := r.GetFromConfigMap(client, k8sVersion) | ||
if err != nil { | ||
t.Errorf("Error getting ConfigMap: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error getting
-> error getting
|
||
err := rt.configMap.create(client) | ||
if err != nil { | ||
t.Errorf("Couldn't create ConfigMap %s", rt.configMap.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't
-> couldn't
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabriziopandini Thanks for the effort! Has a few minor nits, but otherwise it LGTM.
return | ||
} | ||
if err == nil && !reflect.DeepEqual(apiEndpoint, actual) { | ||
t.Errorf("actual doesn't match expected apiEndpoint") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps print actual and expected here?
configMapName := kubeadmconstants.GetKubeletConfigMapName(version) | ||
kubeletCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{}) | ||
if apierrors.IsNotFound(err) { | ||
return nil, fmt.Errorf("") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The actual error message is missing here
) | ||
|
||
// FetchConfigFromFileOrCluster fetches configuration required for upgrading your cluster from a file (which has precedence) or a ConfigMap in the cluster | ||
// TODO: This func should be renamed FetchClusterConfigFromFileOrCluster, and return a ClusterConfiguration instead of an InitConfiguration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may need to keep an updated version of this TODO for the future.
Ideally we should not be forced to have InitConfiguration for anything else than kubeadm init
. I am not sure, that ClusterConfiguration is the answer too (since APIEndpoint is not part of it).
It may be something else, but we may just keep some TODO here, just to mark our intent in reducing the InitConfiguration usages in the long run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I removed the comment about ClusterConfiguration
because we know this isn't the right approach.
For the long run I agree 100% with your intent of reducing the InitConfiguration usages, but better track this with an issue than TODOs in the code.
If you can kindly open the issue this will be great 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed kubernetes/kubeadm#1084
a493ddc
to
18d997f
Compare
c0c0289
to
71bf4f7
Compare
71bf4f7
to
4c2ab68
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only did a quick scan, let me know when you're ready and I'll go through this in detail.
func GetMachineID() (string, error) { | ||
// the IP of the host default network interface as a machine unique id | ||
ip, err := netutil.ChooseBindAddress(nil) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think generating some UUID is pretty useful when folks are changing nodes in a virutual infra will be useful.
|
||
// HasKubeletConfigMap returns true if the Kubelet is expected to have a config map stored in the cluster | ||
func HasKubeletConfigMap(cfg *kubeadmapi.ClusterConfiguration) bool { | ||
return true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
umm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forget it, now removed
KubeProxyConfigMap = "kube-proxy" | ||
|
||
// KubeProxyConfigMapKey specifies in what ConfigMap key the component config of kube-proxy should be stored | ||
KubeProxyConfigMapKey = "config.conf" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the key name used in kube-proxy manifest.. just refactored in a constant because it is now used in different places.
@@ -79,7 +79,7 @@ spec: | |||
imagePullPolicy: IfNotPresent | |||
command: | |||
- /usr/local/bin/kube-proxy | |||
- --config=/var/lib/kube-proxy/config.conf | |||
- --config=/var/lib/kube-proxy/{{ .ProxyConfigMapKey }}s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the trailing s
desired?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, now fixed, thanks
4c2ab68
to
a39396f
Compare
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1st pass run through.
|
||
// Decodes the Config map into the internal component config | ||
obj := &kubeletconfig.KubeletConfiguration{} | ||
err = unmarshalObject(obj, []byte(kubeletCfg.Data[kubeadmconstants.KubeletBaseConfigurationConfigMapKey])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should you index check 1st otherwise you could SEGV here. .Data[kubeadmconstants.KubeletBaseConfigurationConfigMapKey]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed + added UT
|
||
// Decodes the Config map into the internal component config | ||
obj := &kubeproxyconfig.KubeProxyConfiguration{} | ||
err = unmarshalObject(obj, []byte(kubeletCfg.Data[kubeadmconstants.KubeProxyConfigMapKey])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
return nil, err | ||
} | ||
return obj, nil | ||
} | ||
|
||
func unmarshalObject(obj runtime.Object, fileContent []byte) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I swear these functions exist elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function uses a scheme with component configs api registered.
The other unmarshal
func uses a scheme with only kubeadm types registered
} | ||
|
||
// Create a role for granting read only access to the kube-proxy component config ConfigMap | ||
if err := apiclient.CreateOrUpdateRole(client, &rbac.Role{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have tests to validate the updated RBAC rules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only test on RBAC I'm aware of are in test\e2e_kubeadm
but I'm not sure if those test are used in test grid batches...
|
||
// Prepare the ClusterStatus for upload | ||
// Gets the current cluster status | ||
clusterStatus, err := getClusterStatus(client) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we are ok for now, but we should add a //TODO use configmap locks on this object on the get before the update. We may even bug fix that after the freeze
/cc @liztio
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
a39396f
to
076ca60
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
return "", err | ||
} | ||
} else { | ||
return "", fmt.Errorf("Invalid kubelet.conf. X509 certificate expected") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit / optional: errors.New()
instead of fmt.Errorf()
|
||
// We are only putting one certificate in the certificate pem file, so it's safe to just pick the first one | ||
// TODO: Support multiple certs here in order to be able to rotate certs | ||
cert := certs[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have a tracking issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet. I will send tracking issues for TODOs soonish (after lgtm)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabriziopandini at first pass this LGTM, has some tiny nits though
cmd/kubeadm/app/cmd/join.go
Outdated
kubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.AdminKubeConfigFileName) | ||
|
||
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile) | ||
if err != nil { | ||
return errors.Wrap(err, "couldn't create kubernetes client") | ||
} | ||
|
||
err = markmasterphase.MarkMaster(client, j.cfg.NodeRegistration.Name, j.cfg.NodeRegistration.Taints) | ||
if err != nil { | ||
glog.V(1).Infof("[join] uploading currently used configuration to the cluster") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Infof
-> Info
cmd/kubeadm/app/cmd/join.go
Outdated
return fmt.Errorf("error uploading configuration: %v", err) | ||
} | ||
|
||
glog.V(1).Infof("[join] marking the master with right label") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Infof
-> Info
} | ||
|
||
if obj == nil { | ||
t.Errorf("unexpected nil return value") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Errorf
-> Error
if configData == "" { | ||
t2.Fatalf("Fail to find ConfigMap key") | ||
t2.Fatalf("Fail to find ClusterConfigurationConfigMapKey key") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fatalf
-> Fatal
|
||
statusData := masterCfg.Data[kubeadmconstants.ClusterStatusConfigMapKey] | ||
if statusData == "" { | ||
t2.Fatalf("failed to find ClusterStatusConfigMapKey key") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fatalf
-> Fatal
} | ||
|
||
if !reflect.DeepEqual(decodedStatus, status) { | ||
t2.Errorf("the initial and decoded ClusterStatus didn't match") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Errorf
-> Error
|
||
actual, err := getClusterStatus(client) | ||
if err != nil { | ||
t.Errorf("GetClusterStatus returned unexpected error") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Errorf
-> Error
return | ||
} | ||
if tt.expectedClusterEndpoints != len(actual.APIEndpoints) { | ||
t.Errorf("actual ClusterStatus doesn't return expected endpoints") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Errorf
-> Error
// gets the APIEndpoint for the current machine from the ClusterStatus | ||
e, ok := clusterStatus.APIEndpoints[nodeName] | ||
if !ok { | ||
return fmt.Errorf("failed to get APIEndpoint information for this node") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt.Errorf
-> errors.New
076ca60
to
d9b4b1f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
/approve
We're too late for nits, we'll have to beat on this during freeze.
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: fabriziopandini, timothysc The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/test pull-kubernetes-integration |
Automatic merge from submit-queue (batch tested with PRs 63011, 68089, 67944, 68132). If you want to cherry-pick this change to another branch, please follow the instructions here: https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md. |
What this PR does / why we need it:
This PR implements upload and fetch of kubeam config v1alpha3 from cluster.
More in detail:
In upload,
kubeadm-config
getsClusterConfiguration
(without components config which are already stored in separated ConfigMaps)ClusterStatus
(initialised or updated with the API endpoint of the current node)During fetch
InitConfiguration
is composed with:ClusterConfiguration
fromkubeadm-config
APIEndpoint
of the current node fromClusterStatus
inkubeadm-config
Which issue(s) this PR fixes :
refs kubernetes/kubeadm#911, refs kubernetes/kubeadm#963
Special notes for your reviewer:
In order to implement this it was necessary to extend current component config management with a new GetFromConfigMap operation. This is implemented in a separated commit "
implement component configs GetFromConfigMap".
The real change build on this (commi "upload and fetch kubeadm v1alpha3")
Release note:
/cc @kubernetes/sig-cluster-lifecycle-pr-reviews
/sig cluster-lifecycle
/area kubeadm
/kind enhancement
/assign @luxas
/assign @timothysc
/cc @chuckha @rosti @neolit123 @liztio