-
Notifications
You must be signed in to change notification settings - Fork 1k
[swap_syncd] Port swap_syncd task to pytest #1516
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
Changes from all commits
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,5 @@ | ||
| SWITCH_HWSKUS = ["Force10-S6000", "Accton-AS7712-32X", "Celestica-DX010-C32", | ||
| "Seastone-DX010", "Celestica-E1031-T48S4"] | ||
|
|
||
| def is_broadcom_device(hwsku): | ||
| return hwsku in SWITCH_HWSKUS | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| """ | ||
| docker contains utilities for interacting with Docker on the DUT. | ||
| """ | ||
|
|
||
| import collections | ||
| import logging | ||
| import os | ||
| import time | ||
| import yaml | ||
|
|
||
| from common.broadcom_data import is_broadcom_device | ||
| from common.mellanox_data import is_mellanox_device | ||
|
|
||
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| _BASE_DIR = os.path.dirname(os.path.realpath(__file__)) | ||
| SONIC_DOCKER_REGISTRY = os.path.join(_BASE_DIR, "../../../ansible/vars/docker_registry.yml") | ||
|
|
||
| _DockerRegistryInfo = collections.namedtuple('DockerRegistryInfo', 'host username password') | ||
| class DockerRegistryInfo(_DockerRegistryInfo): | ||
| """ | ||
| DockerRegistryInfo holds all the data needed to access a remote Docker registry. | ||
|
|
||
| Attributes: | ||
| host (str): The remote host where the Docker registry is located. | ||
| username (str): The username used to access the registry. | ||
| password (str): The password used to access the registry. | ||
| """ | ||
| pass | ||
|
|
||
| def parse_registry_file(registry_file): | ||
| """ | ||
| parse_registry_file parses the provided file to produce a DockerRegistryInfo. | ||
|
|
||
| See `SONIC_DOCKER_REGISTRY` for the expected format of this file. | ||
|
|
||
| Args: | ||
| registry_file (str): The name of the file holding the registry information. | ||
|
|
||
| Raises: | ||
| IOError: If the file cannot be opened for any reason. | ||
| ValueError: If the provided file is missing any required fields. | ||
|
|
||
| Returns: | ||
| DockerRegistryInfo: The registry info from the registry file. | ||
| """ | ||
|
|
||
| try: | ||
| with open(registry_file) as contents: | ||
| registry_vars = yaml.safe_load(contents) | ||
| except IOError as err: | ||
| _LOGGER.error("Failed to parse registry file \"%s\" (%s)", registry_file, err) | ||
| raise | ||
|
|
||
| host = registry_vars.get("docker_registry_host") | ||
daall marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| username = registry_vars.get("docker_registry_username") | ||
| password = registry_vars.get("docker_registry_password") | ||
|
|
||
| if not host or not username or not password: | ||
| error_message = "Registry file \"{}\" is missing login or hostname".format(registry_file) | ||
| _LOGGER.error(error_message) | ||
| raise ValueError(error_message) | ||
|
|
||
| return DockerRegistryInfo(host, username, password) | ||
|
|
||
| def delete_container(dut, container_name): | ||
| """ | ||
| delete_container attempts to delete the specified container from the DUT. | ||
|
|
||
| Args: | ||
| dut (SonicHost): The target device. | ||
| container_name (str): The name of the container to delete. | ||
| """ | ||
|
|
||
| dut.docker_container(name=container_name, state="absent") | ||
|
|
||
| def download_image(dut, registry, image_name, image_version="latest"): | ||
| """ | ||
| download_image attempts to download the specified image from the registry. | ||
|
|
||
| Args: | ||
| dut (SonicHost): The target device. | ||
| registry (DockerRegistryInfo): The registry from which to pull the image. | ||
| image_name (str): The name of the image to download. | ||
| image_version (str): The version of the image to download. | ||
| """ | ||
|
|
||
| dut.docker_login(registry_url=registry.host, | ||
| username=registry.username, | ||
| password=registry.password) | ||
| dut.docker_image(source="pull", | ||
| name="{}/{}:{}".format(registry.host, image_name, image_version)) | ||
|
|
||
| def tag_image(dut, tag, image_name, image_version="latest"): | ||
|
Contributor
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. these are very slim wrappers around Ansible APIs. You can use the Ansible API directly.
Contributor
Author
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. I kept the wrappers because the interface is a lot simpler than the Ansible APIs. The Ansible APIs are very useful for this sort of thing, but they're also very flexible and have dozens of options to sift through. Most of the time, we really only need to use a few of them. This just saves some effort digging through the Ansible docs to find which 3 options you need (plus, if someone /really/ needs to go do something super specific, they can still use the Ansible API directly). |
||
| """ | ||
| tag_image applies the specified tag to a Docker image on the DUT. | ||
|
|
||
| Args: | ||
| dut (SonicHost): The target device. | ||
| tag (str): The tag to apply to the target image. | ||
| image_name (str): The name of the image to tag. | ||
| image_version (str): The version of the image to tag. | ||
| """ | ||
|
|
||
| dut.docker_image(source="local", | ||
| name="{}:{}".format(image_name, image_version), | ||
| tag=tag) | ||
|
|
||
| def swap_syncd(dut, registry_file=SONIC_DOCKER_REGISTRY): | ||
| """ | ||
| swap_syncd replaces the default syncd container on the DUT with an RPC version of it. | ||
|
|
||
| This command will download a new Docker image to the DUT and restart the swss service. | ||
|
|
||
| Args: | ||
| dut (SonicHost): The target device. | ||
| registry_file (str): The registry file describing where to download the RPC image. | ||
| """ | ||
|
|
||
| minigraph_facts = dut.minigraph_facts(host=dut.hostname)["ansible_facts"] | ||
| hw_sku = minigraph_facts["minigraph_hwsku"] | ||
|
|
||
| # TODO: Getting the vendor identifier should be a common utility | ||
| if is_broadcom_device(hw_sku): | ||
| vendor_id = "brcm" | ||
| elif is_mellanox_device(hw_sku): | ||
| vendor_id = "mlnx" | ||
| else: | ||
| error_message = "HW SKU \"{}\" is not currently supported".format(hw_sku) | ||
| _LOGGER.error(error_message) | ||
| raise ValueError(error_message) | ||
|
|
||
| docker_syncd_name = "docker-syncd-{}".format(vendor_id) | ||
| docker_rpc_image = docker_syncd_name + "-rpc" | ||
|
|
||
| dut.command("systemctl stop swss") | ||
| delete_container(dut, "syncd") | ||
|
|
||
| # Set sysctl RCVBUF parameter for tests | ||
| dut.command("sysctl -w net.core.rmem_max=509430500") | ||
|
|
||
| # TODO: Getting the base image version should be a common utility | ||
| output = dut.command("sonic-cfggen -y /etc/sonic/sonic_version.yml -v build_version") | ||
| sonic_version = output["stdout_lines"][0].strip() | ||
|
|
||
| registry = parse_registry_file(registry_file) | ||
| download_image(dut, registry, docker_rpc_image, sonic_version) | ||
|
|
||
| tag_image(dut, | ||
| "{}/{}".format(registry.host, docker_syncd_name), | ||
| docker_rpc_image, | ||
| sonic_version) | ||
|
|
||
| dut.command("systemctl start swss") | ||
| _LOGGER.info("swss has been restarted, waiting 60 seconds to initialize...") | ||
| time.sleep(60) | ||
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.
We are using many more Broadcom SKU's
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.
I know, this is just the list that I copied from
ansible/group_vars/sonic/vars. It seems like it's been a while since this was updated... 😝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.
in the show version, there is asic field. We should use that instead of the hardware sku, too many skus, too difficult to maintain.
Can you later submit another pr to refactor this?