Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
34 changed files
with
1017 additions
and
162 deletions
apps/metrics/intent/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <parent> | ||
8 | + <groupId>org.onlab.onos</groupId> | ||
9 | + <artifactId>onos-app-metrics</artifactId> | ||
10 | + <version>1.0.0-SNAPSHOT</version> | ||
11 | + <relativePath>../pom.xml</relativePath> | ||
12 | + </parent> | ||
13 | + | ||
14 | + <artifactId>onos-app-metrics-intent</artifactId> | ||
15 | + <packaging>bundle</packaging> | ||
16 | + | ||
17 | + <description>ONOS intent metrics application</description> | ||
18 | + | ||
19 | + <dependencies> | ||
20 | + <dependency> | ||
21 | + <groupId>org.onlab.onos</groupId> | ||
22 | + <artifactId>onos-cli</artifactId> | ||
23 | + <version>${project.version}</version> | ||
24 | + </dependency> | ||
25 | + | ||
26 | + <dependency> | ||
27 | + <groupId>org.apache.karaf.shell</groupId> | ||
28 | + <artifactId>org.apache.karaf.shell.console</artifactId> | ||
29 | + </dependency> | ||
30 | + </dependencies> | ||
31 | + | ||
32 | +</project> |
This diff is collapsed. Click to expand it.
apps/metrics/intent/src/main/java/org/onlab/onos/metrics/intent/IntentMetricsService.java
0 → 100644
1 | +package org.onlab.onos.metrics.intent; | ||
2 | + | ||
3 | +import java.util.List; | ||
4 | + | ||
5 | +import com.codahale.metrics.Gauge; | ||
6 | +import com.codahale.metrics.Meter; | ||
7 | +import org.onlab.onos.net.intent.IntentEvent; | ||
8 | + | ||
9 | +/** | ||
10 | + * Service interface exported by IntentMetrics. | ||
11 | + */ | ||
12 | +public interface IntentMetricsService { | ||
13 | + /** | ||
14 | + * Gets the last saved intent events. | ||
15 | + * | ||
16 | + * @return the last saved intent events. | ||
17 | + */ | ||
18 | + public List<IntentEvent> getEvents(); | ||
19 | + | ||
20 | + /** | ||
21 | + * Gets the Metrics' Gauge for the intent SUBMITTED event timestamp | ||
22 | + * (ms from the epoch). | ||
23 | + * | ||
24 | + * @return the Metrics' Gauge for the intent SUBMITTED event timestamp | ||
25 | + * (ms from the epoch) | ||
26 | + */ | ||
27 | + public Gauge<Long> intentSubmittedTimestampEpochMsGauge(); | ||
28 | + | ||
29 | + /** | ||
30 | + * Gets the Metrics' Gauge for the intent INSTALLED event timestamp | ||
31 | + * (ms from the epoch). | ||
32 | + * | ||
33 | + * @return the Metrics' Gauge for the intent INSTALLED event timestamp | ||
34 | + * (ms from the epoch) | ||
35 | + */ | ||
36 | + public Gauge<Long> intentInstalledTimestampEpochMsGauge(); | ||
37 | + | ||
38 | + /** | ||
39 | + * Gets the Metrics' Gauge for the intent WITHDRAW_REQUESTED event | ||
40 | + * timestamp (ms from the epoch). | ||
41 | + * | ||
42 | + * TODO: This intent event is not implemented yet. | ||
43 | + * | ||
44 | + * @return the Metrics' Gauge for the intent WITHDRAW_REQUESTED event | ||
45 | + * timestamp (ms from the epoch) | ||
46 | + */ | ||
47 | + public Gauge<Long> intentWithdrawRequestedTimestampEpochMsGauge(); | ||
48 | + | ||
49 | + /** | ||
50 | + * Gets the Metrics' Gauge for the intent WITHDRAWN event timestamp | ||
51 | + * (ms from the epoch). | ||
52 | + * | ||
53 | + * @return the Metrics' Gauge for the intent WITHDRAWN event timestamp | ||
54 | + * (ms from the epoch) | ||
55 | + */ | ||
56 | + public Gauge<Long> intentWithdrawnTimestampEpochMsGauge(); | ||
57 | + | ||
58 | + /** | ||
59 | + * Gets the Metrics' Meter for the submitted intents event rate. | ||
60 | + * | ||
61 | + * @return the Metrics' Meter for the submitted intents event rate | ||
62 | + */ | ||
63 | + public Meter intentSubmittedRateMeter(); | ||
64 | + | ||
65 | + /** | ||
66 | + * Gets the Metrics' Meter for the installed intents event rate. | ||
67 | + * | ||
68 | + * @return the Metrics' Meter for the installed intent event rate | ||
69 | + */ | ||
70 | + public Meter intentInstalledRateMeter(); | ||
71 | + | ||
72 | + /** | ||
73 | + * Gets the Metrics' Meter for the withdraw requested intents event rate. | ||
74 | + * | ||
75 | + * @return the Metrics' Meter for the withdraw requested intents event rate | ||
76 | + */ | ||
77 | + public Meter intentWithdrawRequestedRateMeter(); | ||
78 | + | ||
79 | + /** | ||
80 | + * Gets the Metrics' Meter for the withdraw completed intents event rate. | ||
81 | + * | ||
82 | + * @return the Metrics' Meter for the withdraw completed intents event rate | ||
83 | + */ | ||
84 | + public Meter intentWithdrawnRateMeter(); | ||
85 | +} |
apps/metrics/intent/src/main/java/org/onlab/onos/metrics/intent/cli/IntentEventsListCommand.java
0 → 100644
1 | +package org.onlab.onos.metrics.intent.cli; | ||
2 | + | ||
3 | +import java.util.List; | ||
4 | + | ||
5 | +import com.fasterxml.jackson.databind.JsonNode; | ||
6 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
7 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
8 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
9 | +import org.apache.karaf.shell.commands.Command; | ||
10 | +import org.onlab.onos.cli.AbstractShellCommand; | ||
11 | +import org.onlab.onos.metrics.intent.IntentMetricsService; | ||
12 | +import org.onlab.onos.net.intent.IntentEvent; | ||
13 | + | ||
14 | +/** | ||
15 | + * Command to show the list of last intent events. | ||
16 | + */ | ||
17 | +@Command(scope = "onos", name = "intents-events", | ||
18 | + description = "Lists the last intent events") | ||
19 | +public class IntentEventsListCommand extends AbstractShellCommand { | ||
20 | + | ||
21 | + private static final String FORMAT_EVENT = "Event=%s"; | ||
22 | + | ||
23 | + @Override | ||
24 | + protected void execute() { | ||
25 | + IntentMetricsService service = get(IntentMetricsService.class); | ||
26 | + | ||
27 | + if (outputJson()) { | ||
28 | + print("%s", json(service.getEvents())); | ||
29 | + } else { | ||
30 | + for (IntentEvent event : service.getEvents()) { | ||
31 | + print(FORMAT_EVENT, event); | ||
32 | + print(""); // Extra empty line for clarity | ||
33 | + } | ||
34 | + } | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * Produces a JSON array of intent events. | ||
39 | + * | ||
40 | + * @param intentEvents the intent events with the data | ||
41 | + * @return JSON array with the intent events | ||
42 | + */ | ||
43 | + private JsonNode json(List<IntentEvent> intentEvents) { | ||
44 | + ObjectMapper mapper = new ObjectMapper(); | ||
45 | + ArrayNode result = mapper.createArrayNode(); | ||
46 | + | ||
47 | + for (IntentEvent event : intentEvents) { | ||
48 | + result.add(json(mapper, event)); | ||
49 | + } | ||
50 | + return result; | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * Produces JSON object for a intent event. | ||
55 | + * | ||
56 | + * @param mapper the JSON object mapper to use | ||
57 | + * @param intentEvent the intent event with the data | ||
58 | + * @return JSON object for the intent event | ||
59 | + */ | ||
60 | + private ObjectNode json(ObjectMapper mapper, IntentEvent intentEvent) { | ||
61 | + ObjectNode result = mapper.createObjectNode(); | ||
62 | + | ||
63 | + result.put("time", intentEvent.time()) | ||
64 | + .put("type", intentEvent.type().toString()) | ||
65 | + .put("event", intentEvent.toString()); | ||
66 | + return result; | ||
67 | + } | ||
68 | +} |
apps/metrics/intent/src/main/java/org/onlab/onos/metrics/intent/cli/IntentEventsMetricsCommand.java
0 → 100644
1 | +package org.onlab.onos.metrics.intent.cli; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | +import java.util.concurrent.TimeUnit; | ||
5 | + | ||
6 | +import com.codahale.metrics.Gauge; | ||
7 | +import com.codahale.metrics.Meter; | ||
8 | +import com.codahale.metrics.json.MetricsModule; | ||
9 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
10 | +import com.fasterxml.jackson.databind.JsonNode; | ||
11 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
12 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
13 | +import org.apache.karaf.shell.commands.Command; | ||
14 | +import org.onlab.onos.cli.AbstractShellCommand; | ||
15 | +import org.onlab.onos.metrics.intent.IntentMetricsService; | ||
16 | + | ||
17 | +/** | ||
18 | + * Command to show the intent events metrics. | ||
19 | + */ | ||
20 | +@Command(scope = "onos", name = "intents-events-metrics", | ||
21 | + description = "Lists intent events metrics") | ||
22 | +public class IntentEventsMetricsCommand extends AbstractShellCommand { | ||
23 | + | ||
24 | + private static final String FORMAT_GAUGE = | ||
25 | + "Intent %s Event Timestamp (ms from epoch)=%d"; | ||
26 | + private static final String FORMAT_METER = | ||
27 | + "Intent %s Events count=%d rate(events/sec) mean=%f m1=%f m5=%f m15=%f"; | ||
28 | + | ||
29 | + @Override | ||
30 | + protected void execute() { | ||
31 | + IntentMetricsService service = get(IntentMetricsService.class); | ||
32 | + Gauge<Long> gauge; | ||
33 | + Meter meter; | ||
34 | + | ||
35 | + if (outputJson()) { | ||
36 | + ObjectMapper mapper = new ObjectMapper() | ||
37 | + .registerModule(new MetricsModule(TimeUnit.SECONDS, | ||
38 | + TimeUnit.MILLISECONDS, | ||
39 | + false)); | ||
40 | + ObjectNode result = mapper.createObjectNode(); | ||
41 | + // | ||
42 | + gauge = service.intentSubmittedTimestampEpochMsGauge(); | ||
43 | + result.put("intentSubmittedTimestamp", json(mapper, gauge)); | ||
44 | + gauge = service.intentInstalledTimestampEpochMsGauge(); | ||
45 | + result.put("intentInstalledTimestamp", json(mapper, gauge)); | ||
46 | + gauge = service.intentWithdrawRequestedTimestampEpochMsGauge(); | ||
47 | + result.put("intentWithdrawRequestedTimestamp", | ||
48 | + json(mapper, gauge)); | ||
49 | + gauge = service.intentWithdrawnTimestampEpochMsGauge(); | ||
50 | + result.put("intentWithdrawnTimestamp", json(mapper, gauge)); | ||
51 | + // | ||
52 | + meter = service.intentSubmittedRateMeter(); | ||
53 | + result.put("intentSubmittedRate", json(mapper, meter)); | ||
54 | + meter = service.intentInstalledRateMeter(); | ||
55 | + result.put("intentInstalledRate", json(mapper, meter)); | ||
56 | + meter = service.intentWithdrawRequestedRateMeter(); | ||
57 | + result.put("intentWithdrawRequestedRate", json(mapper, meter)); | ||
58 | + meter = service.intentWithdrawnRateMeter(); | ||
59 | + result.put("intentWithdrawnRate", json(mapper, meter)); | ||
60 | + // | ||
61 | + print("%s", result); | ||
62 | + } else { | ||
63 | + gauge = service.intentSubmittedTimestampEpochMsGauge(); | ||
64 | + printGauge("Submitted", gauge); | ||
65 | + gauge = service.intentInstalledTimestampEpochMsGauge(); | ||
66 | + printGauge("Installed", gauge); | ||
67 | + gauge = service.intentWithdrawRequestedTimestampEpochMsGauge(); | ||
68 | + printGauge("Withdraw Requested", gauge); | ||
69 | + gauge = service.intentWithdrawnTimestampEpochMsGauge(); | ||
70 | + printGauge("Withdrawn", gauge); | ||
71 | + // | ||
72 | + meter = service.intentSubmittedRateMeter(); | ||
73 | + printMeter("Submitted", meter); | ||
74 | + meter = service.intentInstalledRateMeter(); | ||
75 | + printMeter("Installed", meter); | ||
76 | + meter = service.intentWithdrawRequestedRateMeter(); | ||
77 | + printMeter("Withdraw Requested", meter); | ||
78 | + meter = service.intentWithdrawnRateMeter(); | ||
79 | + printMeter("Withdrawn", meter); | ||
80 | + } | ||
81 | + } | ||
82 | + | ||
83 | + /** | ||
84 | + * Produces JSON node for an Object. | ||
85 | + * | ||
86 | + * @param mapper the JSON object mapper to use | ||
87 | + * @param object the Object with the data | ||
88 | + * @return JSON node for the Object | ||
89 | + */ | ||
90 | + private JsonNode json(ObjectMapper mapper, Object object) { | ||
91 | + // | ||
92 | + // NOTE: The API for custom serializers is incomplete, | ||
93 | + // hence we have to parse the JSON string to create JsonNode. | ||
94 | + // | ||
95 | + try { | ||
96 | + final String objectJson = mapper.writeValueAsString(object); | ||
97 | + JsonNode objectNode = mapper.readTree(objectJson); | ||
98 | + return objectNode; | ||
99 | + } catch (JsonProcessingException e) { | ||
100 | + log.error("Error writing value as JSON string", e); | ||
101 | + } catch (IOException e) { | ||
102 | + log.error("Error writing value as JSON string", e); | ||
103 | + } | ||
104 | + return null; | ||
105 | + } | ||
106 | + | ||
107 | + /** | ||
108 | + * Prints a Gauge. | ||
109 | + * | ||
110 | + * @param operationStr the string with the intent operation to print | ||
111 | + * @param gauge the Gauge to print | ||
112 | + */ | ||
113 | + private void printGauge(String operationStr, Gauge<Long> gauge) { | ||
114 | + print(FORMAT_GAUGE, operationStr, gauge.getValue()); | ||
115 | + } | ||
116 | + | ||
117 | + /** | ||
118 | + * Prints a Meter. | ||
119 | + * | ||
120 | + * @param operationStr the string with the intent operation to print | ||
121 | + * @param meter the Meter to print | ||
122 | + */ | ||
123 | + private void printMeter(String operationStr, Meter meter) { | ||
124 | + TimeUnit rateUnit = TimeUnit.SECONDS; | ||
125 | + double rateFactor = rateUnit.toSeconds(1); | ||
126 | + print(FORMAT_METER, operationStr, meter.getCount(), | ||
127 | + meter.getMeanRate() * rateFactor, | ||
128 | + meter.getOneMinuteRate() * rateFactor, | ||
129 | + meter.getFiveMinuteRate() * rateFactor, | ||
130 | + meter.getFifteenMinuteRate() * rateFactor); | ||
131 | + } | ||
132 | +} |
1 | +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> | ||
2 | + | ||
3 | + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> | ||
4 | + <command> | ||
5 | + <action class="org.onlab.onos.metrics.intent.cli.IntentEventsListCommand"/> | ||
6 | + </command> | ||
7 | + <command> | ||
8 | + <action class="org.onlab.onos.metrics.intent.cli.IntentEventsMetricsCommand"/> | ||
9 | + </command> | ||
10 | + </command-bundle> | ||
11 | + | ||
12 | +</blueprint> |
... | @@ -17,6 +17,7 @@ | ... | @@ -17,6 +17,7 @@ |
17 | <description>ONOS metrics applications</description> | 17 | <description>ONOS metrics applications</description> |
18 | 18 | ||
19 | <modules> | 19 | <modules> |
20 | + <module>intent</module> | ||
20 | <module>topology</module> | 21 | <module>topology</module> |
21 | </modules> | 22 | </modules> |
22 | 23 | ... | ... |
... | @@ -18,6 +18,15 @@ import org.onlab.metrics.MetricsComponent; | ... | @@ -18,6 +18,15 @@ import org.onlab.metrics.MetricsComponent; |
18 | import org.onlab.metrics.MetricsFeature; | 18 | import org.onlab.metrics.MetricsFeature; |
19 | import org.onlab.metrics.MetricsService; | 19 | import org.onlab.metrics.MetricsService; |
20 | import org.onlab.onos.event.Event; | 20 | import org.onlab.onos.event.Event; |
21 | +import org.onlab.onos.net.device.DeviceEvent; | ||
22 | +import org.onlab.onos.net.device.DeviceListener; | ||
23 | +import org.onlab.onos.net.device.DeviceService; | ||
24 | +import org.onlab.onos.net.host.HostEvent; | ||
25 | +import org.onlab.onos.net.host.HostListener; | ||
26 | +import org.onlab.onos.net.host.HostService; | ||
27 | +import org.onlab.onos.net.link.LinkEvent; | ||
28 | +import org.onlab.onos.net.link.LinkListener; | ||
29 | +import org.onlab.onos.net.link.LinkService; | ||
21 | import org.onlab.onos.net.topology.TopologyEvent; | 30 | import org.onlab.onos.net.topology.TopologyEvent; |
22 | import org.onlab.onos.net.topology.TopologyListener; | 31 | import org.onlab.onos.net.topology.TopologyListener; |
23 | import org.onlab.onos.net.topology.TopologyService; | 32 | import org.onlab.onos.net.topology.TopologyService; |
... | @@ -28,14 +37,26 @@ import org.slf4j.Logger; | ... | @@ -28,14 +37,26 @@ import org.slf4j.Logger; |
28 | */ | 37 | */ |
29 | @Component(immediate = true) | 38 | @Component(immediate = true) |
30 | @Service | 39 | @Service |
31 | -public class TopologyMetrics implements TopologyMetricsService, | 40 | +public class TopologyMetrics implements TopologyMetricsService { |
32 | - TopologyListener { | ||
33 | private static final Logger log = getLogger(TopologyMetrics.class); | 41 | private static final Logger log = getLogger(TopologyMetrics.class); |
34 | 42 | ||
35 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 43 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
44 | + protected DeviceService deviceService; | ||
45 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
46 | + protected HostService hostService; | ||
47 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
48 | + protected LinkService linkService; | ||
49 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
36 | protected TopologyService topologyService; | 50 | protected TopologyService topologyService; |
37 | - private LinkedList<TopologyEvent> lastEvents = new LinkedList<>(); | 51 | + |
38 | - private static final int LAST_EVENTS_MAX_N = 10; | 52 | + private LinkedList<Event> lastEvents = new LinkedList<>(); |
53 | + private static final int LAST_EVENTS_MAX_N = 100; | ||
54 | + | ||
55 | + private final DeviceListener deviceListener = new InnerDeviceListener(); | ||
56 | + private final HostListener hostListener = new InnerHostListener(); | ||
57 | + private final LinkListener linkListener = new InnerLinkListener(); | ||
58 | + private final TopologyListener topologyListener = | ||
59 | + new InnerTopologyListener(); | ||
39 | 60 | ||
40 | // | 61 | // |
41 | // Metrics | 62 | // Metrics |
... | @@ -61,22 +82,33 @@ public class TopologyMetrics implements TopologyMetricsService, | ... | @@ -61,22 +82,33 @@ public class TopologyMetrics implements TopologyMetricsService, |
61 | protected void activate() { | 82 | protected void activate() { |
62 | clear(); | 83 | clear(); |
63 | registerMetrics(); | 84 | registerMetrics(); |
64 | - topologyService.addListener(this); | 85 | + |
86 | + // Register for all topology-related events | ||
87 | + deviceService.addListener(deviceListener); | ||
88 | + hostService.addListener(hostListener); | ||
89 | + linkService.addListener(linkListener); | ||
90 | + topologyService.addListener(topologyListener); | ||
91 | + | ||
65 | log.info("ONOS Topology Metrics started."); | 92 | log.info("ONOS Topology Metrics started."); |
66 | } | 93 | } |
67 | 94 | ||
68 | @Deactivate | 95 | @Deactivate |
69 | public void deactivate() { | 96 | public void deactivate() { |
70 | - topologyService.removeListener(this); | 97 | + // De-register from all topology-related events |
98 | + deviceService.removeListener(deviceListener); | ||
99 | + hostService.removeListener(hostListener); | ||
100 | + linkService.removeListener(linkListener); | ||
101 | + topologyService.removeListener(topologyListener); | ||
102 | + | ||
71 | removeMetrics(); | 103 | removeMetrics(); |
72 | clear(); | 104 | clear(); |
73 | log.info("ONOS Topology Metrics stopped."); | 105 | log.info("ONOS Topology Metrics stopped."); |
74 | } | 106 | } |
75 | 107 | ||
76 | @Override | 108 | @Override |
77 | - public List<TopologyEvent> getEvents() { | 109 | + public List<Event> getEvents() { |
78 | synchronized (lastEvents) { | 110 | synchronized (lastEvents) { |
79 | - return ImmutableList.<TopologyEvent>copyOf(lastEvents); | 111 | + return ImmutableList.<Event>copyOf(lastEvents); |
80 | } | 112 | } |
81 | } | 113 | } |
82 | 114 | ||
... | @@ -90,27 +122,22 @@ public class TopologyMetrics implements TopologyMetricsService, | ... | @@ -90,27 +122,22 @@ public class TopologyMetrics implements TopologyMetricsService, |
90 | return eventRateMeter; | 122 | return eventRateMeter; |
91 | } | 123 | } |
92 | 124 | ||
93 | - @Override | 125 | + /** |
94 | - public void event(TopologyEvent event) { | 126 | + * Records an event. |
95 | - lastEventTimestampEpochMs = System.currentTimeMillis(); | 127 | + * |
96 | - // | 128 | + * @param event the event to record |
97 | - // NOTE: If we want to count each "reason" as a separate event, | 129 | + * @param updateEventRateMeter if true, update the Event Rate Meter |
98 | - // then we should use 'event.reason().size()' instead of '1' to | 130 | + */ |
99 | - // mark the meter below. | 131 | + private void recordEvent(Event event, boolean updateEventRateMeter) { |
100 | - // | ||
101 | - eventRateMeter.mark(1); | ||
102 | - | ||
103 | - log.debug("Topology Event: time = {} type = {} subject = {}", | ||
104 | - event.time(), event.type(), event.subject()); | ||
105 | - for (Event reason : event.reasons()) { | ||
106 | - log.debug("Topology Event Reason: time = {} type = {} subject = {}", | ||
107 | - reason.time(), reason.type(), reason.subject()); | ||
108 | - } | ||
109 | - | ||
110 | - // | ||
111 | - // Keep only the last N events, where N = LAST_EVENTS_MAX_N | ||
112 | - // | ||
113 | synchronized (lastEvents) { | 132 | synchronized (lastEvents) { |
133 | + lastEventTimestampEpochMs = System.currentTimeMillis(); | ||
134 | + if (updateEventRateMeter) { | ||
135 | + eventRateMeter.mark(1); | ||
136 | + } | ||
137 | + | ||
138 | + // | ||
139 | + // Keep only the last N events, where N = LAST_EVENTS_MAX_N | ||
140 | + // | ||
114 | while (lastEvents.size() >= LAST_EVENTS_MAX_N) { | 141 | while (lastEvents.size() >= LAST_EVENTS_MAX_N) { |
115 | lastEvents.remove(); | 142 | lastEvents.remove(); |
116 | } | 143 | } |
... | @@ -119,11 +146,67 @@ public class TopologyMetrics implements TopologyMetricsService, | ... | @@ -119,11 +146,67 @@ public class TopologyMetrics implements TopologyMetricsService, |
119 | } | 146 | } |
120 | 147 | ||
121 | /** | 148 | /** |
149 | + * Inner Device Event Listener class. | ||
150 | + */ | ||
151 | + private class InnerDeviceListener implements DeviceListener { | ||
152 | + @Override | ||
153 | + public void event(DeviceEvent event) { | ||
154 | + recordEvent(event, true); | ||
155 | + log.debug("Device Event: time = {} type = {} event = {}", | ||
156 | + event.time(), event.type(), event); | ||
157 | + } | ||
158 | + } | ||
159 | + | ||
160 | + /** | ||
161 | + * Inner Host Event Listener class. | ||
162 | + */ | ||
163 | + private class InnerHostListener implements HostListener { | ||
164 | + @Override | ||
165 | + public void event(HostEvent event) { | ||
166 | + recordEvent(event, true); | ||
167 | + log.debug("Host Event: time = {} type = {} event = {}", | ||
168 | + event.time(), event.type(), event); | ||
169 | + } | ||
170 | + } | ||
171 | + | ||
172 | + /** | ||
173 | + * Inner Link Event Listener class. | ||
174 | + */ | ||
175 | + private class InnerLinkListener implements LinkListener { | ||
176 | + @Override | ||
177 | + public void event(LinkEvent event) { | ||
178 | + recordEvent(event, true); | ||
179 | + log.debug("Link Event: time = {} type = {} event = {}", | ||
180 | + event.time(), event.type(), event); | ||
181 | + } | ||
182 | + } | ||
183 | + | ||
184 | + /** | ||
185 | + * Inner Topology Event Listener class. | ||
186 | + */ | ||
187 | + private class InnerTopologyListener implements TopologyListener { | ||
188 | + @Override | ||
189 | + public void event(TopologyEvent event) { | ||
190 | + // | ||
191 | + // NOTE: Don't update the eventRateMeter, because the real | ||
192 | + // events are already captured/counted. | ||
193 | + // | ||
194 | + recordEvent(event, false); | ||
195 | + log.debug("Topology Event: time = {} type = {} event = {}", | ||
196 | + event.time(), event.type(), event); | ||
197 | + for (Event reason : event.reasons()) { | ||
198 | + log.debug("Topology Event Reason: time = {} type = {} event = {}", | ||
199 | + reason.time(), reason.type(), reason); | ||
200 | + } | ||
201 | + } | ||
202 | + } | ||
203 | + | ||
204 | + /** | ||
122 | * Clears the internal state. | 205 | * Clears the internal state. |
123 | */ | 206 | */ |
124 | private void clear() { | 207 | private void clear() { |
125 | - lastEventTimestampEpochMs = 0; | ||
126 | synchronized (lastEvents) { | 208 | synchronized (lastEvents) { |
209 | + lastEventTimestampEpochMs = 0; | ||
127 | lastEvents.clear(); | 210 | lastEvents.clear(); |
128 | } | 211 | } |
129 | } | 212 | } | ... | ... |
... | @@ -4,7 +4,7 @@ import java.util.List; | ... | @@ -4,7 +4,7 @@ import java.util.List; |
4 | 4 | ||
5 | import com.codahale.metrics.Gauge; | 5 | import com.codahale.metrics.Gauge; |
6 | import com.codahale.metrics.Meter; | 6 | import com.codahale.metrics.Meter; |
7 | -import org.onlab.onos.net.topology.TopologyEvent; | 7 | +import org.onlab.onos.event.Event; |
8 | 8 | ||
9 | /** | 9 | /** |
10 | * Service interface exported by TopologyMetrics. | 10 | * Service interface exported by TopologyMetrics. |
... | @@ -15,7 +15,7 @@ public interface TopologyMetricsService { | ... | @@ -15,7 +15,7 @@ public interface TopologyMetricsService { |
15 | * | 15 | * |
16 | * @return the last saved topology events. | 16 | * @return the last saved topology events. |
17 | */ | 17 | */ |
18 | - public List<TopologyEvent> getEvents(); | 18 | + public List<Event> getEvents(); |
19 | 19 | ||
20 | /** | 20 | /** |
21 | * Gets the Metrics' Gauge for the last topology event timestamp | 21 | * Gets the Metrics' Gauge for the last topology event timestamp | ... | ... |
... | @@ -19,10 +19,8 @@ import org.onlab.onos.net.topology.TopologyEvent; | ... | @@ -19,10 +19,8 @@ import org.onlab.onos.net.topology.TopologyEvent; |
19 | description = "Lists the last topology events") | 19 | description = "Lists the last topology events") |
20 | public class TopologyEventsListCommand extends AbstractShellCommand { | 20 | public class TopologyEventsListCommand extends AbstractShellCommand { |
21 | 21 | ||
22 | - private static final String FORMAT_EVENT = | 22 | + private static final String FORMAT_EVENT = "Event=%s"; |
23 | - "Topology Event time=%d type=%s subject=%s"; | 23 | + private static final String FORMAT_REASON = " Reason=%s"; |
24 | - private static final String FORMAT_REASON = | ||
25 | - " Reason time=%d type=%s subject=%s"; | ||
26 | 24 | ||
27 | @Override | 25 | @Override |
28 | protected void execute() { | 26 | protected void execute() { |
... | @@ -31,12 +29,13 @@ public class TopologyEventsListCommand extends AbstractShellCommand { | ... | @@ -31,12 +29,13 @@ public class TopologyEventsListCommand extends AbstractShellCommand { |
31 | if (outputJson()) { | 29 | if (outputJson()) { |
32 | print("%s", json(service.getEvents())); | 30 | print("%s", json(service.getEvents())); |
33 | } else { | 31 | } else { |
34 | - for (TopologyEvent event : service.getEvents()) { | 32 | + for (Event event : service.getEvents()) { |
35 | - print(FORMAT_EVENT, event.time(), event.type(), | 33 | + print(FORMAT_EVENT, event); |
36 | - event.subject()); | 34 | + if (event instanceof TopologyEvent) { |
37 | - for (Event reason : event.reasons()) { | 35 | + TopologyEvent topologyEvent = (TopologyEvent) event; |
38 | - print(FORMAT_REASON, reason.time(), reason.type(), | 36 | + for (Event reason : topologyEvent.reasons()) { |
39 | - reason.subject()); | 37 | + print(FORMAT_REASON, reason); |
38 | + } | ||
40 | } | 39 | } |
41 | print(""); // Extra empty line for clarity | 40 | print(""); // Extra empty line for clarity |
42 | } | 41 | } |
... | @@ -46,14 +45,14 @@ public class TopologyEventsListCommand extends AbstractShellCommand { | ... | @@ -46,14 +45,14 @@ public class TopologyEventsListCommand extends AbstractShellCommand { |
46 | /** | 45 | /** |
47 | * Produces a JSON array of topology events. | 46 | * Produces a JSON array of topology events. |
48 | * | 47 | * |
49 | - * @param topologyEvents the topology events with the data | 48 | + * @param events the topology events with the data |
50 | * @return JSON array with the topology events | 49 | * @return JSON array with the topology events |
51 | */ | 50 | */ |
52 | - private JsonNode json(List<TopologyEvent> topologyEvents) { | 51 | + private JsonNode json(List<Event> events) { |
53 | ObjectMapper mapper = new ObjectMapper(); | 52 | ObjectMapper mapper = new ObjectMapper(); |
54 | ArrayNode result = mapper.createArrayNode(); | 53 | ArrayNode result = mapper.createArrayNode(); |
55 | 54 | ||
56 | - for (TopologyEvent event : topologyEvents) { | 55 | + for (Event event : events) { |
57 | result.add(json(mapper, event)); | 56 | result.add(json(mapper, event)); |
58 | } | 57 | } |
59 | return result; | 58 | return result; |
... | @@ -66,32 +65,23 @@ public class TopologyEventsListCommand extends AbstractShellCommand { | ... | @@ -66,32 +65,23 @@ public class TopologyEventsListCommand extends AbstractShellCommand { |
66 | * @param topologyEvent the topology event with the data | 65 | * @param topologyEvent the topology event with the data |
67 | * @return JSON object for the topology event | 66 | * @return JSON object for the topology event |
68 | */ | 67 | */ |
69 | - private ObjectNode json(ObjectMapper mapper, TopologyEvent topologyEvent) { | ||
70 | - ObjectNode result = mapper.createObjectNode(); | ||
71 | - ArrayNode reasons = mapper.createArrayNode(); | ||
72 | - | ||
73 | - for (Event reason : topologyEvent.reasons()) { | ||
74 | - reasons.add(json(mapper, reason)); | ||
75 | - } | ||
76 | - result.put("time", topologyEvent.time()) | ||
77 | - .put("type", topologyEvent.type().toString()) | ||
78 | - .put("subject", topologyEvent.subject().toString()) | ||
79 | - .put("reasons", reasons); | ||
80 | - return result; | ||
81 | - } | ||
82 | - | ||
83 | - /** | ||
84 | - * Produces JSON object for a generic event. | ||
85 | - * | ||
86 | - * @param event the generic event with the data | ||
87 | - * @return JSON object for the generic event | ||
88 | - */ | ||
89 | private ObjectNode json(ObjectMapper mapper, Event event) { | 68 | private ObjectNode json(ObjectMapper mapper, Event event) { |
90 | ObjectNode result = mapper.createObjectNode(); | 69 | ObjectNode result = mapper.createObjectNode(); |
91 | 70 | ||
92 | result.put("time", event.time()) | 71 | result.put("time", event.time()) |
93 | .put("type", event.type().toString()) | 72 | .put("type", event.type().toString()) |
94 | - .put("subject", event.subject().toString()); | 73 | + .put("event", event.toString()); |
74 | + | ||
75 | + // Add the reasons if a TopologyEvent | ||
76 | + if (event instanceof TopologyEvent) { | ||
77 | + TopologyEvent topologyEvent = (TopologyEvent) event; | ||
78 | + ArrayNode reasons = mapper.createArrayNode(); | ||
79 | + for (Event reason : topologyEvent.reasons()) { | ||
80 | + reasons.add(json(mapper, reason)); | ||
81 | + } | ||
82 | + result.put("reasons", reasons); | ||
83 | + } | ||
84 | + | ||
95 | return result; | 85 | return result; |
96 | } | 86 | } |
97 | } | 87 | } | ... | ... |
... | @@ -284,7 +284,7 @@ public class OpticalConfigProvider extends AbstractProvider implements DevicePro | ... | @@ -284,7 +284,7 @@ public class OpticalConfigProvider extends AbstractProvider implements DevicePro |
284 | DefaultLinkDescription linkDescription = | 284 | DefaultLinkDescription linkDescription = |
285 | new DefaultLinkDescription(srcPoint, | 285 | new DefaultLinkDescription(srcPoint, |
286 | snkPoint, | 286 | snkPoint, |
287 | - Link.Type.DIRECT, | 287 | + Link.Type.OPTICAL, |
288 | extendedAttributes); | 288 | extendedAttributes); |
289 | 289 | ||
290 | linkProviderService.linkDetected(linkDescription); | 290 | linkProviderService.linkDetected(linkDescription); |
... | @@ -315,7 +315,7 @@ public class OpticalConfigProvider extends AbstractProvider implements DevicePro | ... | @@ -315,7 +315,7 @@ public class OpticalConfigProvider extends AbstractProvider implements DevicePro |
315 | DefaultLinkDescription linkDescription = | 315 | DefaultLinkDescription linkDescription = |
316 | new DefaultLinkDescription(srcPoint, | 316 | new DefaultLinkDescription(srcPoint, |
317 | snkPoint, | 317 | snkPoint, |
318 | - Link.Type.DIRECT, | 318 | + Link.Type.OPTICAL, |
319 | extendedAttributes); | 319 | extendedAttributes); |
320 | 320 | ||
321 | linkProviderService.linkDetected(linkDescription); | 321 | linkProviderService.linkDetected(linkDescription); | ... | ... |
1 | { | 1 | { |
2 | - "opticalSwitches": [ | 2 | + "opticalSwitches": [ |
3 | { | 3 | { |
4 | "allowed": true, | 4 | "allowed": true, |
5 | "latitude": 37.6, | 5 | "latitude": 37.6, |
... | @@ -12,7 +12,7 @@ | ... | @@ -12,7 +12,7 @@ |
12 | "type": "Roadm" | 12 | "type": "Roadm" |
13 | }, | 13 | }, |
14 | 14 | ||
15 | - { | 15 | + { |
16 | "allowed": true, | 16 | "allowed": true, |
17 | "latitude": 37.3, | 17 | "latitude": 37.3, |
18 | "longitude": 121.9, | 18 | "longitude": 121.9, |
... | @@ -22,9 +22,9 @@ | ... | @@ -22,9 +22,9 @@ |
22 | "numRegen": 0 | 22 | "numRegen": 0 |
23 | }, | 23 | }, |
24 | "type": "Roadm" | 24 | "type": "Roadm" |
25 | - }, | 25 | + }, |
26 | 26 | ||
27 | - { | 27 | + { |
28 | "allowed": true, | 28 | "allowed": true, |
29 | "latitude": 33.9, | 29 | "latitude": 33.9, |
30 | "longitude": 118.4, | 30 | "longitude": 118.4, |
... | @@ -34,10 +34,10 @@ | ... | @@ -34,10 +34,10 @@ |
34 | "numRegen": 2 | 34 | "numRegen": 2 |
35 | }, | 35 | }, |
36 | "type": "Roadm" | 36 | "type": "Roadm" |
37 | - } | 37 | + } |
38 | ], | 38 | ], |
39 | 39 | ||
40 | - "opticalLinks": [ | 40 | + "opticalLinks": [ |
41 | { | 41 | { |
42 | "allowed": true, | 42 | "allowed": true, |
43 | "nodeDpid1": "00:00:ff:ff:ff:ff:ff:01", | 43 | "nodeDpid1": "00:00:ff:ff:ff:ff:ff:01", |
... | @@ -51,10 +51,38 @@ | ... | @@ -51,10 +51,38 @@ |
51 | "port2": 30 | 51 | "port2": 30 |
52 | }, | 52 | }, |
53 | "type": "wdmLink" | 53 | "type": "wdmLink" |
54 | - }, | 54 | + }, |
55 | - | 55 | + { |
56 | - { | 56 | + "allowed": true, |
57 | - "allowed": true, | 57 | + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:03", |
58 | + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:01", | ||
59 | + "params": { | ||
60 | + "distKms": 1000, | ||
61 | + "nodeName1": "ROADM3", | ||
62 | + "nodeName2": "ROADM1", | ||
63 | + "numWaves": 80, | ||
64 | + "port1": 30, | ||
65 | + "port2": 10 | ||
66 | + }, | ||
67 | + "type": "wdmLink" | ||
68 | + }, | ||
69 | + | ||
70 | + { | ||
71 | + "allowed": true, | ||
72 | + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:02", | ||
73 | + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:03", | ||
74 | + "params": { | ||
75 | + "distKms": 2000, | ||
76 | + "nodeName1": "ROADM2", | ||
77 | + "nodeName2": "ROADM3", | ||
78 | + "numWaves": 80, | ||
79 | + "port1": 20, | ||
80 | + "port2": 31 | ||
81 | + }, | ||
82 | + "type": "wdmLink" | ||
83 | + }, | ||
84 | + { | ||
85 | + "allowed": true, | ||
58 | "nodeDpid1": "00:00:ff:ff:ff:ff:ff:03", | 86 | "nodeDpid1": "00:00:ff:ff:ff:ff:ff:03", |
59 | "nodeDpid2": "00:00:ff:ff:ff:ff:ff:02", | 87 | "nodeDpid2": "00:00:ff:ff:ff:ff:ff:02", |
60 | "params": { | 88 | "params": { |
... | @@ -66,10 +94,9 @@ | ... | @@ -66,10 +94,9 @@ |
66 | "port2": 20 | 94 | "port2": 20 |
67 | }, | 95 | }, |
68 | "type": "wdmLink" | 96 | "type": "wdmLink" |
69 | - }, | 97 | + }, |
70 | 98 | ||
71 | - | 99 | + { |
72 | - { | ||
73 | "allowed": true, | 100 | "allowed": true, |
74 | "nodeDpid1": "00:00:ff:ff:ff:ff:00:01", | 101 | "nodeDpid1": "00:00:ff:ff:ff:ff:00:01", |
75 | "nodeDpid2": "00:00:ff:ff:ff:ff:ff:01", | 102 | "nodeDpid2": "00:00:ff:ff:ff:ff:ff:01", |
... | @@ -82,8 +109,21 @@ | ... | @@ -82,8 +109,21 @@ |
82 | }, | 109 | }, |
83 | "type": "pktOptLink" | 110 | "type": "pktOptLink" |
84 | }, | 111 | }, |
112 | + { | ||
113 | + "allowed": true, | ||
114 | + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:01", | ||
115 | + "nodeDpid2": "00:00:ff:ff:ff:ff:00:01", | ||
116 | + "params": { | ||
117 | + "nodeName1": "ROADM1", | ||
118 | + "nodeName2": "ROUTER1", | ||
119 | + "bandWidth": 100000, | ||
120 | + "port1": 11, | ||
121 | + "port2": 10 | ||
122 | + }, | ||
123 | + "type": "pktOptLink" | ||
124 | + }, | ||
85 | 125 | ||
86 | - { | 126 | + { |
87 | "allowed": true, | 127 | "allowed": true, |
88 | "nodeDpid1": "00:00:ff:ff:ff:ff:00:02", | 128 | "nodeDpid1": "00:00:ff:ff:ff:ff:00:02", |
89 | "nodeDpid2": "00:00:ff:ff:ff:ff:ff:02", | 129 | "nodeDpid2": "00:00:ff:ff:ff:ff:ff:02", |
... | @@ -95,7 +135,20 @@ | ... | @@ -95,7 +135,20 @@ |
95 | "port2": 21 | 135 | "port2": 21 |
96 | }, | 136 | }, |
97 | "type": "pktOptLink" | 137 | "type": "pktOptLink" |
98 | - } | 138 | + }, |
139 | + { | ||
140 | + "allowed": true, | ||
141 | + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:02", | ||
142 | + "nodeDpid2": "00:00:ff:ff:ff:ff:00:02", | ||
143 | + "params": { | ||
144 | + "nodeName1": "ROADM2", | ||
145 | + "nodeName2": "ROUTER2", | ||
146 | + "bandWidth": 100000, | ||
147 | + "port1": 21, | ||
148 | + "port2": 10 | ||
149 | + }, | ||
150 | + "type": "pktOptLink" | ||
151 | + } | ||
99 | 152 | ||
100 | ] | 153 | ] |
101 | } | 154 | } | ... | ... |
1 | package org.onlab.onos.sdnip; | 1 | package org.onlab.onos.sdnip; |
2 | 2 | ||
3 | -import com.google.common.base.Objects; | 3 | +import java.util.Collection; |
4 | -import com.google.common.collect.HashMultimap; | 4 | +import java.util.HashMap; |
5 | -import com.google.common.collect.Multimaps; | 5 | +import java.util.HashSet; |
6 | -import com.google.common.collect.SetMultimap; | 6 | +import java.util.Iterator; |
7 | -import com.google.common.util.concurrent.ThreadFactoryBuilder; | 7 | +import java.util.LinkedList; |
8 | -import com.googlecode.concurrenttrees.common.KeyValuePair; | 8 | +import java.util.List; |
9 | -import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory; | 9 | +import java.util.Map; |
10 | -import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; | 10 | +import java.util.Set; |
11 | -import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; | 11 | +import java.util.concurrent.BlockingQueue; |
12 | +import java.util.concurrent.ConcurrentHashMap; | ||
13 | +import java.util.concurrent.ExecutorService; | ||
14 | +import java.util.concurrent.Executors; | ||
15 | +import java.util.concurrent.LinkedBlockingQueue; | ||
16 | +import java.util.concurrent.Semaphore; | ||
17 | + | ||
12 | import org.apache.commons.lang3.tuple.Pair; | 18 | import org.apache.commons.lang3.tuple.Pair; |
13 | import org.onlab.onos.ApplicationId; | 19 | import org.onlab.onos.ApplicationId; |
14 | import org.onlab.onos.net.ConnectPoint; | 20 | import org.onlab.onos.net.ConnectPoint; |
... | @@ -36,20 +42,15 @@ import org.onlab.packet.MacAddress; | ... | @@ -36,20 +42,15 @@ import org.onlab.packet.MacAddress; |
36 | import org.slf4j.Logger; | 42 | import org.slf4j.Logger; |
37 | import org.slf4j.LoggerFactory; | 43 | import org.slf4j.LoggerFactory; |
38 | 44 | ||
39 | -import java.util.Collection; | 45 | +import com.google.common.base.Objects; |
40 | -import java.util.HashMap; | 46 | +import com.google.common.collect.HashMultimap; |
41 | -import java.util.HashSet; | 47 | +import com.google.common.collect.Multimaps; |
42 | -import java.util.Iterator; | 48 | +import com.google.common.collect.SetMultimap; |
43 | -import java.util.LinkedList; | 49 | +import com.google.common.util.concurrent.ThreadFactoryBuilder; |
44 | -import java.util.List; | 50 | +import com.googlecode.concurrenttrees.common.KeyValuePair; |
45 | -import java.util.Map; | 51 | +import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory; |
46 | -import java.util.Set; | 52 | +import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; |
47 | -import java.util.concurrent.BlockingQueue; | 53 | +import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; |
48 | -import java.util.concurrent.ConcurrentHashMap; | ||
49 | -import java.util.concurrent.ExecutorService; | ||
50 | -import java.util.concurrent.Executors; | ||
51 | -import java.util.concurrent.LinkedBlockingQueue; | ||
52 | -import java.util.concurrent.Semaphore; | ||
53 | 54 | ||
54 | /** | 55 | /** |
55 | * This class processes BGP route update, translates each update into a intent | 56 | * This class processes BGP route update, translates each update into a intent |
... | @@ -744,6 +745,21 @@ public class Router implements RouteListener { | ... | @@ -744,6 +745,21 @@ public class Router implements RouteListener { |
744 | } | 745 | } |
745 | 746 | ||
746 | /** | 747 | /** |
748 | + * Gets the pushed route intents. | ||
749 | + * | ||
750 | + * @return the pushed route intents | ||
751 | + */ | ||
752 | + public Collection<MultiPointToSinglePointIntent> getPushedRouteIntents() { | ||
753 | + List<MultiPointToSinglePointIntent> pushedIntents = new LinkedList<>(); | ||
754 | + | ||
755 | + for (Map.Entry<IpPrefix, MultiPointToSinglePointIntent> entry : | ||
756 | + pushedRouteIntents.entrySet()) { | ||
757 | + pushedIntents.add(entry.getValue()); | ||
758 | + } | ||
759 | + return pushedIntents; | ||
760 | + } | ||
761 | + | ||
762 | + /** | ||
747 | * Listener for host events. | 763 | * Listener for host events. |
748 | */ | 764 | */ |
749 | class InternalHostListener implements HostListener { | 765 | class InternalHostListener implements HostListener { | ... | ... |
This diff is collapsed. Click to expand it.
... | @@ -20,8 +20,10 @@ package org.onlab.onos.cli.net; | ... | @@ -20,8 +20,10 @@ package org.onlab.onos.cli.net; |
20 | 20 | ||
21 | import com.fasterxml.jackson.databind.ObjectMapper; | 21 | import com.fasterxml.jackson.databind.ObjectMapper; |
22 | import org.apache.karaf.shell.commands.Command; | 22 | import org.apache.karaf.shell.commands.Command; |
23 | +import org.apache.karaf.shell.commands.Option; | ||
23 | import org.onlab.onos.cli.AbstractShellCommand; | 24 | import org.onlab.onos.cli.AbstractShellCommand; |
24 | import org.onlab.onos.net.topology.Topology; | 25 | import org.onlab.onos.net.topology.Topology; |
26 | +import org.onlab.onos.net.topology.TopologyProvider; | ||
25 | import org.onlab.onos.net.topology.TopologyService; | 27 | import org.onlab.onos.net.topology.TopologyService; |
26 | 28 | ||
27 | /** | 29 | /** |
... | @@ -35,6 +37,10 @@ public class TopologyCommand extends AbstractShellCommand { | ... | @@ -35,6 +37,10 @@ public class TopologyCommand extends AbstractShellCommand { |
35 | private static final String FMT = | 37 | private static final String FMT = |
36 | "time=%s, devices=%d, links=%d, clusters=%d, paths=%d"; | 38 | "time=%s, devices=%d, links=%d, clusters=%d, paths=%d"; |
37 | 39 | ||
40 | + @Option(name = "-r", aliases = "--recompute", description = "Trigger topology re-computation", | ||
41 | + required = false, multiValued = false) | ||
42 | + private boolean recompute = false; | ||
43 | + | ||
38 | protected TopologyService service; | 44 | protected TopologyService service; |
39 | protected Topology topology; | 45 | protected Topology topology; |
40 | 46 | ||
... | @@ -49,7 +55,10 @@ public class TopologyCommand extends AbstractShellCommand { | ... | @@ -49,7 +55,10 @@ public class TopologyCommand extends AbstractShellCommand { |
49 | @Override | 55 | @Override |
50 | protected void execute() { | 56 | protected void execute() { |
51 | init(); | 57 | init(); |
52 | - if (outputJson()) { | 58 | + if (recompute) { |
59 | + get(TopologyProvider.class).triggerRecompute(); | ||
60 | + | ||
61 | + } else if (outputJson()) { | ||
53 | print("%s", new ObjectMapper().createObjectNode() | 62 | print("%s", new ObjectMapper().createObjectNode() |
54 | .put("time", topology.time()) | 63 | .put("time", topology.time()) |
55 | .put("deviceCount", topology.deviceCount()) | 64 | .put("deviceCount", topology.deviceCount()) | ... | ... |
... | @@ -25,7 +25,18 @@ public interface Link extends Annotated, Provided, NetworkResource { | ... | @@ -25,7 +25,18 @@ public interface Link extends Annotated, Provided, NetworkResource { |
25 | /** | 25 | /** |
26 | * Signifies that this link is an edge, i.e. host link. | 26 | * Signifies that this link is an edge, i.e. host link. |
27 | */ | 27 | */ |
28 | - EDGE | 28 | + EDGE, |
29 | + | ||
30 | + /** | ||
31 | + * Signifies that this link represents a logical link backed by | ||
32 | + * some form of a tunnel. | ||
33 | + */ | ||
34 | + TUNNEL, | ||
35 | + | ||
36 | + /** | ||
37 | + * Signifies that this link is realized by optical connection. | ||
38 | + */ | ||
39 | + OPTICAL | ||
29 | } | 40 | } |
30 | 41 | ||
31 | /** | 42 | /** |
... | @@ -49,6 +60,4 @@ public interface Link extends Annotated, Provided, NetworkResource { | ... | @@ -49,6 +60,4 @@ public interface Link extends Annotated, Provided, NetworkResource { |
49 | */ | 60 | */ |
50 | Type type(); | 61 | Type type(); |
51 | 62 | ||
52 | - // LinkInfo info(); // Additional link information / decorations | ||
53 | - | ||
54 | } | 63 | } | ... | ... |
... | @@ -7,4 +7,9 @@ import org.onlab.onos.net.provider.Provider; | ... | @@ -7,4 +7,9 @@ import org.onlab.onos.net.provider.Provider; |
7 | */ | 7 | */ |
8 | public interface TopologyProvider extends Provider { | 8 | public interface TopologyProvider extends Provider { |
9 | 9 | ||
10 | + /** | ||
11 | + * Triggers topology recomputation. | ||
12 | + */ | ||
13 | + void triggerRecompute(); | ||
14 | + | ||
10 | } | 15 | } | ... | ... |
... | @@ -208,7 +208,7 @@ public class LinkManager | ... | @@ -208,7 +208,7 @@ public class LinkManager |
208 | LinkEvent event = store.createOrUpdateLink(provider().id(), | 208 | LinkEvent event = store.createOrUpdateLink(provider().id(), |
209 | linkDescription); | 209 | linkDescription); |
210 | if (event != null) { | 210 | if (event != null) { |
211 | - log.debug("Link {} detected", linkDescription); | 211 | + log.info("Link {} detected", linkDescription); |
212 | post(event); | 212 | post(event); |
213 | } | 213 | } |
214 | } | 214 | } | ... | ... |
... | @@ -5,6 +5,7 @@ import org.apache.felix.scr.annotations.Component; | ... | @@ -5,6 +5,7 @@ import org.apache.felix.scr.annotations.Component; |
5 | import org.apache.felix.scr.annotations.Deactivate; | 5 | import org.apache.felix.scr.annotations.Deactivate; |
6 | import org.apache.felix.scr.annotations.Reference; | 6 | import org.apache.felix.scr.annotations.Reference; |
7 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 7 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
8 | +import org.apache.felix.scr.annotations.Service; | ||
8 | import org.onlab.onos.event.AbstractEventAccumulator; | 9 | import org.onlab.onos.event.AbstractEventAccumulator; |
9 | import org.onlab.onos.event.Event; | 10 | import org.onlab.onos.event.Event; |
10 | import org.onlab.onos.event.EventAccumulator; | 11 | import org.onlab.onos.event.EventAccumulator; |
... | @@ -39,6 +40,7 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -39,6 +40,7 @@ import static org.slf4j.LoggerFactory.getLogger; |
39 | * new topology snapshots. | 40 | * new topology snapshots. |
40 | */ | 41 | */ |
41 | @Component(immediate = true) | 42 | @Component(immediate = true) |
43 | +@Service | ||
42 | public class DefaultTopologyProvider extends AbstractProvider | 44 | public class DefaultTopologyProvider extends AbstractProvider |
43 | implements TopologyProvider { | 45 | implements TopologyProvider { |
44 | 46 | ||
... | @@ -89,7 +91,7 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -89,7 +91,7 @@ public class DefaultTopologyProvider extends AbstractProvider |
89 | linkService.addListener(linkListener); | 91 | linkService.addListener(linkListener); |
90 | 92 | ||
91 | isStarted = true; | 93 | isStarted = true; |
92 | - triggerTopologyBuild(Collections.<Event>emptyList()); | 94 | + triggerRecompute(); |
93 | log.info("Started"); | 95 | log.info("Started"); |
94 | } | 96 | } |
95 | 97 | ||
... | @@ -108,6 +110,11 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -108,6 +110,11 @@ public class DefaultTopologyProvider extends AbstractProvider |
108 | log.info("Stopped"); | 110 | log.info("Stopped"); |
109 | } | 111 | } |
110 | 112 | ||
113 | + @Override | ||
114 | + public void triggerRecompute() { | ||
115 | + triggerTopologyBuild(Collections.<Event>emptyList()); | ||
116 | + } | ||
117 | + | ||
111 | /** | 118 | /** |
112 | * Triggers assembly of topology data citing the specified events as the | 119 | * Triggers assembly of topology data citing the specified events as the |
113 | * reason. | 120 | * reason. |
... | @@ -177,7 +184,11 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -177,7 +184,11 @@ public class DefaultTopologyProvider extends AbstractProvider |
177 | 184 | ||
178 | @Override | 185 | @Override |
179 | public void run() { | 186 | public void run() { |
180 | - buildTopology(reasons); | 187 | + try { |
188 | + buildTopology(reasons); | ||
189 | + } catch (Exception e) { | ||
190 | + log.warn("Unable to compute topology due to: {}", e.getMessage()); | ||
191 | + } | ||
181 | } | 192 | } |
182 | } | 193 | } |
183 | 194 | ... | ... |
... | @@ -195,6 +195,10 @@ public class TopologyManagerTest { | ... | @@ -195,6 +195,10 @@ public class TopologyManagerTest { |
195 | public TestProvider() { | 195 | public TestProvider() { |
196 | super(PID); | 196 | super(PID); |
197 | } | 197 | } |
198 | + | ||
199 | + @Override | ||
200 | + public void triggerRecompute() { | ||
201 | + } | ||
198 | } | 202 | } |
199 | 203 | ||
200 | private static class TestListener implements TopologyListener { | 204 | private static class TestListener implements TopologyListener { | ... | ... |
... | @@ -192,14 +192,6 @@ public class SimpleLinkStore | ... | @@ -192,14 +192,6 @@ public class SimpleLinkStore |
192 | // Creates and stores the link and returns the appropriate event. | 192 | // Creates and stores the link and returns the appropriate event. |
193 | // Guarded by linkDescs value (=locking each Link) | 193 | // Guarded by linkDescs value (=locking each Link) |
194 | private LinkEvent createLink(LinkKey key, Link newLink) { | 194 | private LinkEvent createLink(LinkKey key, Link newLink) { |
195 | - | ||
196 | - if (newLink.providerId().isAncillary()) { | ||
197 | - // TODO: revisit ancillary only Link handling | ||
198 | - | ||
199 | - // currently treating ancillary only as down (not visible outside) | ||
200 | - return null; | ||
201 | - } | ||
202 | - | ||
203 | links.put(key, newLink); | 195 | links.put(key, newLink); |
204 | srcLinks.put(newLink.src().deviceId(), key); | 196 | srcLinks.put(newLink.src().deviceId(), key); |
205 | dstLinks.put(newLink.dst().deviceId(), key); | 197 | dstLinks.put(newLink.dst().deviceId(), key); |
... | @@ -209,10 +201,8 @@ public class SimpleLinkStore | ... | @@ -209,10 +201,8 @@ public class SimpleLinkStore |
209 | // Updates, if necessary the specified link and returns the appropriate event. | 201 | // Updates, if necessary the specified link and returns the appropriate event. |
210 | // Guarded by linkDescs value (=locking each Link) | 202 | // Guarded by linkDescs value (=locking each Link) |
211 | private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) { | 203 | private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) { |
212 | - | ||
213 | if (newLink.providerId().isAncillary()) { | 204 | if (newLink.providerId().isAncillary()) { |
214 | // TODO: revisit ancillary only Link handling | 205 | // TODO: revisit ancillary only Link handling |
215 | - | ||
216 | // currently treating ancillary only as down (not visible outside) | 206 | // currently treating ancillary only as down (not visible outside) |
217 | return null; | 207 | return null; |
218 | } | 208 | } | ... | ... |
1 | package org.onlab.onos.store.trivial.impl; | 1 | package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | -import static org.junit.Assert.*; | 3 | +import com.google.common.collect.Iterables; |
4 | -import static org.onlab.onos.net.DeviceId.deviceId; | ||
5 | -import static org.onlab.onos.net.Link.Type.*; | ||
6 | -import static org.onlab.onos.net.link.LinkEvent.Type.*; | ||
7 | -import static org.onlab.onos.store.trivial.impl.SimpleDeviceStoreTest.assertAnnotationsEquals; | ||
8 | - | ||
9 | -import java.util.Collections; | ||
10 | -import java.util.HashMap; | ||
11 | -import java.util.Map; | ||
12 | -import java.util.Set; | ||
13 | -import java.util.concurrent.CountDownLatch; | ||
14 | -import java.util.concurrent.TimeUnit; | ||
15 | - | ||
16 | import org.junit.After; | 4 | import org.junit.After; |
17 | import org.junit.AfterClass; | 5 | import org.junit.AfterClass; |
18 | import org.junit.Before; | 6 | import org.junit.Before; |
... | @@ -23,17 +11,27 @@ import org.onlab.onos.net.ConnectPoint; | ... | @@ -23,17 +11,27 @@ import org.onlab.onos.net.ConnectPoint; |
23 | import org.onlab.onos.net.DefaultAnnotations; | 11 | import org.onlab.onos.net.DefaultAnnotations; |
24 | import org.onlab.onos.net.DeviceId; | 12 | import org.onlab.onos.net.DeviceId; |
25 | import org.onlab.onos.net.Link; | 13 | import org.onlab.onos.net.Link; |
14 | +import org.onlab.onos.net.Link.Type; | ||
26 | import org.onlab.onos.net.LinkKey; | 15 | import org.onlab.onos.net.LinkKey; |
27 | import org.onlab.onos.net.PortNumber; | 16 | import org.onlab.onos.net.PortNumber; |
28 | import org.onlab.onos.net.SparseAnnotations; | 17 | import org.onlab.onos.net.SparseAnnotations; |
29 | -import org.onlab.onos.net.Link.Type; | ||
30 | import org.onlab.onos.net.link.DefaultLinkDescription; | 18 | import org.onlab.onos.net.link.DefaultLinkDescription; |
31 | import org.onlab.onos.net.link.LinkEvent; | 19 | import org.onlab.onos.net.link.LinkEvent; |
32 | import org.onlab.onos.net.link.LinkStore; | 20 | import org.onlab.onos.net.link.LinkStore; |
33 | import org.onlab.onos.net.link.LinkStoreDelegate; | 21 | import org.onlab.onos.net.link.LinkStoreDelegate; |
34 | import org.onlab.onos.net.provider.ProviderId; | 22 | import org.onlab.onos.net.provider.ProviderId; |
35 | 23 | ||
36 | -import com.google.common.collect.Iterables; | 24 | +import java.util.HashMap; |
25 | +import java.util.Map; | ||
26 | +import java.util.Set; | ||
27 | +import java.util.concurrent.CountDownLatch; | ||
28 | +import java.util.concurrent.TimeUnit; | ||
29 | + | ||
30 | +import static org.junit.Assert.*; | ||
31 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
32 | +import static org.onlab.onos.net.Link.Type.*; | ||
33 | +import static org.onlab.onos.net.link.LinkEvent.Type.*; | ||
34 | +import static org.onlab.onos.store.trivial.impl.SimpleDeviceStoreTest.assertAnnotationsEquals; | ||
37 | 35 | ||
38 | /** | 36 | /** |
39 | * Test of the simple LinkStore implementation. | 37 | * Test of the simple LinkStore implementation. |
... | @@ -301,7 +299,7 @@ public class SimpleLinkStoreTest { | ... | @@ -301,7 +299,7 @@ public class SimpleLinkStoreTest { |
301 | LinkEvent event = linkStore.createOrUpdateLink(PIDA, | 299 | LinkEvent event = linkStore.createOrUpdateLink(PIDA, |
302 | new DefaultLinkDescription(src, dst, INDIRECT, A1)); | 300 | new DefaultLinkDescription(src, dst, INDIRECT, A1)); |
303 | 301 | ||
304 | - assertNull("Ancillary only link is ignored", event); | 302 | + assertNotNull("Ancillary only link is ignored", event); |
305 | 303 | ||
306 | // add Primary link | 304 | // add Primary link |
307 | LinkEvent event2 = linkStore.createOrUpdateLink(PID, | 305 | LinkEvent event2 = linkStore.createOrUpdateLink(PID, |
... | @@ -309,7 +307,7 @@ public class SimpleLinkStoreTest { | ... | @@ -309,7 +307,7 @@ public class SimpleLinkStoreTest { |
309 | 307 | ||
310 | assertLink(DID1, P1, DID2, P2, INDIRECT, event2.subject()); | 308 | assertLink(DID1, P1, DID2, P2, INDIRECT, event2.subject()); |
311 | assertAnnotationsEquals(event2.subject().annotations(), A2, A1); | 309 | assertAnnotationsEquals(event2.subject().annotations(), A2, A1); |
312 | - assertEquals(LINK_ADDED, event2.type()); | 310 | + assertEquals(LINK_UPDATED, event2.type()); |
313 | 311 | ||
314 | // update link type | 312 | // update link type |
315 | LinkEvent event3 = linkStore.createOrUpdateLink(PID, | 313 | LinkEvent event3 = linkStore.createOrUpdateLink(PID, |
... | @@ -375,7 +373,7 @@ public class SimpleLinkStoreTest { | ... | @@ -375,7 +373,7 @@ public class SimpleLinkStoreTest { |
375 | } | 373 | } |
376 | 374 | ||
377 | @Test | 375 | @Test |
378 | - public final void testAncillaryOnlyNotVisible() { | 376 | + public final void testAncillaryVisible() { |
379 | ConnectPoint src = new ConnectPoint(DID1, P1); | 377 | ConnectPoint src = new ConnectPoint(DID1, P1); |
380 | ConnectPoint dst = new ConnectPoint(DID2, P2); | 378 | ConnectPoint dst = new ConnectPoint(DID2, P2); |
381 | 379 | ||
... | @@ -384,18 +382,8 @@ public class SimpleLinkStoreTest { | ... | @@ -384,18 +382,8 @@ public class SimpleLinkStoreTest { |
384 | new DefaultLinkDescription(src, dst, INDIRECT, A1)); | 382 | new DefaultLinkDescription(src, dst, INDIRECT, A1)); |
385 | 383 | ||
386 | // Ancillary only link should not be visible | 384 | // Ancillary only link should not be visible |
387 | - assertEquals(0, linkStore.getLinkCount()); | 385 | + assertEquals(1, linkStore.getLinkCount()); |
388 | - | 386 | + assertNotNull(linkStore.getLink(src, dst)); |
389 | - assertTrue(Iterables.isEmpty(linkStore.getLinks())); | ||
390 | - | ||
391 | - assertNull(linkStore.getLink(src, dst)); | ||
392 | - | ||
393 | - assertEquals(Collections.emptySet(), linkStore.getIngressLinks(dst)); | ||
394 | - | ||
395 | - assertEquals(Collections.emptySet(), linkStore.getEgressLinks(src)); | ||
396 | - | ||
397 | - assertEquals(Collections.emptySet(), linkStore.getDeviceEgressLinks(DID1)); | ||
398 | - assertEquals(Collections.emptySet(), linkStore.getDeviceIngressLinks(DID2)); | ||
399 | } | 387 | } |
400 | 388 | ||
401 | // If Delegates should be called only on remote events, | 389 | // If Delegates should be called only on remote events, | ... | ... |
... | @@ -199,9 +199,16 @@ | ... | @@ -199,9 +199,16 @@ |
199 | 199 | ||
200 | <feature name="onos-app-metrics" version="1.0.0" | 200 | <feature name="onos-app-metrics" version="1.0.0" |
201 | description="ONOS metrics applications"> | 201 | description="ONOS metrics applications"> |
202 | + <feature>onos-app-metrics-intent</feature> | ||
202 | <feature>onos-app-metrics-topology</feature> | 203 | <feature>onos-app-metrics-topology</feature> |
203 | </feature> | 204 | </feature> |
204 | 205 | ||
206 | + <feature name="onos-app-metrics-intent" version="1.0.0" | ||
207 | + description="ONOS intent metrics application"> | ||
208 | + <feature>onos-api</feature> | ||
209 | + <bundle>mvn:org.onlab.onos/onos-app-metrics-intent/1.0.0-SNAPSHOT</bundle> | ||
210 | + </feature> | ||
211 | + | ||
205 | <feature name="onos-app-metrics-topology" version="1.0.0" | 212 | <feature name="onos-app-metrics-topology" version="1.0.0" |
206 | description="ONOS topology metrics application"> | 213 | description="ONOS topology metrics application"> |
207 | <feature>onos-api</feature> | 214 | <feature>onos-api</feature> | ... | ... |
... | @@ -88,7 +88,6 @@ | ... | @@ -88,7 +88,6 @@ |
88 | <version>18.0</version> | 88 | <version>18.0</version> |
89 | </dependency> | 89 | </dependency> |
90 | 90 | ||
91 | - | ||
92 | <dependency> | 91 | <dependency> |
93 | <groupId>io.netty</groupId> | 92 | <groupId>io.netty</groupId> |
94 | <artifactId>netty</artifactId> | 93 | <artifactId>netty</artifactId> | ... | ... |
... | @@ -7,4 +7,4 @@ export OC1="192.168.56.101" | ... | @@ -7,4 +7,4 @@ export OC1="192.168.56.101" |
7 | export OCN="192.168.56.103" | 7 | export OCN="192.168.56.103" |
8 | export OCI="${OC1}" | 8 | export OCI="${OC1}" |
9 | 9 | ||
10 | -export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}" | 10 | +export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core-trivial,onos-cli,onos-rest,onos-openflow,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}" | ... | ... |
tools/test/topos/oe-linear-3.json
0 → 100644
1 | +{ | ||
2 | + "devices" : [ | ||
3 | + { | ||
4 | + "uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM", | ||
5 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", | ||
6 | + "annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 } | ||
7 | + }, | ||
8 | + { | ||
9 | + "uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM", | ||
10 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", | ||
11 | + "annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 } | ||
12 | + }, | ||
13 | + { | ||
14 | + "uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM", | ||
15 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", | ||
16 | + "annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 2 } | ||
17 | + }, | ||
18 | + | ||
19 | + { | ||
20 | + "uri": "of:0000ffffffff0001", "mac": "ffffffffff0003", "type": "SWITCH", | ||
21 | + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", | ||
22 | + "annotations": { "latitude": 37.6, "longitude": 122.3 } | ||
23 | + }, | ||
24 | + { | ||
25 | + "uri": "of:0000ffffffff0002", "mac": "ffffffffff0002", "type": "SWITCH", | ||
26 | + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", | ||
27 | + "annotations": { "latitude": 37.3, "longitude": 121.9 } | ||
28 | + } | ||
29 | + ], | ||
30 | + | ||
31 | + "links" : [ | ||
32 | + { "src": "of:0000ffffffffff01/10", "dst": "of:0000ffffffffff03/30", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM" } }, | ||
33 | + { "src": "of:0000ffffffffff02/20", "dst": "of:0000ffffffffff03/31", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM" } }, | ||
34 | + | ||
35 | + { "src": "of:0000ffffffff0001/10", "dst": "of:0000ffffffffff01/11", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }, | ||
36 | + { "src": "of:0000ffffffff0002/10", "dst": "of:0000ffffffffff02/21", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } } | ||
37 | + ], | ||
38 | + | ||
39 | + "hosts" : [ | ||
40 | + { "mac": "a0:00:00:00:00:11", "vlan": -1, "location": "of:0000ffffffff0001/11", "ip": "1.2.3.4" }, | ||
41 | + { "mac": "a0:00:00:00:00:12", "vlan": -1, "location": "of:0000ffffffff0001/12", "ip": "1.2.3.5" }, | ||
42 | + { "mac": "a0:00:00:00:00:21", "vlan": -1, "location": "of:0000ffffffff0002/11", "ip": "2.2.3.4" }, | ||
43 | + { "mac": "a0:00:00:00:00:22", "vlan": -1, "location": "of:0000ffffffff0002/12", "ip": "2.2.3.5" } | ||
44 | + ] | ||
45 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -32,7 +32,7 @@ public final class ChassisId { | ... | @@ -32,7 +32,7 @@ public final class ChassisId { |
32 | * @param value the value to use. | 32 | * @param value the value to use. |
33 | */ | 33 | */ |
34 | public ChassisId(String value) { | 34 | public ChassisId(String value) { |
35 | - this.value = Long.valueOf(value); | 35 | + this.value = Long.valueOf(value, 16); |
36 | } | 36 | } |
37 | 37 | ||
38 | /** | 38 | /** | ... | ... |
1 | package org.onlab.nio; | 1 | package org.onlab.nio; |
2 | 2 | ||
3 | import org.junit.Before; | 3 | import org.junit.Before; |
4 | +import org.junit.Ignore; | ||
4 | import org.junit.Test; | 5 | import org.junit.Test; |
5 | 6 | ||
6 | import java.net.InetAddress; | 7 | import java.net.InetAddress; |
... | @@ -33,7 +34,8 @@ public class IOLoopIntegrationTest { | ... | @@ -33,7 +34,8 @@ public class IOLoopIntegrationTest { |
33 | } | 34 | } |
34 | } | 35 | } |
35 | 36 | ||
36 | - | 37 | + // TODO: this test can not pass in some environments, need to be improved |
38 | + @Ignore | ||
37 | @Test | 39 | @Test |
38 | public void basic() throws Exception { | 40 | public void basic() throws Exception { |
39 | runTest(MILLION, MESSAGE_LENGTH, TIMEOUT); | 41 | runTest(MILLION, MESSAGE_LENGTH, TIMEOUT); | ... | ... |
... | @@ -23,12 +23,6 @@ | ... | @@ -23,12 +23,6 @@ |
23 | <version>1.0.0-SNAPSHOT</version> | 23 | <version>1.0.0-SNAPSHOT</version> |
24 | <scope>test</scope> | 24 | <scope>test</scope> |
25 | </dependency> | 25 | </dependency> |
26 | - <dependency> | ||
27 | - <groupId>com.google.guava</groupId> | ||
28 | - <artifactId>guava</artifactId> | ||
29 | - <scope>test</scope> | ||
30 | - </dependency> | ||
31 | - | ||
32 | </dependencies> | 26 | </dependencies> |
33 | 27 | ||
34 | <properties> | 28 | <properties> | ... | ... |
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | +package org.onlab.onos.rest; | ||
20 | + | ||
21 | +import com.fasterxml.jackson.databind.JsonNode; | ||
22 | +import org.onlab.onos.net.ConnectPoint; | ||
23 | +import org.onlab.onos.net.DefaultAnnotations; | ||
24 | +import org.onlab.onos.net.Device; | ||
25 | +import org.onlab.onos.net.Host; | ||
26 | +import org.onlab.onos.net.HostId; | ||
27 | +import org.onlab.onos.net.HostLocation; | ||
28 | +import org.onlab.onos.net.Link; | ||
29 | +import org.onlab.onos.net.MastershipRole; | ||
30 | +import org.onlab.onos.net.SparseAnnotations; | ||
31 | +import org.onlab.onos.net.device.DefaultDeviceDescription; | ||
32 | +import org.onlab.onos.net.device.DeviceDescription; | ||
33 | +import org.onlab.onos.net.device.DeviceProvider; | ||
34 | +import org.onlab.onos.net.device.DeviceProviderRegistry; | ||
35 | +import org.onlab.onos.net.device.DeviceProviderService; | ||
36 | +import org.onlab.onos.net.host.DefaultHostDescription; | ||
37 | +import org.onlab.onos.net.host.HostProvider; | ||
38 | +import org.onlab.onos.net.host.HostProviderRegistry; | ||
39 | +import org.onlab.onos.net.host.HostProviderService; | ||
40 | +import org.onlab.onos.net.link.DefaultLinkDescription; | ||
41 | +import org.onlab.onos.net.link.LinkProvider; | ||
42 | +import org.onlab.onos.net.link.LinkProviderRegistry; | ||
43 | +import org.onlab.onos.net.link.LinkProviderService; | ||
44 | +import org.onlab.onos.net.provider.ProviderId; | ||
45 | +import org.onlab.packet.ChassisId; | ||
46 | +import org.onlab.packet.IpPrefix; | ||
47 | +import org.onlab.packet.MacAddress; | ||
48 | +import org.onlab.packet.VlanId; | ||
49 | + | ||
50 | +import java.net.URI; | ||
51 | +import java.util.Iterator; | ||
52 | + | ||
53 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
54 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
55 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
56 | + | ||
57 | +/** | ||
58 | + * Provider of devices and links parsed from a JSON configuration structure. | ||
59 | + */ | ||
60 | +class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { | ||
61 | + | ||
62 | + private static final ProviderId PID = | ||
63 | + new ProviderId("cfg", "org.onlab.onos.rest", true); | ||
64 | + | ||
65 | + private final JsonNode cfg; | ||
66 | + private final DeviceProviderRegistry deviceProviderRegistry; | ||
67 | + private final LinkProviderRegistry linkProviderRegistry; | ||
68 | + private final HostProviderRegistry hostProviderRegistry; | ||
69 | + | ||
70 | + /** | ||
71 | + * Creates a new configuration provider. | ||
72 | + * | ||
73 | + * @param cfg JSON configuration | ||
74 | + * @param deviceProviderRegistry device provider registry | ||
75 | + * @param linkProviderRegistry link provider registry | ||
76 | + * @param hostProviderRegistry host provider registry | ||
77 | + */ | ||
78 | + ConfigProvider(JsonNode cfg, | ||
79 | + DeviceProviderRegistry deviceProviderRegistry, | ||
80 | + LinkProviderRegistry linkProviderRegistry, | ||
81 | + HostProviderRegistry hostProviderRegistry) { | ||
82 | + this.cfg = checkNotNull(cfg, "Configuration cannot be null"); | ||
83 | + this.deviceProviderRegistry = checkNotNull(deviceProviderRegistry, "Device provider registry cannot be null"); | ||
84 | + this.linkProviderRegistry = checkNotNull(linkProviderRegistry, "Link provider registry cannot be null"); | ||
85 | + this.hostProviderRegistry = checkNotNull(hostProviderRegistry, "Host provider registry cannot be null"); | ||
86 | + } | ||
87 | + | ||
88 | + /** | ||
89 | + * Parses the given JSON and provides links as configured. | ||
90 | + */ | ||
91 | + void parse() { | ||
92 | + parseDevices(); | ||
93 | + parseLinks(); | ||
94 | + parseHosts(); | ||
95 | + } | ||
96 | + | ||
97 | + // Parses the given JSON and provides devices. | ||
98 | + private void parseDevices() { | ||
99 | + try { | ||
100 | + DeviceProviderService dps = deviceProviderRegistry.register(this); | ||
101 | + JsonNode nodes = cfg.get("devices"); | ||
102 | + if (nodes != null) { | ||
103 | + for (JsonNode node : nodes) { | ||
104 | + parseDevice(dps, node); | ||
105 | + } | ||
106 | + } | ||
107 | + } finally { | ||
108 | + deviceProviderRegistry.unregister(this); | ||
109 | + } | ||
110 | + } | ||
111 | + | ||
112 | + // Parses the given node with device data and supplies the device. | ||
113 | + private void parseDevice(DeviceProviderService dps, JsonNode node) { | ||
114 | + URI uri = URI.create(get(node, "uri")); | ||
115 | + Device.Type type = Device.Type.valueOf(get(node, "type")); | ||
116 | + String mfr = get(node, "mfr"); | ||
117 | + String hw = get(node, "hw"); | ||
118 | + String sw = get(node, "sw"); | ||
119 | + String serial = get(node, "serial"); | ||
120 | + ChassisId cid = new ChassisId(get(node, "mac")); | ||
121 | + SparseAnnotations annotations = annotations(node.get("annotations")); | ||
122 | + | ||
123 | + DeviceDescription desc = | ||
124 | + new DefaultDeviceDescription(uri, type, mfr, hw, sw, serial, | ||
125 | + cid, annotations); | ||
126 | + dps.deviceConnected(deviceId(uri), desc); | ||
127 | + } | ||
128 | + | ||
129 | + // Parses the given JSON and provides links as configured. | ||
130 | + private void parseLinks() { | ||
131 | + try { | ||
132 | + LinkProviderService lps = linkProviderRegistry.register(this); | ||
133 | + JsonNode nodes = cfg.get("links"); | ||
134 | + if (nodes != null) { | ||
135 | + for (JsonNode node : nodes) { | ||
136 | + parseLink(lps, node, false); | ||
137 | + if (!node.has("halfplex")) { | ||
138 | + parseLink(lps, node, true); | ||
139 | + } | ||
140 | + } | ||
141 | + } | ||
142 | + } finally { | ||
143 | + linkProviderRegistry.unregister(this); | ||
144 | + } | ||
145 | + } | ||
146 | + | ||
147 | + // Parses the given node with link data and supplies the link. | ||
148 | + private void parseLink(LinkProviderService lps, JsonNode node, boolean reverse) { | ||
149 | + ConnectPoint src = connectPoint(get(node, "src")); | ||
150 | + ConnectPoint dst = connectPoint(get(node, "dst")); | ||
151 | + Link.Type type = Link.Type.valueOf(get(node, "type")); | ||
152 | + SparseAnnotations annotations = annotations(node.get("annotations")); | ||
153 | + | ||
154 | + DefaultLinkDescription desc = reverse ? | ||
155 | + new DefaultLinkDescription(dst, src, type, annotations) : | ||
156 | + new DefaultLinkDescription(src, dst, type, annotations); | ||
157 | + lps.linkDetected(desc); | ||
158 | + } | ||
159 | + | ||
160 | + // Parses the given JSON and provides hosts as configured. | ||
161 | + private void parseHosts() { | ||
162 | + try { | ||
163 | + HostProviderService hps = hostProviderRegistry.register(this); | ||
164 | + JsonNode nodes = cfg.get("hosts"); | ||
165 | + if (nodes != null) { | ||
166 | + for (JsonNode node : nodes) { | ||
167 | + parseHost(hps, node); | ||
168 | + } | ||
169 | + } | ||
170 | + } finally { | ||
171 | + hostProviderRegistry.unregister(this); | ||
172 | + } | ||
173 | + } | ||
174 | + | ||
175 | + // Parses the given node with host data and supplies the host. | ||
176 | + private void parseHost(HostProviderService hps, JsonNode node) { | ||
177 | + MacAddress mac = MacAddress.valueOf(get(node, "mac")); | ||
178 | + VlanId vlanId = VlanId.vlanId(node.get("vlan").shortValue()); | ||
179 | + HostId hostId = HostId.hostId(mac, vlanId); | ||
180 | + SparseAnnotations annotations = annotations(node.get("annotations")); | ||
181 | + HostLocation location = new HostLocation(connectPoint(get(node, "location")), 0); | ||
182 | + IpPrefix ip = IpPrefix.valueOf(get(node, "ip")); | ||
183 | + | ||
184 | + DefaultHostDescription desc = | ||
185 | + new DefaultHostDescription(mac, vlanId, location, ip, annotations); | ||
186 | + hps.hostDetected(hostId, desc); | ||
187 | + } | ||
188 | + | ||
189 | + // Produces set of annotations from the given JSON node. | ||
190 | + private SparseAnnotations annotations(JsonNode node) { | ||
191 | + if (node == null) { | ||
192 | + return null; | ||
193 | + } | ||
194 | + | ||
195 | + DefaultAnnotations.Builder builder = DefaultAnnotations.builder(); | ||
196 | + Iterator<String> it = node.fieldNames(); | ||
197 | + while (it.hasNext()) { | ||
198 | + String k = it.next(); | ||
199 | + builder.set(k, node.get(k).asText()); | ||
200 | + } | ||
201 | + return builder.build(); | ||
202 | + } | ||
203 | + | ||
204 | + // Produces a connection point from the specified uri/port text. | ||
205 | + private ConnectPoint connectPoint(String text) { | ||
206 | + int i = text.lastIndexOf("/"); | ||
207 | + return new ConnectPoint(deviceId(text.substring(0, i)), | ||
208 | + portNumber(text.substring(i + 1))); | ||
209 | + } | ||
210 | + | ||
211 | + // Returns string form of the named property in the given JSON object. | ||
212 | + private String get(JsonNode node, String name) { | ||
213 | + return node.path(name).asText(); | ||
214 | + } | ||
215 | + | ||
216 | + @Override | ||
217 | + public void triggerProbe(Device device) { | ||
218 | + } | ||
219 | + | ||
220 | + @Override | ||
221 | + public void roleChanged(Device device, MastershipRole newRole) { | ||
222 | + } | ||
223 | + | ||
224 | + @Override | ||
225 | + public void triggerProbe(Host host) { | ||
226 | + } | ||
227 | + | ||
228 | + @Override | ||
229 | + public ProviderId id() { | ||
230 | + return PID; | ||
231 | + } | ||
232 | +} |
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | +package org.onlab.onos.rest; | ||
20 | + | ||
21 | +import com.fasterxml.jackson.databind.JsonNode; | ||
22 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
23 | +import org.onlab.onos.net.device.DeviceProviderRegistry; | ||
24 | +import org.onlab.onos.net.host.HostProviderRegistry; | ||
25 | +import org.onlab.onos.net.link.LinkProviderRegistry; | ||
26 | +import org.onlab.rest.BaseResource; | ||
27 | + | ||
28 | +import javax.ws.rs.Consumes; | ||
29 | +import javax.ws.rs.POST; | ||
30 | +import javax.ws.rs.Path; | ||
31 | +import javax.ws.rs.Produces; | ||
32 | +import javax.ws.rs.core.MediaType; | ||
33 | +import javax.ws.rs.core.Response; | ||
34 | +import java.io.IOException; | ||
35 | +import java.io.InputStream; | ||
36 | + | ||
37 | +/** | ||
38 | + * Resource that acts as an ancillary provider for uploading pre-configured | ||
39 | + * devices, ports and links. | ||
40 | + */ | ||
41 | +@Path("config") | ||
42 | +public class ConfigResource extends BaseResource { | ||
43 | + | ||
44 | + @POST | ||
45 | + @Path("topology") | ||
46 | + @Consumes(MediaType.APPLICATION_JSON) | ||
47 | + @Produces(MediaType.APPLICATION_JSON) | ||
48 | + public Response topology(InputStream input) throws IOException { | ||
49 | + ObjectMapper mapper = new ObjectMapper(); | ||
50 | + JsonNode cfg = mapper.readTree(input); | ||
51 | + new ConfigProvider(cfg, get(DeviceProviderRegistry.class), | ||
52 | + get(LinkProviderRegistry.class), | ||
53 | + get(HostProviderRegistry.class)).parse(); | ||
54 | + return Response.ok(mapper.createObjectNode().toString()).build(); | ||
55 | + } | ||
56 | + | ||
57 | +} |
1 | +{ | ||
2 | + "devices" : [ | ||
3 | + { | ||
4 | + "uri": "of:00000000000001", "type": "ROADM", "mfr": "Foo, Inc.", "hw": "Alpha", "sw": "1.2.3", | ||
5 | + "serial": "ab321", "mac": "00000000000001", "annotations": {"foo": "bar"}, | ||
6 | + "ports": [] | ||
7 | + }, | ||
8 | + { | ||
9 | + "uri": "of:00000000000002", "type": "ROADM", "mfr": "Foo, Inc.", "hw": "Alpha", "sw": "1.2.3", | ||
10 | + "serial": "ab456", "mac": "00000000000002", "annotations": {"foo": "bar"}, | ||
11 | + "ports": [] | ||
12 | + } | ||
13 | + ], | ||
14 | + | ||
15 | + "links" : [ | ||
16 | + { "src": "of:00000000000001/1", "dst": "of:00000000000002/1", "type": "OPTICAL" }, | ||
17 | + { "src": "of:00000000000002/1", "dst": "of:00000000000001/1", "type": "OPTICAL" } | ||
18 | + ] | ||
19 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -44,6 +44,11 @@ | ... | @@ -44,6 +44,11 @@ |
44 | </dependency> | 44 | </dependency> |
45 | 45 | ||
46 | <dependency> | 46 | <dependency> |
47 | + <groupId>com.google.guava</groupId> | ||
48 | + <artifactId>guava</artifactId> | ||
49 | + </dependency> | ||
50 | + | ||
51 | + <dependency> | ||
47 | <groupId>com.sun.jersey</groupId> | 52 | <groupId>com.sun.jersey</groupId> |
48 | <artifactId>jersey-servlet</artifactId> | 53 | <artifactId>jersey-servlet</artifactId> |
49 | </dependency> | 54 | </dependency> |
... | @@ -93,6 +98,7 @@ | ... | @@ -93,6 +98,7 @@ |
93 | ${project.groupId}.${project.artifactId} | 98 | ${project.groupId}.${project.artifactId} |
94 | </Bundle-SymbolicName> | 99 | </Bundle-SymbolicName> |
95 | <Import-Package> | 100 | <Import-Package> |
101 | + org.slf4j, | ||
96 | org.osgi.framework, | 102 | org.osgi.framework, |
97 | javax.ws.rs,javax.ws.rs.core, | 103 | javax.ws.rs,javax.ws.rs.core, |
98 | com.sun.jersey.api.core, | 104 | com.sun.jersey.api.core, |
... | @@ -100,6 +106,8 @@ | ... | @@ -100,6 +106,8 @@ |
100 | com.sun.jersey.server.impl.container.servlet, | 106 | com.sun.jersey.server.impl.container.servlet, |
101 | com.fasterxml.jackson.databind, | 107 | com.fasterxml.jackson.databind, |
102 | com.fasterxml.jackson.databind.node, | 108 | com.fasterxml.jackson.databind.node, |
109 | + com.google.common.base.*, | ||
110 | + org.onlab.packet.*, | ||
103 | org.onlab.rest.*, | 111 | org.onlab.rest.*, |
104 | org.onlab.onos.* | 112 | org.onlab.onos.* |
105 | </Import-Package> | 113 | </Import-Package> | ... | ... |
-
Please register or login to post a comment