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

Delete and Modify events are not getting trigged #3652

Open
MohammadNC opened this issue Aug 21, 2024 · 5 comments
Open

Delete and Modify events are not getting trigged #3652

MohammadNC opened this issue Aug 21, 2024 · 5 comments
Labels
lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale.

Comments

@MohammadNC
Copy link

MohammadNC commented Aug 21, 2024

Describe the bug
I am watching kubernate secret in infine loop, in any change happened to secret, watch should trigger appropriate events like ADDED or MODIFIED or DELETED.
but in my case DELETE event is not triggered and most important point is that Thread is getting struck.

Client Version
19.0.0

Kubernetes Version
1.23.10

Java Version
. Java 17

below is code snippet to reproduce the issue.

import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Secret;
import io.kubernetes.client.openapi.models.V1SecretList;
import io.kubernetes.client.util.Config;
import io.kubernetes.client.util.Watch;
import com.google.gson.reflect.TypeToken;

import java.io.IOException;
import java.util.List;

public class SecretWatcher {

public static void watchSecret() throws IOException, ApiException {
    ApiClient client = Config.defaultClient();
    CoreV1Api api = new CoreV1Api(client);

    List<String> secretNames = List.of("secret1", "secret2", "secret3");

    while (true) {
try (Watch<V1Secret> watch = watchForNamespace(this.nameSpace)) {
		try {
			for (Watch.Response<V1Secret> item : watch) {
				if (secretNames.contains(item.object.getMetadata().getName())) {
					logger.debug("Item type received is: " + item.type);
					switch (item.type) {
						case "ADDED":
							handleEventAdded(item.object);
							break;
						case "MODIFIED":
							handleEventModified(item.object);
							break;
						case "DELETED":
							handleEventDeleted(item.object);
							break;
						default:
							continue;
					}
					break;
				}
			}
		} catch (Exception e) {

			logger.error("Exception occurred during handling item.type event. Reason: " + e.getMessage());
		}
	} catch (Exception excep) {
		logger.error("Exception occurred while monitoring K8 Resource  " + excep.getMessage());
	}
    }
}


	public Watch<V1Secret> watchForNamespace(String nameSpace) {
	Watch<V1Secret> watch = null;
	try {
		watch = Watch.createWatch(getClient(), getApi().listNamespacedSecretCall(nameSpace, null, null, null, null,
				null, null, null, null, Boolean.TRUE, null, Boolean.TRUE, null), new TypeToken<Watch.Response<V1Secret>>() {
		}.getType());
		logger.debug("Watch created for secrets in namespace: " + nameSpace);
	} catch (ApiException e) {
		logger.error("Failed to create watch for secrets in namespace:" + nameSpace + " Reason: " + e.getMessage());
	}
	return watch;
}

}

Kindly suggest how we can achieve all event triggered correctly.

@MohammadNC
Copy link
Author

And also noticed that with the below code snippet thread is getting stuck.

private boolean checkConfigFilesPresent(String nameSpace, String secretName, ArrayList fileNameList) {

	try {
		V1SecretList listSecret = new CoreV1Api().listNamespacedSecret(nameSpace, null, null, null, null,
				null, null, null, null, null, null, Boolean.TRUE);
		for (V1Secret secret : listSecret.getItems()) {
			if (secret.getMetadata().getName().equals(secretName)) {
				Map<String, byte[]> map = secret.getData();
				for (String fileName : fileNameList) {
					if (map.get(fileName) == null) {
						return false;
					}
				}
			}
		}

	} catch (ApiException e) {
		e.printStackTrace();
	}
	return true;
}

please check this one also.

@brendandburns
Copy link
Contributor

Getting watches right is tricky, I would strongly encourage you to use the Informer class instead of trying to roll your own watch code, there is an example here:

https://github.com/kubernetes-client/java/blob/b85fb963d2796a1cb982d73ae2ae36cdce857e5e/examples/examples-release-latest/src/main/java/io/kubernetes/client/examples/InformerExample.java

