Skip to content
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

change pod from a node to another in runtime #105

Closed
ViniciusDeAndrade opened this issue Oct 27, 2017 · 12 comments
Closed

change pod from a node to another in runtime #105

ViniciusDeAndrade opened this issue Oct 27, 2017 · 12 comments

Comments

@ViniciusDeAndrade
Copy link

Hi everybody.
I saw in k8 tutorial that we can select the node where we want to deploy a pod. It is using the nodeSelector.
So, I am trying to change this property while my k8 application is running.
My main class has this code to set a new node selector:

`public class Test {

public static void main(String[] args) throws FileNotFoundException, ApiException {
	final String podName = "etcd-swarm1";

	//final String oldNode = "swarm1";
	final String newNode = "swarm5";
	
	PodAbstraction podAbstraction = new PodAbstraction(podName, newNode);
	RuntimeDealer runtimeDealer = new RuntimeDealer();
	V1Pod pod = runtimeDealer.searchPod(podName);
	
	podAbstraction.updateNodeSelector(pod);	
			
}

}`

And, my podAbstraction class, has the method updateNodeSelector(), which is:

public void updateNodeSelector(V1Pod pod) {	
	//System.out.println("the pod is on node : "+"\n"+pod.getSpec().toString());
	pod.getSpec().setNodeSelector(this.nodeSelector);
	pod.getSpec().setNodeName("swarm5");
	System.out.println("and now it is on node: "+pod.getSpec().getNodeName());
}

Aparently it is now enough to make a pod leave on node to another (in my case, I am trying to move the pod
etcd-swarm1 from the node swarm1 to the node swarm5).

Finally, I got this message on my terminal after running this java-client program( I have abstracted some comands here):

vinicius@vinicius-VPCEG17FB:~/Documentos$ kubectl  get pods -o wide 
NAME                                    READY     STATUS    RESTARTS   AGE       IP            NODE
etcd-swarm1                             1/1       Running   0          20d       10.66.66.23   swarm1

As you can see, it has not been moved.
Does someone has any idea of how I can complete the task of moving a pod from a node to another one?
Thanks

@lwander
Copy link
Contributor

lwander commented Oct 27, 2017

I think you'll have to send that updated V1Pod back to the Kubernetes master for that change to be reflected. You can send a patch request with patchNamespacedPod(..) in the CoreV1Api.

@ViniciusDeAndrade
Copy link
Author

this way is good enough?

public void updateNodeSelector(V1Pod pod) throws ApiException {		
	pod.getSpec().setNodeSelector(this.nodeSelector);
	pod.getSpec().setNodeName("swarm5");
		
	String podName = pod.getMetadata().getName();
	String podNamespace = pod.getMetadata().getNamespace();		
		
	K8Instance.getInstance().patchNamespacedPod(podName, podNamespace, null, null);
	System.out.println("and now it is on node: "+pod.getSpec().getNodeName());
		
}

PS.: I did not understand all the parameters yet.

@lwander
Copy link
Contributor

lwander commented Oct 27, 2017

Well I don't know what K8Instance.getInstance() is, but you definitely need to pass the diff between the current pod and the desired pod to your patchNamespacedPod call. Take a look at what kubectl does when you edit a pod in detail by passing -v 9 as a flag.

@ViniciusDeAndrade
Copy link
Author

Hello again.
I have restarted my code. So it is simpler now.
But I still got some errors. Look my main class:

package mainTest;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Collections;

import io.kubernetes.client.ApiClient;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.Configuration;
import io.kubernetes.client.apis.AppsV1beta1Api;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.models.V1Pod;
import io.kubernetes.client.util.Config;
import io.kubernetes.client.util.KubeConfig;
import k8_object.ObjectsDealer;

public class Verify {
	public static void main(String[] args) throws FileNotFoundException, ApiException {
		//setting the environment
		final String pathToGfadsConfigFile = "/home/vinicius/Documentos/gfads-test.config";
		FileReader gfadsConfigFile = new FileReader(pathToGfadsConfigFile);
		KubeConfig kc = KubeConfig.loadKubeConfig(gfadsConfigFile);
		ApiClient client = Config.fromConfig(kc);
		Configuration.setDefaultApiClient(client);
		
		//getting the environment
		CoreV1Api core = new CoreV1Api();
		AppsV1beta1Api beta = new AppsV1beta1Api();
		
		//dealing with pods		
		ObjectsDealer k8objects = new ObjectsDealer();
		String podName = "kube-proxy-8ktf4";
		V1Pod pod = k8objects.findPod(core,podName);
		
		//setting labels to pods
		String key = "key";
		String operator = "In";
		String value = "value";
		pod = k8objects.setLabelsToPods(core, podName, key, podName, operator, Collections.singletonList(value));
		System.out.println("got here");
		
		core.patchNamespacedPod(podName, pod.getMetadata().getNamespace(), pod, null);
		
		System.out.println("it works");		
	}
}

and here, is what my console prints:

got here
Exception in thread "main" io.kubernetes.client.ApiException: Internal Server Error
	at io.kubernetes.client.ApiClient.handleResponse(ApiClient.java:882)
	at io.kubernetes.client.ApiClient.execute(ApiClient.java:798)
	at io.kubernetes.client.apis.CoreV1Api.patchNamespacedPodWithHttpInfo(CoreV1Api.java:19235)
	at io.kubernetes.client.apis.CoreV1Api.patchNamespacedPod(CoreV1Api.java:19218)
	at mainTest.Verify.main(Verify.java:44)

As you can see, It bugs the patch method where I want to update a pod. Can anyone help me?

Ps.: If you want to see my second class... :

package k8_object;

import java.util.List;

