Support for display secrets (#21)
Some checks failed
Java CI with Gradle / build (push) Has been cancelled

This commit is contained in:
Michael N. Lipp 2024-03-20 11:03:09 +01:00 committed by GitHub
parent 85b0a160f3
commit 3103452170
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 2081 additions and 658 deletions

View file

@ -26,6 +26,9 @@ public class Constants {
/** The Constant APP_NAME. */
public static final String APP_NAME = "vm-runner";
/** The Constant COMP_DISPLAY_SECRETS. */
public static final String COMP_DISPLAY_SECRET = "display-secret";
/** The Constant VM_OP_NAME. */
public static final String VM_OP_NAME = "vm-operator";

View file

@ -44,6 +44,7 @@ import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
// TODO: Auto-generated Javadoc
/**
* Helpers for K8s API.
*/
@ -74,6 +75,35 @@ public class K8s {
return Optional.empty();
}
/**
* Returns a new context with the given version as preferred version.
*
* @param context the context
* @param version the version
* @return the API resource
*/
public static APIResource preferred(APIResource context, String version) {
assert context.getVersions().contains(version);
return new APIResource(context.getGroup(),
context.getVersions(), version, context.getKind(),
context.getNamespaced(), context.getResourcePlural(),
context.getResourceSingular());
}
/**
* Return a string representation of the context (API resource).
*
* @param context the context
* @return the string
*/
@SuppressWarnings("PMD.UseLocaleWithCaseConversions")
public static String toString(APIResource context) {
return (Strings.isNullOrEmpty(context.getGroup()) ? ""
: context.getGroup() + "/")
+ context.getPreferredVersion().toUpperCase()
+ context.getKind();
}
/**
* Convert Yaml to Json.
*
@ -156,6 +186,7 @@ public class K8s {
* @param api the api
* @param existing the existing
* @param update the update
* @return the t
* @throws ApiException the api exception
*/
public static <T extends KubernetesObject, LT extends KubernetesListObject>
@ -199,8 +230,10 @@ public class K8s {
* * If `type` is not set, set it to "Normal"
* * If `regarding` is not set, set it to the given object.
*
* @param client the client
* @param object the object
* @param event the event
* @throws ApiException
* @throws ApiException the api exception
*/
@SuppressWarnings("PMD.NPathComplexity")
public static void createEvent(ApiClient client,

View file

@ -18,10 +18,14 @@
package org.jdrupes.vmoperator.common;
import com.google.gson.Gson;
import io.kubernetes.client.Discovery.APIResource;
import io.kubernetes.client.apimachinery.GroupVersionKind;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.util.generic.options.ListOptions;
import java.io.Reader;
import java.util.Collection;
/**
* A stub for namespaced custom objects. It uses a dynamic model
@ -47,6 +51,24 @@ public class K8sDynamicStub
Class<K8sDynamicModels> objectListClass, K8sClient client,
APIResource context, String namespace, String name) {
super(objectClass, objectListClass, client, context, namespace, name);
// Make sure that we have an adapter for our type
Gson gson = client.getJSON().getGson();
if (!checkAdapters(client)) {
client.getJSON().setGson(gson.newBuilder()
.registerTypeAdapterFactory(
new K8sDynamicModelTypeAdapterFactory())
.create());
}
}
private boolean checkAdapters(ApiClient client) {
return K8sDynamicModelTypeAdapterFactory.K8sDynamicModelCreator.class
.equals(client.getJSON().getGson().getAdapter(K8sDynamicModel.class)
.getClass())
&& K8sDynamicModelTypeAdapterFactory.K8sDynamicModelsCreator.class
.equals(client.getJSON().getGson()
.getAdapter(K8sDynamicModels.class).getClass());
}
/**
@ -83,8 +105,7 @@ public class K8sDynamicStub
@SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop",
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.UseObjectForClearerAPI" })
public static K8sDynamicStub get(K8sClient client,
APIResource context, String namespace, String name)
throws ApiException {
APIResource context, String namespace, String name) {
return K8sGenericStub.get(K8sDynamicModel.class, K8sDynamicModels.class,
client, context, namespace, name, K8sDynamicStub::new);
}
@ -106,4 +127,37 @@ public class K8sDynamicStub
K8sDynamicModels.class, client, context, model,
K8sDynamicStub::new);
}
/**
* Get the stubs for the objects in the given namespace that match
* the criteria from the given options.
*
* @param client the client
* @param namespace the namespace
* @param options the options
* @return the collection
* @throws ApiException the api exception
*/
public static Collection<K8sDynamicStub> list(K8sClient client,
APIResource context, String namespace, ListOptions options)
throws ApiException {
return K8sGenericStub.list(K8sDynamicModel.class,
K8sDynamicModels.class, client, context, namespace, options,
K8sDynamicStub::new);
}
/**
* Get the stubs for the objects in the given namespace.
*
* @param client the client
* @param namespace the namespace
* @return the collection
* @throws ApiException the api exception
*/
public static Collection<K8sDynamicStub> list(K8sClient client,
APIResource context, String namespace)
throws ApiException {
return list(client, context, namespace, new ListOptions());
}
}

View file

@ -18,21 +18,22 @@
package org.jdrupes.vmoperator.common;
import com.google.gson.Gson;
import io.kubernetes.client.Discovery.APIResource;
import io.kubernetes.client.apimachinery.GroupVersionKind;
import io.kubernetes.client.common.KubernetesListObject;
import io.kubernetes.client.common.KubernetesObject;
import io.kubernetes.client.custom.V1Patch;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.util.Strings;
import io.kubernetes.client.util.generic.GenericKubernetesApi;
import io.kubernetes.client.util.generic.options.GetOptions;
import io.kubernetes.client.util.generic.options.ListOptions;
import io.kubernetes.client.util.generic.options.PatchOptions;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@ -49,145 +50,16 @@ public class K8sGenericStub<O extends KubernetesObject,
L extends KubernetesListObject> {
protected final K8sClient client;
private final GenericKubernetesApi<O, L> api;
protected final String group;
protected final String version;
protected final String kind;
protected final String plural;
protected final APIResource context;
protected final String namespace;
protected final String name;
/**
* Get a namespaced object stub. If the version in parameter
* `gvk` is an empty string, the stub refers to the first object
* found with matching group and kind.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the stub type
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param gvk the group, version and kind
* @param namespace the namespace
* @param name the name
* @param provider the provider
* @return the stub if the object exists
* @throws ApiException the api exception
*/
@SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop",
"PMD.AvoidInstantiatingObjectsInLoops" })
public static <O extends KubernetesObject, L extends KubernetesListObject,
R extends K8sGenericStub<O, L>>
R get(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, GroupVersionKind gvk, String namespace,
String name, GenericSupplier<O, L, R> provider)
throws ApiException {
var context = K8s.context(client, gvk.getGroup(), gvk.getVersion(),
gvk.getKind());
if (context.isEmpty()) {
throw new ApiException("No known API for " + gvk.getGroup()
+ "/" + gvk.getVersion() + " " + gvk.getKind());
}
return provider.get(objectClass, objectListClass, client, context.get(),
namespace, name);
}
/**
* Get a namespaced object stub.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the stub type
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param context the context
* @param namespace the namespace
* @param name the name
* @param provider the provider
* @return the stub if the object exists
* @throws ApiException the api exception
*/
@SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop",
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.UseObjectForClearerAPI" })
public static <O extends KubernetesObject, L extends KubernetesListObject,
R extends K8sGenericStub<O, L>>
R get(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, APIResource context, String namespace,
String name, GenericSupplier<O, L, R> provider)
throws ApiException {
return provider.get(objectClass, objectListClass, client,
context, namespace, name);
}
/**
* Get a namespaced object stub for a newly created object.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the stub type
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param context the context
* @param model the model
* @param provider the provider
* @return the stub if the object exists
* @throws ApiException the api exception
*/
@SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop",
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.UseObjectForClearerAPI" })
public static <O extends KubernetesObject, L extends KubernetesListObject,
R extends K8sGenericStub<O, L>>
R create(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, APIResource context, O model,
GenericSupplier<O, L, R> provider) throws ApiException {
var api = new GenericKubernetesApi<>(objectClass, objectListClass,
context.getGroup(), context.getPreferredVersion(),
context.getResourcePlural(), client);
api.create(model).throwsApiException();
return provider.get(objectClass, objectListClass, client,
context, model.getMetadata().getNamespace(),
model.getMetadata().getName());
}
/**
* Get the stubs for the objects in the given namespace that match
* the criteria from the given options.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the stub type
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param context the context
* @param namespace the namespace
* @param options the options
* @param provider the provider
* @return the collection
* @throws ApiException the api exception
*/
public static <O extends KubernetesObject, L extends KubernetesListObject,
R extends K8sGenericStub<O, L>>
Collection<R> list(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, APIResource context, String namespace,
ListOptions options, SpecificSupplier<O, L, R> provider)
throws ApiException {
var api = new GenericKubernetesApi<>(objectClass, objectListClass,
context.getGroup(), context.getPreferredVersion(),
context.getResourcePlural(), client);
var objs = api.list(namespace, options).throwsApiException();
var result = new ArrayList<R>();
for (var item : objs.getObject().getItems()) {
result.add(
provider.get(client, namespace, item.getMetadata().getName()));
}
return result;
}
/**
* Instantiates a new namespaced custom object stub.
* Instantiates a new stub for the object specified. If the object
* exists in the context specified, the version (see
* {@link #version()} is bound to the existing object's version.
* Else the stub is dangling with the version set to the context's
* preferred version.
*
* @param objectClass the object class
* @param objectListClass the object list class
@ -196,35 +68,47 @@ public class K8sGenericStub<O extends KubernetesObject,
* @param namespace the namespace
* @param name the name
*/
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
protected K8sGenericStub(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, APIResource context, String namespace,
String name) {
this.client = client;
group = context.getGroup();
version = context.getPreferredVersion();
kind = context.getKind();
plural = context.getResourcePlural();
this.namespace = namespace;
this.name = name;
Gson gson = client.getJSON().getGson();
if (!checkAdapters(client)) {
client.getJSON().setGson(gson.newBuilder()
.registerTypeAdapterFactory(
new K8sDynamicModelTypeAdapterFactory())
.create());
// Bind version
var foundVersion = context.getPreferredVersion();
GenericKubernetesApi<O, L> testApi = null;
GetOptions mdOpts
= new GetOptions().isPartialObjectMetadataRequest(true);
for (var version : candidateVersions(context)) {
testApi = new GenericKubernetesApi<>(objectClass, objectListClass,
context.getGroup(), version, context.getResourcePlural(),
client);
if (testApi.get(namespace, name, mdOpts)
.isSuccess()) {
foundVersion = version;
break;
}
}
api = new GenericKubernetesApi<>(objectClass,
objectListClass, group, version, plural, client);
if (foundVersion.equals(context.getPreferredVersion())) {
this.context = context;
} else {
this.context = K8s.preferred(context, foundVersion);
}
api = Optional.ofNullable(testApi)
.orElseGet(() -> new GenericKubernetesApi<>(objectClass,
objectListClass, group(), version(), plural(), client));
}
private boolean checkAdapters(ApiClient client) {
return K8sDynamicModelTypeAdapterFactory.K8sDynamicModelCreator.class
.equals(client.getJSON().getGson().getAdapter(K8sDynamicModel.class)
.getClass())
&& K8sDynamicModelTypeAdapterFactory.K8sDynamicModelsCreator.class
.equals(client.getJSON().getGson()
.getAdapter(K8sDynamicModels.class).getClass());
/**
* Gets the context.
*
* @return the context
*/
public APIResource context() {
return context;
}
/**
@ -233,7 +117,7 @@ public class K8sGenericStub<O extends KubernetesObject,
* @return the group
*/
public String group() {
return group;
return context.getGroup();
}
/**
@ -242,7 +126,7 @@ public class K8sGenericStub<O extends KubernetesObject,
* @return the version
*/
public String version() {
return version;
return context.getPreferredVersion();
}
/**
@ -251,7 +135,7 @@ public class K8sGenericStub<O extends KubernetesObject,
* @return the kind
*/
public String kind() {
return kind;
return context.getKind();
}
/**
@ -260,7 +144,7 @@ public class K8sGenericStub<O extends KubernetesObject,
* @return the plural
*/
public String plural() {
return plural;
return context.getResourcePlural();
}
/**
@ -387,32 +271,149 @@ public class K8sGenericStub<O extends KubernetesObject,
APIResource context, String namespace, String name);
}
/**
* A supplier for specific stubs.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the result type
*/
public interface SpecificSupplier<O extends KubernetesObject,
L extends KubernetesListObject, R extends K8sGenericStub<O, L>> {
/**
* Gets a new stub.
*
* @param client the client
* @param namespace the namespace
* @param name the name
* @return the result
*/
R get(K8sClient client, String namespace, String name);
}
@Override
@SuppressWarnings("PMD.UseLocaleWithCaseConversions")
public String toString() {
return (Strings.isNullOrEmpty(group) ? "" : group + "/")
+ version.toUpperCase() + kind + " " + namespace + ":" + name;
return (Strings.isNullOrEmpty(group()) ? "" : group() + "/")
+ version().toUpperCase() + kind() + " " + namespace + ":" + name;
}
/**
* Get a namespaced object stub. If the version in parameter
* `gvk` is an empty string, the stub refers to the first object
* found with matching group and kind.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the stub type
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param gvk the group, version and kind
* @param namespace the namespace
* @param name the name
* @param provider the provider
* @return the stub if the object exists
* @throws ApiException the api exception
*/
@SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop" })
public static <O extends KubernetesObject, L extends KubernetesListObject,
R extends K8sGenericStub<O, L>>
R get(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, GroupVersionKind gvk, String namespace,
String name, GenericSupplier<O, L, R> provider)
throws ApiException {
var context = K8s.context(client, gvk.getGroup(), gvk.getVersion(),
gvk.getKind());
if (context.isEmpty()) {
throw new ApiException("No known API for " + gvk.getGroup()
+ "/" + gvk.getVersion() + " " + gvk.getKind());
}
return provider.get(objectClass, objectListClass, client, context.get(),
namespace, name);
}
/**
* Get a namespaced object stub.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the stub type
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param context the context
* @param namespace the namespace
* @param name the name
* @param provider the provider
* @return the stub if the object exists
* @throws ApiException the api exception
*/
@SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop",
"PMD.UseObjectForClearerAPI" })
public static <O extends KubernetesObject, L extends KubernetesListObject,
R extends K8sGenericStub<O, L>>
R get(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, APIResource context, String namespace,
String name, GenericSupplier<O, L, R> provider) {
return provider.get(objectClass, objectListClass, client,
context, namespace, name);
}
/**
* Get a namespaced object stub for a newly created object.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the stub type
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param context the context
* @param model the model
* @param provider the provider
* @return the stub if the object exists
* @throws ApiException the api exception
*/
@SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop",
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.UseObjectForClearerAPI" })
public static <O extends KubernetesObject, L extends KubernetesListObject,
R extends K8sGenericStub<O, L>>
R create(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, APIResource context, O model,
GenericSupplier<O, L, R> provider) throws ApiException {
var api = new GenericKubernetesApi<>(objectClass, objectListClass,
context.getGroup(), context.getPreferredVersion(),
context.getResourcePlural(), client);
api.create(model).throwsApiException();
return provider.get(objectClass, objectListClass, client,
context, model.getMetadata().getNamespace(),
model.getMetadata().getName());
}
/**
* Get the stubs for the objects in the given namespace that match
* the criteria from the given options.
*
* @param <O> the object type
* @param <L> the object list type
* @param <R> the stub type
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param context the context
* @param namespace the namespace
* @param options the options
* @param provider the provider
* @return the collection
* @throws ApiException the api exception
*/
public static <O extends KubernetesObject, L extends KubernetesListObject,
R extends K8sGenericStub<O, L>>
Collection<R> list(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, APIResource context, String namespace,
ListOptions options, GenericSupplier<O, L, R> provider)
throws ApiException {
var result = new ArrayList<R>();
for (var version : candidateVersions(context)) {
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
var api = new GenericKubernetesApi<>(objectClass, objectListClass,
context.getGroup(), version, context.getResourcePlural(),
client);
var objs = api.list(namespace, options).throwsApiException();
for (var item : objs.getObject().getItems()) {
result.add(provider.get(objectClass, objectListClass, client,
context, namespace, item.getMetadata().getName()));
}
}
return result;
}
private static List<String> candidateVersions(APIResource context) {
var result = new LinkedList<>(context.getVersions());
result.remove(context.getPreferredVersion());
result.add(0, context.getPreferredVersion());
return result;
}
}

View file

@ -0,0 +1,230 @@
/*
* VM-Operator
* Copyright (C) 2024 Michael N. Lipp
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jdrupes.vmoperator.common;
import io.kubernetes.client.Discovery.APIResource;
import io.kubernetes.client.common.KubernetesListObject;
import io.kubernetes.client.common.KubernetesObject;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.util.Watch.Response;
import io.kubernetes.client.util.generic.GenericKubernetesApi;
import io.kubernetes.client.util.generic.options.ListOptions;
import java.time.Duration;
import java.time.Instant;
import java.util.function.BiConsumer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* An observer that watches namespaced resources in a given context and
* invokes a handler on changes.
*
* @param <O> the object type for the context
* @param <L> the object list type for the context
*/
public class K8sObserver<O extends KubernetesObject,
L extends KubernetesListObject> {
/**
* The type of change reported by {@link Response} as enum.
*/
public enum ResponseType {
ADDED, MODIFIED, DELETED
}
@SuppressWarnings("PMD.FieldNamingConventions")
protected final Logger logger = Logger.getLogger(getClass().getName());
protected final K8sClient client;
protected final GenericKubernetesApi<O, L> api;
protected final APIResource context;
protected final String namespace;
protected final ListOptions options;
protected final Thread thread;
protected BiConsumer<K8sClient, Response<O>> handler;
protected BiConsumer<K8sObserver<O, L>, Throwable> onTerminated;
/**
* Create and start a new observer for objects in the given context
* (using preferred version) and namespace with the given options.
*
* @param objectClass the object class
* @param objectListClass the object list class
* @param client the client
* @param context the context
* @param namespace the namespace
* @param options the options
*/
@SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop",
"PMD.UseObjectForClearerAPI", "PMD.AvoidCatchingThrowable",
"PMD.CognitiveComplexity" })
public K8sObserver(Class<O> objectClass, Class<L> objectListClass,
K8sClient client, APIResource context, String namespace,
ListOptions options) {
this.client = client;
this.context = context;
this.namespace = namespace;
this.options = options;
api = new GenericKubernetesApi<>(objectClass, objectListClass,
context.getGroup(), context.getPreferredVersion(),
context.getResourcePlural(), client);
thread = new Thread(() -> {
try {
logger.info(() -> "Watching " + context.getResourcePlural()
+ " (" + context.getPreferredVersion() + ")"
+ " in " + namespace);
// Watch sometimes terminates without apparent reason.
while (!Thread.currentThread().isInterrupted()) {
Instant startedAt = Instant.now();
try {
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
var changed = api.watch(namespace, options).iterator();
while (changed.hasNext()) {
handler.accept(client, changed.next());
}
} catch (ApiException e) {
logger.log(Level.FINE, e, () -> "Problem watching"
+ " (will retry): " + e.getMessage());
delayRestart(startedAt);
}
}
if (onTerminated != null) {
onTerminated.accept(this, null);
}
} catch (Throwable e) {
logger.log(Level.SEVERE, e, () -> "Probem watching: "
+ e.getMessage());
if (onTerminated != null) {
onTerminated.accept(this, e);
}
}
});
thread.setDaemon(true);
}
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
private void delayRestart(Instant started) {
var runningFor = Duration
.between(started, Instant.now()).toMillis();
if (runningFor < 5000) {
logger.log(Level.FINE, () -> "Waiting... ");
try {
Thread.sleep(5000 - runningFor);
} catch (InterruptedException e1) { // NOPMD
// Retry
}
logger.log(Level.FINE, () -> "Retrying");
}
}
/**
* Sets the handler.
*
* @param handler the handler
* @return the observer
*/
public K8sObserver<O, L>
handler(BiConsumer<K8sClient, Response<O>> handler) {
this.handler = handler;
return this;
}
/**
* Sets a function to invoke if the observer terminates. First argument
* is this observer, the second is the throwable that caused the
* abnormal termination or `null` if the observer was terminated
* by {@link #stop()}.
*
* @param onTerminated the on terminated
* @return the observer
*/
public K8sObserver<O, L> onTerminated(
BiConsumer<K8sObserver<O, L>, Throwable> onTerminated) {
this.onTerminated = onTerminated;
return this;
}
/**
* Start the observer.
*
* @return the observer
*/
public K8sObserver<O, L> start() {
if (handler == null) {
throw new IllegalStateException("No handler defined");
}
thread.start();
return this;
}
/**
* Stops the observer.
*
* @return the observer
*/
public K8sObserver<O, L> stop() {
thread.interrupt();
return this;
}
/**
* Returns the client.
*
* @return the client
*/
public K8sClient client() {
return client;
}
/**
* Returns the context.
*
* @return the context
*/
public APIResource context() {
return context;
}
/**
* Returns the observed namespace.
*
* @return the namespace
*/
public String getNamespace() {
return namespace;
}
/**
* Returns the options for object selection.
*
* @return the list options
*/
public ListOptions options() {
return options;
}
@Override
@SuppressWarnings("PMD.UseLocaleWithCaseConversions")
public String toString() {
return "Observer for " + K8s.toString(context) + " " + namespace;
}
}

View file

@ -30,6 +30,9 @@ import java.util.List;
public class K8sV1ConfigMapStub
extends K8sGenericStub<V1ConfigMap, V1ConfigMapList> {
public static final APIResource CONTEXT = new APIResource("", List.of("v1"),
"v1", "ConfigMap", true, "configmaps", "configmap");
/**
* Instantiates a new stub.
*
@ -40,9 +43,7 @@ public class K8sV1ConfigMapStub
protected K8sV1ConfigMapStub(K8sClient client, String namespace,
String name) {
super(V1ConfigMap.class, V1ConfigMapList.class, client,
new APIResource("", List.of("v1"), "v1", "ConfigMap", true,
"configmaps", "configmap"),
namespace, name);
CONTEXT, namespace, name);
}
/**

View file

@ -33,6 +33,10 @@ import java.util.Optional;
public class K8sV1DeploymentStub
extends K8sGenericStub<V1Deployment, V1DeploymentList> {
/** The deployment's context. */
public static final APIResource CONTEXT = new APIResource("apps",
List.of("v1"), "v1", "Pod", true, "deployments", "deployment");
/**
* Instantiates a new stub.
*
@ -43,22 +47,7 @@ public class K8sV1DeploymentStub
protected K8sV1DeploymentStub(K8sClient client, String namespace,
String name) {
super(V1Deployment.class, V1DeploymentList.class, client,
new APIResource("apps", List.of("v1"), "v1", "Pod", true,
"deployments", "deployment"),
namespace, name);
}
/**
* Gets the stub for the given namespace and name.
*
* @param client the client
* @param namespace the namespace
* @param name the name
* @return the deployment stub
*/
public static K8sV1DeploymentStub get(K8sClient client, String namespace,
String name) {
return new K8sV1DeploymentStub(client, namespace, name);
CONTEXT, namespace, name);
}
/**
@ -74,4 +63,17 @@ public class K8sV1DeploymentStub
+ "\", \"value\": " + replicas + "}]"),
client.defaultPatchOptions());
}
/**
* Gets the stub for the given namespace and name.
*
* @param client the client
* @param namespace the namespace
* @param name the name
* @return the deployment stub
*/
public static K8sV1DeploymentStub get(K8sClient client, String namespace,
String name) {
return new K8sV1DeploymentStub(client, namespace, name);
}
}

View file

@ -32,6 +32,7 @@ import java.util.List;
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
public class K8sV1PodStub extends K8sGenericStub<V1Pod, V1PodList> {
/** The pods' context. */
public static final APIResource CONTEXT
= new APIResource("", List.of("v1"), "v1", "Pod", true, "pods", "pod");
@ -72,7 +73,17 @@ public class K8sV1PodStub extends K8sGenericStub<V1Pod, V1PodList> {
public static Collection<K8sV1PodStub> list(K8sClient client,
String namespace, ListOptions options) throws ApiException {
return K8sGenericStub.list(V1Pod.class, V1PodList.class, client,
CONTEXT, namespace, options, K8sV1PodStub::new);
CONTEXT, namespace, options, K8sV1PodStub::getGeneric);
}
/**
* Provide {@link GenericSupplier}.
*/
@SuppressWarnings("PMD.UnusedFormalParameter")
private static K8sV1PodStub getGeneric(Class<V1Pod> objectClass,
Class<V1PodList> objectListClass, K8sClient client,
APIResource context, String namespace, String name) {
return new K8sV1PodStub(client, namespace, name);
}
}

View file

@ -0,0 +1,60 @@
/*
* VM-Operator
* Copyright (C) 2024 Michael N. Lipp
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jdrupes.vmoperator.common;
import io.kubernetes.client.Discovery.APIResource;
import io.kubernetes.client.openapi.models.V1Secret;
import io.kubernetes.client.openapi.models.V1SecretList;
import java.util.List;
/**
* A stub for secrets (v1).
*/
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
public class K8sV1SecretStub extends K8sGenericStub<V1Secret, V1SecretList> {
public static final APIResource CONTEXT = new APIResource("", List.of("v1"),
"v1", "Secret", true, "secrets", "secret");
/**
* Instantiates a new stub.
*
* @param client the client
* @param namespace the namespace
* @param name the name
*/
protected K8sV1SecretStub(K8sClient client, String namespace,
String name) {
super(V1Secret.class, V1SecretList.class, client,
CONTEXT, namespace, name);
}
/**
* Gets the stub for the given namespace and name.
*
* @param client the client
* @param namespace the namespace
* @param name the name
* @return the config map stub
*/
public static K8sV1SecretStub get(K8sClient client, String namespace,
String name) {
return new K8sV1SecretStub(client, namespace, name);
}
}

View file

@ -30,6 +30,11 @@ import java.util.List;
public class K8sV1StatefulSetStub
extends K8sGenericStub<V1StatefulSet, V1StatefulSetList> {
/** The stateful sets' context */
public static final APIResource CONTEXT
= new APIResource("apps", List.of("v1"), "v1", "StatefulSet", true,
"statefulsets", "statefulset");
/**
* Instantiates a new stub.
*
@ -39,9 +44,7 @@ public class K8sV1StatefulSetStub
*/
protected K8sV1StatefulSetStub(K8sClient client, String namespace,
String name) {
super(V1StatefulSet.class, V1StatefulSetList.class, client,
new APIResource("apps", List.of("v1"), "v1", "StatefulSet", true,
"statefulsets", "statefulset"),
super(V1StatefulSet.class, V1StatefulSetList.class, client, CONTEXT,
namespace, name);
}