@MohammadNC
Copy link
Author

MohammadNC commented Aug 22, 2024

Hi @brendandburns

Thank you for your suggestion.

I implemented the following code snippet to monitor Kubernetes secrets. However, when performing different operations like adding, modifying, and deleting a secret, no events were triggered.

`package com.example.demo.informer;

import io.kubernetes.client.informer.ResourceEventHandler;
import io.kubernetes.client.informer.SharedIndexInformer;
import io.kubernetes.client.informer.SharedInformerFactory;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Secret;
import io.kubernetes.client.openapi.models.V1SecretList;
import okhttp3.OkHttpClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.concurrent.TimeUnit;

public class SecretWatcher implements Runnable {

private static final Logger logger = LogManager.getLogger(SecretWatcher.class);
String nameSpace;
private final CoreV1Api api;
SharedInformerFactory informerFactory;

public SecretWatcher(String nameSpace) {
    this.nameSpace = nameSpace;
    this.api = new CoreV1Api();
    ApiClient apiClient = this.api.getApiClient();
    OkHttpClient httpClient =
            apiClient.getHttpClient().newBuilder().readTimeout(0, TimeUnit.SECONDS).build();
    apiClient.setHttpClient(httpClient);
    this.informerFactory = new SharedInformerFactory(apiClient);
}


@Override
public void run() {
    logger.info("Starting ConfigWatchProcess ");

    while (true) {
        try {
            SharedIndexInformer<V1Secret> secretInformer =
                    this.informerFactory.sharedIndexInformerFor(
                            (CallGeneratorParams) -> {
                                return this.api.listNamespacedSecretCall(nameSpace, null, null,
                                        null, null, null, null, null,
                                        null, Boolean.TRUE, null, Boolean.TRUE, null);
                            },
                            V1Secret.class,
                            V1SecretList.class);

            secretInformer.addEventHandler(
                    new ResourceEventHandler<V1Secret>() {
                        @Override
                        public void onAdd(V1Secret secret) {
                            String secretName = getSecretName(secret);
                            logger.warn("Add event is triggered for Secret : {}", secretName);
                            handleEventAdded(secret);
                        }

                        @Override
                        public void onUpdate(V1Secret oldSecret, V1Secret newSecret) {
                            String olSecretName = getSecretName(newSecret);
                            String newSecretName = getSecretName(newSecret);
                            logger.warn("olSecretName: {}, newSecretName:{}", olSecretName, newSecretName);
                            handleEventModified(newSecret);
                        }

                        @Override
                        public void onDelete(V1Secret secret, boolean deletedFinalStateUnknown) {
                            String secretName = getSecretName(secret);
                            logger.warn("Delete event is triggered for Secret : {}", secretName);
                            handleEventDeleted(secret);
                        }
                    });
            logger.warn("Starting the informer..");
            informerFactory.startAllRegisteredInformers();
            Thread.sleep(1000);
        } catch (Exception e) {
            logger.error("Exception occurred while monitorning...");
        }
    }

}

private void handleEventAdded(V1Secret secret) {
    logger.warn("Handling of Add secret ....");
}

private void handleEventModified(V1Secret secret) {
    logger.warn("Handling of Modified secret ....");
}

private void handleEventDeleted(V1Secret secret) {
    logger.warn("Handling of deleted secret ....");
}

private String getSecretName(V1Secret secret) {
    return secret.getMetadata().getName();
}

}
`

Could you please suggest how to resolve this issue so that all events are properly triggered?

My request is to continuously monitor Kubernetes secrets, ensuring that whenever any action is performed on a secret, the appropriate event is triggered.

@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Mark this issue as fresh with /remove-lifecycle stale
  • Close this issue with /close
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle stale

@k8s-ci-robot k8s-ci-robot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Nov 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale.
Projects
None yet
Development

No branches or pull requests

4 participants