Table of Contents
Introduction
The controller using OpenDayLight and SLI need to integrated MD-SAL and context memory. This page will provide some sample code and design details.
If you are not interested in the provider code or design, but work on directed graphs you can skip to NodeString Format (fill in link).
Current Design
- Yang model is created by hand or using a tool.
- YangTools (ODL project) generates java classes from the YangModel.
- MdsalHelper (ATT code) can convert the generated java object to and from context memory format.
Today the binding aware broker is being used. The DOM data broker is not supported currently. Below is a detailed diagram of the overall flow.
Sample Code
MdsalHelper has a method accepting the generated builder class and the properties object. The provider code should populate the properties object before invoking the directed graph.
This is how all of the data setup is done for context memory. For example if we have an RPC and we want everything on the input loaded into context memory we would have the below lines
@Override protected ProvideCustomerVnfNamesRequestOutput execute(ProvideCustomerVnfNamesRequestInput input) throws BusinessObjectException { ProvideCustomerVnfNamesRequestOutputBuilder b = new ProvideCustomerVnfNamesRequestOutputBuilder(); Properties properties = new Properties(); ProvideCustomerVnfNamesRequestInputBuilder builder = new ProvideCustomerVnfNamesRequestInputBuilder(input); MdsalHelper.toProperties(properties, builder); return null; }
The signature of this method is determined by the generated interface BAREUCPEAPIService. The next steps to make this code work would be to execute the graph with this properties object.
If the RPC needs to read from the config or operational tree you must retrieve the appropriate builder object and load it into the same properties object. The below block of code can be used to get the builder for config or operational based on the service instance id.
protected ServiceDataBuilder getData(InstanceIdentifier<ServiceList> id, LogicalDatastoreType type) { String siid = id.toString(); Optional<ServiceList> data = null; try { ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); data = readTx.read(type, id).get(); } catch (InterruptedException | ExecutionException e) { log.error("Caught Exception reading MD-SAL (" + type + ") for [" + siid + "] ", e); } log.debug("data:" + data); if (data.isPresent()) { ServiceData serviceData = (ServiceData) data.get().getServiceData(); ServiceDataBuilder serviceDataBuilder = new ServiceDataBuilder(serviceData); if (serviceData != null) { log.info("Read MD-SAL (" + type + ") data for [" + siid + "] ServiceData: " + serviceData); return serviceDataBuilder; } else { log.info("No service-data found in MD-SAL (" + type + ") for [" + siid + "] "); } } else { log.info("No data found in MD-SAL (" + type + ") for [" + siid + "] "); } return null; }
This identifier can be built from a string coming in on the RPC a sample method is below
protected InstanceIdentifier<ServiceList> getInstanceIdentifier(String serviceInstanceId) { return InstanceIdentifier.<Services> builder(Services.class).child(ServiceList.class, new ServiceListKey(serviceInstanceId)).toInstance(); }
To execute the graph we get an instance of SvcLogicService
BundleContext bctx = FrameworkUtil.getBundle(SvcLogicService.class).getBundleContext(); // Get SvcLogicService reference ServiceReference sref = bctx.getServiceReference(SvcLogicService.NAME); SvcLogicService svcLogic = (SvcLogicService) bctx.getService(sref);
Then execute is called on this instance. The provider code is responsible for mapping YANG RPCs to Directed Graphs.
public Properties execute(String module, String rpc, String version, String mode, Properties parms) throws SvcLogicException;
The properties object created previously that has been populated with input, config and operational data should be passed in here.
After execution the graph has modified the properties object. This object can be changed back into a builder and the builder can be used to update MD-SAL config or operational.
ServiceDataBuilder serviceDataBuilder = new ServiceDataBuilder(); MdsalHelper.toBuilder(properties, serviceDataBuilder);
This object could then be passed into
private void SaveServiceList(final ServiceList entry, boolean merge, LogicalDatastoreType storeType) throws IllegalStateException { // Each entry will be identifiable by a unique key, we have to create that identifier InstanceIdentifier.InstanceIdentifierBuilder<ServiceList> serviceListIdBuilder = InstanceIdentifier.<Services>builder(Services.class) .child(ServiceList.class, entry.getKey()); InstanceIdentifier<ServiceList> path = serviceListIdBuilder.toInstance(); int tries = 2; while(true) { try { WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); if (merge) { tx.merge(storeType, path, entry); } else { tx.put(storeType, path, entry); } tx.submit().checkedGet(); log.debug("Update DataStore succeeded"); break; } catch (final TransactionCommitFailedException e) { if(e instanceof OptimisticLockFailedException) { if(--tries <= 0) { log.debug("Got OptimisticLockFailedException on last try - failing "); throw new IllegalStateException(e); } log.debug("Got OptimisticLockFailedException - trying again "); } else { log.debug("Update DataStore failed"); throw new IllegalStateException(e); } } } }
An example of this call would look like
SaveServiceList(serviceListBuilder.build(),true,LogicalDatastoreType.CONFIGURATION);
NodeString Format
See NodeString Format.