Skip to content

Allow Lighty to get restconf path from configuration#2241

Merged
ihrasko merged 1 commit into
PANTHEONtech:mainfrom
Tobianas:fix_endpoint
Aug 8, 2025
Merged

Allow Lighty to get restconf path from configuration#2241
ihrasko merged 1 commit into
PANTHEONtech:mainfrom
Tobianas:fix_endpoint

Conversation

@Tobianas

Copy link
Copy Markdown
Contributor

RESTCONF_CONFIG_ROOT_ELEMENT_NAME was hard-coded to be /restconf and the logic to apply different endpoint is no longer present after JaxRS rework.

JIRA: LIGHTY-375

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @Tobianas, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a limitation where the RESTCONF root path was hardcoded within Lighty. It introduces the necessary changes to allow Lighty to read and apply the RESTCONF servlet context path from its configuration, providing greater flexibility for deployment environments and aligning with the original intent of supporting different endpoints as per JIRA LIGHTY-375.

Highlights

  • Configurable RESTCONF Root Path: The previously hardcoded /restconf root element name for the RESTCONF API is now configurable, allowing Lighty to dynamically determine the path from its application configuration.
  • Dynamic Configuration Loading: The RESTCONF_CONFIG_ROOT_ELEMENT_NAME field in RestConfConfigUtils is now updated at runtime by reading the restconfServletContextPath property from the restconf section within the loaded JSON configuration.
  • Field Modifiability: The RESTCONF_CONFIG_ROOT_ELEMENT_NAME field's declaration was changed from public static final String to private static String, enabling its value to be modified after initialization based on configuration.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request introduces the ability to configure the RESTCONF root element name from a configuration file. The changes involve modifying a static variable and adding logic to parse the configuration file. I've identified potential NullPointerException and IndexOutOfBoundsException issues due to missing null checks and boundary checks, and also pointed out code duplication.

return new RestConfConfiguration();
} else {
RESTCONF_CONFIG_ROOT_ELEMENT_NAME = configNode.get("restconf").get(
"restconfServletContextPath").asText().substring(1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The code assumes that restconfServletContextPath always starts with a /. If it doesn't, substring(1) will cause an IndexOutOfBoundsException. Add a check to ensure the string is not empty and starts with / before calling substring(1).

                    String servletPath = servletPathNode.asText();
                    if (servletPath != null && !servletPath.isEmpty() && servletPath.startsWith("/")) {
                        RESTCONF_CONFIG_ROOT_ELEMENT_NAME = servletPath.substring(1);
                    }

Comment on lines +115 to +116
RESTCONF_CONFIG_ROOT_ELEMENT_NAME = configNode.get("restconf").get(
"restconfServletContextPath").asText().substring(1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to the previous occurrence, this code directly accesses nested JSON nodes without null checks, and assumes restconfServletContextPath starts with /. Add null checks and a check for / before calling substring(1) to prevent potential exceptions.

        else {
            JsonNode restconfNode = configNode.get("restconf");
            if (restconfNode != null) {
                JsonNode servletPathNode = restconfNode.get("restconfServletContextPath");
                if (servletPathNode != null) {
                    String servletPath = servletPathNode.asText();
                    if (servletPath != null && !servletPath.isEmpty() && servletPath.startsWith("/")) {
                        RESTCONF_CONFIG_ROOT_ELEMENT_NAME = servletPath.substring(1);
                    }
                }
            }
        }

@Tobianas
Tobianas force-pushed the fix_endpoint branch 3 times, most recently from d618a1d to 0b95350 Compare June 24, 2025 07:29
@Tobianas

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mutable static field, which can lead to concurrency problems. There's also a potential StringIndexOutOfBoundsException and code duplication. Suggestions have been provided to address these points.

public static final int MAXIMUM_FRAGMENT_LENGTH = 0;
public static final int IDLE_TIMEOUT = 30000;
public static final int HEARTBEAT_INTERVAL = 10000;
private static String RESTCONF_CONFIG_ENDPOINT_ELEMENT_NAME = "restconf";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Introducing a mutable static field in a utility class can lead to thread-safety issues and unpredictable behavior in concurrent environments. Consider alternatives like passing the configuration value explicitly or using a ThreadLocal to store the value.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont run Lighty.io in multiple instances and Lighty.io runs this code allways once during startup

Comment on lines 184 to 176
private static void hasRestconfServletContextPath(final JsonNode configNode){
if (!configNode.get(RESTCONF_CONFIG_ROOT_ELEMENT_NAME).has("restconfServletContextPath")) {
LOG.warn("Json config does not contain restconfServletContextPath element. Using default.");
} else {
RESTCONF_CONFIG_ENDPOINT_ELEMENT_NAME = configNode.get("restconf").get(
"restconfServletContextPath").asText().substring(1);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The call to .substring(1) is unsafe as it assumes the path string always starts with / and has a length greater than 1. Validate the configured restconfServletContextPath to prevent StringIndexOutOfBoundsException at runtime. Also, configNode.get("restconf") should use the RESTCONF_CONFIG_ROOT_ELEMENT_NAME constant.

    private static void hasRestconfServletContextPath(final JsonNode configNode){
        final JsonNode restconfNode = configNode.get(RESTCONF_CONFIG_ROOT_ELEMENT_NAME);
        if (!restconfNode.has("restconfServletContextPath")) {
            LOG.warn("Json config does not contain restconfServletContextPath element. Using default.");
        } else {
            final String path = restconfNode.get("restconfServletContextPath").asText();
            if (path != null && path.startsWith("/") && path.length() > 1) {
                RESTCONF_CONFIG_ENDPOINT_ELEMENT_NAME = path.substring(1);
            } else if ("/".equals(path)) {
                RESTCONF_CONFIG_ENDPOINT_ELEMENT_NAME = "";
            } else {
                LOG.warn("Value of restconfServletContextPath ('{}') is invalid. Using default.", path);
            }
        }
    }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We allways set this field with /

Comment on lines 76 to 75
} else {
hasRestconfServletContextPath(configNode);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The else block calling hasRestconfServletContextPath is duplicated in the overloaded getRestConfConfiguration method. Extract this common logic into a private helper method to adhere to DRY principles.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of getRestConfConfiguration() method is duplicated with the other one, this would require us to completly rework this class.

@Tobianas
Tobianas force-pushed the fix_endpoint branch 4 times, most recently from 617be99 to f13e759 Compare August 8, 2025 12:23
JaxRs rework broke configurability of restconf base path, this
patch resolves this issue by providing the path directly to
JaxRsEndpoint.

JIRA: LIGHTY-375
Signed-off-by: tobias.pobocik <tobias.pobocik@pantheon.tech>
@ihrasko
ihrasko self-requested a review August 8, 2025 14:50
@ihrasko
ihrasko merged commit e1de5d3 into PANTHEONtech:main Aug 8, 2025
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants