Work-in-progress. Completed page will be linked into the Tutorials and Walkthroughs page. |
This tutorial shows you how to incorporate tunable parameters into your component by making the link-flapping behavior of the NullLinkProvider from the Provider Tutorial configurable.
By completing this tutorial, you will understand:
@Property
and @Modified
annotations to add and use tunable parametersWhile we use a Provider in this tutorial, the procedure described here is also applicable to applications.
As in the case of other tutorials, ${ONOS_ROOT} refers to the project root directory of ONOS, and ${KARAF_ROOT} refers to the installation location of Apache Karaf.
We use Component Contexts to pass configuration information to the component. The following should be added to the component's POM file, in this case, the Provider-specific pom.xml, in ${ONOS_ROOT}/providers/null/link :
<!-- This is needed by ComponentContext, used for tunable configuration --> <dependencies> <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.compendium</artifactId> </dependency> </dependencies> |
We make a few modifications to the NullLinkProvider
:
// new imports import static com.google.common.base.Strings.isNullOrEmpty; import org.osgi.service.component.ComponentContext; import org.apache.felix.scr.annotations.Modified; import java.util.Dictionary; // ...<snip>... public class NullLinkProvider extends AbstractProvider implements LinkProvider { private final Logger log = getLogger(getClass()); // The Manager serving as communication point between the ONOS core and this Provider @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected LinkProviderRegistry providerRegistry; // The interface that defines how this Provider can interact with the core private LinkProviderService providerService; public NullLinkProvider() { // ProviderId is used by the core to identify this Provider // The schema "null" and FQDN of the Null southbound comprise this ID super(new ProviderId("null", "org.onosproject.provider.nil")); } @Activate public void activate(ComponentContext context) { providerService = providerRegistry.register(this); deviceService.addListener(linkProvider); // launch exactly one LinkDriver if (!modified(context)) { log.info("Using defaults: flicker={}, eventRate={}", FLICKER, DEFAULT_RATE); linkDriver.submit(new LinkDriver()); } log.info("started"); } @Deactivate public void deactivate(ComponentContext context) { // ... } // The method called when configuration changes are made @Modified public boolean modified(ComponentContext context) { return false; } // ...<snip>... } |
We note two features needed for configurability:
ComponentContext context
: Used to pass around information read from a configuration file@Modified
: Annotation indicating that the modified()
method should be called when configuration changes are made.We call modified()
from activate()
so that the configuration file is read at module startup. Afterwards, the @modified
annotation causes modified()
to be called whenever the file is changed.
The two tunable parameters for the NullLinkProvider are:
Luckily, we had already defined the variables associated with these parameters, flicker
and eventRate
, so we annotate them (and change FLICKER
to false):
// new imports import org.apache.felix.scr.annotations.Property; // ...<snip>... public class NullLinkProvider extends AbstractProvider implements LinkProvider { // ...<snip>... // Default values for tunable parameters private static final boolean FLICKER = false; private static final int DEFAULT_RATE = 3000; @Property(name = "flicker", boolValue = FLICKER, label = "Setting to flap links") private boolean flicker = FLICKER; @Property(name = "eventRate", intValue = DEFAULT_RATE, label = "Duration between Link Event") private int eventRate = DEFAULT_RATE; // ...<snip>... |
Next, we implement modified()
to parse out the values set for these parameters.
@Modified public boolean modified(ComponentContext context) { // if there's no file, fall back to defaults if (context == null) { log.info("No configs, using defaults: flicker={}, eventRate={}", FLICKER, DEFAULT_RATE); return false; } Dictionary<?, ?> properties = context.getProperties(); boolean flickSetting; int newRate; // try to extract values keyed on the parameters' names try { String s = (String) properties.get("flicker"); flickSetting = isNullOrEmpty(s) ? flicker : Boolean.valueOf(s.trim()); s = (String) properties.get("eventRate"); newRate = isNullOrEmpty(s) ? eventRate : Integer.valueOf(s.trim()); } catch (Exception e) { log.warn(e.getMessage()); flickSetting = flicker; newRate = eventRate; } if (flicker != flickSetting) { flicker = flickSetting; } // launch a LinkDriver with the new values, if they were changed if (flicker) { if (eventRate != newRate) { eventRate = newRate; } linkDriver.submit(new LinkDriver()); log.info("Using settings: flicker={}, eventRate={}", flicker, eventRate); return true; } return false; } |
The configurations associated with tunable components are named by the FQDN of the component. For example, the NullLinkProvider, this would be org.onosproject.provider.nil.link.impl.NullLinkProvider.cfg. The files are added to different locations, depending on where you want to run ONOS:
The contents of the file are simple, a list of parameter names and their values:
# Sample configurations for the NullLinkProvider. # # If enabled, generates LinkDetected and LinkVanished events # to make the link appear to be flapping. # # flicker = true # # If enabled, sets the time between LinkEvent generation, # in milliseconds. # # eventRate = 2000 |
We can now rebuild the Null Providers to test the configurability of this Provider.