Committed by
Gerrit Code Review
Using provider pattern for cluster metadata.
Change-Id: I5a572b3df9149be959dde9868a9c594dec26a3e0
Showing
10 changed files
with
386 additions
and
136 deletions
... | @@ -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; | ||
49 | 50 | ||
50 | - /** | 51 | + private ClusterMetadata() { |
51 | - * Returns a new cluster metadata builder. | 52 | + providerId = null; |
52 | - * @return The cluster metadata builder. | 53 | + name = null; |
53 | - */ | 54 | + nodes = null; |
54 | - public static Builder builder() { | 55 | + partitions = null; |
55 | - return new Builder(); | 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 | + } | ||
74 | + | ||
75 | + public ClusterMetadata(String name, | ||
76 | + Set<ControllerNode> nodes, | ||
77 | + Set<Partition> partitions) { | ||
78 | + this(new ProviderId("none", "none"), name, nodes, partitions); | ||
79 | + } | ||
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); | ||
76 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
79 | + Set<NodeId> getActivePartitionMembers(PartitionId partitionId); | ||
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> { | ||
24 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
23 | +public interface ClusterMetadataProviderRegistry | ||
24 | + extends ProviderRegistry<ClusterMetadataProvider, ClusterMetadataProviderService> { | ||
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 | ... | ... |
This diff is collapsed. Click to expand it.
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 | ... | ... |
-
Please register or login to post a comment