-
Notifications
You must be signed in to change notification settings - Fork 277
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
Add Validation Framework #2725
Add Validation Framework #2725
Changes from all commits
b9b597c
6fdf7c3
9011dc0
7db7795
d7a055b
34a5f9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
import logging | ||
import sys | ||
|
||
from system import console | ||
from validation_workflow.validation_args import ValidationArgs | ||
|
||
|
||
def main() -> int: | ||
|
||
args = ValidationArgs() | ||
|
||
console.configure(level=args.logging_level) | ||
logging.getLogger("urllib3").setLevel(logging.WARNING) | ||
|
||
dist = args.DISTRIBUTION_MAP.get(args.distribution, None) | ||
dist.download_artifacts(projects=args.projects, version=args.version) | ||
|
||
return 0 | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#### Automate the Validation during Releases. | ||
The input requires a mandatory version number , optional --distribution types(tar,rpm,yum) and --platform type (currently uses only linux) to automatically download and verify the artifacts. | ||
|
||
*Usage* | ||
``` | ||
./validation.sh --version 2.3.0 --distribution rpm --platform linux | ||
``` | ||
The following options are available. | ||
|
||
| name | description | | ||
|------------------------|---------------------------------------------------------------------| | ||
| version | Accepts a mandatory version number. | | ||
| -d, --distribution | Assigns the distribution type specifed by the user | | ||
| -p, --platform | Determines the platform type of the atrifacts. | | ||
| --verbose | Show more verbose output. | | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
# | ||
# This page intentionally left blank. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
|
||
import os | ||
|
||
import requests | ||
|
||
from system.temporary_directory import TemporaryDirectory | ||
|
||
|
||
class DownloadUtils: | ||
@staticmethod | ||
def is_url_valid(url: str) -> bool: | ||
response = requests.head(url) | ||
status = bool(response.status_code == 200) | ||
return status | ||
|
||
@staticmethod | ||
def download(url: str, tmp_dir: TemporaryDirectory) -> bool: | ||
# This method writes the contents from the response object into temporary directory file name fetched from the end of the url. | ||
response = requests.get(url, stream=True) | ||
path = os.path.join(tmp_dir.name, os.path.basename(url)) | ||
status = bool(open(path, "wb").write(response.content)) | ||
return status |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
|
||
from abc import ABC, abstractmethod | ||
|
||
from system.temporary_directory import TemporaryDirectory | ||
|
||
|
||
class Validation(ABC): | ||
base_url = "https://artifacts.opensearch.org/releases/bundle/" | ||
tmp_dir = TemporaryDirectory() | ||
|
||
@classmethod | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this a classmethod after all? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removing class method threw me an error |
||
@abstractmethod | ||
def download_artifacts(self, projects: list, version: str) -> bool: | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
import argparse | ||
import logging | ||
|
||
from validation_workflow.validation_rpm import ValidationRpm | ||
from validation_workflow.validation_tar import ValidationTar | ||
from validation_workflow.validation_yum import ValidationYum | ||
|
||
|
||
class ValidationArgs: | ||
SUPPORTED_PLATFORMS = ["linux"] | ||
DISTRIBUTION_MAP = { | ||
"tar": ValidationTar, | ||
"yum": ValidationYum, | ||
"rpm": ValidationRpm | ||
} | ||
|
||
def __init__(self) -> None: | ||
parser = argparse.ArgumentParser(description="Validation Framework for Validation Workflow.") | ||
parser.add_argument( | ||
"--version", | ||
type=str, | ||
required=True, | ||
help="Product version to validate" | ||
) | ||
parser.add_argument( | ||
"-d", | ||
"--distribution", | ||
type=str, | ||
choices=self.DISTRIBUTION_MAP.keys(), | ||
help="Distribution to validate.", | ||
default="tar", | ||
dest="distribution" | ||
) | ||
parser.add_argument( | ||
"-p", | ||
"--platform", | ||
type=str, | ||
choices=self.SUPPORTED_PLATFORMS, | ||
help="Platform to validate.", | ||
default="linux" | ||
) | ||
parser.add_argument( | ||
"--stgosbuild", | ||
type=str, | ||
required=False, | ||
help="The opensearchstaging OpenSearch image build number if required, for example : 6039\n", | ||
default="", | ||
dest="stgosbuild", | ||
) | ||
parser.add_argument( | ||
"--stgosdbuild", | ||
type=str, | ||
required=False, | ||
help="The opensearchstaging OpenSearchDashboard image build number if required, for example : 4104\n", | ||
default="", | ||
dest="stgosdbuild", | ||
) | ||
parser.add_argument( | ||
"-v", | ||
"--verbose", | ||
help="Show more verbose output.", | ||
action="store_const", | ||
default=logging.INFO, | ||
const=logging.DEBUG, | ||
dest="logging_level", | ||
) | ||
|
||
args = parser.parse_args() | ||
self.version = args.version | ||
self.logging_level = args.logging_level | ||
self.distribution = args.distribution | ||
self.platform = args.platform | ||
self.projects = ["opensearch", "opensearch-dashboards"] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
import logging | ||
|
||
from validation_workflow.download_utils import DownloadUtils | ||
from validation_workflow.validation import Validation | ||
|
||
|
||
class ValidationRpm(Validation, DownloadUtils): | ||
|
||
@classmethod | ||
def download_artifacts(self, projects: list, version: str) -> bool: | ||
architectures = ["x64", "arm64"] | ||
for project in projects: | ||
for architecture in architectures: | ||
url = f"{self.base_url}{project}/{version}/{project}-{version}-linux-{architecture}.rpm" | ||
if ValidationRpm.is_url_valid(url) and ValidationRpm.download(url, self.tmp_dir): | ||
logging.info(f"Valid URL - {url} and Download Successful !") | ||
else: | ||
logging.info(f"Invalid URL - {url}") | ||
raise Exception(f"Invalid url - {url}") | ||
return True |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
import logging | ||
|
||
from validation_workflow.download_utils import DownloadUtils | ||
from validation_workflow.validation import Validation | ||
|
||
|
||
class ValidationTar(Validation, DownloadUtils): | ||
|
||
@classmethod | ||
def download_artifacts(self, projects: list, version: str) -> bool: | ||
architectures = ["x64", "arm64"] | ||
for project in projects: | ||
for architecture in architectures: | ||
url = f"{self.base_url}{project}/{version}/{project}-{version}-linux-{architecture}.tar.gz" | ||
if ValidationTar.is_url_valid(url) and ValidationTar.download(url, self.tmp_dir): | ||
logging.info(f"Valid URL - {url} and Download Successful !") | ||
else: | ||
logging.info(f"Invalid URL - {url}") | ||
raise Exception(f"Invalid url - {url}") | ||
return True |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
import logging | ||
|
||
from validation_workflow.download_utils import DownloadUtils | ||
from validation_workflow.validation import Validation | ||
|
||
|
||
class ValidationYum(Validation, DownloadUtils): | ||
|
||
@classmethod | ||
def download_artifacts(self, projects: list, version: str) -> bool: | ||
for project in projects: | ||
url = f"{self.base_url}{project}/{version[0:1]}.x/{project}-{version[0:1]}.x.repo" | ||
if ValidationYum.is_url_valid(url) and ValidationYum.download(url, self.tmp_dir): | ||
logging.info(f"Valid URL - {url} and Download Successful !") | ||
else: | ||
logging.info(f"Invalid URL - {url}") | ||
raise Exception(f"Invalid url - {url}") | ||
return True |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
|
||
import unittest | ||
from typing import Any | ||
from unittest.mock import Mock, patch | ||
|
||
import pytest | ||
from pytest import CaptureFixture | ||
|
||
from src.run_validation import main | ||
from src.validation_workflow.validation_args import ValidationArgs | ||
|
||
|
||
class TestRunValidation(unittest.TestCase): | ||
|
||
@pytest.fixture(autouse=True) | ||
def getCapfd(self, capfd: CaptureFixture) -> None: | ||
self.capfd = capfd | ||
|
||
@patch("argparse._sys.argv", ["run_validation.py", "--help"]) | ||
def test_usage(self, *mocks: Any) -> None: | ||
with self.assertRaises(SystemExit): | ||
main() | ||
|
||
out, _ = self.capfd.readouterr() | ||
self.assertTrue(out.startswith("usage:")) | ||
|
||
@patch("argparse._sys.argv", ["run_validation.py", "--version", "1.3.6"]) | ||
@patch("src.validation_workflow.validation_tar.ValidationTar.download_artifacts", return_value=True) | ||
@patch("run_validation.main", return_value=0) | ||
def test_main_default(self, mock_tar: Mock, *mocks: Any) -> None: | ||
self.assertEqual(ValidationArgs().version, "1.3.6") | ||
self.assertEqual(ValidationArgs().distribution, "tar") | ||
self.assertNotEqual(ValidationArgs().distribution, "rpm") | ||
|
||
@patch("argparse._sys.argv", ["run_validation.py", "--version", "2.1.0", "--distribution", "rpm"]) | ||
@patch("src.validation_workflow.validation_rpm.ValidationRpm.download_artifacts", return_value=True) | ||
@patch("run_validation.main", return_value=0) | ||
def test_main_rpm(self, mock_tar: Mock, *mocks: Any) -> None: | ||
self.assertEqual(ValidationArgs().version, "2.1.0") | ||
self.assertEqual(ValidationArgs().distribution, "rpm") | ||
self.assertNotEqual(ValidationArgs().distribution, "tar") | ||
|
||
@patch("argparse._sys.argv", ["run_validation.py", "--version", "2.1.0", "--distribution", "yum"]) | ||
@patch("src.validation_workflow.validation_yum.ValidationYum.download_artifacts", return_value=True) | ||
@patch("run_validation.main", return_value=0) | ||
def test_main_yum(self, mock_tar: Mock, *mocks: Any) -> None: | ||
self.assertEqual(ValidationArgs().version, "2.1.0") | ||
self.assertEqual(ValidationArgs().distribution, "yum") | ||
self.assertNotEqual(ValidationArgs().distribution, "tar") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
import os | ||
import sys | ||
|
||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../src")) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Copyright OpenSearch Contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# The OpenSearch Contributors require contributions made to | ||
# this file be licensed under the Apache-2.0 license or a | ||
# compatible open source license. | ||
|
||
import logging | ||
import unittest | ||
from unittest.mock import patch | ||
|
||
from validation_workflow.validation_args import ValidationArgs | ||
|
||
|
||
class TestValidationArgs(unittest.TestCase): | ||
|
||
VALIDATION_PY = "./src/run_validation.py" \ | ||
|
||
|
||
@patch("argparse._sys.argv", [VALIDATION_PY, "--version", "2.3.0"]) | ||
def test_version(self) -> None: | ||
self.assertTrue(ValidationArgs().version) | ||
self.assertEqual(ValidationArgs().version, "2.3.0") | ||
self.assertNotEqual(ValidationArgs().version, "2.1.0") | ||
|
||
@patch("argparse._sys.argv", [VALIDATION_PY, "--version", "2.1.0", "--distribution", "rpm"]) | ||
def test_distribution(self) -> None: | ||
self.assertEqual(ValidationArgs().distribution, "rpm") | ||
|
||
@patch("argparse._sys.argv", [VALIDATION_PY, "--version", "1.3.6", "--platform", "linux"]) | ||
def test_platform_default(self) -> None: | ||
self.assertEqual(ValidationArgs().platform, "linux") | ||
|
||
@patch("argparse._sys.argv", [VALIDATION_PY, "--version", "1.3.0"]) | ||
def test_verbose_default(self) -> None: | ||
self.assertEqual(ValidationArgs().logging_level, logging.INFO) | ||
|
||
@patch("argparse._sys.argv", [VALIDATION_PY, "--version", "1.3.0", "--verbose"]) | ||
def test_verbose_true(self) -> None: | ||
self.assertTrue(ValidationArgs().logging_level, logging.DEBUG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: rename to download_artifacts
Just download is bit confusing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a different function in downloadutils.py which is called by the download_artifacts method in tar, rpm and yum.