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

Set correct List key type in gNMI simulator #1796

Merged
merged 1 commit into from
Mar 20, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,33 @@
import java.time.Instant;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.opendaylight.yangtools.yang.common.Decimal64;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.Uint16;
import org.opendaylight.yangtools.yang.common.Uint32;
import org.opendaylight.yangtools.yang.common.Uint64;
import org.opendaylight.yangtools.yang.common.Uint8;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.TypeDefinitions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -347,11 +358,67 @@ private Optional<DataSchemaNode> findAugmentationFromOuterModel(final String ele
.findFirst();
}

private static YangInstanceIdentifier getYIIDWithNewPredicateNode(final YangInstanceIdentifier resultIdentifier,
private YangInstanceIdentifier getYIIDWithNewPredicateNode(final YangInstanceIdentifier resultIdentifier,
final PathElem currentElement) {
final var qname = resultIdentifier.getLastPathArgument().getNodeType();
final Map<QName, Object> keysMap = currentElement.getKeyMap().entrySet().stream()
.collect(Collectors.toMap(e -> QName.create(qname, e.getKey()), Map.Entry::getValue));
.collect(Collectors.toMap(e -> QName.create(qname, e.getKey()), Map.Entry::getValue));

for (final var entry : keysMap.entrySet()) {
final var keyNode = resultIdentifier.node(NodeIdentifierWithPredicates.of(qname, keysMap))
.node(entry.getKey());
final var baseTypeDef = getBaseTypeDef(keyNode);
entry.setValue(mapToCorrectDataType(baseTypeDef, (String) entry.getValue()));
}
return resultIdentifier.node(NodeIdentifierWithPredicates.of(qname, keysMap));
}

private TypeDefinition<?> getBaseTypeDef(final YangInstanceIdentifier identifier) {
final var nodeAndStack = DataSchemaContextTree.from(context).enterPath(identifier).get();
final var dataSchemaNode = nodeAndStack.node().dataSchemaNode();
var resultDataSchemaType = ((TypedDataSchemaNode) dataSchemaNode).getType();
if (resultDataSchemaType instanceof LeafrefTypeDefinition leafRefType) {
final var leafRefPathOrig = leafRefType.getPathStatement().getOriginalString();
final var leafRefPathList = Arrays.stream(leafRefPathOrig.split("/")).filter(s -> !s.isEmpty()).toList();
final var stack = nodeAndStack.stack();
for (final var path : leafRefPathList) {
if ("..".equals(path)) {
stack.exit();
} else {
stack.enterSchemaTree(QName.create(stack.currentModule().localQNameModule(), path));
}
}
resultDataSchemaType = ((TypedDataSchemaNode) stack.currentStatement()).getType();
}
return resultDataSchemaType.getBaseType() != null ? resultDataSchemaType.getBaseType() : resultDataSchemaType;
}

private Object mapToCorrectDataType(final TypeDefinition<?> typeDefinition, final String value) {
final var qname = typeDefinition.getQName();
if (typeDefinition instanceof IdentityrefTypeDefinition identityType) {
final var firstIdentity = identityType.getIdentities().iterator().next();
final var identityQname = firstIdentity.getQName();
final var values = value.split(":");
final var identityRefName = values[values.length - 1];
return QName.create(identityQname, identityRefName);
} else if (qname.equals(TypeDefinitions.BOOLEAN)) {
return Boolean.valueOf(value);
} else if (qname.equals(TypeDefinitions.DECIMAL64)) {
return Decimal64.valueOf(value);
} else if (qname.equals(TypeDefinitions.INT8) || qname.equals(TypeDefinitions.INT16)
|| qname.equals(TypeDefinitions.INT32) || qname.equals(TypeDefinitions.INT64)) {
return Integer.parseInt(value);
} else if (qname.equals(TypeDefinitions.UINT8)) {
return Uint8.valueOf(value);
} else if (qname.equals(TypeDefinitions.UINT16)) {
return Uint16.valueOf(value);
} else if (qname.equals(TypeDefinitions.UINT32)) {
return Uint32.valueOf(value);
} else if (qname.equals(TypeDefinitions.UINT64)) {
return Uint64.valueOf(value);
} else {
// Other types which can be sent as a String type.
return value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,67 @@ public void setAugmentedTestInterfaceConfigTest() throws Exception {
assertEquals("UPDATE", setResponse.getResponse(0).getOp().toString());
}

@Test
public void setContainerWithMultipleListKeyInPathTest() throws Exception {
final var testDataPath = Gnmi.Path.newBuilder()
.addElem(Gnmi.PathElem.newBuilder()
.setName("gnmi-test-model:test-data")
.build())
.build();
final var multipleListKeyUpdate = Gnmi.Update.newBuilder()
.setPath(testDataPath)
.setVal(Gnmi.TypedValue.newBuilder()
.setJsonIetfVal(ByteString.copyFromUtf8("""
{
"multiple-key-list" : [
{
"number": 10,
"leafref-key": 15,
"identityref-key": "openconfig-aaa-types:SYSTEM_ROLE_ADMIN",
"union-key": "unbounded"
}
]
}
"""))
.build())
.build();

final var innerDataPath = Gnmi.Path.newBuilder()
.addElem(Gnmi.PathElem.newBuilder()
.setName("gnmi-test-model:test-data")
.build())
.addElem(Gnmi.PathElem.newBuilder()
.setName("multiple-key-list")
.putKey("number", "10")
.putKey("leafref-key", "15")
.putKey("identityref-key", "openconfig-aaa-types:SYSTEM_ROLE_ADMIN")
.putKey("union-key", "unbounded")
.build())
.addElem(Gnmi.PathElem.newBuilder()
.setName("inner-container")
.build())
.build();
final var innerDataUpdate = Gnmi.Update.newBuilder()
.setPath(innerDataPath)
.setVal(Gnmi.TypedValue.newBuilder()
.setJsonIetfVal(ByteString.copyFromUtf8("""
{
"inner-data": "data"
}
"""))
.build())
.build();
final var setRequest = Gnmi.SetRequest.newBuilder()
.addUpdate(multipleListKeyUpdate)
.addUpdate(innerDataUpdate)
.build();
LOG.info("Sending set request:\n{}", setRequest);

final var setResponse = sessionProvider.getGnmiSession().set(setRequest).get();
assertEquals("UPDATE", setResponse.getResponse(0).getOp().toString());
assertEquals("UPDATE", setResponse.getResponse(1).getOp().toString());
}

@Test
public void crudComplexValueTest() throws ExecutionException, InterruptedException, IOException, JSONException {
final Gnmi.Path path = Gnmi.Path.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module gnmi-test-model {
prefix "gtm";

import openconfig-extensions { prefix oc-ext; }
import openconfig-inet-types { prefix inet; }
import openconfig-aaa-types { prefix types; }

oc-ext:openconfig-version "1.0.0";

Expand All @@ -24,6 +26,35 @@ module gnmi-test-model {
type string;
}
}
list multiple-key-list {
key "number leafref-key identityref-key union-key";
leaf number {
type inet:as-number;
}
leaf leafref-key {
type leafref {
path "../number";
}
}
leaf identityref-key {
type identityref {
base "types:SYSTEM_DEFINED_ROLES";
}
}
leaf union-key {
type union {
type int32;
type enumeration {
enum "unbounded";
}
}
}
container inner-container {
leaf inner-data {
type string;
}
}
}
}

list base-list {
Expand Down
Loading