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