Madan Jampani
Committed by Gerrit Code Review

Using provider pattern for cluster metadata.

Change-Id: I5a572b3df9149be959dde9868a9c594dec26a3e0
...@@ -20,10 +20,10 @@ import java.util.Collection; ...@@ -20,10 +20,10 @@ import java.util.Collection;
20 import java.util.Set; 20 import java.util.Set;
21 import java.util.stream.Collectors; 21 import java.util.stream.Collectors;
22 22
23 -import org.apache.commons.collections.CollectionUtils; 23 +import org.onosproject.net.Provided;
24 +import org.onosproject.net.provider.ProviderId;
24 25
25 import static com.google.common.base.Preconditions.checkNotNull; 26 import static com.google.common.base.Preconditions.checkNotNull;
26 -import static com.google.common.base.Verify.verifyNotNull;
27 import static com.google.common.base.Verify.verify; 27 import static com.google.common.base.Verify.verify;
28 28
29 import com.google.common.base.MoreObjects; 29 import com.google.common.base.MoreObjects;
...@@ -38,21 +38,49 @@ import com.google.common.collect.Sets; ...@@ -38,21 +38,49 @@ import com.google.common.collect.Sets;
38 * of {@link org.onosproject.cluster.ControllerNode nodes} and the collection of data 38 * of {@link org.onosproject.cluster.ControllerNode nodes} and the collection of data
39 * {@link org.onosproject.cluster.Partition partitions}. 39 * {@link org.onosproject.cluster.Partition partitions}.
40 */ 40 */
41 -public final class ClusterMetadata { 41 +public final class ClusterMetadata implements Provided {
42 42
43 // Name to use when the ClusterMetadataService is in transient state 43 // Name to use when the ClusterMetadataService is in transient state
44 public static final String NO_NAME = ""; 44 public static final String NO_NAME = "";
45 45
46 - private String name; 46 + private final ProviderId providerId;
47 - private Set<ControllerNode> nodes; 47 + private final String name;
48 - private Set<Partition> partitions; 48 + private final Set<ControllerNode> nodes;
49 + private final Set<Partition> partitions;
50 +
51 + private ClusterMetadata() {
52 + providerId = null;
53 + name = null;
54 + nodes = null;
55 + partitions = null;
56 + }
57 +
58 + public ClusterMetadata(ProviderId providerId,
59 + String name,
60 + Set<ControllerNode> nodes,
61 + Set<Partition> partitions) {
62 + this.providerId = checkNotNull(providerId);
63 + this.name = checkNotNull(name);
64 + this.nodes = ImmutableSet.copyOf(checkNotNull(nodes));
65 + // verify that partitions are constituted from valid cluster nodes.
66 + boolean validPartitions = Collections2.transform(nodes, ControllerNode::id)
67 + .containsAll(partitions
68 + .stream()
69 + .flatMap(r -> r.getMembers().stream())
70 + .collect(Collectors.toSet()));
71 + verify(validPartitions, "Partition locations must be valid cluster nodes");
72 + this.partitions = ImmutableSet.copyOf(checkNotNull(partitions));
73 + }
49 74
50 - /** 75 + public ClusterMetadata(String name,
51 - * Returns a new cluster metadata builder. 76 + Set<ControllerNode> nodes,
52 - * @return The cluster metadata builder. 77 + Set<Partition> partitions) {
53 - */ 78 + this(new ProviderId("none", "none"), name, nodes, partitions);
54 - public static Builder builder() { 79 + }
55 - return new Builder(); 80 +
81 + @Override
82 + public ProviderId providerId() {
83 + return providerId;
56 } 84 }
57 85
58 /** 86 /**
...@@ -84,6 +112,7 @@ public final class ClusterMetadata { ...@@ -84,6 +112,7 @@ public final class ClusterMetadata {
84 @Override 112 @Override
85 public String toString() { 113 public String toString() {
86 return MoreObjects.toStringHelper(ClusterMetadata.class) 114 return MoreObjects.toStringHelper(ClusterMetadata.class)
115 + .add("providerId", providerId)
87 .add("name", name) 116 .add("name", name)
88 .add("nodes", nodes) 117 .add("nodes", nodes)
89 .add("partitions", partitions) 118 .add("partitions", partitions)
...@@ -92,7 +121,7 @@ public final class ClusterMetadata { ...@@ -92,7 +121,7 @@ public final class ClusterMetadata {
92 121
93 @Override 122 @Override
94 public int hashCode() { 123 public int hashCode() {
95 - return Arrays.deepHashCode(new Object[] {name, nodes, partitions}); 124 + return Arrays.deepHashCode(new Object[] {providerId, name, nodes, partitions});
96 } 125 }
97 126
98 /* 127 /*
...@@ -116,74 +145,4 @@ public final class ClusterMetadata { ...@@ -116,74 +145,4 @@ public final class ClusterMetadata {
116 return Sets.symmetricDifference(this.nodes, that.nodes).isEmpty() 145 return Sets.symmetricDifference(this.nodes, that.nodes).isEmpty()
117 && Sets.symmetricDifference(this.partitions, that.partitions).isEmpty(); 146 && Sets.symmetricDifference(this.partitions, that.partitions).isEmpty();
118 } 147 }
119 -
120 - /**
121 - * Builder for a {@link ClusterMetadata} instance.
122 - */
123 - public static class Builder {
124 -
125 - private final ClusterMetadata metadata;
126 -
127 - public Builder() {
128 - metadata = new ClusterMetadata();
129 - }
130 -
131 - /**
132 - * Sets the cluster name, returning the cluster metadata builder for method chaining.
133 - * @param name cluster name
134 - * @return this cluster metadata builder
135 - */
136 - public Builder withName(String name) {
137 - metadata.name = checkNotNull(name);
138 - return this;
139 - }
140 -
141 - /**
142 - * Sets the collection of cluster nodes, returning the cluster metadata builder for method chaining.
143 - * @param controllerNodes collection of cluster nodes
144 - * @return this cluster metadata builder
145 - */
146 - public Builder withControllerNodes(Collection<ControllerNode> controllerNodes) {
147 - metadata.nodes = ImmutableSet.copyOf(checkNotNull(controllerNodes));
148 - return this;
149 - }
150 -
151 - /**
152 - * Sets the partitions, returning the cluster metadata builder for method chaining.
153 - * @param partitions collection of partitions
154 - * @return this cluster metadata builder
155 - */
156 - public Builder withPartitions(Collection<Partition> partitions) {
157 - metadata.partitions = ImmutableSet.copyOf(checkNotNull(partitions));
158 - return this;
159 - }
160 -
161 - /**
162 - * Builds the cluster metadata.
163 - * @return cluster metadata
164 - * @throws com.google.common.base.VerifyException VerifyException if the metadata is misconfigured
165 - */
166 - public ClusterMetadata build() {
167 - verifyMetadata();
168 - return metadata;
169 - }
170 -
171 - /**
172 - * Validates the constructed metadata for semantic correctness.
173 - * @throws VerifyException if the metadata is misconfigured.
174 - */
175 - private void verifyMetadata() {
176 - verifyNotNull(metadata.getName(), "Cluster name must be specified");
177 - verify(CollectionUtils.isNotEmpty(metadata.getNodes()), "Cluster nodes must be specified");
178 - verify(CollectionUtils.isNotEmpty(metadata.getPartitions()), "Cluster partitions must be specified");
179 -
180 - // verify that partitions are constituted from valid cluster nodes.
181 - boolean validPartitions = Collections2.transform(metadata.getNodes(), ControllerNode::id)
182 - .containsAll(metadata.getPartitions()
183 - .stream()
184 - .flatMap(r -> r.getMembers().stream())
185 - .collect(Collectors.toSet()));
186 - verify(validPartitions, "Partition locations must be valid cluster nodes");
187 - }
188 - }
189 } 148 }
......
1 /* 1 /*
2 - * Copyright 2015 Open Networking Laboratory 2 + * Copyright 2015-2016 Open Networking Laboratory
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
...@@ -15,27 +15,31 @@ ...@@ -15,27 +15,31 @@
15 */ 15 */
16 package org.onosproject.cluster; 16 package org.onosproject.cluster;
17 17
18 -import java.util.Collection; 18 +import java.util.Set;
19 19
20 -import org.onosproject.store.Store; 20 +import org.onosproject.net.provider.Provider;
21 import org.onosproject.store.service.Versioned; 21 import org.onosproject.store.service.Versioned;
22 22
23 /** 23 /**
24 - * Manages persistence of {@link ClusterMetadata cluster metadata}; not intended for direct use. 24 + * Abstraction of a {@link ClusterMetadata cluster metadata} provider.
25 */ 25 */
26 -public interface ClusterMetadataStore extends Store<ClusterMetadataEvent, ClusterMetadataStoreDelegate> { 26 +public interface ClusterMetadataProvider extends Provider {
27 27
28 /** 28 /**
29 - * Returns the cluster metadata. 29 + * Tells if this provider is currently available and therefore can provide ClusterMetadata.
30 - * <p> 30 + * @return {@code true} if this provider is available and can provide cluster metadata.
31 - * The retuned metadata is encapsulated as a {@link Versioned versioned} and therefore has a specific version. 31 + */
32 + boolean isAvailable();
33 +
34 + /**
35 + * Returns the current cluster metadata.
32 * @return cluster metadata 36 * @return cluster metadata
33 */ 37 */
34 Versioned<ClusterMetadata> getClusterMetadata(); 38 Versioned<ClusterMetadata> getClusterMetadata();
35 39
36 /** 40 /**
37 - * Updates the cluster metadata. 41 + * Updates cluster metadata.
38 - * @param metadata new metadata value 42 + * @param metadata new metadata
39 */ 43 */
40 void setClusterMetadata(ClusterMetadata metadata); 44 void setClusterMetadata(ClusterMetadata metadata);
41 45
...@@ -54,12 +58,12 @@ public interface ClusterMetadataStore extends Store<ClusterMetadataEvent, Cluste ...@@ -54,12 +58,12 @@ public interface ClusterMetadataStore extends Store<ClusterMetadataEvent, Cluste
54 /** 58 /**
55 * Removes a controller node from the list of active members for a partition. 59 * Removes a controller node from the list of active members for a partition.
56 * @param partitionId partition identifier 60 * @param partitionId partition identifier
57 - * @param nodeId id of controller node 61 + * @param nodeId identifier of controller node
58 */ 62 */
59 void removeActivePartitionMember(PartitionId partitionId, NodeId nodeId); 63 void removeActivePartitionMember(PartitionId partitionId, NodeId nodeId);
60 64
61 /** 65 /**
62 - * Returns the collection of controller nodes that are the active members for a partition. 66 + * Returns the set of controller nodes that are the active members for a partition.
63 * <p> 67 * <p>
64 * Active members of a partition are typically those that are actively 68 * Active members of a partition are typically those that are actively
65 * participating in the data replication protocol being employed. When 69 * participating in the data replication protocol being employed. When
...@@ -72,5 +76,5 @@ public interface ClusterMetadataStore extends Store<ClusterMetadataEvent, Cluste ...@@ -72,5 +76,5 @@ public interface ClusterMetadataStore extends Store<ClusterMetadataEvent, Cluste
72 * @param partitionId partition identifier 76 * @param partitionId partition identifier
73 * @return identifiers of controller nodes that are active members 77 * @return identifiers of controller nodes that are active members
74 */ 78 */
75 - Collection<NodeId> getActivePartitionMembers(PartitionId partitionId); 79 + Set<NodeId> getActivePartitionMembers(PartitionId partitionId);
76 } 80 }
......
1 /* 1 /*
2 - * Copyright 2015 Open Networking Laboratory 2 + * Copyright 2015-2016 Open Networking Laboratory
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
...@@ -15,10 +15,11 @@ ...@@ -15,10 +15,11 @@
15 */ 15 */
16 package org.onosproject.cluster; 16 package org.onosproject.cluster;
17 17
18 -import org.onosproject.store.StoreDelegate; 18 +import org.onosproject.net.provider.ProviderRegistry;
19 19
20 /** 20 /**
21 - * Cluster metadata store delegate abstraction. 21 + * Abstraction of a cluster metadata provider registry.
22 */ 22 */
23 -public interface ClusterMetadataStoreDelegate extends StoreDelegate<ClusterMetadataEvent> { 23 +public interface ClusterMetadataProviderRegistry
24 + extends ProviderRegistry<ClusterMetadataProvider, ClusterMetadataProviderService> {
24 } 25 }
......
1 +/*
2 + * Copyright 2015-2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.cluster;
17 +
18 +import org.onosproject.net.provider.ProviderService;
19 +import org.onosproject.store.service.Versioned;
20 +
21 +/**
22 + * Service through which a {@link ClusterMetadataProvider provider} can notify core of
23 + * updates made to cluster metadata.
24 + */
25 +public interface ClusterMetadataProviderService extends ProviderService<ClusterMetadataProvider> {
26 +
27 + /**
28 + * Notifies about a change to cluster metadata.
29 + * @param newMetadata new cluster metadata value
30 + */
31 + void clusterMetadataChanged(Versioned<ClusterMetadata> newMetadata);
32 +
33 + /**
34 + * Notifies that a node just become the active member of a partition.
35 + * @param partitionId partition identifier
36 + * @param nodeId identifier of node
37 + */
38 + void newActiveMemberForPartition(PartitionId partitionId, NodeId nodeId);
39 +}
...@@ -108,4 +108,14 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro ...@@ -108,4 +108,14 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro
108 return providersByScheme.get(deviceId.uri().getScheme()); 108 return providersByScheme.get(deviceId.uri().getScheme());
109 } 109 }
110 110
111 + /**
112 + * Returns the provider registered with the specified scheme.
113 + *
114 + * @param scheme provider scheme
115 + * @return provider
116 + */
117 + protected synchronized P getProvider(String scheme) {
118 + return providersByScheme.get(scheme);
119 + }
120 +
111 } 121 }
......
...@@ -42,7 +42,6 @@ import org.onosproject.event.AbstractListenerManager; ...@@ -42,7 +42,6 @@ import org.onosproject.event.AbstractListenerManager;
42 import org.slf4j.Logger; 42 import org.slf4j.Logger;
43 43
44 import com.google.common.collect.Collections2; 44 import com.google.common.collect.Collections2;
45 -import com.google.common.collect.Lists;
46 import com.google.common.collect.Sets; 45 import com.google.common.collect.Sets;
47 46
48 import java.util.ArrayList; 47 import java.util.ArrayList;
...@@ -139,11 +138,7 @@ public class ClusterManager ...@@ -139,11 +138,7 @@ public class ClusterManager
139 checkNotNull(nodes, "Nodes cannot be null"); 138 checkNotNull(nodes, "Nodes cannot be null");
140 checkArgument(!nodes.isEmpty(), "Nodes cannot be empty"); 139 checkArgument(!nodes.isEmpty(), "Nodes cannot be empty");
141 140
142 - ClusterMetadata metadata = ClusterMetadata.builder() 141 + ClusterMetadata metadata = new ClusterMetadata("default", nodes, buildDefaultPartitions(nodes));
143 - .withName("default")
144 - .withControllerNodes(nodes)
145 - .withPartitions(buildDefaultPartitions(nodes))
146 - .build();
147 clusterMetadataAdminService.setClusterMetadata(metadata); 142 clusterMetadataAdminService.setClusterMetadata(metadata);
148 try { 143 try {
149 log.warn("Shutting down container for cluster reconfiguration!"); 144 log.warn("Shutting down container for cluster reconfiguration!");
...@@ -175,10 +170,10 @@ public class ClusterManager ...@@ -175,10 +170,10 @@ public class ClusterManager
175 } 170 }
176 } 171 }
177 172
178 - private static Collection<Partition> buildDefaultPartitions(Collection<ControllerNode> nodes) { 173 + private static Set<Partition> buildDefaultPartitions(Collection<ControllerNode> nodes) {
179 List<ControllerNode> sorted = new ArrayList<>(nodes); 174 List<ControllerNode> sorted = new ArrayList<>(nodes);
180 Collections.sort(sorted, (o1, o2) -> o1.id().toString().compareTo(o2.id().toString())); 175 Collections.sort(sorted, (o1, o2) -> o1.id().toString().compareTo(o2.id().toString()));
181 - Collection<Partition> partitions = Lists.newArrayList(); 176 + Set<Partition> partitions = Sets.newHashSet();
182 // add p0 partition 177 // add p0 partition
183 partitions.add(new DefaultPartition(PartitionId.from(0), 178 partitions.add(new DefaultPartition(PartitionId.from(0),
184 Sets.newHashSet(Collections2.transform(nodes, ControllerNode::id)))); 179 Sets.newHashSet(Collections2.transform(nodes, ControllerNode::id))));
......
...@@ -21,81 +21,117 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -21,81 +21,117 @@ import static org.slf4j.LoggerFactory.getLogger;
21 import java.net.InetAddress; 21 import java.net.InetAddress;
22 import java.net.NetworkInterface; 22 import java.net.NetworkInterface;
23 import java.net.SocketException; 23 import java.net.SocketException;
24 +import java.net.URI;
25 +import java.net.URISyntaxException;
24 import java.util.Collection; 26 import java.util.Collection;
25 import java.util.Enumeration; 27 import java.util.Enumeration;
26 28
27 import org.apache.felix.scr.annotations.Activate; 29 import org.apache.felix.scr.annotations.Activate;
28 import org.apache.felix.scr.annotations.Component; 30 import org.apache.felix.scr.annotations.Component;
29 import org.apache.felix.scr.annotations.Deactivate; 31 import org.apache.felix.scr.annotations.Deactivate;
30 -import org.apache.felix.scr.annotations.Reference;
31 -import org.apache.felix.scr.annotations.ReferenceCardinality;
32 import org.apache.felix.scr.annotations.Service; 32 import org.apache.felix.scr.annotations.Service;
33 import org.onlab.packet.IpAddress; 33 import org.onlab.packet.IpAddress;
34 import org.onosproject.cluster.ClusterMetadata; 34 import org.onosproject.cluster.ClusterMetadata;
35 import org.onosproject.cluster.ClusterMetadataAdminService; 35 import org.onosproject.cluster.ClusterMetadataAdminService;
36 import org.onosproject.cluster.ClusterMetadataEvent; 36 import org.onosproject.cluster.ClusterMetadataEvent;
37 import org.onosproject.cluster.ClusterMetadataEventListener; 37 import org.onosproject.cluster.ClusterMetadataEventListener;
38 +import org.onosproject.cluster.ClusterMetadataProvider;
39 +import org.onosproject.cluster.ClusterMetadataProviderRegistry;
40 +import org.onosproject.cluster.ClusterMetadataProviderService;
38 import org.onosproject.cluster.ClusterMetadataService; 41 import org.onosproject.cluster.ClusterMetadataService;
39 -import org.onosproject.cluster.ClusterMetadataStore;
40 -import org.onosproject.cluster.ClusterMetadataStoreDelegate;
41 import org.onosproject.cluster.ControllerNode; 42 import org.onosproject.cluster.ControllerNode;
42 -import org.onosproject.event.AbstractListenerManager; 43 +import org.onosproject.cluster.NodeId;
44 +import org.onosproject.cluster.PartitionId;
45 +import org.onosproject.net.provider.AbstractListenerProviderRegistry;
46 +import org.onosproject.net.provider.AbstractProviderService;
43 import org.onosproject.store.service.Versioned; 47 import org.onosproject.store.service.Versioned;
44 import org.slf4j.Logger; 48 import org.slf4j.Logger;
45 49
50 +import com.google.common.base.Throwables;
51 +
46 /** 52 /**
47 * Implementation of ClusterMetadataService. 53 * Implementation of ClusterMetadataService.
48 */ 54 */
49 @Component(immediate = true) 55 @Component(immediate = true)
50 @Service 56 @Service
51 public class ClusterMetadataManager 57 public class ClusterMetadataManager
52 - extends AbstractListenerManager<ClusterMetadataEvent, ClusterMetadataEventListener> 58 + extends AbstractListenerProviderRegistry<ClusterMetadataEvent,
53 - implements ClusterMetadataService, ClusterMetadataAdminService { 59 + ClusterMetadataEventListener,
60 + ClusterMetadataProvider,
61 + ClusterMetadataProviderService>
62 + implements ClusterMetadataService, ClusterMetadataAdminService, ClusterMetadataProviderRegistry {
54 63
55 private final Logger log = getLogger(getClass()); 64 private final Logger log = getLogger(getClass());
56 private ControllerNode localNode; 65 private ControllerNode localNode;
57 66
58 - private ClusterMetadataStoreDelegate delegate = new InternalStoreDelegate();
59 -
60 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 - protected ClusterMetadataStore store;
62 -
63 @Activate 67 @Activate
64 public void activate() { 68 public void activate() {
65 - store.setDelegate(delegate); 69 + // FIXME: Need to ensure all cluster metadata providers are registered before we activate
66 eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry); 70 eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry);
67 - establishSelfIdentity();
68 log.info("Started"); 71 log.info("Started");
69 } 72 }
70 73
71 @Deactivate 74 @Deactivate
72 public void deactivate() { 75 public void deactivate() {
73 - store.unsetDelegate(delegate);
74 eventDispatcher.removeSink(ClusterMetadataEvent.class); 76 eventDispatcher.removeSink(ClusterMetadataEvent.class);
75 log.info("Stopped"); 77 log.info("Stopped");
76 } 78 }
77 79
78 @Override 80 @Override
79 public ClusterMetadata getClusterMetadata() { 81 public ClusterMetadata getClusterMetadata() {
80 - return Versioned.valueOrElse(store.getClusterMetadata(), null); 82 + Versioned<ClusterMetadata> metadata = getProvider().getClusterMetadata();
83 + return metadata.value();
84 + }
85 +
86 +
87 + @Override
88 + protected ClusterMetadataProviderService createProviderService(
89 + ClusterMetadataProvider provider) {
90 + return new InternalClusterMetadataProviderService(provider);
81 } 91 }
82 92
83 @Override 93 @Override
84 public ControllerNode getLocalNode() { 94 public ControllerNode getLocalNode() {
95 + if (localNode == null) {
96 + establishSelfIdentity();
97 + }
85 return localNode; 98 return localNode;
86 } 99 }
87 100
88 @Override 101 @Override
89 public void setClusterMetadata(ClusterMetadata metadata) { 102 public void setClusterMetadata(ClusterMetadata metadata) {
90 checkNotNull(metadata, "Cluster metadata cannot be null"); 103 checkNotNull(metadata, "Cluster metadata cannot be null");
91 - store.setClusterMetadata(metadata); 104 + ClusterMetadataProvider primaryProvider = getPrimaryProvider();
105 + if (primaryProvider == null) {
106 + throw new IllegalStateException("Missing primary provider. Cannot update cluster metadata");
107 + }
108 + primaryProvider.setClusterMetadata(metadata);
92 } 109 }
93 110
94 - // Store delegate to re-post events emitted from the store. 111 + /**
95 - private class InternalStoreDelegate implements ClusterMetadataStoreDelegate { 112 + * Returns the provider to use for fetching cluster metadata.
96 - @Override 113 + * @return cluster metadata provider
97 - public void notify(ClusterMetadataEvent event) { 114 + */
98 - post(event); 115 + private ClusterMetadataProvider getProvider() {
116 + ClusterMetadataProvider primaryProvider = getPrimaryProvider();
117 + if (primaryProvider != null && primaryProvider.isAvailable()) {
118 + return primaryProvider;
119 + }
120 + log.warn("Primary cluster metadata provider not available. Using default fallback.");
121 + return getProvider("default");
122 + }
123 +
124 + /**
125 + * Returns the primary provider for cluster metadata.
126 + * @return primary cluster metadata provider
127 + */
128 + private ClusterMetadataProvider getPrimaryProvider() {
129 + try {
130 + URI uri = new URI(System.getProperty("onos.cluster.metadata.uri", "config:///cluster.json"));
131 + return getProvider(uri.getScheme());
132 + } catch (URISyntaxException e) {
133 + Throwables.propagate(e);
134 + return null;
99 } 135 }
100 } 136 }
101 137
...@@ -129,4 +165,25 @@ public class ClusterMetadataManager ...@@ -129,4 +165,25 @@ public class ClusterMetadataManager
129 throw new IllegalStateException("Cannot determine local IP", e); 165 throw new IllegalStateException("Cannot determine local IP", e);
130 } 166 }
131 } 167 }
168 +
169 + private class InternalClusterMetadataProviderService
170 + extends AbstractProviderService<ClusterMetadataProvider>
171 + implements ClusterMetadataProviderService {
172 +
173 + InternalClusterMetadataProviderService(ClusterMetadataProvider provider) {
174 + super(provider);
175 + }
176 +
177 + @Override
178 + public void clusterMetadataChanged(Versioned<ClusterMetadata> newMetadata) {
179 + log.info("Cluster metadata changed. New metadata: {}", newMetadata);
180 + post(new ClusterMetadataEvent(ClusterMetadataEvent.Type.METADATA_CHANGED, newMetadata.value()));
181 + }
182 +
183 + @Override
184 + public void newActiveMemberForPartition(PartitionId partitionId, NodeId nodeId) {
185 + log.info("Node {} is active member for partition {}", nodeId, partitionId);
186 + // TODO: notify listeners
187 + }
188 + }
132 } 189 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -13,39 +13,32 @@ ...@@ -13,39 +13,32 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.store.cluster.impl; 16 +package org.onosproject.cluster.impl;
17 17
18 -import static com.google.common.base.Preconditions.checkNotNull;
19 -import static java.net.NetworkInterface.getNetworkInterfaces;
20 import static org.slf4j.LoggerFactory.getLogger; 18 import static org.slf4j.LoggerFactory.getLogger;
21 19
22 import java.io.File; 20 import java.io.File;
23 import java.io.IOException; 21 import java.io.IOException;
24 -import java.net.InetAddress; 22 +import java.util.Set;
25 -import java.net.Inet4Address;
26 -import java.net.NetworkInterface;
27 -import java.util.Arrays;
28 -import java.util.Collection;
29 -import java.util.Collections;
30 import java.util.concurrent.atomic.AtomicReference; 23 import java.util.concurrent.atomic.AtomicReference;
31 -import java.util.function.Function;
32 24
33 import org.apache.felix.scr.annotations.Activate; 25 import org.apache.felix.scr.annotations.Activate;
34 import org.apache.felix.scr.annotations.Component; 26 import org.apache.felix.scr.annotations.Component;
35 import org.apache.felix.scr.annotations.Deactivate; 27 import org.apache.felix.scr.annotations.Deactivate;
36 -import org.apache.felix.scr.annotations.Service; 28 +import org.apache.felix.scr.annotations.Reference;
29 +import org.apache.felix.scr.annotations.ReferenceCardinality;
37 import org.onlab.packet.IpAddress; 30 import org.onlab.packet.IpAddress;
38 import org.onosproject.cluster.ClusterMetadata; 31 import org.onosproject.cluster.ClusterMetadata;
39 -import org.onosproject.cluster.ClusterMetadataEvent; 32 +import org.onosproject.cluster.ClusterMetadataProvider;
40 -import org.onosproject.cluster.ClusterMetadataStore; 33 +import org.onosproject.cluster.ClusterMetadataProviderRegistry;
41 -import org.onosproject.cluster.ClusterMetadataStoreDelegate; 34 +import org.onosproject.cluster.ClusterMetadataProviderService;
42 import org.onosproject.cluster.ControllerNode; 35 import org.onosproject.cluster.ControllerNode;
43 import org.onosproject.cluster.DefaultControllerNode; 36 import org.onosproject.cluster.DefaultControllerNode;
44 import org.onosproject.cluster.DefaultPartition; 37 import org.onosproject.cluster.DefaultPartition;
45 import org.onosproject.cluster.NodeId; 38 import org.onosproject.cluster.NodeId;
46 import org.onosproject.cluster.Partition; 39 import org.onosproject.cluster.Partition;
47 import org.onosproject.cluster.PartitionId; 40 import org.onosproject.cluster.PartitionId;
48 -import org.onosproject.store.AbstractStore; 41 +import org.onosproject.net.provider.ProviderId;
49 import org.onosproject.store.service.Versioned; 42 import org.onosproject.store.service.Versioned;
50 import org.slf4j.Logger; 43 import org.slf4j.Logger;
51 44
...@@ -60,31 +53,34 @@ import com.fasterxml.jackson.databind.ObjectMapper; ...@@ -60,31 +53,34 @@ import com.fasterxml.jackson.databind.ObjectMapper;
60 import com.fasterxml.jackson.databind.SerializerProvider; 53 import com.fasterxml.jackson.databind.SerializerProvider;
61 import com.fasterxml.jackson.databind.module.SimpleModule; 54 import com.fasterxml.jackson.databind.module.SimpleModule;
62 import com.google.common.base.Throwables; 55 import com.google.common.base.Throwables;
63 -import com.google.common.collect.Lists;
64 import com.google.common.collect.Sets; 56 import com.google.common.collect.Sets;
65 import com.google.common.io.Files; 57 import com.google.common.io.Files;
66 58
59 +import static com.google.common.base.Preconditions.checkState;
60 +
67 /** 61 /**
68 - * ClusterMetadataStore backed by a local file. 62 + * Provider of {@link ClusterMetadata cluster metadata} sourced from a local config file.
69 */ 63 */
70 -@Component(immediate = true, enabled = true) 64 +@Component(immediate = true)
71 -@Service 65 +public class ConfigFileBasedClusterMetadataProvider implements ClusterMetadataProvider {
72 -public class StaticClusterMetadataStore
73 - extends AbstractStore<ClusterMetadataEvent, ClusterMetadataStoreDelegate>
74 - implements ClusterMetadataStore {
75 66
76 private final Logger log = getLogger(getClass()); 67 private final Logger log = getLogger(getClass());
77 68
78 - private static final String ONOS_IP = "ONOS_IP"; 69 + // constants for filed names (used in serialization)
79 - private static final String ONOS_INTERFACE = "ONOS_INTERFACE"; 70 + private static final String ID = "id";
80 - private static final String ONOS_ALLOW_IPV6 = "ONOS_ALLOW_IPV6"; 71 + private static final String PORT = "port";
81 - private static final String DEFAULT_ONOS_INTERFACE = "eth0"; 72 + private static final String IP = "ip";
82 - private static final String CLUSTER_METADATA_FILE = "../config/cluster.json"; 73 +
83 - private static final int DEFAULT_ONOS_PORT = 9876; 74 + private static final File CONFIG_FILE = new File("../config/cluster.json");
84 - private final File metadataFile = new File(CLUSTER_METADATA_FILE); 75 +
85 - private AtomicReference<ClusterMetadata> metadata = new AtomicReference<>(); 76 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 + protected ClusterMetadataProviderRegistry providerRegistry;
78 +
79 + private static final ProviderId PROVIDER_ID = new ProviderId("config", "none");
80 + private AtomicReference<Versioned<ClusterMetadata>> cachedMetadata = new AtomicReference<>();
81 +
86 private ObjectMapper mapper; 82 private ObjectMapper mapper;
87 - private long version; 83 + private ClusterMetadataProviderService providerService;
88 84
89 @Activate 85 @Activate
90 public void activate() { 86 public void activate() {
...@@ -98,65 +94,38 @@ public class StaticClusterMetadataStore ...@@ -98,65 +94,38 @@ public class StaticClusterMetadataStore
98 module.addSerializer(PartitionId.class, new PartitionIdSerializer()); 94 module.addSerializer(PartitionId.class, new PartitionIdSerializer());
99 module.addDeserializer(PartitionId.class, new PartitionIdDeserializer()); 95 module.addDeserializer(PartitionId.class, new PartitionIdDeserializer());
100 mapper.registerModule(module); 96 mapper.registerModule(module);
101 - File metadataFile = new File(CLUSTER_METADATA_FILE); 97 + providerService = providerRegistry.register(this);
102 - if (metadataFile.exists()) {
103 - try {
104 - metadata.set(mapper.readValue(metadataFile, ClusterMetadata.class));
105 - version = metadataFile.lastModified();
106 - } catch (IOException e) {
107 - Throwables.propagate(e);
108 - }
109 - } else {
110 - String localIp = getSiteLocalAddress();
111 - ControllerNode localNode =
112 - new DefaultControllerNode(new NodeId(localIp), IpAddress.valueOf(localIp), DEFAULT_ONOS_PORT);
113 - // p0 partition
114 - Partition basePartition = new DefaultPartition(PartitionId.from(0), Sets.newHashSet(localNode.id()));
115 - // p1 partition
116 - Partition extendedPartition = new DefaultPartition(PartitionId.from(1), Sets.newHashSet(localNode.id()));
117 - metadata.set(ClusterMetadata.builder()
118 - .withName("default")
119 - .withControllerNodes(Arrays.asList(localNode))
120 - .withPartitions(Lists.newArrayList(basePartition, extendedPartition))
121 - .build());
122 - version = System.currentTimeMillis();
123 - }
124 log.info("Started"); 98 log.info("Started");
125 } 99 }
126 100
127 @Deactivate 101 @Deactivate
128 public void deactivate() { 102 public void deactivate() {
103 + providerRegistry.unregister(this);
129 log.info("Stopped"); 104 log.info("Stopped");
130 } 105 }
131 106
132 @Override 107 @Override
133 - public void setDelegate(ClusterMetadataStoreDelegate delegate) { 108 + public ProviderId id() {
134 - checkNotNull(delegate, "Delegate cannot be null"); 109 + return PROVIDER_ID;
135 - this.delegate = delegate;
136 } 110 }
137 111
138 @Override 112 @Override
139 - public void unsetDelegate(ClusterMetadataStoreDelegate delegate) { 113 + public Versioned<ClusterMetadata> getClusterMetadata() {
140 - this.delegate = null; 114 + checkState(isAvailable());
115 + synchronized (this) {
116 + if (cachedMetadata.get() == null) {
117 + loadMetadata();
141 } 118 }
142 - 119 + return cachedMetadata.get();
143 - @Override
144 - public boolean hasDelegate() {
145 - return this.delegate != null;
146 } 120 }
147 -
148 - @Override
149 - public Versioned<ClusterMetadata> getClusterMetadata() {
150 - return new Versioned<>(metadata.get(), version);
151 } 121 }
152 122
153 @Override 123 @Override
154 public void setClusterMetadata(ClusterMetadata metadata) { 124 public void setClusterMetadata(ClusterMetadata metadata) {
155 - checkNotNull(metadata);
156 try { 125 try {
157 - Files.createParentDirs(metadataFile); 126 + Files.createParentDirs(CONFIG_FILE);
158 - mapper.writeValue(metadataFile, metadata); 127 + mapper.writeValue(CONFIG_FILE, metadata);
159 - this.metadata.set(metadata); 128 + providerService.clusterMetadataChanged(new Versioned<>(metadata, CONFIG_FILE.lastModified()));
160 } catch (IOException e) { 129 } catch (IOException e) {
161 Throwables.propagate(e); 130 Throwables.propagate(e);
162 } 131 }
...@@ -173,13 +142,29 @@ public class StaticClusterMetadataStore ...@@ -173,13 +142,29 @@ public class StaticClusterMetadataStore
173 } 142 }
174 143
175 @Override 144 @Override
176 - public Collection<NodeId> getActivePartitionMembers(PartitionId partitionId) { 145 + public Set<NodeId> getActivePartitionMembers(PartitionId partitionId) {
177 - return metadata.get().getPartitions() 146 + throw new UnsupportedOperationException();
178 - .stream() 147 + }
179 - .filter(r -> r.getId().equals(partitionId)) 148 +
180 - .findFirst() 149 + @Override
181 - .map(r -> r.getMembers()) 150 + public boolean isAvailable() {
182 - .orElse(null); 151 + return CONFIG_FILE.exists();
152 + }
153 +
154 + private void loadMetadata() {
155 + ClusterMetadata metadata = null;
156 + long version = 0;
157 + try {
158 + metadata = mapper.readValue(CONFIG_FILE, ClusterMetadata.class);
159 + version = metadata.hashCode();
160 + } catch (IOException e) {
161 + Throwables.propagate(e);
162 + }
163 + cachedMetadata.set(new Versioned<>(new ClusterMetadata(PROVIDER_ID,
164 + metadata.getName(),
165 + Sets.newHashSet(metadata.getNodes()),
166 + Sets.newHashSet(metadata.getPartitions())),
167 + version));
183 } 168 }
184 169
185 private static class PartitionDeserializer extends JsonDeserializer<Partition> { 170 private static class PartitionDeserializer extends JsonDeserializer<Partition> {
...@@ -212,9 +197,9 @@ public class StaticClusterMetadataStore ...@@ -212,9 +197,9 @@ public class StaticClusterMetadataStore
212 public void serialize(ControllerNode node, JsonGenerator jgen, SerializerProvider provider) 197 public void serialize(ControllerNode node, JsonGenerator jgen, SerializerProvider provider)
213 throws IOException, JsonProcessingException { 198 throws IOException, JsonProcessingException {
214 jgen.writeStartObject(); 199 jgen.writeStartObject();
215 - jgen.writeStringField("id", node.id().toString()); 200 + jgen.writeStringField(ID, node.id().toString());
216 - jgen.writeStringField("ip", node.ip().toString()); 201 + jgen.writeStringField(IP, node.ip().toString());
217 - jgen.writeNumberField("port", node.tcpPort()); 202 + jgen.writeNumberField(PORT, node.tcpPort());
218 jgen.writeEndObject(); 203 jgen.writeEndObject();
219 } 204 }
220 } 205 }
...@@ -224,9 +209,9 @@ public class StaticClusterMetadataStore ...@@ -224,9 +209,9 @@ public class StaticClusterMetadataStore
224 public ControllerNode deserialize(JsonParser jp, DeserializationContext ctxt) 209 public ControllerNode deserialize(JsonParser jp, DeserializationContext ctxt)
225 throws IOException, JsonProcessingException { 210 throws IOException, JsonProcessingException {
226 JsonNode node = jp.getCodec().readTree(jp); 211 JsonNode node = jp.getCodec().readTree(jp);
227 - NodeId nodeId = new NodeId(node.get("id").textValue()); 212 + NodeId nodeId = new NodeId(node.get(ID).textValue());
228 - IpAddress ip = IpAddress.valueOf(node.get("ip").textValue()); 213 + IpAddress ip = IpAddress.valueOf(node.get(IP).textValue());
229 - int port = node.get("port").asInt(); 214 + int port = node.get(PORT).asInt();
230 return new DefaultControllerNode(nodeId, ip, port); 215 return new DefaultControllerNode(nodeId, ip, port);
231 } 216 }
232 } 217 }
...@@ -247,62 +232,4 @@ public class StaticClusterMetadataStore ...@@ -247,62 +232,4 @@ public class StaticClusterMetadataStore
247 return new NodeId(node.asText()); 232 return new NodeId(node.asText());
248 } 233 }
249 } 234 }
250 -
251 -
252 - private static String getSiteLocalAddress() {
253 -
254 - /*
255 - * If the IP ONOS should use is set via the environment variable we will assume it is valid and should be used.
256 - * Setting the IP address takes presidence over setting the interface via the environment.
257 - */
258 - String useOnosIp = System.getenv(ONOS_IP);
259 - if (useOnosIp != null) {
260 - return useOnosIp;
261 - }
262 -
263 - // Read environment variables for IP interface information or set to default
264 - String useOnosInterface = System.getenv(ONOS_INTERFACE);
265 - if (useOnosInterface == null) {
266 - useOnosInterface = DEFAULT_ONOS_INTERFACE;
267 - }
268 -
269 - // Capture if they want to limit IP address selection to only IPv4 (default).
270 - boolean allowIPv6 = (System.getenv(ONOS_ALLOW_IPV6) != null);
271 -
272 - Function<NetworkInterface, IpAddress> ipLookup = nif -> {
273 - IpAddress fallback = null;
274 -
275 - // nif can be null if the interface name specified doesn't exist on the node's host
276 - if (nif != null) {
277 - for (InetAddress address : Collections.list(nif.getInetAddresses())) {
278 - if (address.isSiteLocalAddress() && (allowIPv6 || address instanceof Inet4Address)) {
279 - return IpAddress.valueOf(address);
280 - }
281 - if (fallback == null && !address.isLoopbackAddress() && !address.isMulticastAddress()
282 - && (allowIPv6 || address instanceof Inet4Address)) {
283 - fallback = IpAddress.valueOf(address);
284 - }
285 - }
286 - }
287 - return fallback;
288 - };
289 - try {
290 - IpAddress ip = ipLookup.apply(NetworkInterface.getByName(useOnosInterface));
291 - if (ip != null) {
292 - return ip.toString();
293 - }
294 - for (NetworkInterface nif : Collections.list(getNetworkInterfaces())) {
295 - if (!nif.getName().equals(useOnosInterface)) {
296 - ip = ipLookup.apply(nif);
297 - if (ip != null) {
298 - return ip.toString();
299 - }
300 - }
301 - }
302 - } catch (Exception e) {
303 - throw new IllegalStateException("Unable to get network interfaces", e);
304 - }
305 -
306 - return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString();
307 - }
308 } 235 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +/*
2 + * Copyright 2015-2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.cluster.impl;
17 +
18 +import static java.net.NetworkInterface.getNetworkInterfaces;
19 +import static org.slf4j.LoggerFactory.getLogger;
20 +
21 +import java.net.Inet4Address;
22 +import java.net.InetAddress;
23 +import java.net.NetworkInterface;
24 +import java.util.Collections;
25 +import java.util.Set;
26 +import java.util.concurrent.atomic.AtomicReference;
27 +import java.util.function.Function;
28 +
29 +import org.apache.felix.scr.annotations.Activate;
30 +import org.apache.felix.scr.annotations.Component;
31 +import org.apache.felix.scr.annotations.Deactivate;
32 +import org.apache.felix.scr.annotations.Reference;
33 +import org.apache.felix.scr.annotations.ReferenceCardinality;
34 +import org.onlab.packet.IpAddress;
35 +import org.onosproject.cluster.ClusterMetadata;
36 +import org.onosproject.cluster.ClusterMetadataProvider;
37 +import org.onosproject.cluster.ClusterMetadataProviderRegistry;
38 +import org.onosproject.cluster.ControllerNode;
39 +import org.onosproject.cluster.DefaultControllerNode;
40 +import org.onosproject.cluster.DefaultPartition;
41 +import org.onosproject.cluster.NodeId;
42 +import org.onosproject.cluster.Partition;
43 +import org.onosproject.cluster.PartitionId;
44 +import org.onosproject.net.provider.ProviderId;
45 +import org.onosproject.store.service.Versioned;
46 +import org.slf4j.Logger;
47 +
48 +import com.google.common.collect.ImmutableSet;
49 +import com.google.common.collect.Sets;
50 +
51 +/**
52 + * Provider of default {@link ClusterMetadata cluster metadata}.
53 + */
54 +@Component(immediate = true)
55 +public class DefaultClusterMetadataProvider implements ClusterMetadataProvider {
56 +
57 + private final Logger log = getLogger(getClass());
58 +
59 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
60 + protected ClusterMetadataProviderRegistry providerRegistry;
61 +
62 + private static final String ONOS_IP = "ONOS_IP";
63 + private static final String ONOS_INTERFACE = "ONOS_INTERFACE";
64 + private static final String ONOS_ALLOW_IPV6 = "ONOS_ALLOW_IPV6";
65 + private static final String DEFAULT_ONOS_INTERFACE = "eth0";
66 + private static final int DEFAULT_ONOS_PORT = 9876;
67 + private static final ProviderId PROVIDER_ID = new ProviderId("default", "none");
68 + private AtomicReference<Versioned<ClusterMetadata>> cachedMetadata = new AtomicReference<>();
69 +
70 + @Activate
71 + public void activate() {
72 + String localIp = getSiteLocalAddress();
73 + ControllerNode localNode =
74 + new DefaultControllerNode(new NodeId(localIp), IpAddress.valueOf(localIp), DEFAULT_ONOS_PORT);
75 + // p0 partition
76 + Partition basePartition = new DefaultPartition(PartitionId.from(0), Sets.newHashSet(localNode.id()));
77 + // p1 partition
78 + Partition extendedPartition = new DefaultPartition(PartitionId.from(1), Sets.newHashSet(localNode.id()));
79 + ClusterMetadata metadata = new ClusterMetadata(PROVIDER_ID,
80 + "default",
81 + ImmutableSet.of(localNode),
82 + ImmutableSet.of(basePartition, extendedPartition));
83 + long version = System.currentTimeMillis();
84 + cachedMetadata.set(new Versioned<>(metadata, version));
85 + providerRegistry.register(this);
86 + log.info("Started");
87 + }
88 +
89 + @Deactivate
90 + public void deactivate() {
91 + providerRegistry.unregister(this);
92 + log.info("Stopped");
93 + }
94 +
95 + @Override
96 + public ProviderId id() {
97 + return PROVIDER_ID;
98 + }
99 +
100 + @Override
101 + public Versioned<ClusterMetadata> getClusterMetadata() {
102 + return cachedMetadata.get();
103 + }
104 +
105 + @Override
106 + public void setClusterMetadata(ClusterMetadata metadata) {
107 + throw new UnsupportedOperationException();
108 + }
109 +
110 + @Override
111 + public void addActivePartitionMember(PartitionId partitionId, NodeId nodeId) {
112 + throw new UnsupportedOperationException();
113 + }
114 +
115 + @Override
116 + public void removeActivePartitionMember(PartitionId partitionId, NodeId nodeId) {
117 + throw new UnsupportedOperationException();
118 + }
119 +
120 + @Override
121 + public Set<NodeId> getActivePartitionMembers(PartitionId partitionId) {
122 + throw new UnsupportedOperationException();
123 + }
124 +
125 + @Override
126 + public boolean isAvailable() {
127 + return true;
128 + }
129 +
130 + private static String getSiteLocalAddress() {
131 +
132 + /*
133 + * If the IP ONOS should use is set via the environment variable we will assume it is valid and should be used.
134 + * Setting the IP address takes presidence over setting the interface via the environment.
135 + */
136 + String useOnosIp = System.getenv(ONOS_IP);
137 + if (useOnosIp != null) {
138 + return useOnosIp;
139 + }
140 +
141 + // Read environment variables for IP interface information or set to default
142 + String useOnosInterface = System.getenv(ONOS_INTERFACE);
143 + if (useOnosInterface == null) {
144 + useOnosInterface = DEFAULT_ONOS_INTERFACE;
145 + }
146 +
147 + // Capture if they want to limit IP address selection to only IPv4 (default).
148 + boolean allowIPv6 = (System.getenv(ONOS_ALLOW_IPV6) != null);
149 +
150 + Function<NetworkInterface, IpAddress> ipLookup = nif -> {
151 + IpAddress fallback = null;
152 +
153 + // nif can be null if the interface name specified doesn't exist on the node's host
154 + if (nif != null) {
155 + for (InetAddress address : Collections.list(nif.getInetAddresses())) {
156 + if (address.isSiteLocalAddress() && (allowIPv6 || address instanceof Inet4Address)) {
157 + return IpAddress.valueOf(address);
158 + }
159 + if (fallback == null && !address.isLoopbackAddress() && !address.isMulticastAddress()
160 + && (allowIPv6 || address instanceof Inet4Address)) {
161 + fallback = IpAddress.valueOf(address);
162 + }
163 + }
164 + }
165 + return fallback;
166 + };
167 + try {
168 + IpAddress ip = ipLookup.apply(NetworkInterface.getByName(useOnosInterface));
169 + if (ip != null) {
170 + return ip.toString();
171 + }
172 + for (NetworkInterface nif : Collections.list(getNetworkInterfaces())) {
173 + if (!nif.getName().equals(useOnosInterface)) {
174 + ip = ipLookup.apply(nif);
175 + if (ip != null) {
176 + return ip.toString();
177 + }
178 + }
179 + }
180 + } catch (Exception e) {
181 + throw new IllegalStateException("Unable to get network interfaces", e);
182 + }
183 +
184 + return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString();
185 + }
186 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -954,10 +954,9 @@ public class LldpLinkProviderTest { ...@@ -954,10 +954,9 @@ public class LldpLinkProviderTest {
954 final NodeId nid = new NodeId("test-node"); 954 final NodeId nid = new NodeId("test-node");
955 final IpAddress addr = IpAddress.valueOf(0); 955 final IpAddress addr = IpAddress.valueOf(0);
956 final Partition p = new DefaultPartition(PartitionId.from(1), Sets.newHashSet(nid)); 956 final Partition p = new DefaultPartition(PartitionId.from(1), Sets.newHashSet(nid));
957 - return ClusterMetadata.builder() 957 + return new ClusterMetadata("test-cluster",
958 - .withName("test-cluster") 958 + Sets.newHashSet(new DefaultControllerNode(nid, addr)),
959 - .withControllerNodes(Sets.newHashSet(new DefaultControllerNode(nid, addr))) 959 + Sets.newHashSet(p));
960 - .withPartitions(Sets.newHashSet(p)).build();
961 } 960 }
962 961
963 @Override 962 @Override
......