Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport to main]Adding backwards compatibility test for ml-commons plugin (#681) #776

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/test_bwc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Test MLCommons BWC
on:
push:
branches:
- "*"
pull_request:
branches:
- "*"

jobs:
Build-ad:
strategy:
matrix:
java: [11,17]
fail-fast: false

name: Test MLCommons BWC
runs-on: ubuntu-latest

steps:
- name: Setup Java ${{ matrix.java }}
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}

# ml-commons
- name: Checkout MLCommons
uses: actions/checkout@v2

- name: Assemble MLCommons
run: |
plugin_version=`./gradlew properties -q | grep "opensearch_build:" | awk '{print $2}'`
echo plugin_version $plugin_version
./gradlew assemble
echo "Creating ./plugin/src/test/resources/org/opensearch/ml/bwc..."
mkdir -p ./plugin/src/test/resources/org/opensearch/ml/bwc
- name: Run MLCommons Backwards Compatibility Tests
run: |
echo "Running backwards compatibility tests ..."
./gradlew bwcTestSuite -Dtests.security.manager=false
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ client/build/
common/build/
ml-algorithms/build/
plugin/build/
plugin/src/test/resources/bwc/*
.DS_Store
4 changes: 4 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ This package uses the [Gradle](https://docs.gradle.org/current/userguide/usergui
6. `./gradlew integTest -Dtests.method="<method name>"` run specific integ test method, for example `./gradlew integTest -Dtests.method="testTrainAndPredictKmeans"`
7. `./gradlew integTest -Dtests.rest.cluster=localhost:9200 -Dtests.cluster=localhost:9200 -Dtests.clustername="docker-cluster" -Dhttps=true -Duser=admin -Dpassword=admin` launches integration tests against a local cluster and run tests with security. Detail steps: (1)download OpenSearch tarball to local and install by running `opensearch-tar-install.sh`; (2)build ML plugin zip with your change and install ML plugin zip; (3)restart local test cluster; (4) run this gradle command to test.
8. `./gradlew spotlessApply` formats code. And/or import formatting rules in `.eclipseformat.xml` with IDE.
9. `./gradlew adBwcCluster#mixedClusterTask -Dtests.security.manager=false` launches a cluster with three nodes of bwc version of OpenSearch with anomaly-detection and job-scheduler and tests backwards compatibility by upgrading one of the nodes with the current version of OpenSearch with anomaly-detection and job-scheduler creating a mixed cluster.
10. `./gradlew adBwcCluster#rollingUpgradeClusterTask -Dtests.security.manager=false` launches a cluster with three nodes of bwc version of OpenSearch with anomaly-detection and job-scheduler and tests backwards compatibility by performing rolling upgrade of each node with the current version of OpenSearch with anomaly-detection and job-scheduler.
11. `./gradlew adBwcCluster#fullRestartClusterTask -Dtests.security.manager=false` launches a cluster with three nodes of bwc version of OpenSearch with anomaly-detection and job-scheduler and tests backwards compatibility by performing a full restart on the cluster upgrading all the nodes with the current version of OpenSearch with anomaly-detection and job-scheduler.
12. `./gradlew bwcTestSuite -Dtests.security.manager=false` runs all the above bwc tests combined.

When launching a cluster using one of the above commands logs are placed in `/build/cluster/run node0/opensearch-<version>/logs`. Though the logs are teed to the console, in practices it's best to check the actual log file.

Expand Down
171 changes: 170 additions & 1 deletion plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ integTest {
}
}

// BWC test can only run within the BWC gradle task bwcsuite or its dependent tasks.
if (System.getProperty('tests.rest.bwcsuite') == null) {
filter {
excludeTestsMatching "org.opensearch.ml.bwc.*IT"
}
}

// The 'doFirst' delays till execution time.
doFirst {
// Tell the test JVM if the cluster JVM is running under a debugger so that tests can
Expand Down Expand Up @@ -266,7 +273,8 @@ List<String> jacocoExclusions = [
'org.opensearch.ml.task.MLExecuteTaskRunner',
'org.opensearch.ml.action.profile.MLProfileTransportAction',
'org.opensearch.ml.action.models.DeleteModelTransportAction.1',
'org.opensearch.ml.rest.RestMLPredictionAction'
'org.opensearch.ml.rest.RestMLPredictionAction',
'org.opensearch.ml.breaker.DiskCircuitBreaker'
]

jacocoTestCoverageVerification {
Expand Down Expand Up @@ -383,3 +391,164 @@ tasks.withType(licenseHeaders.class) {
checkstyle {
toolVersion = '8.29'
}

String bwcVersion = "2.4.0.0"
String bwcShortVersion = bwcVersion[0..4]
String baseName = "mlCommonsBwcCluster"
String bwcMlPlugin = "opensearch-ml-" + bwcVersion + ".zip"
String bwcFilePath = "src/test/resources/org/opensearch/ml/bwc/"
String bwcRemoteFile = "https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/" + bwcShortVersion + "/latest/linux/x64/tar/builds/opensearch/plugins/" + bwcMlPlugin
String opensearchMlPlugin = "opensearch-ml-" + project.version + ".zip"

2.times {i ->
testClusters {
"${baseName}$i" {
testDistribution = "ARCHIVE"
versions = [bwcShortVersion, opensearch_version]
numberOfNodes = 3
plugin(provider(new Callable<RegularFile>() {
@Override
RegularFile call() throws Exception {
return new RegularFile() {
@Override
File getAsFile() {
File bwcDir = new File('./plugin/' + bwcFilePath)
if (!bwcDir.exists()) {
bwcDir.mkdirs()
}
File dir = new File('./plugin/' + bwcFilePath + bwcVersion)
if (!dir.exists()) {
dir.mkdirs()
}
File f = new File(dir, bwcMlPlugin)
if (!f.exists()) {
new URL(bwcRemoteFile).withInputStream{ ins -> f.withOutputStream{ it << ins }}
}
return fileTree(bwcFilePath + bwcVersion).getSingleFile()
}
}
}
}))
setting 'path.repo', "${buildDir}/cluster/shared/repo/${baseName}"
setting 'http.content_type.required', 'true'
}
}
}

List<Provider<RegularFile>> plugins = [
provider(new Callable<RegularFile>() {
@Override
RegularFile call() throws Exception {
return new RegularFile() {
@Override
File getAsFile() {
project.mkdir "$bwcFilePath/$project.version"
copy {
from "$buildDir/distributions/$opensearchMlPlugin"
into "$bwcFilePath/$project.version"
}
return fileTree(bwcFilePath + project.version).getSingleFile()
}
}
}
})
]

// Creates 2 test clusters with 3 nodes of the old version.
2.times { i ->
task "${baseName}#oldVersionClusterTask$i"(type: StandaloneRestIntegTestTask) {
useCluster testClusters."${baseName}$i"
filter {
includeTestsMatching "org.opensearch.ml.bwc.*IT"
}
systemProperty 'tests.rest.bwcsuite', 'old_cluster'
systemProperty 'tests.rest.bwcsuite_round', 'old'
systemProperty 'tests.plugin_bwc_version', bwcVersion
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}$i".allHttpSocketURI.join(",")}")
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}$i".getName()}")
}
}

// Upgrade one node of the old cluster to new OpenSearch version with upgraded plugin version
// This results in a mixed cluster with 2 nodes on the old version and 1 upgraded node.
// This is also used as a one third upgraded cluster for a rolling upgrade.
task "${baseName}#mixedClusterTask"(type: StandaloneRestIntegTestTask) {
useCluster testClusters."${baseName}0"
dependsOn "${baseName}#oldVersionClusterTask0"
doFirst {
testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins)
}
filter {
includeTestsMatching "org.opensearch.ml.bwc.*IT"
}
systemProperty 'tests.rest.bwcsuite', 'mixed_cluster'
systemProperty 'tests.rest.bwcsuite_round', 'first'
systemProperty 'tests.plugin_bwc_version', bwcVersion
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}")
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}")
}

// Upgrades the second node to new OpenSearch version with upgraded plugin version after the first node is upgraded.
// This results in a mixed cluster with 1 node on the old version and 2 upgraded nodes.
// This is used for rolling upgrade.
task "${baseName}#twoThirdsUpgradedClusterTask"(type: StandaloneRestIntegTestTask) {
dependsOn "${baseName}#mixedClusterTask"
useCluster testClusters."${baseName}0"
doFirst {
testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins)
}
filter {
includeTestsMatching "org.opensearch.ml.bwc.*IT"
}
systemProperty 'tests.rest.bwcsuite', 'mixed_cluster'
systemProperty 'tests.rest.bwcsuite_round', 'second'
systemProperty 'tests.plugin_bwc_version', bwcVersion
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}")
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}")
}

// Upgrade the third node to new OpenSearch version with upgraded plugin version after the second node is upgraded.
// This results in a fully upgraded cluster.
// This is used for rolling upgrade.
task "${baseName}#rollingUpgradeClusterTask"(type: StandaloneRestIntegTestTask) {
dependsOn "${baseName}#twoThirdsUpgradedClusterTask"
useCluster testClusters."${baseName}0"
doFirst {
testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins)
}
filter {
includeTestsMatching "org.opensearch.ml.bwc.*IT"
}
mustRunAfter "${baseName}#mixedClusterTask"
systemProperty 'tests.rest.bwcsuite', 'mixed_cluster'
systemProperty 'tests.rest.bwcsuite_round', 'third'
systemProperty 'tests.plugin_bwc_version', bwcVersion
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}")
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}")
}

// Upgrades all the nodes of the old cluster to new OpenSearch version with upgraded plugin version
// at the same time resulting in a fully upgraded cluster.
task "${baseName}#fullRestartClusterTask"(type: StandaloneRestIntegTestTask) {
dependsOn "${baseName}#oldVersionClusterTask1"
useCluster testClusters."${baseName}1"
doFirst {
testClusters."${baseName}1".upgradeAllNodesAndPluginsToNextVersion(plugins)
}
filter {
includeTestsMatching "org.opensearch.ml.bwc.*IT"
}
systemProperty 'tests.rest.bwcsuite', 'upgraded_cluster'
systemProperty 'tests.plugin_bwc_version', bwcVersion
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}1".allHttpSocketURI.join(",")}")
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}1".getName()}")
}

// A bwc test suite which runs all the bwc tasks combined
task bwcTestSuite(type: StandaloneRestIntegTestTask) {
exclude '**/*Test*'
exclude '**/*IT*'
dependsOn tasks.named("${baseName}#mixedClusterTask")
dependsOn tasks.named("${baseName}#rollingUpgradeClusterTask")
dependsOn tasks.named("${baseName}#fullRestartClusterTask")
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
import org.opensearch.common.io.stream.StreamInput;
import org.opensearch.common.settings.Settings;
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.ml.breaker.MLCircuitBreakerService;
import org.opensearch.ml.common.FunctionName;
import org.opensearch.ml.common.MLTask;
import org.opensearch.ml.common.breaker.MLCircuitBreakerService;
import org.opensearch.ml.common.transport.forward.MLForwardAction;
import org.opensearch.ml.common.transport.forward.MLForwardInput;
import org.opensearch.ml.common.transport.forward.MLForwardRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.ml.common.breaker;
package org.opensearch.ml.breaker;

