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

Support new distribution-validations and add few enhancements to validation workflow #4447

Merged
merged 6 commits into from
Feb 20, 2024
Merged
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
8 changes: 8 additions & 0 deletions src/validation_workflow/deb/__init__.py
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.
61 changes: 61 additions & 0 deletions src/validation_workflow/deb/validation_deb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# 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 os

from system.execute import execute
from test_workflow.integ_test.utils import get_password
from validation_workflow.api_test_cases import ApiTestCases
from validation_workflow.download_utils import DownloadUtils
from validation_workflow.validation import Validation
from validation_workflow.validation_args import ValidationArgs


class ValidateDeb(Validation, DownloadUtils):
def __init__(self, args: ValidationArgs) -> None:
super().__init__(args)

def installation(self) -> bool:
try:
for project in self.args.projects:
set_password = f' env OPENSEARCH_INITIAL_ADMIN_PASSWORD={get_password(str(self.args.version))}' if project == "opensearch" else ""
execute(f'sudo dpkg --purge {project}', ".")
execute(f'sudo {set_password} dpkg -i {os.path.basename(self.args.file_path.get(project))}', str(self.tmp_dir.path))
except:
raise Exception("Failed to install OpenSearch/OpenSearch-Dashboards")
return True

def start_cluster(self) -> bool:
try:
for project in self.args.projects:
execute(f'sudo systemctl enable {project}', ".")
execute(f'sudo systemctl start {project}', ".")
execute(f'sudo systemctl status {project}', ".")
except:
raise Exception('Failed to Start Cluster')
return True

def validation(self) -> bool:
if self.check_cluster_readiness():
test_result, counter = ApiTestCases().test_apis(self.args.version, self.args.projects,
self.check_for_security_plugin(os.path.join(os.sep, "usr", "share", "opensearch")) if self.args.allow_http else True)
if (test_result):
logging.info(f'All tests Pass : {counter}')
return True
else:
raise Exception(f'Not all tests Pass : {counter}')
else:
raise Exception("Cluster is not ready for API test")

def cleanup(self) -> bool:
try:
for project in self.args.projects:
execute(f'sudo dpkg --purge {project}', ".")
except Exception as e:
raise Exception(f'Exception occurred either while attempting to stop cluster or removing OpenSearch/OpenSearch-Dashboards. {str(e)}')
return True
2 changes: 1 addition & 1 deletion src/validation_workflow/docker/inspect_docker_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self, image_id: str, image_name: str, prod_image_tag: str) -> None:
self.image_id = image_id
self.image_name = image_name
self.prod_image_tag = prod_image_tag
self.image_tag = ValidationArgs().stg_tag('opensearch_dashboards').replace(" ", "") if ("dashboards" in self.image_name) else ValidationArgs().stg_tag('opensearch').replace(" ", "")
self.image_tag = ValidationArgs().stg_tag('opensearch-dashboards').replace(" ", "") if ("dashboards" in self.image_name) else ValidationArgs().stg_tag('opensearch').replace(" ", "")
self.auth_token_url = "https://auth.docker.io/token?"
self.auth_service_scope = "service=registry.docker.io&scope=repository:"
self.registry_url = "https://index.docker.io/v2/"
Expand Down
51 changes: 8 additions & 43 deletions src/validation_workflow/docker/validation_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@
import os
import shutil
import subprocess
import time
from subprocess import PIPE
from typing import Any

import requests

from system.temporary_directory import TemporaryDirectory
from validation_workflow.api_request import ApiTest
from test_workflow.integ_test.utils import get_password
from validation_workflow.api_test_cases import ApiTestCases
from validation_workflow.docker.inspect_docker_image import InspectDockerImage
from validation_workflow.validation import Validation
Expand Down Expand Up @@ -61,8 +57,7 @@ def start_cluster(self) -> bool:
def validation(self) -> bool:
# STEP 2 . inspect image digest between opensearchproject(downloaded/local) and opensearchstaging(dockerHub)
if not self.args.using_staging_artifact_only:
self.image_names_list = [self.args.OS_image, self.args.OSD_image]
self.image_names_list = [x for x in self.image_names_list if (os.path.basename(x) in self.args.projects)]
self.image_names_list = ['opensearchproject/' + project for project in self.args.projects]
self.image_digests = list(map(lambda x: self.inspect_docker_image(x[0], x[1]), zip(self.image_ids.values(), self.image_names_list))) # type: ignore
if all(self.image_digests):
logging.info('Image digest is validated.\n\n')
Expand All @@ -79,7 +74,7 @@ def validation(self) -> bool:
self.args.version
)
if return_code:
logging.info('Checking if cluster is ready for API test in every 10 seconds\n\n')
logging.info('Checking if cluster is ready for API test in every 5 seconds\n\n')

