Skip to content
This repository has been archived by the owner on Jul 31, 2023. It is now read-only.

Commit

Permalink
Merge pull request #70 from kappnav/Issue#100-KindActionMappingSupport
Browse files Browse the repository at this point in the history
KAM support initial code
  • Loading branch information
susanodom authored Apr 3, 2020
2 parents 449e746 + 3bf5b91 commit 4cd0d21
Show file tree
Hide file tree
Showing 7 changed files with 1,145 additions and 393 deletions.
614 changes: 319 additions & 295 deletions src/main/java/application/rest/v1/ActionsEndpoint.java

Large diffs are not rendered by default.

33 changes: 25 additions & 8 deletions src/main/java/application/rest/v1/ComponentsEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class ComponentsEndpoint extends KAppNavEndpoint {
private static final String ACTION_MAP_PROPERTY_NAME = "action-map";
private static final String SECTION_MAP_PROPERTY_NAME = "section-map";
private static final String KIND_PROPERTY_NAME = "kind";
private static final String APIVERSION_PROPERTY_NAME = "apiVersion";

@Inject
private ComponentInfoRegistry registry;
Expand Down Expand Up @@ -107,24 +108,27 @@ private Response processComponentKinds(ApiClient client, List<ComponentKind> com
Set<String> apiVersions = registry.getComponentGroupApiVersions(v);
for (String apiVersion : apiVersions) {
if (apiVersion != null) {
System.out.println("processComponentKinds using apiVersion: " + apiVersion + " for Application: " + appName +" componentKind group: " + v.group + " kind: " + v.kind);
if (Logger.isDebugEnabled()) {
Logger.log(className, "processComponentKinds", Logger.LogType.DEBUG, "Using apiVersion: " + apiVersion +
" for Application: " + appName +" componentKind group: " + v.group + " kind: " + v.kind);
}
if (!registry.isNamespaced(client, v.kind, apiVersion)) {
Object o = registry.listClusterObject(client, v.kind, apiVersion, null, labelSelector, null, null);
processComponents(client, response, v, getItemsAsList(client, o));
processComponents(client, response, v, apiVersion, getItemsAsList(client, o));
} else {
// If the component kind is namespaced, query components for each of the specified namespaces.
final String apiVersion1 = apiVersion; // to avoid compiler error
namespaces.forEach(n -> {
try {
Object o = registry.listNamespacedObject(client, v.kind, apiVersion1, n, null, labelSelector, null, null);
processComponents(client, response, v, getItemsAsList(client, o), appNamespace, appName);
processComponents(client, response, v, apiVersion, getItemsAsList(client, o), appNamespace, appName);
} catch (ApiException e) {
}
});
}
} else {
if (Logger.isWarningEnabled()) {
Logger.log(className, "processComponentKinds", Logger.LogType.WARNING, " Application: " + appName +" componentKind group: " + v.group + " kind: " + v.kind + " not recognized. skipping");
Logger.log(className, "processComponentKinds", Logger.LogType.WARNING, "Application: " + appName +" componentKind group: " + v.group + " kind: " + v.kind + " not recognized. skipping");
}
}
}
Expand All @@ -139,27 +143,40 @@ private Response processComponentKinds(ApiClient client, List<ComponentKind> com
return Response.ok(response.getJSON()).build();
}

private void processComponents(ApiClient client, ComponentResponse response, ComponentKind componentKind, List<JsonObject> components) {
private void processComponents(ApiClient client, ComponentResponse response, ComponentKind componentKind,
String apiVersion, List<JsonObject> components) {
final ConfigMapProcessor processor = new ConfigMapProcessor(componentKind.kind);
final SectionConfigMapProcessor sectionProcessor = new SectionConfigMapProcessor(componentKind.kind);
components.forEach(v -> {
// Add 'kind' property to components that are missing it.
if (v.get(KIND_PROPERTY_NAME) == null) {
v.addProperty(KIND_PROPERTY_NAME, componentKind.kind);
}
}

// Add 'apiVersion' property to components that are missing it.
if (v.get(APIVERSION_PROPERTY_NAME) == null) {
v.addProperty(APIVERSION_PROPERTY_NAME, apiVersion);
}

response.add(v, processor.getConfigMap(client, v, ConfigMapProcessor.ConfigMapType.ACTION), sectionProcessor.processSectionMap(client, v));
});
}

private void processComponents(ApiClient client, ComponentResponse response, ComponentKind componentKind, List<JsonObject> components, String appNamespace, String appName) {
private void processComponents(ApiClient client, ComponentResponse response, ComponentKind componentKind,
String apiVersion, List<JsonObject> components, String appNamespace, String appName) {
final ConfigMapProcessor processor = new ConfigMapProcessor(componentKind.kind);
final SectionConfigMapProcessor sectionProcessor = new SectionConfigMapProcessor(componentKind.kind);
components.forEach(v -> {
// Add 'kind' property to components that are missing it.
if (v.get(KIND_PROPERTY_NAME) == null) {
v.addProperty(KIND_PROPERTY_NAME, componentKind.kind);
}


// Add 'apiVersion' property to components that are missing it.
if (v.get(APIVERSION_PROPERTY_NAME) == null) {
v.addProperty(APIVERSION_PROPERTY_NAME, apiVersion);
}

// filter out recursive app from component list
if (!(componentKind.kind.equals("Application") &&
getComponentName(v).equals(appName) &&
Expand Down
58 changes: 45 additions & 13 deletions src/main/java/application/rest/v1/KAppNavEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public abstract class KAppNavEndpoint {

protected static final String NAME_PATTERN_ONE_OR_MORE = "^[a-z0-9-.:]+$";
protected static final String NAME_PATTERN_ZERO_OR_MORE = "^[a-z0-9-.:]*$";
protected static final String API_VERSION_PATTERN_ZERO_OR_MORE = "^[a-z0-9-.:/]*$";
protected static final String API_VERSION_PATTERN_ZERO_OR_MORE = "^[a-z0-9-.:/%]*$";

private static final boolean DISABLE_TRUST_ALL_CERTS;
private static final String DISABLE_TRUST_ALL_CERTS_PROPERTY = "kappnav.disable.trust.all.certs";
Expand Down Expand Up @@ -87,7 +87,11 @@ public String run() {
private static final String KAPPNAV_STATUS_PROPERTY_NAME = "kappnav.status";
private static final String KAPPNAV_SUB_KIND_PROPERTY_NAME = "kappnav.subkind";

// Status object properties.
// Kind actions mapping properties
private static final String API_VERSION_PROPERTY_NAME = "apiVersion";
private static final String KIND_PROPERTY_NAME = "kind";

// Status object properties.
private static final String VALUE_PROPERTY_NAME = "value";
private static final String FLYOVER_PROPERTY_NAME = "flyover";
private static final String FLYOVER_NLS_PROPERTY_NAME = "flyover.nls";
Expand Down Expand Up @@ -163,8 +167,45 @@ public static JsonObject getItemAsObject(ApiClient client, Object resource) {
return null;
}

public static String getComponentApiVersion(JsonObject component, String kind) {
if (Logger.isEntryEnabled())
Logger.log(className, "getComponentApiVersion", Logger.LogType.ENTRY,"kind = " + kind);

final JsonElement apiv_e = component.get(API_VERSION_PROPERTY_NAME);
String apiVersion = null;
if (apiv_e != null)
apiVersion = apiv_e.getAsString();

if (apiVersion == null || apiVersion.length() == 0) {
if (Logger.isEntryEnabled())
Logger.log(className, "getComponentApiVersion", Logger.LogType.ENTRY,
"apiVersion is null or empty and get it from ComponentInfoRegistry");
apiVersion = ComponentInfoRegistry.CORE_KIND_TO_API_VERSION_MAP.get(kind);
}

if (Logger.isExitEnabled())
Logger.log(className, "getComponentApiVersion", Logger.LogType.EXIT,"apiVersion = "
+ apiVersion);
return apiVersion;
}

public static String getComponentKind(JsonObject component) {
if (Logger.isEntryEnabled())
Logger.log(className, "getComponentKind", Logger.LogType.ENTRY,"");

final JsonElement kind_e = component.get(KIND_PROPERTY_NAME);
String kind = null;
if (kind_e != null)
kind = kind_e.getAsString();

if (Logger.isExitEnabled())
Logger.log(className, "getComponentKind", Logger.LogType.EXIT,"kind = "
+ kind);
return kind;
}

public static String getComponentSubKind(JsonObject component) {
if (Logger.isEntryEnabled()) {
if (Logger.isEntryEnabled()) {
Logger.log(className, "getComponentSubKind", Logger.LogType.ENTRY,"");
}
final JsonObject metadata = component.getAsJsonObject(METADATA_PROPERTY_NAME);
Expand Down Expand Up @@ -195,27 +236,18 @@ public static String getComponentSubKind(JsonObject component) {
}

public static String getComponentName(JsonObject component) {
if (Logger.isEntryEnabled()) {
Logger.log(className, "getComponentName", Logger.LogType.ENTRY,"");
}
final JsonObject metadata = component.getAsJsonObject(METADATA_PROPERTY_NAME);
if (metadata != null) {
JsonElement e = metadata.get(NAME_PROPERTY_NAME);
if (e != null && e.isJsonPrimitive()) {
String componentName = e.getAsString();
if (Logger.isExitEnabled()) {
Logger.log(className, "getComponentName", Logger.LogType.EXIT, componentName);
}
return componentName;
}
} else {
if (Logger.isDebugEnabled()) {
Logger.log(className, "getComponentName", Logger.LogType.DEBUG, "Metadata is null.");
}
}
if (Logger.isExitEnabled()) {
Logger.log(className, "getComponentName", Logger.LogType.EXIT, "Return null.");
}
return null;
}

Expand Down Expand Up @@ -479,7 +511,7 @@ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
}

protected static String encodeURLParameter(String s) {
public static String encodeURLParameter(String s) {
try {
return URLEncoder.encode(s, "UTF-8");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ public String getName() {

@Override
public String resolve(ResolutionContext context, String suffix) throws PatternException {
if (Logger.isErrorEnabled()) {
Logger.log(ResourceResolver.class.getName(), "resolve", Logger.LogType.ERROR, "For suffix=" + suffix);
if (Logger.isDebugEnabled()) {
Logger.log(ResourceResolver.class.getName(), "resolve", Logger.LogType.DEBUG, "For suffix=" + suffix);
}
final JSONPathParser parser = new JSONPathParser();
final JSONPath path = parser.parse(suffix);
Expand Down
56 changes: 46 additions & 10 deletions src/main/java/application/rest/v1/configmaps/ConfigMapCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.lang.ref.SoftReference;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -27,6 +28,7 @@

import com.google.common.reflect.TypeToken;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.ibm.kappnav.logging.Logger;
import com.squareup.okhttp.Call;

Expand Down Expand Up @@ -122,6 +124,29 @@ private Selector getSelector() {
});
}

public static ArrayList <JsonObject> getConfigMapsAsJSON(ApiClient client, ArrayList<QName> configMapsList) {
ArrayList<JsonObject> configMaps = new ArrayList<JsonObject>();
for (int i=0; i<configMapsList.size(); i++) {
if (Logger.isDebugEnabled()) {
Logger.log(CLASS_NAME, "getConfigMapsAsJSON", Logger.LogType.DEBUG,
"configMapsList["+i+"]="+configMapsList.get(i));
}
QName mapName = configMapsList.get(i); // list entry format: mapname@namespace

// Configmap lookup in either the resource's namespace for an instance specfic configmaps
// or in the KindActionMapping resource's namespace for others.
V1ConfigMap map = getConfigMap(client, mapName.getNamespaceURI() , mapName.getLocalPart());
if (map != null) {
final JsonElement element = client.getJSON().getGson().toJsonTree(map);
if (element != null && element.isJsonObject()) {
JsonObject mapJson = element.getAsJsonObject();
configMaps.add(mapJson);
}
}
} // for loop
return configMaps;
}

public static JsonElement getConfigMapAsJSON(ApiClient client, String namespace, String name) {
V1ConfigMap map = getConfigMap(client, namespace, name);
if (map != null) {
Expand All @@ -131,13 +156,20 @@ public static JsonElement getConfigMapAsJSON(ApiClient client, String namespace,
}

public static V1ConfigMap getConfigMap(ApiClient client, String namespace, String name) {
if (Logger.isEntryEnabled())
Logger.log(CLASS_NAME, "getConfigMap", Logger.LogType.ENTRY, "name = " + name + ", namespace = " + namespace);

QName tuple = new QName(namespace, name);
Map<QName,SoftReference<V1ConfigMap>> mapCache = MAP_CACHE_REF.get();
if (mapCache != null) {
if (mapCache.containsKey(tuple)) {
SoftReference<V1ConfigMap> ref = mapCache.get(tuple);
V1ConfigMap map = ref.get();
if (map != null || ref == NULL_REFERENCE) {
if (Logger.isExitEnabled())
Logger.log(CLASS_NAME, "getConfigMap", Logger.LogType.EXIT,
"name = " + name + " in namespace " + namespace + " is found in the cache.");

return map;
}
if (Logger.isDebugEnabled()) {
Expand All @@ -152,10 +184,9 @@ public static V1ConfigMap getConfigMap(ApiClient client, String namespace, Strin
synchronized (LOCK) {
LOCK.notify();
}
if (Logger.isDebugEnabled()) {
if (Logger.isDebugEnabled())
Logger.log(CLASS_NAME, "getConfigMap", Logger.LogType.DEBUG,
"No ConfigMap cache available. Notify thread (" + WATCHER_THREAD_NAME + ") to awaken and re-establish the cache.");
}
}
try {
CoreV1Api api = new CoreV1Api();
Expand All @@ -164,28 +195,33 @@ public static V1ConfigMap getConfigMap(ApiClient client, String namespace, Strin
V1ConfigMap map = api.readNamespacedConfigMap(name, namespace, null, null, null);
if (mapCache != null) {
mapCache.put(tuple, new SoftReference<>(map));
if (Logger.isDebugEnabled()) {
if (Logger.isDebugEnabled())
Logger.log(CLASS_NAME, "getConfigMap", Logger.LogType.DEBUG,
"Found ConfigMap, Name: " + name + ", Namespace: "
+ namespace + ". Storing it in the cache.");
}
}
if (Logger.isExitEnabled())
Logger.log(CLASS_NAME, "getConfigMap", Logger.LogType.EXIT,
"name = " + name + " is found in namespace " + namespace);

return map;
}
catch (ApiException e) {
if (Logger.isDebugEnabled()) {
if (Logger.isDebugEnabled())
Logger.log(CLASS_NAME, "getConfigMap", Logger.LogType.DEBUG, "Caught ApiException: " + e.toString());
}
}
// No ConfigMap. Store null reference in the cache.
if (mapCache != null) {
mapCache.put(tuple, NULL_REFERENCE);
if (Logger.isDebugEnabled()) {
if (Logger.isDebugEnabled())
Logger.log(CLASS_NAME, "getConfigMap", Logger.LogType.DEBUG,
"ConfigMap, Name: " + name + ", Namespace: "
+ namespace + " not found. Storing a null reference in the cache.");
}
}
+ namespace + " not found. Storing a null reference in the cache.");
}
if (Logger.isExitEnabled())
Logger.log(CLASS_NAME, "getConfigMap", Logger.LogType.EXIT,
"Return null as the confignmap " + name + " is not found in " + namespace);

return null;
}
}
Loading

0 comments on commit 4cd0d21

Please sign in to comment.