public enum BreakerName {
MEMORY,
DISK
DISK,
NATIVE_MEMORY
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.ml.common.breaker;
package org.opensearch.ml.breaker;

/**
* An interface for circuit breaker.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.ml.common.breaker;

import org.opensearch.ml.common.exception.MLException;
package org.opensearch.ml.breaker;

import java.io.File;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

import org.opensearch.ml.common.exception.MLException;

/**
* A circuit breaker for disk usage.
*/
public class DiskCircuitBreaker extends ThresholdCircuitBreaker<Long> {
// TODO: make this value configurable as cluster setting
private static final String ML_DISK_CB = "Disk Circuit Breaker";
public static final long DEFAULT_DISK_SHORTAGE_THRESHOLD = 5L;
private static final long GB = 1024 * 1024 * 1024;
private String diskDir;

public DiskCircuitBreaker(String diskDir) {
Expand All @@ -32,17 +34,17 @@ public DiskCircuitBreaker(long threshold, String diskDir) {

@Override
public String getName() {
return ML_DISK_CB;
return ML_DISK_CB;
}

@Override
public boolean isOpen() {
try {
return AccessController.doPrivileged((PrivilegedExceptionAction<Boolean>) () -> {
return (new File(diskDir).getFreeSpace()/1024/1024/1024) < getThreshold(); // in GB
return (new File(diskDir).getFreeSpace() / GB) < getThreshold(); // in GB
});
} catch (PrivilegedActionException e) {
throw new MLException("Failed to run disk circuit breaker");
}
}
}
}
Loading