From 193b4cab24d23838581951398ecd907160ed6b11 Mon Sep 17 00:00:00 2001 From: Mauro Mugnaini Date: Thu, 7 Jul 2022 16:51:27 +0200 Subject: [PATCH] Added `AlignGatewaysUsers` and `SendContextUsersRoles` (#23628) utility functions. --- CHANGELOG.md | 3 + pom.xml | 4 +- .../publisher/utils/AlignGatewaysUsers.java | 126 ++++++++++++++++++ .../utils/SendContextUsersRoles.java | 121 +++++++++++++++++ src/test/resources/log4j.xml | 23 ++++ 5 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/gcube/portal/event/publisher/utils/AlignGatewaysUsers.java create mode 100644 src/test/java/org/gcube/portal/event/publisher/utils/SendContextUsersRoles.java create mode 100644 src/test/resources/log4j.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index bd63e4a..01a2568 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm # Changelog for "event-publisher-portal" +## [v1.2.0-SNAPSHOT] +Added `AlignGatewaysUsers` and `SendContextUsersRoles` (#23628) utility functions. + ## [v1.1.1] `UserGroupRoleEventPublisher` don't send events if the group is not enabled (#21925) diff --git a/pom.xml b/pom.xml index 663e2fb..51a2fd5 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.gcube.portal event-publisher-hook - 1.1.1 + 1.2.0-SNAPSHOT war @@ -36,7 +36,7 @@ org.gcube.distribution maven-portal-bom - 3.6.3 + 3.6.4 pom import diff --git a/src/test/java/org/gcube/portal/event/publisher/utils/AlignGatewaysUsers.java b/src/test/java/org/gcube/portal/event/publisher/utils/AlignGatewaysUsers.java new file mode 100644 index 0000000..770dfd8 --- /dev/null +++ b/src/test/java/org/gcube/portal/event/publisher/utils/AlignGatewaysUsers.java @@ -0,0 +1,126 @@ +package org.gcube.portal.event.publisher.utils; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URLEncoder; + +import org.gcube.event.publisher.BufferedEventProcessor; +import org.gcube.event.publisher.Event; +import org.gcube.event.publisher.EventProcessorException; +import org.gcube.portal.event.publisher.lr62.model.UserEvent; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Usage: AlignGatewaysUsers <conductor-endpoint> <client-id> <client-secret> <keycloak-token-endpoint> <json-export-resource> [<gw-suffix>]
+ * + * + * The JSON input file is structured as "gateway and users" array, with users that belong to the gateway in an array. + * Refer to the example below for further details. + * + *
+ * [
+ *   {
+ *       "gateway": "ATest Gateway",
+ *       "users": [
+ *           "gino.chino"
+ *       ]
+ *   },
+ *   {
+ *       "gateway": "A gCube Snapshot Gateway",
+ *       "users": [
+ *           "pino.lino",
+ *           "gino.stilla",
+ *           "cvcvcvcvcv"
+ *       ]
+ *   },
+ *   [...]
+ * ]
+ * 
+ * + * @author Mauro Mugnaini + * + */ +public class AlignGatewaysUsers { + + private static final Logger logger = LoggerFactory.getLogger(AlignGatewaysUsers.class); + + private static final String SENDER_ID = "gw2users-align"; + private static final String GW_SUFFIX = "+Gateway"; + + @SuppressWarnings("unchecked") + public AlignGatewaysUsers(String conductorEndpoint, String clientId, String clientSecret, + String keycloakTokenEndpoint, String jsonExportResource, String gateway2export) + throws IOException, ParseException, InterruptedException { + + BufferedEventProcessor processor = null; + try { + processor = new BufferedEventProcessor(conductorEndpoint, clientId, + clientSecret, keycloakTokenEndpoint, tobeSent -> { + String user = (String) tobeSent.get(UserEvent.USER_ENTRY); + String group = (String) tobeSent.get(UserEvent.GROUP_ENTRY); + return user + "@" + group; + }); + + } catch (EventProcessorException e) { + logger.error("Cannot create processor object. Exiting...", e); + System.exit(1); + } + + JSONArray export = (JSONArray) new JSONParser().parse( + new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream(jsonExportResource))); + + long start = System.currentTimeMillis(); + for (int i = 0; i < export.size(); i++) { + JSONObject entry = (JSONObject) export.get(i); + String gateway = URLEncoder.encode((String) entry.get("gateway"), "UTF-8"); + if (gateway2export != null && !gateway.equals(gateway2export)) { + continue; + } else { + logger.info("- Processing gateway: {}", gateway); + } + JSONArray usersArray = (JSONArray) entry.get("users"); + for (int j = 0; j < usersArray.size(); j++) { + String user = (String) usersArray.get(j); + // Group object is too difficult to implement as fake because is mapped via GroupManager + // This is the workaround by using event base class directly: + Event event = new Event(UserEvent.UG_CREATED_NAME, "manual", SENDER_ID); + event.put(UserEvent.USER_ENTRY, user); + event.put(UserEvent.GROUP_ENTRY, gateway); + logger.debug(" * Offering: {}", user); + processor.enqueueEvent(event); + } + } + do { + Thread.sleep(1000); + } while (processor.allQueuedFinishedCorrectly()); + + long elapsed = System.currentTimeMillis() - start; + logger.info("\t\t\tFinished! Handled {} events in {} ms", processor.getCount(), elapsed); + logger.info("\t\t\tErrors: {} - Stats per event: min: {} ms - max: {} ms.", + new Object[] { processor.getErrors(), processor.getMin(), processor.getMax() }); + + System.exit(0); + } + + public static void main(String[] args) throws IOException, ParseException, InterruptedException { + if (args.length < 5) { + System.err.println( + "Not all arguments where provided.\nUsage: AlignGatewaysUsers []"); + + System.exit(1); + } + String conductorEndpoint = args[0]; + String clientId = args[1]; + String clientSecret = args[2]; + String keycloakTokenEndpoint = args[3]; + String jsonExportResource = args[4]; + new AlignGatewaysUsers(conductorEndpoint, clientId, clientSecret, keycloakTokenEndpoint, jsonExportResource, + args.length == 6 ? args[5] + GW_SUFFIX : null); + } + +} \ No newline at end of file diff --git a/src/test/java/org/gcube/portal/event/publisher/utils/SendContextUsersRoles.java b/src/test/java/org/gcube/portal/event/publisher/utils/SendContextUsersRoles.java new file mode 100644 index 0000000..3b87964 --- /dev/null +++ b/src/test/java/org/gcube/portal/event/publisher/utils/SendContextUsersRoles.java @@ -0,0 +1,121 @@ +package org.gcube.portal.event.publisher.utils; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URLEncoder; + +import org.gcube.event.publisher.BufferedEventProcessor; +import org.gcube.event.publisher.Event; +import org.gcube.event.publisher.EventProcessorException; +import org.gcube.portal.event.publisher.lr62.model.UserGroupRoleEvent; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Usage: SendContextUsersRoles <conductor-endpoint> <client-id> <client-secret> <keycloak-token-endpoint> <role> <json-export-resource>.
+ * + * + * The JSON input file is structured as "context to users" entries, with context as key and users array as value. The role is passed as argument. + * Refer to the example below for further details. + * + *
+ * {
+ *   "/root/VO1/VRE1": ["gino.chino"],
+ *   "/root/VO1/VRE2": ["lino.mando"],
+ *   "/root/VO2/VRE3": ["nella.baci", "gino.stilla", "rino.manda"],
+ *   "/root/VO3/VRE4": ["lorian.manda"],
+ *   [...]
+ * }
+ * 
+ * + * @author Mauro Mugnaini + * + */ +public class SendContextUsersRoles { + + private static final Logger logger = LoggerFactory.getLogger(BufferedEventProcessor.class); + + private static final Boolean DRY_RUN = Boolean.FALSE; + private static final String SENDER_ID_PREFIX = "re-align-role_"; + + @SuppressWarnings("unchecked") + public SendContextUsersRoles(String conductorEndpoint, String clientId, String clientSecret, + String keycloakTokenEndpoint, String role, String jsonExportResource) + throws IOException, ParseException, InterruptedException { + + BufferedEventProcessor processor = null; + try { + processor = new BufferedEventProcessor(conductorEndpoint, clientId, + clientSecret, keycloakTokenEndpoint, tobeSent -> { + String user = (String) tobeSent.get(UserGroupRoleEvent.USER_ENTRY); + String group = (String) tobeSent.get(UserGroupRoleEvent.GROUP_ENTRY); + return user + "@" + group + ":" + role; + }); + + } catch (EventProcessorException e) { + logger.error("Cannot create processor object. Exiting...", e); + System.exit(1); + } + + JSONObject export = (JSONObject) new JSONParser().parse( + new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream(jsonExportResource))); + + long start = System.currentTimeMillis(); + String sender = SENDER_ID_PREFIX + role.toLowerCase(); + int howMany = 0; + for (Object contextObject : export.keySet()) { + String context = contextObject.toString(); + String encodedContext = URLEncoder.encode(context, "UTF-8"); + JSONArray usersArray = (JSONArray) export.get(context); + for (int j = 0; j < usersArray.size(); j++) { + String user = (String) usersArray.get(j); + // Since Group object is too difficult to implement as a dummy because is mapped via GroupManager, + // this is the workaround by using base event class directly: + Event event = new Event(UserGroupRoleEvent.CREATED_NAME, "manual", sender); + event.put(UserGroupRoleEvent.USER_ENTRY, user); + event.put(UserGroupRoleEvent.GROUP_ENTRY, encodedContext); + event.put(UserGroupRoleEvent.ROLE_ENTRY, role); + logger.info(" * Offering: {}", user); + if (!DRY_RUN) { + processor.enqueueEvent(event); + } else { + logger.debug("Next event: {}", event); + } + howMany += 1; + } + } + logger.info("Events are {}", howMany); + do { + Thread.sleep(1000); + } while (processor.allQueuedFinishedCorrectly()); + + long elapsed = System.currentTimeMillis() - start; + logger.info("\t\t\tFinished! Handled {} events in {} ms", processor.getCount(), elapsed); + logger.info("\t\t\tErrors: {} - Stats per event: min: {} ms - max: {} ms.", + new Object[] { processor.getErrors(), processor.getMin(), processor.getMax() }); + + System.exit(0); + } + + public static void main(String[] args) throws IOException, ParseException, InterruptedException { + if (args.length < 6) { + System.err.println( + "Not all arguments where provided.\nUsage: SendContextUsersRoles "); + + System.exit(1); + } + String conductorEndpoint = args[0]; + String clientId = args[1]; + String clientSecret = args[2]; + String keycloakTokenEndpoint = args[3]; + String role = args[4]; + String jsonExportResource = args[5]; + new SendContextUsersRoles(conductorEndpoint, clientId, clientSecret, keycloakTokenEndpoint, role, + jsonExportResource); + } + +} \ No newline at end of file diff --git a/src/test/resources/log4j.xml b/src/test/resources/log4j.xml new file mode 100644 index 0000000..35e31bf --- /dev/null +++ b/src/test/resources/log4j.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file