mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-15 17:31:31 +02:00
Add rolling upgrade test.
Change-Id: Id1b09361aa69f1665f19c312933798b5206d46ac
This commit is contained in:
parent
a84936d87e
commit
ca7660a289
@ -18,6 +18,7 @@ package org.onosproject.distributedprimitives.cli;
|
|||||||
import org.apache.karaf.shell.commands.Argument;
|
import org.apache.karaf.shell.commands.Argument;
|
||||||
import org.apache.karaf.shell.commands.Command;
|
import org.apache.karaf.shell.commands.Command;
|
||||||
import org.onosproject.cli.AbstractShellCommand;
|
import org.onosproject.cli.AbstractShellCommand;
|
||||||
|
import org.onosproject.core.Version;
|
||||||
import org.onosproject.store.serializers.KryoNamespaces;
|
import org.onosproject.store.serializers.KryoNamespaces;
|
||||||
import org.onosproject.store.service.ConsistentMap;
|
import org.onosproject.store.service.ConsistentMap;
|
||||||
import org.onosproject.store.service.Serializer;
|
import org.onosproject.store.service.Serializer;
|
||||||
@ -64,6 +65,8 @@ public class ConsistentMapTestCommand extends AbstractShellCommand {
|
|||||||
map = storageService.<String, String>consistentMapBuilder()
|
map = storageService.<String, String>consistentMapBuilder()
|
||||||
.withName(name)
|
.withName(name)
|
||||||
.withSerializer(Serializer.using(KryoNamespaces.BASIC))
|
.withSerializer(Serializer.using(KryoNamespaces.BASIC))
|
||||||
|
.withVersion(Version.version("1.0.0"))
|
||||||
|
.withCompatibilityFunction((value, version) -> version + ":" + value)
|
||||||
.build();
|
.build();
|
||||||
if ("get".equals(operation)) {
|
if ("get".equals(operation)) {
|
||||||
print(map.get(arg1));
|
print(map.get(arg1));
|
||||||
@ -95,6 +98,22 @@ public class ConsistentMapTestCommand extends AbstractShellCommand {
|
|||||||
} else {
|
} else {
|
||||||
print("%b", map.replace(arg1, arg2, arg3));
|
print("%b", map.replace(arg1, arg2, arg3));
|
||||||
}
|
}
|
||||||
|
} else if ("compatiblePut".equals(operation)) {
|
||||||
|
ConsistentMap<String, String> map = storageService.<String, String>consistentMapBuilder()
|
||||||
|
.withName(name)
|
||||||
|
.withSerializer(Serializer.using(KryoNamespaces.BASIC))
|
||||||
|
.withCompatibilityFunction((value, version) -> version + ":" + value)
|
||||||
|
.withVersion(Version.version("2.0.0"))
|
||||||
|
.build();
|
||||||
|
print(map.put(arg1, arg2));
|
||||||
|
} else if ("compatibleGet".equals(operation)) {
|
||||||
|
ConsistentMap<String, String> map = storageService.<String, String>consistentMapBuilder()
|
||||||
|
.withName(name)
|
||||||
|
.withSerializer(Serializer.using(KryoNamespaces.BASIC))
|
||||||
|
.withCompatibilityFunction((value, version) -> version + ":" + value)
|
||||||
|
.withVersion(Version.version("2.0.0"))
|
||||||
|
.build();
|
||||||
|
print(map.get(arg1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +100,9 @@ public final class Version implements Comparable<Version> {
|
|||||||
public static Version fromInt(int version) {
|
public static Version fromInt(int version) {
|
||||||
int major = (version >> 24) & 0xff;
|
int major = (version >> 24) & 0xff;
|
||||||
int minor = (version >> 16) & 0xff;
|
int minor = (version >> 16) & 0xff;
|
||||||
int patch = (version) & 0xffff;
|
int patch = (version >> 8) & 0xff;
|
||||||
return new Version(major, minor, String.valueOf(patch), null);
|
int build = version & 0xff;
|
||||||
|
return new Version(major, minor, String.valueOf(patch), String.valueOf(build));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,13 +158,30 @@ public final class Version implements Comparable<Version> {
|
|||||||
public int toInt() {
|
public int toInt() {
|
||||||
byte major = (byte) this.major;
|
byte major = (byte) this.major;
|
||||||
byte minor = (byte) this.minor;
|
byte minor = (byte) this.minor;
|
||||||
short patch;
|
|
||||||
|
byte patch;
|
||||||
|
if (this.patch != null) {
|
||||||
try {
|
try {
|
||||||
patch = (short) Integer.parseInt(this.patch);
|
patch = (byte) Integer.parseInt(this.patch.replaceAll("[^0-9]", ""));
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
patch = 0;
|
patch = 0;
|
||||||
}
|
}
|
||||||
return major << 24 | (minor & 0xff) << 16 | (patch & 0xffff);
|
} else {
|
||||||
|
patch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte build;
|
||||||
|
if (this.build != null) {
|
||||||
|
try {
|
||||||
|
build = (byte) Integer.parseInt(this.build.replaceAll("[^0-9]", ""));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
build = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
build = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return major << 24 | (minor & 0xff) << 16 | (patch & 0xff) << 8 | (build & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,25 +83,30 @@ public class VersionTest {
|
|||||||
|
|
||||||
version1 = version("1.2");
|
version1 = version("1.2");
|
||||||
version2 = Version.fromInt(version1.toInt());
|
version2 = Version.fromInt(version1.toInt());
|
||||||
assertEquals(version2, version(1, 2, "0", null));
|
assertEquals(version2, version(1, 2, "0", "0"));
|
||||||
|
|
||||||
version1 = version("1.2.foo.bar");
|
version1 = version("1.2.foo.bar");
|
||||||
version2 = Version.fromInt(version1.toInt());
|
version2 = Version.fromInt(version1.toInt());
|
||||||
assertEquals(version2, version(1, 2, "0", null));
|
assertEquals(version2, version(1, 2, "0", "0"));
|
||||||
|
|
||||||
version1 = version("1.2.3");
|
version1 = version("1.2.3");
|
||||||
version2 = Version.fromInt(version1.toInt());
|
version2 = Version.fromInt(version1.toInt());
|
||||||
assertEquals(version2, version(1, 2, "3", null));
|
assertEquals(version2, version(1, 2, "3", "0"));
|
||||||
|
|
||||||
version1 = version("255.254.65535.252");
|
version1 = version("1.2.3-SNAPSHOT");
|
||||||
version2 = Version.fromInt(version1.toInt());
|
version2 = Version.fromInt(version1.toInt());
|
||||||
assertEquals(version2, version(255, 254, "65535", null));
|
assertEquals(version2, version(1, 2, "3", "0"));
|
||||||
|
|
||||||
|
version1 = version("255.254.253.252");
|
||||||
|
version2 = Version.fromInt(version1.toInt());
|
||||||
|
assertEquals(version2, version(255, 254, "253", "252"));
|
||||||
|
|
||||||
assertTrue(version("0.0.2").toInt() > version("0.0.1").toInt());
|
assertTrue(version("0.0.2").toInt() > version("0.0.1").toInt());
|
||||||
assertTrue(version("0.1.0").toInt() > version("0.0.1").toInt());
|
assertTrue(version("0.1.0").toInt() > version("0.0.1").toInt());
|
||||||
assertTrue(version("1.0.0").toInt() > version("0.1.0").toInt());
|
assertTrue(version("1.0.0").toInt() > version("0.1.0").toInt());
|
||||||
assertTrue(version("1.1.0").toInt() > version("1.0.1").toInt());
|
assertTrue(version("1.1.0").toInt() > version("1.0.1").toInt());
|
||||||
assertTrue(version("2.1.1").toInt() > version("1.10.10").toInt());
|
assertTrue(version("2.1.1").toInt() > version("1.10.10").toInt());
|
||||||
|
assertTrue(version("0.1.0-rc2").toInt() > version("0.1.0-rc1").toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -105,13 +105,6 @@ public class UpgradeManager
|
|||||||
|
|
||||||
Upgrade upgrade = getState();
|
Upgrade upgrade = getState();
|
||||||
|
|
||||||
// If the upgrade state is not initialized, ensure this node matches the version of the cluster.
|
|
||||||
if (!upgrade.status().active() && !Objects.equals(upgrade.source(), localVersion)) {
|
|
||||||
log.error("Node version {} inconsistent with cluster version {}", localVersion, upgrade.source());
|
|
||||||
throw new IllegalStateException("Node version " + localVersion +
|
|
||||||
" inconsistent with cluster version " + upgrade.source());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the upgrade state is initialized then check the node version.
|
// If the upgrade state is initialized then check the node version.
|
||||||
if (upgrade.status() == Upgrade.Status.INITIALIZED) {
|
if (upgrade.status() == Upgrade.Status.INITIALIZED) {
|
||||||
// If the source version equals the target version, attempt to update the target version.
|
// If the source version equals the target version, attempt to update the target version.
|
||||||
|
@ -19,11 +19,17 @@ import com.google.common.collect.Sets;
|
|||||||
import io.atomix.protocols.raft.proxy.RaftProxy;
|
import io.atomix.protocols.raft.proxy.RaftProxy;
|
||||||
import io.atomix.protocols.raft.service.RaftService;
|
import io.atomix.protocols.raft.service.RaftService;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.onlab.util.HexString;
|
||||||
import org.onlab.util.Tools;
|
import org.onlab.util.Tools;
|
||||||
import org.onosproject.store.primitives.MapUpdate;
|
import org.onosproject.store.primitives.MapUpdate;
|
||||||
import org.onosproject.store.primitives.TransactionId;
|
import org.onosproject.store.primitives.TransactionId;
|
||||||
|
import org.onosproject.store.primitives.impl.CompatibleValue;
|
||||||
|
import org.onosproject.store.primitives.impl.DistributedPrimitives;
|
||||||
|
import org.onosproject.store.serializers.KryoNamespaces;
|
||||||
|
import org.onosproject.store.service.AsyncConsistentMap;
|
||||||
import org.onosproject.store.service.MapEvent;
|
import org.onosproject.store.service.MapEvent;
|
||||||
import org.onosproject.store.service.MapEventListener;
|
import org.onosproject.store.service.MapEventListener;
|
||||||
|
import org.onosproject.store.service.Serializer;
|
||||||
import org.onosproject.store.service.TransactionLog;
|
import org.onosproject.store.service.TransactionLog;
|
||||||
import org.onosproject.store.service.Version;
|
import org.onosproject.store.service.Version;
|
||||||
import org.onosproject.store.service.Versioned;
|
import org.onosproject.store.service.Versioned;
|
||||||
@ -584,6 +590,50 @@ public class AtomixConsistentMapTest extends AtomixTestBase<AtomixConsistentMap>
|
|||||||
assertTrue(Arrays.equals(value2, event.newValue().value()));
|
assertTrue(Arrays.equals(value2, event.newValue().value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompatibilityFunction() throws Throwable {
|
||||||
|
AtomixConsistentMap atomixMap = newPrimitive("testCompatibilityFunction");
|
||||||
|
|
||||||
|
Serializer rawSerializer = Serializer.using(KryoNamespaces.API, CompatibleValue.class);
|
||||||
|
Serializer valueSerializer = Serializer.using(KryoNamespaces.BASIC);
|
||||||
|
|
||||||
|
// Convert the byte[] value to CompatibleValue<byte[]>
|
||||||
|
AsyncConsistentMap<String, CompatibleValue<byte[]>> rawMap = DistributedPrimitives.newTranscodingMap(
|
||||||
|
atomixMap,
|
||||||
|
key -> HexString.toHexString(rawSerializer.encode(key)),
|
||||||
|
string -> rawSerializer.decode(HexString.fromHexString(string)),
|
||||||
|
value -> value == null ? null : rawSerializer.encode(value),
|
||||||
|
bytes -> rawSerializer.decode(bytes));
|
||||||
|
|
||||||
|
// Convert the CompatibleValue<byte[]> value to CompatibleValue<V> using the user-provided serializer.
|
||||||
|
AsyncConsistentMap<String, CompatibleValue<String>> compatibleMap =
|
||||||
|
DistributedPrimitives.newTranscodingMap(
|
||||||
|
rawMap,
|
||||||
|
key -> key,
|
||||||
|
key -> key,
|
||||||
|
value -> value == null ? null :
|
||||||
|
new CompatibleValue<byte[]>(valueSerializer.encode(value.value()), value.version()),
|
||||||
|
value -> value == null ? null :
|
||||||
|
new CompatibleValue<String>(valueSerializer.decode(value.value()), value.version()));
|
||||||
|
|
||||||
|
AsyncConsistentMap<String, String> map1 = DistributedPrimitives.newCompatibleMap(
|
||||||
|
compatibleMap,
|
||||||
|
(value, version) -> version + ":" + value,
|
||||||
|
org.onosproject.core.Version.version("1.0.0"));
|
||||||
|
AsyncConsistentMap<String, String> map2 = DistributedPrimitives.newCompatibleMap(
|
||||||
|
compatibleMap,
|
||||||
|
(value, version) -> version + ":" + value,
|
||||||
|
org.onosproject.core.Version.version("1.0.1"));
|
||||||
|
|
||||||
|
map1.put("foo", "Hello world!").join();
|
||||||
|
assertEquals("Hello world!", map1.get("foo").join().value());
|
||||||
|
assertEquals("1.0.0:Hello world!", map2.get("foo").join().value());
|
||||||
|
|
||||||
|
map2.put("bar", "Hello world again!").join();
|
||||||
|
assertEquals("Hello world again!", map2.get("bar").join().value());
|
||||||
|
assertEquals("1.0.1:Hello world again!", map1.get("bar").join().value());
|
||||||
|
}
|
||||||
|
|
||||||
private static class TestMapEventListener implements MapEventListener<String, byte[]> {
|
private static class TestMapEventListener implements MapEventListener<String, byte[]> {
|
||||||
|
|
||||||
private final BlockingQueue<MapEvent<String, byte[]>> queue = new ArrayBlockingQueue<>(1);
|
private final BlockingQueue<MapEvent<String, byte[]>> queue = new ArrayBlockingQueue<>(1);
|
||||||
|
82
tools/test/scenarios/rolling-upgrade.xml
Normal file
82
tools/test/scenarios/rolling-upgrade.xml
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright 2018-present Open Networking Foundation
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<scenario name="rolling-upgrade" description="ONOS cluster rolling upgrade">
|
||||||
|
<import file="${ONOS_SCENARIOS}/dist-setup.xml"/>
|
||||||
|
<dependency name="Distributed-Primitives-Setup"/>
|
||||||
|
|
||||||
|
<group name="Upgrade" requires="Distributed-Primitives-Setup">
|
||||||
|
<step name="Push-Bits" exec="onos-push-bits-through-proxy" if="${OCT}"/>
|
||||||
|
|
||||||
|
<group name="Perform-Upgrade">
|
||||||
|
<sequential var="${OC#}"
|
||||||
|
starts="Stop-Service-${#}"
|
||||||
|
ends="Wait-for-Start-${#-1}">
|
||||||
|
<step name="Stop-Service-${#}"
|
||||||
|
exec="onos-service ${OC#} stop"/>
|
||||||
|
|
||||||
|
<step name="Wait-for-Stop-${#}"
|
||||||
|
exec="onos-wait-for-stop ${OC#}"
|
||||||
|
requires="~Stop-Service-${#}"/>
|
||||||
|
|
||||||
|
<step name="Uninstall-${#}"
|
||||||
|
exec="onos-uninstall ${OC#}"
|
||||||
|
requires="~Wait-for-Stop-${#}"/>
|
||||||
|
|
||||||
|
<step name="Push-Bits-${#}"
|
||||||
|
exec="onos-push-bits ${OC#}"
|
||||||
|
unless="${OCT}"
|
||||||
|
requires="~Stop-Service-${#}"/>
|
||||||
|
|
||||||
|
<step name="Install-Upgrade-${#}"
|
||||||
|
exec="onos-install -v ${OC#}"
|
||||||
|
requires="Push-Bits-${#},Push-Bits,Uninstall-${#}"/>
|
||||||
|
|
||||||
|
<step name="Secure-SSH-${#}"
|
||||||
|
exec="onos-secure-ssh -u ${ONOS_WEB_USER} -p ${ONOS_WEB_PASS} ${OC#}"
|
||||||
|
requires="~Install-Upgrade-${#}"/>
|
||||||
|
|
||||||
|
<step name="Wait-for-Start-${#}"
|
||||||
|
exec="onos-wait-for-start ${OC#}"
|
||||||
|
requires="Secure-SSH-${#}"/>
|
||||||
|
|
||||||
|
<step name="Distributed-Primitives-Check-Apps-${#}"
|
||||||
|
exec="onos-check-apps ${OC#} distributedprimitives includes"
|
||||||
|
requires="Wait-for-Start-${#}"/>
|
||||||
|
</sequential>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group name="Verify-Upgrade" requires="Perform-Upgrade">
|
||||||
|
<parallel var="${OC#}">
|
||||||
|
<step name="Check-Nodes-${#}"
|
||||||
|
exec="onos-check-nodes ${OC#}"
|
||||||
|
delay="3"/>
|
||||||
|
|
||||||
|
<step name="Check-Components-${#}"
|
||||||
|
exec="onos-check-components ${OC#}"
|
||||||
|
delay="5"
|
||||||
|
requires="~Check-Nodes-${#}"/>
|
||||||
|
|
||||||
|
<step name="Check-Logs-${#}"
|
||||||
|
exec="onos-check-logs ${OC#}"
|
||||||
|
requires="~Check-Components-${#}"/>
|
||||||
|
|
||||||
|
<step name="Check-Apps-${#}"
|
||||||
|
exec="onos-check-apps ${OC#} ${ONOS_APPS},distributedprimitives includes"
|
||||||
|
requires="~Check-Components-${#}"/>
|
||||||
|
</parallel>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</scenario>
|
Loading…
x
Reference in New Issue
Block a user