Juan Hernandez has posted comments on this change. Change subject: webadmin: UI Plugins PoC, revision 5 ......................................................................
Patch Set 1: (26 inline comments) Some mostly minor comments inside. .................................................... File backend/manager/dbscripts/upgrade/pre_upgrade/0000_config.sql Line 501: select fn_db_add_config_value('UseSecureConnectionWithServers','true','general'); Line 502: select fn_db_add_config_value('UseVdsBrokerInProc','true','general'); Line 503: select fn_db_add_config_value('UtilizationThresholdInPercent','80','general'); Line 504: select fn_db_add_config_value('UIPluginConfigPath','ui-plugins','general'); Line 505: select fn_db_add_config_value('UIPluginDataPath','ui-plugins','general'); Do we really need to make this configurable? I don't see any reason to add parameters for this. Line 506: select fn_db_add_config_value('ValidNumOfMonitors','1,2,4','general'); Line 507: select fn_db_add_config_value('VcpuConsumptionPercentage','10','general'); Line 508: --Handling Host Installation Bootstrap Script URL Line 509: select fn_db_add_config_value('VdcBootStrapUrl','http://example.com/engine/vds_scripts','general'); .................................................... File backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/config/Config.java Line 101: * DataDir configuration value. Line 102: * Line 103: * @return an absolute path for UIPluginDataPath Line 104: */ Line 105: public static String resolveUIPluginDataPath() { Instead of using ConfigValues.DataDir I would suggest to use LocalConfig.getInstance().getUsrDir(). This uses the variable ENGINE_ETC from /etc/ovirt-engine and has the advantage that can be different in different engine nodes in an hypothetical cluster. Line 106: return ConfigUtil.resolvePath(Config.<String> GetValue(ConfigValues.DataDir), Line 107: Config.<String> GetValue(ConfigValues.UIPluginDataPath)); Line 108: } Line 109: Line 112: * ConfigDir configuration value. Line 113: * Line 114: * @return an absolute path for UIPluginConfigPath Line 115: */ Line 116: public static String resolveUIPluginConfigPath() { Same as before, but with getEtcDir(). Line 117: return ConfigUtil.resolvePath(Config.<String> GetValue(ConfigValues.ConfigDir), Line 118: Config.<String> GetValue(ConfigValues.UIPluginConfigPath)); Line 119: } Line 120: .................................................... File backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/config/ConfigValues.java Line 1529: UIPluginDataPath(391), Line 1530: Line 1531: @TypeConverterAttribute(String.class) Line 1532: @DefaultValueAttribute("ui-plugins") Line 1533: UIPluginConfigPath(392), Do we really need these parameters? Line 1534: Line 1535: Invalid(65535); Line 1536: Line 1537: private int intValue; .................................................... File backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ServletUtils.java Line 49: public static boolean isSane(String path) { Line 50: // Check that the path is not too long: Line 51: final int lenght = path.length(); Line 52: if (lenght > PATH_MAX) { Line 53: log.error("The path is " + lenght + " characters long, which is longer than the maximum allowed " + PATH_MAX + "."); That was my fault, Vojtech just moved it from FileServlet. Line 54: return false; Line 55: } Line 56: Line 57: // Check that there aren't potentially dangerous directory navigation sequences: .................................................... File frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/plugin/PluginDataManager.java Line 45: this.pluginConfigDir = new File(pluginConfigPath); Line 46: this.mapper = createJsonMapper(); Line 47: } Line 48: Line 49: ObjectMapper createJsonMapper() { Shouldn't this be private? Line 50: ObjectMapper mapper = new ObjectMapper(); Line 51: mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); Line 52: return mapper; Line 53: } Line 186: boolean isJsonFile(File pathname) { Line 187: return pathname.isFile() && pathname.canRead() && pathname.getName().endsWith(JSON_FILE_SUFFIX); Line 188: } Line 189: Line 190: JsonNode readJsonNode(File file) { Private? Line 191: JsonNode node = null; Line 192: try { Line 193: node = mapper.readValue(file, JsonNode.class); Line 194: } catch (IOException e) { Line 196: } Line 197: return node; Line 198: } Line 199: Line 200: JsonNode readConfigurationNode(File configurationFile) { Private? Line 201: return isJsonFile(configurationFile) ? readJsonNode(configurationFile) : null; Line 202: } Line 203: Line 204: String getConfigurationFileName(File descriptorFile) { Line 200: JsonNode readConfigurationNode(File configurationFile) { Line 201: return isJsonFile(configurationFile) ? readJsonNode(configurationFile) : null; Line 202: } Line 203: Line 204: String getConfigurationFileName(File descriptorFile) { Private? Line 205: return descriptorFile.getName().replace(JSON_FILE_SUFFIX, CONFIG_FILE_SUFFIX); Line 206: } Line 207: .................................................... File frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/plugin/PluginResourceServlet.java Line 20: * descriptor/configuration data as part of its request handling. Line 21: */ Line 22: public class PluginResourceServlet extends HttpServlet { Line 23: Line 24: private static final long serialVersionUID = 1L; 1? I know this is mostly useless, but can you generate a real id? Line 25: Line 26: private static final Logger logger = Logger.getLogger(PluginResourceServlet.class); Line 27: Line 28: private File baseDir; Line 41: // Ensure non-null request path Line 42: requestPath = requestPath == null ? slash : requestPath; Line 43: Line 44: // Remove leading '/' character Line 45: requestPath = requestPath.startsWith(slash) ? requestPath.substring(1) : requestPath; If you need to remove leading slash it is maybe better to do a loop, in case there are several. Line 46: Line 47: // Split plugin name from relative file path Line 48: String[] parts = requestPath.split(slash, 2); Line 49: if (parts.length == 2 && !parts[0].trim().isEmpty() && !parts[1].trim().isEmpty()) { Line 45: requestPath = requestPath.startsWith(slash) ? requestPath.substring(1) : requestPath; Line 46: Line 47: // Split plugin name from relative file path Line 48: String[] parts = requestPath.split(slash, 2); Line 49: if (parts.length == 2 && !parts[0].trim().isEmpty() && !parts[1].trim().isEmpty()) { Maybe StringUtils.isNotBlank(parts[0]) && StringUtils.isNotBlank(parts[1]) ? Line 50: pluginName = parts[0]; Line 51: requestFilePath = parts[1]; Line 52: } else { Line 53: logger.error("Missing UI plugin name and/or relative file path for request [" + request.getRequestURI() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ .................................................... File frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/Plugin.java Line 53: * Verifies if the plugin is currently in one of the given states. Line 54: * <p> Line 55: * Returns {@code true} if successful, {@code false} otherwise. Line 56: */ Line 57: boolean checkCurrentState(List<PluginState> possibleCurrentStates) { Private? Line 58: boolean match = possibleCurrentStates.contains(state); Line 59: assert match : "Unexpected plugin state [" + state + "], should be one of: " + possibleCurrentStates; //$NON-NLS-1$ //$NON-NLS-2$ Line 60: return match; Line 61: } Line 63: /** Line 64: * Verifies if the plugin is currently in one of the given states, and moves plugin state to {@code newState} if Line 65: * successful. Line 66: */ Line 67: void moveToState(List<PluginState> possibleCurrentStates, PluginState newState) { Private? Line 68: if (checkCurrentState(possibleCurrentStates)) { Line 69: state = newState; Line 70: } Line 71: } Line 72: Line 73: /** Line 74: * Verifies if the plugin is currently in the given state, and moves plugin state to {@code newState} if successful. Line 75: */ Line 76: void moveToState(PluginState possibleCurrentState, PluginState newState) { Private? Line 77: moveToState(Arrays.asList(possibleCurrentState), newState); Line 78: } Line 79: Line 80: public void markAsLoading() { .................................................... File frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginManager.java Line 37: exposePluginApi(); Line 38: defineAndLoadPlugins(); Line 39: } Line 40: Line 41: Plugin getPlugin(String pluginName) { Public? Line 42: return plugins.get(pluginName); Line 43: } Line 44: Line 45: Collection<Plugin> getPlugins() { Line 41: Plugin getPlugin(String pluginName) { Line 42: return plugins.get(pluginName); Line 43: } Line 44: Line 45: Collection<Plugin> getPlugins() { Public? Line 46: return plugins.values(); Line 47: } Line 48: Line 49: void addPlugin(Plugin plugin) { Line 45: Collection<Plugin> getPlugins() { Line 46: return plugins.values(); Line 47: } Line 48: Line 49: void addPlugin(Plugin plugin) { Public? Line 50: plugins.put(plugin.getMetaData().getName(), plugin); Line 51: } Line 52: Line 53: /** Line 52: Line 53: /** Line 54: * Defines all plugins that were detected when serving WebAdmin host page, and loads them as necessary. Line 55: */ Line 56: void defineAndLoadPlugins() { Private? Line 57: PluginDefinitions definitions = PluginDefinitions.instance(); Line 58: Line 59: if (definitions != null) { Line 60: JsArray<PluginMetaData> metaDataArray = definitions.getMetaDataArray(); Line 71: Line 72: /** Line 73: * Defines a plugin from the given meta-data, and loads it as necessary. Line 74: */ Line 75: void defineAndLoadPlugin(PluginMetaData pluginMetaData) { Private? Line 76: String pluginName = pluginMetaData.getName(); Line 77: String pluginHostPageUrl = pluginMetaData.getHostPageUrl(); Line 78: Line 79: if (pluginName == null || pluginName.trim().isEmpty()) { Line 107: Line 108: /** Line 109: * Loads the given plugin by attaching the corresponding iframe element to DOM. Line 110: */ Line 111: void loadPlugin(Plugin plugin) { Private? Line 112: if (plugin.isInState(PluginState.DEFINED)) { Line 113: logger.info("Loading plugin [" + plugin.getMetaData().getName() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ Line 114: Document.get().getBody().appendChild(plugin.getIFrameElement()); Line 115: plugin.markAsLoading(); Line 204: * <li>the plugin is either {@linkplain PluginState#INITIALIZING initializing} (actions performed from UiInit Line 205: * function), or {@linkplain PluginState#IN_USE in use} (actions performed from other event handler functions) Line 206: * </ul> Line 207: */ Line 208: boolean canDoPluginAction(String pluginName) { Private? Line 209: Plugin plugin = getPlugin(pluginName); Line 210: boolean pluginInitializingOrInUse = plugin != null Line 211: ? plugin.isInState(PluginState.INITIALIZING) || plugin.isInState(PluginState.IN_USE) : false; Line 212: return canInvokePlugins && pluginInitializingOrInUse; Line 214: Line 215: /** Line 216: * Registers an event handler object (object containing plugin event handler functions) for the given plugin. Line 217: */ Line 218: void registerPluginEventHandlerObject(String pluginName, JavaScriptObject pluginEventHandlerObject) { Private? Line 219: Plugin plugin = getPlugin(pluginName); Line 220: Line 221: if (plugin != null && pluginEventHandlerObject != null) { Line 222: plugin.setEventHandlerObject(pluginEventHandlerObject); Line 260: * <p> Line 261: * If UiInit function fails due to uncaught exception, the plugin will be {@linkplain PluginState#FAILED removed Line 262: * from service}. Line 263: */ Line 264: void initPlugin(String pluginName) { Private? Line 265: Plugin plugin = getPlugin(pluginName); Line 266: Line 267: if (canInvokePlugins && plugin != null && plugin.isInState(PluginState.READY)) { Line 268: logger.info("Initializing plugin [" + pluginName + "]"); //$NON-NLS-1$ //$NON-NLS-2$ Line 280: Line 281: /** Line 282: * Removes the given plugin from service due to plugin failure. Line 283: */ Line 284: void pluginFailed(Plugin plugin) { Private? Line 285: Document.get().getBody().removeChild(plugin.getIFrameElement()); Line 286: plugin.markAsFailed(); Line 287: logger.warning("Plugin [" + plugin.getMetaData().getName() + "] removed from service due to failure"); //$NON-NLS-1$ //$NON-NLS-2$ Line 288: } Line 289: Line 290: /** Line 291: * Returns the configuration object associated with the given plugin, or {@code null} if no such object exists. Line 292: */ Line 293: JavaScriptObject getConfigObject(String pluginName) { Public? Line 294: Plugin plugin = getPlugin(pluginName); Line 295: return plugin != null ? plugin.getMetaData().getConfigObject() : null; Line 296: } Line 297: -- To view, visit http://gerrit.ovirt.org/8120 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ibbf7659f023d8929fb0a8303061851bb7ee555bc Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Vojtech Szocs <vsz...@redhat.com> Gerrit-Reviewer: Juan Hernandez <juan.hernan...@redhat.com> Gerrit-Reviewer: Yair Zaslavsky <yzasl...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches