Skip to content

Commit ddacd49

Browse files
erjiaqingrestyled-commits
andauthoredAug 29, 2023
Reenable Cirque tests (project-chip#28350)
* Revert "Disabling Cirque for now" This reverts commit b587d14. * Fix cirque test scripts * Restyled by prettier-json * Restyled by isort * Fix ot-br-posix * Restyled by clang-format --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 0ff8f19 commit ddacd49

35 files changed

+563
-51
lines changed
 

‎.github/workflows/cirque.yaml

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Copyright (c) 2020-2023 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: Cirque
16+
17+
on:
18+
push:
19+
pull_request:
20+
merge_group:
21+
workflow_dispatch:
22+
23+
concurrency:
24+
group: ${{ github.ref }}-${{ github.workflow }}-${{ (github.event_name == 'pull_request' && github.event.number) || (github.event_name == 'workflow_dispatch' && github.run_number) || github.sha }}
25+
cancel-in-progress: true
26+
27+
env:
28+
CHIP_NO_LOG_TIMESTAMPS: true
29+
30+
jobs:
31+
cirque:
32+
name: Cirque
33+
34+
env:
35+
GITHUB_CACHE_PATH: /tmp/cirque-cache
36+
37+
runs-on: ubuntu-latest
38+
if: github.actor != 'restyled-io[bot]'
39+
40+
# need to run with privilege, which isn't supported by job.XXX.contaner
41+
# https://github.com/actions/container-action/issues/2
42+
# container:
43+
# image: ghcr.io/project-chip/chip-build-cirque:0.8
44+
# volumes:
45+
# - "/tmp:/tmp"
46+
# - "/dev/pts:/dev/pts"
47+
# env:
48+
# LOG_DIR: /tmp/cirque_test_output/
49+
# CLEANUP_DOCKER_FOR_CI: 1
50+
# options: "--privileged"
51+
52+
steps:
53+
- name: Checkout
54+
uses: actions/checkout@v3
55+
- name: Checkout submodules
56+
uses: ./.github/actions/checkout-submodules
57+
with:
58+
platform: linux
59+
60+
- name: Bootstrap Cache
61+
uses: ./.github/actions/bootstrap-cache
62+
- name: Bootstrap Cirque
63+
run: |
64+
integrations/docker/images/stage-2/chip-build-cirque/run.sh \
65+
-- sh -c " \
66+
git config --global --add safe.directory '*' \
67+
&& bash scripts/bootstrap.sh \
68+
&& chown -R $(id -u):$(id -g) .environment \
69+
"
70+
71+
- name: Get Cirque Bootstrap cache key
72+
id: cirque-bootstrap-cache-key
73+
run: echo "val=$(scripts/tests/cirque_tests.sh cachekeyhash)" >> $GITHUB_OUTPUT
74+
- uses: Wandalen/wretry.action@v1.3.0
75+
name: Cirque Bootstrap cache
76+
if: ${{ !env.ACT }}
77+
continue-on-error: true
78+
timeout-minutes: 10
79+
with:
80+
action: buildjet/cache@v3
81+
attempt_limit: 3
82+
attempt_delay: 2000
83+
with: |
84+
key: ${{ runner.os }}-cirque-${{ steps.cirque-bootstrap-cache-key.outputs.val }}
85+
restore-keys: ${{ runner.os }}-cirque-
86+
path: ${{ env.GITHUB_CACHE_PATH }}
87+
- name: Cirque Bootstrap
88+
run: |
89+
integrations/docker/images/stage-2/chip-build-cirque/run.sh \
90+
--env GITHUB_ACTION_RUN=1 \
91+
--env GITHUB_CACHE_PATH=${{ env.GITHUB_CACHE_PATH }} \
92+
--volume /tmp:/tmp \
93+
-- scripts/tests/cirque_tests.sh bootstrap
94+
95+
- name: Artifact suffix
96+
id: outsuffix
97+
uses: haya14busa/action-cond@v1
98+
if: ${{ !env.ACT }}
99+
with:
100+
cond: ${{ github.event.pull_request.number == '' }}
101+
if_true: "${{ github.sha }}"
102+
if_false: "pull-${{ github.event.pull_request.number }}"
103+
- name: Build Binaries
104+
run: |
105+
integrations/docker/images/stage-2/chip-build-cirque/run.sh \
106+
-- sh -c " \
107+
git config --global --add safe.directory '*' \
108+
&& scripts/build/gn_gen_cirque.sh \
109+
"
110+
- name: Run Tests
111+
run: |
112+
integrations/docker/images/stage-2/chip-build-cirque/run.sh \
113+
--env LOG_DIR=/tmp/cirque_test_output \
114+
--env CLEANUP_DOCKER_FOR_CI=1 \
115+
--env GITHUB_ACTION_RUN=1 \
116+
--privileged \
117+
--volume /tmp:/tmp \
118+
--volume /dev/pts:/dev/pts \
119+
-- sh -c " \
120+
git config --global --add safe.directory '*' \
121+
&& scripts/tests/cirque_tests.sh run_all_tests \
122+
"
123+
124+
125+
- name: Uploading Binaries
126+
uses: actions/upload-artifact@v3
127+
if: ${{ always() && !env.ACT }}
128+
with:
129+
name: cirque_log-${{steps.outsuffix.outputs.value}}-logs
130+
path: /tmp/cirque_test_output/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
ARG VERSION=latest
2+
FROM ghcr.io/project-chip/chip-build:${VERSION}
3+
LABEL org.opencontainers.image.source https://github.com/project-chip/connectedhomeip
4+
5+
# Bazel
6+
RUN set -x \
7+
&& apt-get update \
8+
&& DEBIAN_FRONTEND=noninteractive apt-get install -fy \
9+
curl gnupg \
10+
&& curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg \
11+
&& mv bazel.gpg /etc/apt/trusted.gpg.d/ \
12+
&& echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list \
13+
&& apt-get update \
14+
&& DEBIAN_FRONTEND=noninteractive apt-get install -fy \
15+
bazel \
16+
&& : # aids diffs
17+
18+
# Docker
19+
RUN set -x \
20+
&& apt-get update \
21+
&& DEBIAN_FRONTEND=noninteractive apt-get install -fy \
22+
curl gnupg-agent apt-transport-https ca-certificates \
23+
software-properties-common \
24+
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \
25+
&& python3.8 `which add-apt-repository` \
26+
"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
27+
&& apt-get update \
28+
&& DEBIAN_FRONTEND=noninteractive apt-get install -fy \
29+
docker-ce docker-ce-cli containerd.io \
30+
&& : # aids diffs
31+
32+
# Other Cirque prereqs
33+
RUN set -x \
34+
&& apt-get update \
35+
&& DEBIAN_FRONTEND=noninteractive apt-get install -fy \
36+
sudo socat psmisc tigervnc-standalone-server xorg xauth \
37+
python3-pip python3-venv libdbus-glib-1-dev \
38+
uuid-runtime libgirepository1.0-dev \
39+
&& : # aids diffs
40+
41+
COPY requirements_nogrpc.txt /requirements.txt
42+
43+
RUN set -x \
44+
&& pip3 install -r requirements.txt \
45+
&& xinit -- /usr/bin/Xvnc \
46+
&& : # aids diffs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Docker connectedhomeip:chip-build-cirque
2+
3+
project-chip/chip-build-cirque is the name of the Docker image used by CHIP for
4+
continuous integration and other builds when using Cirque. It builds upon the
5+
chip-build image and adds system dependencies needed by Cirque.
6+
7+
Contents of this directory:
8+
9+
- build.sh - utility for building (and optionally) tagging and pushing the
10+
chip-build Docker image
11+
- version - the semver-style version of the image in use for this branch of
12+
CHIP
13+
- Dockerfile - description of the image
14+
15+
Please update version when any required tooling is updated. Some rough
16+
guidelines:
17+
18+
- Updating a tool? Increment dot version unless the tool has a major version
19+
delta or a backward incompatibility
20+
- Adding a tool? Increment minor version: e.g. 0.2.1 -> 0.3.0
21+
- Removing a tool? Increment major version: e.g. 1.2 -> 2.0
22+
23+
Note, you must have privileged access to the connectedhomeip area on Docker Hub
24+
to push the image.
25+
26+
Typical use:
27+
28+
1. new build tool dependency identified
29+
2. add tool to Dockerfile
30+
3. update version
31+
4. `$ ./build.sh`, which installs the image locally as the new version
32+
5. update the image version in the devcontainer.json and CI manifests
33+
6. verify that the build works locally in the new image
34+
7. `$ docker login`
35+
8. `$ ./build.sh --push --latest`, _*Note:*_ omit `--latest` unless on the
36+
master branch
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../build.sh
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmd2
2+
docker >= 4.1.0
3+
flask == 2.2.2
4+
pycodestyle >= 2.5.0
5+
pylint == 2.4
6+
pyroute2 >= 0.5.7
7+
six >= 1.12
8+
toml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../run.sh
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../base/chip-build/version
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright (c) 2020 Project CHIP Authors
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import logging
18+
import subprocess
19+
import sys
20+
import time
21+
from dataclasses import dataclass
22+
from enum import Enum
23+
from multiprocessing.connection import Client, Listener
24+
from pathlib import Path
25+
26+
import click
27+
28+
log = logging.getLogger()
29+
log.setLevel(logging.DEBUG)
30+
31+
sh = logging.StreamHandler()
32+
sh.setFormatter(
33+
logging.Formatter(
34+
'%(asctime)s [%(name)s] %(levelname)s %(message)s'))
35+
log.addHandler(sh)
36+
37+
38+
class CommandStatus(Enum):
39+
"""Enum class for passing status code of execute CirqueDaemon command, not CHIP error codes."""
40+
SUCCESS = 0
41+
FAILURE = 1
42+
UNKNOWN_COMMAND = 2
43+
INVALID_ARGUMENT = 3
44+
45+
46+
@dataclass
47+
class CommandResponse:
48+
"""Class for holding status of running CirqueDaemon commands."""
49+
status_code: CommandStatus
50+
error_message: str = ""
51+
52+
53+
class ShellCommand:
54+
def __init__(self, args=None):
55+
self._args = args
56+
57+
def __call__(self):
58+
if not self._args:
59+
return CommandResponse(CommandStatus.INVALID_ARGUMENT, "Cannot spwan background process")
60+
log.info("Will run command: {}".format(self._args))
61+
try:
62+
# As the command will be execued in background, we won't return the exit code of the program.
63+
subprocess.Popen(
64+
self._args, stdout=sys.stdout, stderr=sys.stderr)
65+
return CommandResponse(CommandStatus.SUCCESS)
66+
except Exception as ex:
67+
return CommandResponse(CommandStatus.FAILURE, "Failed to run command: {}".format(ex))
68+
69+
70+
class InvalidCommand:
71+
def __init__(self, args=None):
72+
self._args = args
73+
74+
def __call__(self):
75+
return CommandResponse(CommandStatus.FAILURE, "invalid command")
76+
77+
78+
SERVER_ADDRESS = "/tmp/cirque-helper.socket"
79+
CLIENT_WAIT_TIMEOUT_SECONDS = 5
80+
81+
82+
def CommandFactory(args):
83+
commands = {
84+
"run": ShellCommand
85+
}
86+
if len(args) == 0:
87+
return InvalidCommand()
88+
return commands.get(args[0], InvalidCommand)(args[1:])
89+
90+
91+
def ServerMain(args):
92+
extraOptions = {
93+
"otbr-agent": ShellCommand(["otbr-agent", "-I", "wpan0", "-B", "eth0", "spinel+hdlc+uart:///dev/ttyUSB0"])
94+
}
95+
96+
with Listener(SERVER_ADDRESS) as listener:
97+
log.info("Server running on {}".format(SERVER_ADDRESS))
98+
for extraOption in args:
99+
cmd = extraOptions.get(extraOption, InvalidCommand())
100+
cmd()
101+
102+
while True:
103+
with listener.accept() as conn:
104+
log.info("Received connection")
105+
cmd = CommandFactory(conn.recv())
106+
conn.send(cmd())
107+
108+
109+
def ClientMain(args):
110+
if len(args) == 0:
111+
sys.exit(1)
112+
# The server may start very slowly, wait for a few seconds to see if the server will start.
113+
for _ in range(CLIENT_WAIT_TIMEOUT_SECONDS):
114+
socks = Path(SERVER_ADDRESS)
115+
if socks.exists():
116+
break
117+
time.sleep(1)
118+
# If the address does not exist, Client constructor will throw an exception, so no need to add a flag.
119+
with Client(SERVER_ADDRESS) as conn:
120+
conn.send(args)
121+
res = conn.recv()
122+
print(res)
123+
if res.status_code != CommandStatus.SUCCESS:
124+
sys.exit(1)
125+
126+
127+
@click.command()
128+
@click.option('--server', is_flag=True)
129+
@click.argument('command', nargs=-1)
130+
def main(server, command):
131+
if server:
132+
ServerMain(command)
133+
else:
134+
ClientMain(command)
135+
136+
137+
if __name__ == '__main__':
138+
main()

0 commit comments

Comments
 (0)