if self.check_cluster_readiness():
# STEP 4 . OS, OSD API validation
Expand All @@ -94,8 +89,8 @@ def validation(self) -> bool:
raise Exception(f'Not all tests Pass : {_counter}')
else:
raise Exception("Cluster is not ready for API test.")
else:
raise Exception('The container failed to start. Exiting the validation.')
else:
raise Exception('The container failed to start. Exiting the validation.')

return True

Expand Down Expand Up @@ -129,36 +124,6 @@ def cleanup_process(self) -> bool:

return('returncode=0' in (str(result)))

def check_http_request(self) -> bool:
self.test_readiness_urls = {
'https://localhost:9200/': 'opensearch cluster API',
'http://localhost:5601/api/status': 'opensearch-dashboards API',
}

for url, name in self.test_readiness_urls.items():
try:
status_code, response_text = ApiTest(url, self.args.version).api_get()
if status_code != 200:
logging.error(f'Error connecting to {name} ({url}): status code {status_code}')
return False
except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout) as e:
logging.error(f'Error connecting to {name} ({url}): {e}')
return False
return True

def check_cluster_readiness(self) -> bool:
max_retry = 20
retry_count = 0
while retry_count < max_retry:
logging.info(f'sleeping 10sec for retry {retry_count + 1}/{max_retry}')
time.sleep(10)
if self.check_http_request():
logging.info('\n\ncluster is now ready for API test\n\n')
return True
retry_count += 1
logging.error(f"Maximum number of retries ({max_retry}) reached. Cluster is not ready for API test.")
return False

def get_artifact_image_name(self, artifact: str, using_staging_artifact_only: str) -> Any:
self.image_names = {
'dockerhub': {
Expand Down Expand Up @@ -241,7 +206,6 @@ def run_container(self, image_ids: dict, version: str) -> Any:
'2': 'docker-compose-2.x.yml'
}

self.tmp_dir = TemporaryDirectory()
self.target_yml_file = os.path.join(self.tmp_dir.name, 'docker-compose.yml')

self.major_version_number = version[0]
Expand All @@ -252,8 +216,9 @@ def run_container(self, image_ids: dict, version: str) -> Any:
self.replacements = [(f'opensearchproject/{key}:{self.major_version_number}', value) for key, value in image_ids.items()]

list(map(lambda r: self.inplace_change(self.target_yml_file, r[0], r[1]), self.replacements))

os.environ["OPENSEARCH_INITIAL_ADMIN_PASSWORD"] = get_password(str(version))
# spin up containers
self.docker_compose_up = f'docker-compose -f {self.target_yml_file} up -d'
services = "opensearch-node1 opensearch-node2" if "opensearch-dashboards" not in self.args.projects else ""
self.docker_compose_up = f'docker-compose -f {self.target_yml_file} up -d {services}'
result = subprocess.run(self.docker_compose_up, shell=True, stdout=PIPE, stderr=PIPE, universal_newlines=True)
return ('returncode=0' in (str(result)), self.target_yml_file)
37 changes: 9 additions & 28 deletions src/validation_workflow/rpm/validation_rpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@

import logging
import os
import time

from system.execute import execute
from system.temporary_directory import TemporaryDirectory
from test_workflow.integ_test.utils import get_password
from validation_workflow.api_test_cases import ApiTestCases
from validation_workflow.download_utils import DownloadUtils
Expand All @@ -22,26 +20,6 @@ class ValidateRpm(Validation, DownloadUtils):

def __init__(self, args: ValidationArgs) -> None:
super().__init__(args)
self.base_url_production = "https://artifacts.opensearch.org/releases/bundle/"
self.base_url_staging = "https://ci.opensearch.org/ci/dbc/distribution-build-"
self.tmp_dir = TemporaryDirectory()

def download_artifacts(self) -> bool:
isFilePathEmpty = bool(self.args.file_path)
for project in self.args.projects:
if (isFilePathEmpty):
if ("https:" not in self.args.file_path.get(project)):
self.copy_artifact(self.args.file_path.get(project), str(self.tmp_dir.path))
else:
self.args.version = self.get_version(self.args.file_path.get(project))
self.check_url(self.args.file_path.get(project))
else:
if (self.args.artifact_type == "staging"):
self.args.file_path[project] = f"{self.base_url_staging}{project}/{self.args.version}/{self.args.build_number[project]}/linux/{self.args.arch}/{self.args.distribution}/dist/{project}/{project}-{self.args.version}-linux-{self.args.arch}.rpm" # noqa: E501
else:
self.args.file_path[project] = f"{self.base_url_production}{project}/{self.args.version}/{project}-{self.args.version}-linux-{self.args.arch}.rpm"
self.check_url(self.args.file_path.get(project))
return True

def installation(self) -> bool:
try:
Expand All @@ -58,7 +36,6 @@ def start_cluster(self) -> bool:
try:
for project in self.args.projects:
execute(f'sudo systemctl start {project}', ".")
time.sleep(20)
(stdout, stderr, status) = execute(f'sudo systemctl status {project}', ".")
if(status == 0):
logging.info(stdout)
Expand All @@ -70,12 +47,16 @@ def start_cluster(self) -> bool:
return True

def validation(self) -> bool:
test_result, counter = ApiTestCases().test_apis(self.args.version, self.args.projects, self.check_for_security_plugin(os.path.join(os.sep, "usr", "share", "opensearch")) if not self.args.force_https else True) # noqa: E501
if (test_result):
logging.info(f'All tests Pass : {counter}')
return True
if self.check_cluster_readiness():
test_result, counter = ApiTestCases().test_apis(self.args.version, self.args.projects,
self.check_for_security_plugin(os.path.join(os.sep, "usr", "share", "opensearch")) if self.args.allow_http else True)
if (test_result):
logging.info(f'All tests Pass : {counter}')
return True
else:
raise Exception(f'Not all tests Pass : {counter}')
else:
raise Exception(f'Not all tests Pass : {counter}')
raise Exception("Cluster is not ready for API test")

def cleanup(self) -> bool:
try:
Expand Down
38 changes: 9 additions & 29 deletions src/validation_workflow/tar/validation_tar.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@

import logging
import os
import time

from system.execute import execute
from system.process import Process
from system.temporary_directory import TemporaryDirectory
from test_workflow.integ_test.utils import get_password
from validation_workflow.api_test_cases import ApiTestCases
from validation_workflow.download_utils import DownloadUtils
Expand All @@ -23,29 +21,9 @@ class ValidateTar(Validation, DownloadUtils):

def __init__(self, args: ValidationArgs) -> None:
super().__init__(args)
self.base_url_production = "https://artifacts.opensearch.org/releases/bundle/"
self.base_url_staging = "https://ci.opensearch.org/ci/dbc/distribution-build-"
self.tmp_dir = TemporaryDirectory()
self.os_process = Process()
self.osd_process = Process()

def download_artifacts(self) -> bool:
isFilePathEmpty = bool(self.args.file_path)
for project in self.args.projects:
if (isFilePathEmpty):
if ("https:" not in self.args.file_path.get(project)):
self.copy_artifact(self.args.file_path.get(project), str(self.tmp_dir.path))
else:
self.args.version = self.get_version(self.args.file_path.get(project))
self.check_url(self.args.file_path.get(project))
else:
if (self.args.artifact_type == "staging"):
self.args.file_path[project] = f"{self.base_url_staging}{project}/{self.args.version}/{self.args.build_number[project]}/linux/{self.args.arch}/{self.args.distribution}/dist/{project}/{project}-{self.args.version}-linux-{self.args.arch}.tar.gz" # noqa: E501
else:
self.args.file_path[project] = f"{self.base_url_production}{project}/{self.args.version}/{project}-{self.args.version}-linux-{self.args.arch}.tar.gz"
self.check_url(self.args.file_path.get(project))
return True

def installation(self) -> bool:
try:
for project in self.args.projects:
Expand All @@ -58,22 +36,24 @@ def installation(self) -> bool:
def start_cluster(self) -> bool:
try:
self.os_process.start(f'export OPENSEARCH_INITIAL_ADMIN_PASSWORD={get_password(str(self.args.version))} && ./opensearch-tar-install.sh', os.path.join(self.tmp_dir.path, "opensearch"))
time.sleep(85)
if ("opensearch-dashboards" in self.args.projects):
self.osd_process.start(os.path.join(str(self.tmp_dir.path), "opensearch-dashboards", "bin", "opensearch-dashboards"), ".")
time.sleep(20)
logging.info('Started cluster')
except:
raise Exception('Failed to Start Cluster')
return True

def validation(self) -> bool:
test_result, counter = ApiTestCases().test_apis(self.args.version, self.args.projects, self.check_for_security_plugin(os.path.join(self.tmp_dir.path, "opensearch")) if not self.args.force_https else True) # noqa: E501
if (test_result):
logging.info(f'All tests Pass : {counter}')
if self.check_cluster_readiness():
test_result, counter = ApiTestCases().test_apis(self.args.version, self.args.projects,
self.check_for_security_plugin(os.path.join(self.tmp_dir.path, "opensearch")) if self.args.allow_http else True)
if (test_result):
logging.info(f'All tests Pass : {counter}')
return True
else:
raise Exception(f'Not all tests Pass : {counter}')
else:
raise Exception(f'Not all tests Pass : {counter}')
return True
raise Exception("Cluster is not ready for API test")

def cleanup(self) -> bool:
try:
Expand Down
Loading
Loading