Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NMS-15717 : DeviceConfig via Minion fails if sshScript output contains control characters. #7537

Open
wants to merge 4 commits into
base: foundation-2023
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion features/poller/api/pom.xml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,24 @@
<artifactId>hibernate-jpa-2.0-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
<version>${eclipselinkVersion}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>${eclipselinkVersion}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
</project>
2 changes: 2 additions & 0 deletions features/poller/api/src/main/java/org/opennms/netmgt/poller/DeviceConfig.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement(name="device-config")
@XmlAccessorType(XmlAccessType.NONE)
Expand All @@ -44,6 +45,7 @@ public class DeviceConfig {
private String filename;

@XmlAttribute(name="scriptOutput")
@XmlJavaTypeAdapter(EscapeSequenceAdapter.class)
private String scriptOutput;

public DeviceConfig(String scriptOutput) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2023 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2023 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <[email protected]>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/

package org.opennms.netmgt.poller;

import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class EscapeSequenceAdapter extends XmlAdapter<String, String> {
private static final Logger LOG = LoggerFactory.getLogger(EscapeSequenceAdapter.class);

public EscapeSequenceAdapter() {

}

@Override
public String unmarshal(String v) throws Exception {
if (v != null) {
v = v.replace("&#xd;", "\r")
.replace("&#xa;", "\n");
}
try {
return v;
} catch (XMLMarshalException e) {
LOG.warn("Unable to unmarshal escape sequences value '{}' to a script output. Returning null instead.", v);
return null;
}
}

@Override
public String marshal(String v) throws Exception {
if (v != null) {
v = v.replace("\r", "&#xd;")
.replace("\n", "&#xa;");
}
try {
return v;
} catch (XMLMarshalException e) {
LOG.warn("Unable to marshal escape sequences value '{}' to a script output. Returning null instead.", v);
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2023 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2023 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <[email protected]>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/

package org.opennms.netmgt.poller;

import org.eclipse.persistence.jaxb.JAXBContext;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.junit.Test;

import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;

public class DeviceConfigTest {

@Test
public void testMarshalling() throws javax.xml.bind.JAXBException {
String scriptOutput = "HP J8692A Switch 3500yl-24G\r\r\nSoftware revision K.16.02.0026\r\r\n\r\r\n" +
" (C) Copyright 2018 Hewlett Packard Enterprise Development LP\r\n" +
"RESTRICTED RIGHTS LEGEND\r\n Confidential computer software. Valid license from Hewlett Packard Enterprise\r\n" +
"Development LP required for possession, use or copying. Consistent with FAR\r\n" +
"12.211 and 12.212, Commercial Computer Software, Computer Software\r\n" +
"Documentation, and Technical Data for Commercial Items are licensed to the\r\n" +
"U.S. Government under vendor's standard commercial license.\r\n" +
"^[[1;13r^[[1;1H^[[24;1HPress any key to continue\r\n" +
"^[[13;1H^[[?25h^[[24;27H^[[?6l^[[1;24r^[[?7h^[[2J^[[1;1H^[[1920;1920H^[[6n^[[1;1H";

DeviceConfig deviceConfig = new DeviceConfig(scriptOutput);
JAXBContext jaxbContext = (JAXBContext) JAXBContextFactory.createContext(new Class[]{DeviceConfig.class}, null);

Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter stringWriter = new StringWriter();
marshaller.marshal(deviceConfig, stringWriter);
String xmlOutput = stringWriter.toString();

assertNotNull(xmlOutput);
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><device-config scriptOutput=\"HP J8692A Switch 3500yl-24G&amp;#xd;&amp;#xd;&amp;#xa;Software revision K.16.02.0026&amp;#xd;&amp;#xd;&amp;#xa;&amp;#xd;&amp;#xd;&amp;#xa; (C) Copyright 2018 Hewlett Packard Enterprise Development LP&amp;#xd;&amp;#xa;RESTRICTED RIGHTS LEGEND&amp;#xd;&amp;#xa; Confidential computer software. Valid license from Hewlett Packard Enterprise&amp;#xd;&amp;#xa;Development LP required for possession, use or copying. Consistent with FAR&amp;#xd;&amp;#xa;12.211 and 12.212, Commercial Computer Software, Computer Software&amp;#xd;&amp;#xa;Documentation, and Technical Data for Commercial Items are licensed to the&amp;#xd;&amp;#xa;U.S. Government under vendor's standard commercial license.&amp;#xd;&amp;#xa;^[[1;13r^[[1;1H^[[24;1HPress any key to continue&amp;#xd;&amp;#xa;^[[13;1H^[[?25h^[[24;27H^[[?6l^[[1;24r^[[?7h^[[2J^[[1;1H^[[1920;1920H^[[6n^[[1;1H\"/>",xmlOutput);

}

@Test
public void testUnmarshalling() throws javax.xml.bind.JAXBException {

String xmlInput = "<device-config content=\"\" filename=\"startup-config\" " +
"scriptOutput=\"HP J8692A Switch 3500yl-24G&#xd;&#xd;&#xa;Software revision K.16.02.0026&#xd;&#xd;&#xa;&#xd;&#xd;&#xa; " +
"(C) Copyright 2018 Hewlett Packard Enterprise Development LP&#xd;&#xa;&#xd;&#xa;RESTRICTED RIGHTS LEGEND&#xd;&#xa;" +
" Confidential computer software. Valid license from Hewlett Packard Enterprise&#xd;&#xa;Development LP required for possession, use or copying. Consistent with FAR&#xd;&#xa;" +
"12.211 and 12.212, Commercial Computer Software, Computer Software&#xd;&#xa;Documentation, and Technical Data for Commercial Items are licensed to the&#xd;&#xa;" +
"U.S. Government under vendor's standard commercial license.&#xd;&#xa;&#xd;&#xa;^[[1;13r^[[1;1H^[[24;1HPress any key to continue^[[13;1H^[[?25h^[[24;27H^[[?6l^[[1;24r^[[?7h^[[2J^[[1;1H^[[1920;1920H^[[6n^[[1;1H\"/>";

JAXBContext jaxbContext = (JAXBContext) JAXBContextFactory.createContext(new Class[]{DeviceConfig.class}, null);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

StringReader stringReader = new StringReader(xmlInput);
DeviceConfig deviceConfig = (DeviceConfig) unmarshaller.unmarshal(stringReader);

String expectedOutputStartWith = "HP J8692A Switch 3500yl-24G\r\r\nSoftware revision K.16.02.0026\r\r\n\r\r\n" +
" (C) Copyright 2018 Hewlett Packard Enterprise Development LP\r\n" ;
String expectedOutputEndWith = "^[[1;13r^[[1;1H^[[24;1HPress any key to continue^[[13;1H^[[?25h^[[24;27H^[[?6l^[[1;24r^[[?7h^[[2J^[[1;1H^[[1920;1920H^[[6n^[[1;1H";
String expectedOutputMiddleString = "12.211 and 12.212, Commercial Computer Software, Computer Software\r\n" +
"Documentation, and Technical Data for Commercial Items are licensed to the\r\n" ;

assertNotNull(deviceConfig);
assertTrue(deviceConfig.getScriptOutput().contains(expectedOutputStartWith));
assertTrue(deviceConfig.getScriptOutput().contains(expectedOutputMiddleString));
assertTrue(deviceConfig.getScriptOutput().contains(expectedOutputEndWith));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2023 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2023 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <[email protected]>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/

package org.opennms.netmgt.poller;


import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;


public class EscapeSequenceAdapterTest {

private EscapeSequenceAdapter adapter;

@Before
public void setUp() {
adapter = new EscapeSequenceAdapter();
}

@Test
public void testUnmarshalWithEscapeSequences() throws Exception {
String input = "Hello&#xd;World&#xa;Test";
String expected = "Hello\rWorld\nTest";
String result = adapter.unmarshal(input);
assertNotNull(result, "Result should not be null");
assertEquals("Escape sequences should be replaced correctly", expected, result);
}

@Test
public void testUnmarshalWithNullValue() throws Exception {
String result = adapter.unmarshal(null);
assertNull("Null input should return null", result);
}

@Test
public void testMarshalWithSpecialCharacters() throws Exception {
String input = "Hello\rWorld\nTest";
String expected = "Hello&#xd;World&#xa;Test";
String result = adapter.marshal(input);
assertNotNull(result,"Result should not be null");
assertEquals("Special characters should be converted to escape sequences",expected, result);
}
@Test
public void testMarshalWithNullValue() throws Exception {
String result = adapter.marshal(null);
assertNull("Null input should return null",result);
}

@Test
public void testUnmarshalWithNoEscapeSequences() throws Exception {
String input = "NoEscapeSequenceHere";
String expected = "NoEscapeSequenceHere";
String result = adapter.unmarshal(input);
assertNotNull( "Result should not be null",result);
assertEquals("Input without escape sequences should remain unchanged",expected, result);
}

@Test
public void testMarshalWithNoSpecialCharacters() throws Exception {
String input = "NormalString";
String expected = "NormalString";
String result = adapter.marshal(input);
assertNotNull( "Result should not be null",result);
assertEquals( "Input without special characters should remain unchanged",expected, result);
}
}
Loading