Use less gson internally.

This commit is contained in:
Michael Lipp 2024-11-08 16:48:07 +00:00
parent 8e692a03fe
commit c8781c2d8e
33 changed files with 1405 additions and 905 deletions

View file

@ -157,27 +157,6 @@ public class K8s {
return Optional.of(apiRes);
}
/**
* Get an object from its metadata.
*
* @param <T> the generic type
* @param <LT> the generic type
* @param api the api
* @param meta the meta
* @return the object
*/
@Deprecated
@SuppressWarnings("PMD.GenericsNaming")
public static <T extends KubernetesObject, LT extends KubernetesListObject>
Optional<T>
get(GenericKubernetesApi<T, LT> api, V1ObjectMeta meta) {
var response = api.get(meta.getNamespace(), meta.getName());
if (response.isSuccess()) {
return Optional.of(response.getObject());
}
return Optional.empty();
}
/**
* Apply the given patch data.
*

View file

@ -27,6 +27,7 @@ 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.KubernetesApiResponse;
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject;
import io.kubernetes.client.util.generic.options.GetOptions;
import io.kubernetes.client.util.generic.options.ListOptions;
import io.kubernetes.client.util.generic.options.PatchOptions;
@ -47,7 +48,7 @@ import java.util.function.Function;
* @param <O> the generic type
* @param <L> the generic type
*/
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.TooManyMethods" })
public class K8sGenericStub<O extends KubernetesObject,
L extends KubernetesListObject> {
protected final K8sClient client;
@ -224,7 +225,7 @@ public class K8sGenericStub<O extends KubernetesObject,
* @param patchType the patch type
* @param patch the patch
* @param options the options
* @return the kubernetes api response
* @return the kubernetes api response if successful
* @throws ApiException the api exception
*/
public Optional<O> patch(String patchType, V1Patch patch,
@ -239,7 +240,7 @@ public class K8sGenericStub<O extends KubernetesObject,
*
* @param patchType the patch type
* @param patch the patch
* @return the kubernetes api response
* @return the kubernetes api response if successful
* @throws ApiException the api exception
*/
public Optional<O>
@ -248,6 +249,21 @@ public class K8sGenericStub<O extends KubernetesObject,
return patch(patchType, patch, opts);
}
/**
* Apply the given definition.
*
* @param def the def
* @return the kubernetes api response if successful
* @throws ApiException the api exception
*/
public Optional<O> apply(DynamicKubernetesObject def) throws ApiException {
PatchOptions opts = new PatchOptions();
opts.setForce(true);
opts.setFieldManager("kubernetes-java-kubectl-apply");
return patch(V1Patch.PATCH_FORMAT_APPLY_YAML,
new V1Patch(client.getJSON().serialize(def)), opts);
}
/**
* Update the object.
*

View file

@ -0,0 +1,332 @@
/*
* 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.openapi.models.V1ObjectMeta;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.jdrupes.vmoperator.util.DataPath;
/**
* Represents a VM definition.
*/
@SuppressWarnings({ "PMD.DataClass" })
public class VmDefinition {
private String kind;
private String apiVersion;
private V1ObjectMeta metadata;
private Map<String, Object> spec;
private Map<String, Object> status;
private final Map<String, Object> extra = new ConcurrentHashMap<>();
/**
* The VM state from the VM definition.
*/
public enum RequestedVmState {
STOPPED, RUNNING
}
/**
* Permissions for accessing and manipulating the VM.
*/
public enum Permission {
START("start"), STOP("stop"), RESET("reset"),
ACCESS_CONSOLE("accessConsole");
@SuppressWarnings("PMD.UseConcurrentHashMap")
private static Map<String, Permission> reprs = new HashMap<>();
static {
for (var value : EnumSet.allOf(Permission.class)) {
reprs.put(value.repr, value);
}
}
private final String repr;
Permission(String repr) {
this.repr = repr;
}
/**
* Create permission from representation in CRD.
*
* @param value the value
* @return the permission
*/
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
public static Set<Permission> parse(String value) {
if ("*".equals(value)) {
return EnumSet.allOf(Permission.class);
}
return Set.of(reprs.get(value));
}
@Override
public String toString() {
return repr;
}
}
/**
* Gets the kind.
*
* @return the kind
*/
public String getKind() {
return kind;
}
/**
* Sets the kind.
*
* @param kind the kind to set
*/
public void setKind(String kind) {
this.kind = kind;
}
/**
* Gets the api version.
*
* @return the apiVersion
*/
public String getApiVersion() {
return apiVersion;
}
/**
* Sets the api version.
*
* @param apiVersion the apiVersion to set
*/
public void setApiVersion(String apiVersion) {
this.apiVersion = apiVersion;
}
/**
* Gets the metadata.
*
* @return the metadata
*/
public V1ObjectMeta getMetadata() {
return metadata;
}
/**
* Gets the metadata.
*
* @return the metadata
*/
public V1ObjectMeta metadata() {
return metadata;
}
/**
* Sets the metadata.
*
* @param metadata the metadata to set
*/
public void setMetadata(V1ObjectMeta metadata) {
this.metadata = metadata;
}
/**
* Gets the spec.
*
* @return the spec
*/
public Map<String, Object> getSpec() {
return spec;
}
/**
* Gets the spec.
*
* @return the spec
*/
public Map<String, Object> spec() {
return spec;
}
/**
* Get a value from the spec using {@link DataPath#get}.
*
* @param <T> the generic type
* @param selectors the selectors
* @return the value, if found
*/
public <T> Optional<T> fromSpec(Object... selectors) {
return DataPath.get(spec, selectors);
}
/**
* Get a value from the `spec().get("vm")` using {@link DataPath#get}.
*
* @param <T> the generic type
* @param selectors the selectors
* @return the value, if found
*/
public <T> Optional<T> fromVm(Object... selectors) {
return DataPath.get(spec, "vm")
.flatMap(vm -> DataPath.get(vm, selectors));
}
/**
* Sets the spec.
*
* @param spec the spec to set
*/
public void setSpec(Map<String, Object> spec) {
this.spec = spec;
}
/**
* Gets the status.
*
* @return the status
*/
public Map<String, Object> getStatus() {
return status;
}
/**
* Gets the status.
*
* @return the status
*/
public Map<String, Object> status() {
return status;
}
/**
* Get a value from the status using {@link DataPath#get}.
*
* @param <T> the generic type
* @param selectors the selectors
* @return the value, if found
*/
public <T> Optional<T> fromStatus(Object... selectors) {
return DataPath.get(status, selectors);
}
/**
* Sets the status.
*
* @param status the status to set
*/
public void setStatus(Map<String, Object> status) {
this.status = status;
}
/**
* Set extra data (locally used, unknown to kubernetes).
*
* @param property the property
* @param value the value
* @return the VM definition
*/
public VmDefinition extra(String property, Object value) {
extra.put(property, value);
return this;
}
/**
* Return extra data.
*
* @param property the property
* @return the object
*/
@SuppressWarnings("unchecked")
public <T> T extra(String property) {
return (T) extra.get(property);
}
/**
* Returns the definition's name.
*
* @return the string
*/
public String name() {
return metadata.getName();
}
/**
* Returns the definition's namespace.
*
* @return the string
*/
public String namespace() {
return metadata.getNamespace();
}
/**
* Return the requested VM state
*
* @return the string
*/
public RequestedVmState vmState() {
// TODO
return fromVm("state")
.map(s -> "Running".equals(s) ? RequestedVmState.RUNNING
: RequestedVmState.STOPPED)
.orElse(RequestedVmState.STOPPED);
}
/**
* Collect all permissions for the given user with the given roles.
*
* @param user the user
* @param roles the roles
* @return the sets the
*/
public Set<Permission> permissionsFor(String user,
Collection<String> roles) {
return this.<List<Map<String, Object>>> fromSpec("permissions")
.orElse(Collections.emptyList()).stream()
.filter(p -> DataPath.get(p, "user").map(u -> u.equals(user))
.orElse(false)
|| DataPath.get(p, "role").map(roles::contains).orElse(false))
.map(p -> DataPath.<List<String>> get(p, "may")
.orElse(Collections.emptyList()).stream())
.flatMap(Function.identity())
.map(Permission::parse).map(Set::stream)
.flatMap(Function.identity()).collect(Collectors.toSet());
}
/**
* Get the display password serial.
*
* @return the optional
*/
public Optional<Long> displayPasswordSerial() {
return this.<Number> fromStatus("displayPasswordSerial")
.map(Number::longValue);
}
}

View file

@ -20,16 +20,6 @@ package org.jdrupes.vmoperator.common;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.jdrupes.vmoperator.util.GsonPtr;
/**
* Represents a VM definition.
@ -37,55 +27,6 @@ import org.jdrupes.vmoperator.util.GsonPtr;
@SuppressWarnings("PMD.DataClass")
public class VmDefinitionModel extends K8sDynamicModel {
/**
* The VM state from the VM definition.
*/
public enum RequestedVmState {
STOPPED, RUNNING
}
/**
* Permissions for accessing and manipulating the VM.
*/
public enum Permission {
START("start"), STOP("stop"), RESET("reset"),
ACCESS_CONSOLE("accessConsole");
@SuppressWarnings("PMD.UseConcurrentHashMap")
private static Map<String, Permission> reprs = new HashMap<>();
static {
for (var value : EnumSet.allOf(Permission.class)) {
reprs.put(value.repr, value);
}
}
private final String repr;
Permission(String repr) {
this.repr = repr;
}
/**
* Create permission from representation in CRD.
*
* @param value the value
* @return the permission
*/
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
public static Set<Permission> parse(String value) {
if ("*".equals(value)) {
return EnumSet.allOf(Permission.class);
}
return Set.of(reprs.get(value));
}
@Override
public String toString() {
return repr;
}
}
/**
* Instantiates a new model from the JSON representation.
*
@ -95,49 +36,4 @@ public class VmDefinitionModel extends K8sDynamicModel {
public VmDefinitionModel(Gson delegate, JsonObject json) {
super(delegate, json);
}
/**
* Collect all permissions for the given user with the given roles.
*
* @param user the user
* @param roles the roles
* @return the sets the
*/
public Set<Permission> permissionsFor(String user,
Collection<String> roles) {
return GsonPtr.to(data())
.getAsListOf(JsonObject.class, "spec", "permissions")
.stream().filter(p -> GsonPtr.to(p).getAsString("user")
.map(u -> u.equals(user)).orElse(false)
|| GsonPtr.to(p).getAsString("role").map(roles::contains)
.orElse(false))
.map(p -> GsonPtr.to(p).getAsListOf(JsonPrimitive.class, "may")
.stream())
.flatMap(Function.identity()).map(p -> p.getAsString())
.map(Permission::parse).map(Set::stream)
.flatMap(Function.identity()).collect(Collectors.toSet());
}
/**
* Return the requested VM state
*
* @return the string
*/
public RequestedVmState vmState() {
return GsonPtr.to(data()).getAsString("spec", "vm", "state")
.map(s -> "Running".equals(s) ? RequestedVmState.RUNNING
: RequestedVmState.STOPPED)
.orElse(RequestedVmState.STOPPED);
}
/**
* Get the display password serial.
*
* @return the optional
*/
public Optional<Long> displayPasswordSerial() {
return GsonPtr.to(status())
.get(JsonPrimitive.class, "displayPasswordSerial")
.map(JsonPrimitive::getAsLong);
}
}