Skip to content
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
5 changes: 5 additions & 0 deletions .azure-pipelines/run-test-elastictest-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ parameters:
type: string
default: ""

- name: SETUP_CONTAINER_PARAMS
type: string
default: ""

- name: SKIP_REMOVE_ADD_TOPO_FOR_NIGHTLY
type: string
default: "True"
Expand Down Expand Up @@ -263,6 +267,7 @@ steps:
--test-set ${{ parameters.TEST_SET }} \
--kvm-build-id $(KVM_BUILD_ID) \
--kvm-image-branch "${{ parameters.KVM_IMAGE_BRANCH }}" \
--setup-container-params "${{ parameters.SETUP_CONTAINER_PARAMS }}" \
--skip-remove-add-topo-for-nightly ${{ parameters.SKIP_REMOVE_ADD_TOPO_FOR_NIGHTLY }} \
--add-topo-params "${{ parameters.ADD_TOPO_PARAMS }}" \
--deploy-mg-extra-params="${{ parameters.DEPLOY_MG_EXTRA_PARAMS }}" \
Expand Down
19 changes: 19 additions & 0 deletions .azure-pipelines/test_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ def create(self, topology, test_plan_name="my_test_plan", deploy_mg_extra_params
if max_execute_seconds == 0 and test_plan_type == "PR":
max_execute_seconds = int(os.environ.get("TIMEOUT_IN_SECONDS_PR_TEST_PLAN", 21600))

# Check and add GitHub api proxy env to setup-container params
setup_container_params = kwargs.get("setup_container_params", "")
github_api_proxy = os.getenv("SONIC_AUTOMATION_PROXY_GITHUB_ISSUES_URL", None)
if github_api_proxy:
setup_container_params = (f"{setup_container_params} "
f"-e SONIC_AUTOMATION_PROXY_GITHUB_ISSUES_URL={github_api_proxy}")

print(
f"Creating test plan, topology: {topology}, name: {test_plan_name}, "
f"build info:{repo_name} {pr_id} {build_id}"
Expand Down Expand Up @@ -338,6 +345,7 @@ def create(self, topology, test_plan_name="my_test_plan", deploy_mg_extra_params
"lock_wait_timeout_seconds": lock_wait_timeout_seconds,
},
"test_option": {
"setup_container_params": setup_container_params,
"skip_remove_add_topo_for_nightly": kwargs.get("skip_remove_add_topo_for_nightly", True),
"add_topo_params": kwargs.get("add_topo_params", ""),
"stop_on_failure": kwargs.get("stop_on_failure", True),
Expand Down Expand Up @@ -619,6 +627,16 @@ def poll(self, test_plan_id, interval=60, timeout=-1, expected_state="", expecte
required=False,
help="Test set."
)
parser_create.add_argument(
"--setup-container-params",
type=str,
nargs='?',
const='',
dest="setup_container_params",
default="",
required=False,
help="Setup sonic-mgmt container params"
)
parser_create.add_argument(
"--skip-remove-add-topo-for-nightly",
type=ast.literal_eval,
Expand Down Expand Up @@ -1084,6 +1102,7 @@ def poll(self, test_plan_id, interval=60, timeout=-1, expected_state="", expecte
args.topology,
test_plan_name=test_plan_name,
skip_remove_add_topo_for_nightly=args.skip_remove_add_topo_for_nightly,
setup_container_params=args.setup_container_params,
add_topo_params=args.add_topo_params,
deploy_mg_extra_params=args.deploy_mg_extra_params,
kvm_build_id=args.kvm_build_id,
Expand Down
9 changes: 7 additions & 2 deletions setup-container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ declare EXISTING_CONTAINER_NAME=""
# Arguments -----------------------------------------------------------------------------------------------------------
#

ENV_VARS=""
CONTAINER_NAME=""
IMAGE_ID=""
LINK_DIR=""
Expand Down Expand Up @@ -103,6 +104,7 @@ function show_help_and_exit() {
echo " -n <container_name> set the name of the Docker container"
echo
echo "Other options:"
echo " -e <VAR=value> set environment variable inside the container (can be used multiple times)"
echo " -i <image_id> specify Docker image to use. This can be an image ID (hashed value) or an image name."
echo " If no value is provided, defaults to the following images in the specified order:"
echo " 1. The local image named \"docker-sonic-mgmt\""
Expand Down Expand Up @@ -362,7 +364,7 @@ function start_local_container() {
docker start ${CONTAINER_NAME}
else
log_info "creating a container: ${CONTAINER_NAME} ..."
eval "docker run -d -t ${PUBLISH_PORTS} -h ${CONTAINER_NAME} \
eval "docker run -d -t ${PUBLISH_PORTS} ${ENV_VARS} -h ${CONTAINER_NAME} \
-v \"$(dirname "${SCRIPT_DIR}"):${LINK_DIR}:rslave\" ${MOUNT_POINTS} \
--name \"${CONTAINER_NAME}\" \"${LOCAL_IMAGE}\" /bin/bash ${SILENT_HOOK}" || \
exit_failure "failed to start a container: ${CONTAINER_NAME}"
Expand Down Expand Up @@ -440,11 +442,14 @@ if [[ $# -eq 0 ]]; then
show_help_and_exit "${EXIT_SUCCESS}"
fi

while getopts "n:i:d:m:p:fvxh" opt; do
while getopts "e:n:i:d:m:p:fvxh" opt; do
case "${opt}" in
n )
CONTAINER_NAME="${OPTARG}"
;;
e )
ENV_VARS+=" -e ${OPTARG}"
;;
i )
IMAGE_ID="${OPTARG}"
;;
Expand Down
70 changes: 51 additions & 19 deletions tests/common/plugins/conditional_mark/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
"""
import logging
import multiprocessing
import os
import re
import six
import requests

from abc import ABCMeta, abstractmethod
from urllib.parse import urlencode

import requests
import six

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -38,28 +40,58 @@ def __init__(self, url, proxies):
self.proxies = proxies

def is_active(self):
"""Check if the issue is still active.
"""Check if the GitHub issue is still active.

If unable to get issue state, always consider it as active.
Attempt to fetch issue details via proxy if configured. If proxy fails, retry with direct GitHub API URL.
If unable to retrieve issue state, assume the issue is active (safe default).

Returns:
bool: False if the issue is closed else True.
"""
try:
response = requests.get(self.api_url, proxies=self.proxies, timeout=10)

def fetch_issue(url):
response = requests.get(url, proxies=self.proxies, timeout=10)
response.raise_for_status()
issue_data = response.json()
if issue_data.get('state', '') == 'closed':
logger.debug('Issue {} is closed'.format(self.url))
labels = issue_data.get('labels', [])
if any(['name' in label and 'duplicate' in label['name'].lower() for label in labels]):
logger.warning('GitHub issue: {} looks like duplicate and was closed. Please re-check and ignore'
'the test on the parent issue'.format(self.url))
return False
except Exception as e:
logger.error('Get details for {} failed with: {}'.format(self.url, repr(e)))

logger.debug('Issue {} is active. Or getting issue state failed, consider it as active anyway'.format(self.url))
return response.json()

direct_url = self.api_url
proxy_url = os.getenv("SONIC_AUTOMATION_PROXY_GITHUB_ISSUES_URL")

issue_data = None

# Attempt to access via proxy first (if configured)
# The proxy is used to work around GitHub's unauthenticated rate limit (60 requests/hour per IP).
# For details, refer to GitHub API rate limits documentation:
# https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#primary-rate-limit-for-unauthenticated-users
if proxy_url:
try:
proxy_endpoint = f"{proxy_url.rstrip('/')}/?{urlencode({'github_issue_url': direct_url})}"
logger.info("Attempting to access GitHub API via proxy.")
issue_data = fetch_issue(proxy_endpoint)
except Exception as proxy_err:
logger.warning(f"Proxy access failed: {proxy_err}. Falling back to direct API.")

# Fallback to direct URL if proxy is not set or fails
if issue_data is None:
try:
logger.info(f"Accessing GitHub API directly: {direct_url}")
issue_data = fetch_issue(direct_url)
except Exception as direct_err:
logger.error(f"Access GitHub API directly failed for {direct_url}: {direct_err}")
logger.debug(f"Issue {direct_url} is considered active due to API access failure.")
return True

# Check issue state
if issue_data.get('state') == 'closed':
logger.debug(f"Issue {direct_url} is closed.")
labels = issue_data.get('labels', [])
if any('name' in label and 'duplicate' in label['name'].lower() for label in labels):
logger.warning(
f"GitHub issue {direct_url} appears to be a duplicate and was closed. "
f"Consider ignoring related test failures.")
return False

logger.debug(f"Issue {direct_url} is active.")
return True


Expand Down
Loading