import io.kubernetes.client.ApiException;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.models.V1LabelSelector;
import io.kubernetes.client.models.V1LabelSelectorRequirement;
import io.kubernetes.client.models.V1Pod;
import io.kubernetes.client.models.V1PodList;

public class ObjectsDealer {

	public V1Pod findPod(CoreV1Api core, String podName) throws ApiException {
		V1PodList list = core.listPodForAllNamespaces(null, null, null, null, null, null);
		for (V1Pod item : list.getItems()) 
			if(item.getMetadata().getName().equalsIgnoreCase(podName))
				return item;
		return null;
	}

	public V1Pod setLabelsToPods(CoreV1Api core, String podName, String key, String matchLabelsItem, String operator, List<String> values) throws ApiException {
		//setting label selector and label requirement. I still do not know what is a requirement of their difference
		V1LabelSelector selector = new V1LabelSelector();
		V1LabelSelectorRequirement requirement = new V1LabelSelectorRequirement();
		selector.putMatchLabelsItem(key, matchLabelsItem);
		requirement.setKey(key);
		requirement.setOperator(operator);
		requirement.setValues(values);
		
		V1Pod pod = setLabels(core, podName, selector, requirement);		
		return pod;
	}
	
	private V1Pod setLabels(CoreV1Api core, String podName, V1LabelSelector selector, V1LabelSelectorRequirement requirement) throws ApiException {
		V1Pod pod = this.findPod(core, podName);
		pod.getMetadata().setLabels(selector.getMatchLabels());
		//I Still don't know why the requirement is here. It is useless.
		return pod;
	}
}


@ViniciusDeAndrade
Copy link
Author

I have tried to use a example given here, in this page samples
But I still got errors:

Exception when calling CoreV1Api#patchNamespacedPod
io.kubernetes.client.ApiException: Missing the required parameter 'body' when calling patchNamespacedPod(Async)
	at io.kubernetes.client.apis.CoreV1Api.patchNamespacedPodValidateBeforeCall(CoreV1Api.java:19194)
	at io.kubernetes.client.apis.CoreV1Api.patchNamespacedPodWithHttpInfo(CoreV1Api.java:19233)
	at io.kubernetes.client.apis.CoreV1Api.patchNamespacedPod(CoreV1Api.java:19218)
	at main.Example.main(Example.java:40)

OMG, What is going on?

Here is the code:


package main;

import java.io.FileNotFoundException;
import java.io.FileReader;

import io.kubernetes.client.ApiClient;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.Configuration;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.auth.ApiKeyAuth;
import io.kubernetes.client.models.V1Pod;
import io.kubernetes.client.util.Config;
import io.kubernetes.client.util.KubeConfig;

/**
 * patch pod example from 
 * https://github.com/kubernetes-client/java/blob/master/kubernetes/docs/CoreV1Api.md#patchNamespacedPod
 * @author vinicius
 *
 */
public class Example {
	public static void main(String[] args) throws FileNotFoundException {
		//setting the environment
		final String pathToGfadsConfigFile = "/home/vinicius/Documentos/gfads-test.config";
		FileReader gfadsConfigFile = new FileReader(pathToGfadsConfigFile);
		KubeConfig kc = KubeConfig.loadKubeConfig(gfadsConfigFile);
		ApiClient client = Config.fromConfig(kc);
		Configuration.setDefaultApiClient(client);


		CoreV1Api apiInstance = new CoreV1Api();

		String name = "name_example"; // String | name of the Pod
		String namespace = "namespace_example"; // String | object name and auth scope, such as for teams and projects
		Object body = null; // Object | 
		String pretty = "pretty_example"; // String | If 'true', then the output is pretty printed.


		try {
			V1Pod result = apiInstance.patchNamespacedPod(name, namespace, body, pretty);
			System.out.println(result);
		} catch (ApiException e) {
			System.err.println("Exception when calling CoreV1Api#patchNamespacedPod");
			e.printStackTrace();
		}

	}
}

@lwander
Copy link
Contributor

lwander commented Oct 31, 2017

Those example are auto-generated, and might not be great, sorry about that.

Looks like Object body = null; // Object, and the error message "Missing the required parameter 'body' when calling patchNamespacedPod(Async)" is pointing us in the right direction. If you want to see what you need to send as the body, you can use kubectl to help: kubectl edit pod <pod name> -v 9 will print all http traffic on STDERR and show you how to format your request.

You can also take a look at how I used the patch methods & generated the body using JsonDiff here.

@brendandburns
Copy link
Contributor

fwiw, I don't think patch is what you want here (it does a PATCH which probably isn't what you want) I think you want a PUT in which case you want: replaceNamespacedPod.

@ViniciusDeAndrade
Copy link
Author

Mr. Wander, I was trying to copy your patchDeployment method, but I got a problem.
This method calls another one called determineJsonPatch, witch deals with a Object that that is not on the default API, the ObjectMapper.

Also, there is more one thing. These methods works with a Map[], but what is it? The Map I know is a Map< T , T >;

Since now, I thank you for all your help

@ViniciusDeAndrade
Copy link
Author

If someone can see what is going on, I have made my code simpler with just 2 classes.
One main, and one with some simple methods, easy to understand/abstract ('cause they work) and two print near the end of the main class, which just the first works before the patch method.
the code is here .

Thank you all.

@lwander
Copy link
Contributor

lwander commented Nov 1, 2017

@brendandburns makes a good point, you should be able to get away with calling replaceNamespacePod which will take a V1Pod as an argument, instead of an arbitrary json path. That list of maps is described here: http://jsonpatch.com/. The ObjectMapper just helps serialize the k8s client resources into JSON & Map<String, Object> types.

@brendandburns
Copy link
Contributor

I'm going to close this as it is a request for help rather than a true issue...

@brendandburns
Copy link
Contributor

(feel free to ask for more help and re-open, though, if need be)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants