diff --git a/.azure-pipelines/docker-sonic-slave-arm64.yml b/.azure-pipelines/docker-sonic-slave-arm64.yml deleted file mode 100644 index 6350d8fd3b5d..000000000000 --- a/.azure-pipelines/docker-sonic-slave-arm64.yml +++ /dev/null @@ -1,52 +0,0 @@ -# Starter pipeline -# Start with a minimal pipeline that you can customize to build and deploy your code. -# Add steps that build, run tests, deploy, and more: -# https://aka.ms/yaml -# Build and push sonic-slave-[buster|jessie|stretch] images for amd64/armhf/arm64 -resources: - repositories: - - repository: buildimage - type: github - name: sonic-net/sonic-buildimage - ref: master - endpoint: sonic-net - -schedules: -- cron: "0 8 * * *" - branches: - include: - - master - - 202012 - always: true - -trigger: none -pr: - branches: - include: - - master - paths: - include: - - sonic-slave-jessie - - sonic-slave-stretch - - sonic-slave-buster - - sonic-slave-bullseye - - .azure-pipelines - -parameters: -- name: 'dists' - type: object - default: - - bullseye - - buster - - stretch - -stages: -- stage: Build - jobs: - - ${{ each dist in parameters.dists }}: - - ${{ if contains(variables['Build.DefinitionName'], dist) }}: - - template: docker-sonic-slave-template.yml - parameters: - pool: sonicbld-arm64 - arch: arm64 - dist: ${{ dist }} diff --git a/.azure-pipelines/docker-sonic-slave-armhf.yml b/.azure-pipelines/docker-sonic-slave-armhf.yml deleted file mode 100644 index fcdad5f2cd19..000000000000 --- a/.azure-pipelines/docker-sonic-slave-armhf.yml +++ /dev/null @@ -1,52 +0,0 @@ -# Starter pipeline -# Start with a minimal pipeline that you can customize to build and deploy your code. -# Add steps that build, run tests, deploy, and more: -# https://aka.ms/yaml -# Build and push sonic-slave-[buster|jessie|stretch] images for amd64/armhf/arm64 -resources: - repositories: - - repository: buildimage - type: github - name: sonic-net/sonic-buildimage - ref: master - endpoint: sonic-net - -schedules: -- cron: "0 8 * * *" - branches: - include: - - master - - 202012 - always: true - -trigger: none -pr: - branches: - include: - - master - paths: - include: - - sonic-slave-jessie - - sonic-slave-stretch - - sonic-slave-buster - - sonic-slave-bullseye - - .azure-pipelines - -parameters: -- name: 'dists' - type: object - default: - - bullseye - - buster - - stretch - -stages: -- stage: Build - jobs: - - ${{ each dist in parameters.dists }}: - - ${{ if contains(variables['Build.DefinitionName'], dist) }}: - - template: docker-sonic-slave-template.yml - parameters: - pool: sonicbld-armhf - arch: armhf - dist: ${{ dist }} diff --git a/.azure-pipelines/docker-sonic-slave-template.yml b/.azure-pipelines/docker-sonic-slave-template.yml index 2cf06638a4cc..142ff5fa3f6f 100644 --- a/.azure-pipelines/docker-sonic-slave-template.yml +++ b/.azure-pipelines/docker-sonic-slave-template.yml @@ -10,6 +10,9 @@ parameters: - amd64 - armhf - arm64 +- name: march + type: string + default: '' - name: dist type: string values: @@ -32,89 +35,44 @@ parameters: - sonicbld-armhf jobs: -- job: Build_${{ parameters.dist }}_${{ parameters.arch }} +- job: Build_${{ parameters.dist }}_${{ parameters.march }}${{ parameters.arch }} timeoutInMinutes: 360 + variables: + - template: /.azure-pipelines/template-variables.yml@buildimage + - template: /.azure-pipelines/azure-pipelines-repd-build-variables.yml@buildimage pool: ${{ parameters.pool }} steps: - template: cleanup.yml - - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - - template: template-clean-sonic-slave.yml - - ${{ else }}: - - template: '/.azure-pipelines/template-clean-sonic-slave.yml@buildimage' + - template: /.azure-pipelines/template-clean-sonic-slave.yml@buildimage - checkout: self clean: true submodules: recursive + - task: Docker@2 + displayName: Login to ACR + inputs: + command: login + containerRegistry: ${{ parameters.registry_conn }} - bash: | set -ex + image_tag=$(BLDENV=${{ parameters.dist }} make -f Makefile.work showtag PLATFORM=generic PLATFORM_ARCH=${{ parameters.arch }} | grep sonic-slave | tail -n 1) + image_latest=$(echo $(echo $image_tag | awk -F: '{print$1}'):latest) + docker rmi $image_tag || true - SLAVE_DIR=sonic-slave-${{ parameters.dist }} - if [ x${{ parameters.pool }} == x"sonicbld" ]; then - if [ x${{ parameters.arch }} == x"amd64" ]; then - SLAVE_BASE_IMAGE=${SLAVE_DIR} - SLAVE_BASE_IMAGE_UPLOAD=${SLAVE_DIR} - elif [ x${{ parameters.pool }} == x"sonicbld" ]; then - SLAVE_BASE_IMAGE=${SLAVE_DIR}-march-${{ parameters.arch }} - SLAVE_BASE_IMAGE_UPLOAD=${SLAVE_DIR}-march-${{ parameters.arch }} - fi - elif [[ x${{ parameters.pool }} == x"sonicbld-armhf" && x${{ parameters.arch }} == x"armhf" ]]; then - SLAVE_BASE_IMAGE=${SLAVE_DIR} - SLAVE_BASE_IMAGE_UPLOAD=${SLAVE_DIR}-armhf - elif [[ x${{ parameters.pool }} == x"sonicbld-arm64" && x${{ parameters.arch }} == x"arm64" ]]; then - SLAVE_BASE_IMAGE=${SLAVE_DIR} - SLAVE_BASE_IMAGE_UPLOAD=${SLAVE_DIR}-arm64 - else - echo "do not support build ${{ parameters.arch }} on ${{ parameters.pool }}" - exit 1 + if [[ "$(Build.Reason)" =~ [a-zA-Z]*CI ]] && docker pull ${{ parameters.registry_url }}/${image_tag};then + exit 0 fi - if [ x"$(Build.SourceBranchName)" == x"202012" ]; then - BUILD_OPTIONS = 'SONIC_VERSION_CONTROL_COMPONENTS=deb,py2,py3,web,git,docker' + DOCKER_DATA_ROOT_FOR_MULTIARCH=/data/march/docker BLDENV=${{ parameters.dist }} make -f Makefile.work configure PLATFORM=generic PLATFORM_ARCH=${{ parameters.arch }} $args || docker image ls $image_tag + if [[ "$(Build.Reason)" == "PullRequest" ]];then + exit 0 fi - tmpfile=$(mktemp) - - echo ${{ parameters.arch }} > .arch - - DOCKER_DATA_ROOT_FOR_MULTIARCH=/data/march/docker BLDENV=${{ parameters.dist }} $(BUILD_OPTIONS) make -f Makefile.work sonic-slave-build | tee $tmpfile - SLAVE_BASE_TAG=$(grep "^Checking sonic-slave-base image:" $tmpfile | awk -F ':' '{print $3}') - SLAVE_TAG=$(grep "^Checking sonic-slave image:" $tmpfile | awk -F ':' '{print $3}') - - mkdir -p target - - docker tag $SLAVE_BASE_IMAGE:$SLAVE_BASE_TAG $REGISTRY_SERVER/$SLAVE_BASE_IMAGE_UPLOAD:latest - docker tag $SLAVE_BASE_IMAGE:$SLAVE_BASE_TAG $REGISTRY_SERVER/$SLAVE_BASE_IMAGE_UPLOAD:$SLAVE_BASE_TAG - if [ "$SLAVE_BASE_IMAGE_UPLOAD" != "$SLAVE_DIR" ]; then - docker tag $SLAVE_BASE_IMAGE:$SLAVE_BASE_TAG $REGISTRY_SERVER/$SLAVE_DIR:latest-${{ parameters.arch }} - docker tag $SLAVE_BASE_IMAGE:$SLAVE_BASE_TAG $REGISTRY_SERVER/$SLAVE_DIR:$SLAVE_BASE_TAG + docker tag ${image_tag} ${REGISTRY_SERVER}/${image_tag} + docker push ${REGISTRY_SERVER}/${image_tag} + if [[ "${{ parameters.arch }}" == "amd64" ]];then + docker tag ${image_tag} ${REGISTRY_SERVER}/${image_latest} + docker push ${REGISTRY_SERVER}/${image_latest} fi - set +x - echo "##vso[task.setvariable variable=VARIABLE_SLAVE_BASE_IMAGE]$SLAVE_BASE_IMAGE_UPLOAD" - echo "##vso[task.setvariable variable=VARIABLE_SLAVE_BASE_TAG]$SLAVE_BASE_TAG" env: REGISTRY_SERVER: ${{ parameters.registry_url }} displayName: Build sonic-slave-${{ parameters.dist }}-${{ parameters.arch }} - - - task: Docker@2 - condition: ne(variables['Build.Reason'], 'PullRequest') - displayName: Upload image - inputs: - containerRegistry: ${{ parameters.registry_conn }} - repository: $(VARIABLE_SLAVE_BASE_IMAGE) - command: push - ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: - tags: | - $(VARIABLE_SLAVE_BASE_TAG) - latest - ${{ else }}: - tags: | - $(VARIABLE_SLAVE_BASE_TAG) - - ${{ if ne(parameters.arch, 'amd64') }}: - - task: Docker@2 - condition: ne(variables['Build.Reason'], 'PullRequest') - displayName: Upload image ${{ parameters.dist }} - inputs: - containerRegistry: ${{ parameters.registry_conn }} - repository: "sonic-slave-${{ parameters.dist }}" - command: push - tags: | - $(VARIABLE_SLAVE_BASE_TAG) diff --git a/.azure-pipelines/docker-sonic-slave.yml b/.azure-pipelines/docker-sonic-slave.yml index cd8a6df4aff4..dd7a11d2c531 100644 --- a/.azure-pipelines/docker-sonic-slave.yml +++ b/.azure-pipelines/docker-sonic-slave.yml @@ -12,26 +12,28 @@ resources: endpoint: sonic-net schedules: -- cron: "0 8 * * *" +- cron: "0 0 * * 0" + displayName: Weekly build branches: include: - master - - 202012 + - 202??? always: true -trigger: none -pr: +pr: none +trigger: + batch: true branches: include: - master + - 202??? paths: include: - - sonic-slave-jessie - - sonic-slave-stretch - - sonic-slave-buster - - sonic-slave-bullseye + - sonic-slave-* - src/sonic-build-hooks - - .azure-pipelines + - files/build/versions + - Makefile + - Makefile.work parameters: - name: 'arches' @@ -60,15 +62,21 @@ stages: - ${{ each dist in parameters.dists }}: - ${{ if endswith(variables['Build.DefinitionName'], dist) }}: - ${{ each arch in parameters.arches }}: - - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - - template: docker-sonic-slave-template.yml - parameters: - pool: sonicbld - arch: ${{ arch }} - dist: ${{ dist }} - - ${{ else }}: - - template: '/.azure-pipelines/docker-sonic-slave-template.yml@buildimage' + - template: .azure-pipelines/docker-sonic-slave-template.yml@buildimage + parameters: + pool: sonicbld + arch: ${{ arch }} + dist: ${{ dist }} +- stage: Build_march + dependsOn: [] + jobs: + - ${{ each dist in parameters.dists }}: + - ${{ if endswith(variables['Build.DefinitionName'], dist) }}: + - ${{ each arch in parameters.arches }}: + - ${{ if ne(arch, 'amd64') }}: + - template: .azure-pipelines/docker-sonic-slave-template.yml@buildimage parameters: - pool: sonicbld + pool: sonicbld-${{ arch }} arch: ${{ arch }} dist: ${{ dist }} + march: march_ diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1ff6883573d2..d553f7a4d0c4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -39,6 +39,8 @@ Write a short (one line) summary that describes the changes in this pull request for inclusion in the changelog: --> +#### Ensure to add label/tag for the feature raised. example - [PR#2174](https://github.com/sonic-net/sonic-utilities/pull/2174) where, Generic Config and Update feature has been labelled as GCU. + #### Link to config_db schema for YANG module changes + diff --git a/dockers/docker-ptf/Dockerfile.j2 b/dockers/docker-ptf/Dockerfile.j2 index c73d12f3245a..35c85fd1eac4 100644 --- a/dockers/docker-ptf/Dockerfile.j2 +++ b/dockers/docker-ptf/Dockerfile.j2 @@ -136,7 +136,7 @@ RUN rm -rf /debs \ && cd /opt \ && wget https://raw.githubusercontent.com/p4lang/ptf/master/ptf_nn/ptf_nn_agent.py -RUN python3 -m venv env-python3 +RUN python3 -m venv --system-site-packages env-python3 # Activating a virtualenv. The virtualenv automatically works for RUN, ENV and CMD. ENV VIRTUAL_ENV=/root/env-python3 @@ -173,7 +173,8 @@ RUN python3 -m pip install setuptools \ && pip3 install itsdangerous \ && pip3 install retrying \ && pip3 install jinja2 \ - && pip3 install scapy==2.4.5 + && pip3 install scapy==2.4.5 \ + && pip3 install thrift {% if docker_ptf_whls.strip() -%} # Copy locally-built Python wheel dependencies diff --git a/dockers/docker-sonic-mgmt/Dockerfile.j2 b/dockers/docker-sonic-mgmt/Dockerfile.j2 index 42aaa3525a64..c6b4d1600a8e 100755 --- a/dockers/docker-sonic-mgmt/Dockerfile.j2 +++ b/dockers/docker-sonic-mgmt/Dockerfile.j2 @@ -1,5 +1,5 @@ {% set prefix = DEFAULT_CONTAINER_REGISTRY %} -FROM {{ prefix }}ubuntu:18.04 +FROM {{ prefix }}ubuntu:20.04 ENV DEBIAN_FRONTEND=noninteractive @@ -21,8 +21,6 @@ RUN apt-get update && apt-get install -y build-essential \ psmisc \ python \ python-dev \ - python-scapy \ - python-pip \ python3-pip \ python3-venv \ rsyslog \ @@ -31,10 +29,20 @@ RUN apt-get update && apt-get install -y build-essential \ sudo \ tcpdump \ telnet \ - vim + vim \ + python-is-python2 \ + software-properties-common + +RUN add-apt-repository -y universe +RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py \ + && python2 get-pip.py + +RUN curl -L http://archive.ubuntu.com/ubuntu/pool/universe/s/scapy/python-scapy_2.3.3-3_all.deb \ + --output python-scapy_2.3.3-3_all.deb \ + && dpkg -i python-scapy_2.3.3-3_all.deb RUN pip install setuptools==44.1.1 -RUN pip install cffi==1.10.0 \ +RUN pip install cffi==1.12.0 \ contextlib2==0.6.0.post1 \ cryptography==3.3.2 \ "future>=0.16.0" \ @@ -78,6 +86,7 @@ RUN pip install cffi==1.10.0 \ allure-pytest==2.8.22 \ celery[redis]==4.4.7 \ msrest==0.6.21 \ + python-dateutil \ && git clone https://github.com/p4lang/scapy-vxlan.git \ && cd scapy-vxlan \ && python setup.py install \ @@ -96,7 +105,7 @@ RUN pip install cffi==1.10.0 \ && rm -f 1.0.0.tar.gz \ && pip install nnpy \ && pip install dpkt \ - && pip install scapy==2.4.5 --upgrade + && pip install scapy==2.4.5 --upgrade --ignore-installed # Install docker-ce-cli RUN apt-get update \ @@ -114,10 +123,6 @@ RUN apt-get update \ # Install Azure CLI RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash -# Install Microsoft Azure Kusto Library for Python -RUN pip install azure-kusto-data==0.0.13 \ - azure-kusto-ingest==0.0.13 - RUN pip install wheel==0.33.6 ## Copy and install sonic-mgmt docker dependencies @@ -193,8 +198,7 @@ ENV PATH="$VIRTUAL_ENV/bin:$PATH" ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 PYTHONIOENCODING=UTF-8 -RUN python3 -m pip install --upgrade --ignore-installed pip setuptools==58.4.0 - +RUN python3 -m pip install --upgrade --ignore-installed pip setuptools==58.4.0 wheel==0.33.6 RUN python3 -m pip install setuptools-rust \ aiohttp \ defusedxml \ @@ -210,6 +214,7 @@ RUN python3 -m pip install setuptools-rust \ ixnetwork-restpy==1.0.64 \ ixnetwork-open-traffic-generator==0.0.79 \ snappi[ixnetwork,convergence]==0.7.44 \ + markupsafe==2.0.1 \ jinja2==2.7.2 \ jsonpatch \ lxml \ @@ -237,7 +242,6 @@ RUN python3 -m pip install setuptools-rust \ tabulate \ textfsm==1.1.2 \ virtualenv \ - wheel==0.33.6 \ pysubnettree \ nnpy \ dpkt \ @@ -250,7 +254,8 @@ RUN python3 -m pip install setuptools-rust \ ptf \ scapy==2.4.5 \ celery[redis]==4.4.7 \ - msrest==0.6.21 + msrest==0.6.21 \ + python-dateutil -# Deactivating a virtualenv. +# Deactivating a virtualenv ENV PATH="$BACKUP_OF_PATH" diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index a77706cad497..ace39df4e546 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -87,7 +87,7 @@ function preStartAction() {%- if docker_container_name == "database" %} WARM_DIR=/host/warmboot if [ "$DATABASE_TYPE" != "chassisdb" ]; then - if [[ ("$BOOT_TYPE" == "warm" || "$BOOT_TYPE" == "fastfast") && -f $WARM_DIR/dump.rdb ]]; then + if [[ ("$BOOT_TYPE" == "warm" || "$BOOT_TYPE" == "fastfast" || "$BOOT_TYPE" == "fast") && -f $WARM_DIR/dump.rdb ]]; then # Load redis content from /host/warmboot/dump.rdb docker cp $WARM_DIR/dump.rdb database$DEV:/var/lib/redis/dump.rdb else @@ -170,16 +170,26 @@ function postStartAction() ip netns exec "$NET_NS" ip addr add 127.0.0.1/16 dev lo ip netns exec "$NET_NS" ip addr del 127.0.0.1/8 dev lo + slot_id=$(python3 -c 'import sonic_platform.platform; platform_chassis = sonic_platform.platform.Platform().get_chassis(); print(platform_chassis.get_my_slot())' 2>/dev/null) + supervisor_slot_id=$(python3 -c 'import sonic_platform.platform; platform_chassis = sonic_platform.platform.Platform().get_chassis(); print(platform_chassis.get_supervisor_slot())' 2>/dev/null) + + # Create eth1 in database instance + if [[ "${slot_id}" == "${supervisor_slot_id}" ]]; then + ip link add name ns-eth1"$NET_NS" type veth peer name eth1@"$NET_NS" + ip link set dev eth1@"$NET_NS" master br1 + ip link set dev eth1@"$NET_NS" up + else + ip link add name ns-eth1"$NET_NS" link eth1-midplane type macvlan mode bridge + fi + # Create eth1 in database instance - ip link add name ns-eth1"$NET_NS" link eth1-midplane type macvlan mode bridge ip link set dev ns-eth1"$NET_NS" netns "$NET_NS" ip netns exec "$NET_NS" ip link set ns-eth1"$NET_NS" name eth1 # Configure IP address and enable eth1 - lc_slot_id=$(python3 -c 'import sonic_platform.platform; platform_chassis = sonic_platform.platform.Platform().get_chassis(); print(platform_chassis.get_my_slot())' 2>/dev/null) - lc_ip_address=`echo $midplane_subnet | awk -F. '{print $1 "." $2}'`.$lc_slot_id.$(($DEV + 10)) - lc_subnet_mask=${midplane_subnet#*/} - ip netns exec "$NET_NS" ip addr add $lc_ip_address/$lc_subnet_mask dev eth1 + slot_ip_address=`echo $midplane_subnet | awk -F. '{print $1 "." $2}'`.$slot_id.$(($DEV + 10)) + slot_subnet_mask=${midplane_subnet#*/} + ip netns exec "$NET_NS" ip addr add $slot_ip_address/$slot_subnet_mask dev eth1 ip netns exec "$NET_NS" ip link set dev eth1 up # Allow localnet routing on the new interfaces if midplane is using a @@ -208,7 +218,7 @@ function postStartAction() ($(docker exec -i database$DEV sonic-db-cli PING | grep -c PONG) -gt 0) ]]; do sleep 1; done - if [[ ("$BOOT_TYPE" == "warm" || "$BOOT_TYPE" == "fastfast") && -f $WARM_DIR/dump.rdb ]]; then + if [[ ("$BOOT_TYPE" == "warm" || "$BOOT_TYPE" == "fastfast" || "$BOOT_TYPE" == "fast") && -f $WARM_DIR/dump.rdb ]]; then # retain the dump file from last boot for debugging purposes mv $WARM_DIR/dump.rdb $WARM_DIR/dump.rdb.old else @@ -584,6 +594,17 @@ stop() { {%- endif %} } +kill() { + {%- if docker_container_name == "database" %} + docker kill $DOCKERNAME + if [ "$DEV" ]; then + ip netns delete "$NET_NS" + fi + {%- else %} + /usr/local/bin/container kill $DOCKERNAME + {%- endif %} +} + DOCKERNAME={{docker_container_name}} OP=$1 DEV=$2 # namespace/device number to operate on @@ -611,7 +632,7 @@ fi [ -f /etc/sonic/sonic-environment ] && . /etc/sonic/sonic-environment case "$1" in - start|wait|stop) + start|wait|stop|kill) $1 ;; *) diff --git a/files/build_templates/mgmt-framework.service.j2 b/files/build_templates/mgmt-framework.service.j2 index 1eb983a897fb..ff99afe62bc1 100644 --- a/files/build_templates/mgmt-framework.service.j2 +++ b/files/build_templates/mgmt-framework.service.j2 @@ -8,6 +8,6 @@ Before=ntp-config.service [Service] User={{ sonicadmin_user }} -ExecStartPre=/usr/bin/{{docker_container_name}}.sh start -ExecStart=/usr/bin/{{docker_container_name}}.sh wait -ExecStop=/usr/bin/{{docker_container_name}}.sh stop +ExecStartPre=/usr/local/bin/{{docker_container_name}}.sh start +ExecStart=/usr/local/bin/{{docker_container_name}}.sh wait +ExecStop=/usr/local/bin/{{docker_container_name}}.sh stop diff --git a/files/build_templates/per_namespace/bgp.service.j2 b/files/build_templates/per_namespace/bgp.service.j2 index 0c9f01fe8b68..61eb71c4db9a 100644 --- a/files/build_templates/per_namespace/bgp.service.j2 +++ b/files/build_templates/per_namespace/bgp.service.j2 @@ -7,6 +7,7 @@ After=updategraph.service BindsTo=sonic.target After=sonic.target Before=ntp-config.service +After=interfaces-config.service StartLimitIntervalSec=1200 StartLimitBurst=3 diff --git a/files/build_templates/per_namespace/database.service.j2 b/files/build_templates/per_namespace/database.service.j2 index c42995d2054c..c5c8f267d972 100644 --- a/files/build_templates/per_namespace/database.service.j2 +++ b/files/build_templates/per_namespace/database.service.j2 @@ -14,9 +14,9 @@ StartLimitBurst=3 [Service] User=root -ExecStartPre=/usr/bin/{{docker_container_name}}.sh start{% if multi_instance == 'true' %} %i{% endif %} -ExecStart=/usr/bin/{{docker_container_name}}.sh wait{% if multi_instance == 'true' %} %i{% endif %} -ExecStop=/usr/bin/{{docker_container_name}}.sh stop{% if multi_instance == 'true' %} %i{% endif %} +ExecStartPre=/usr/local/bin/{{docker_container_name}}.sh start{% if multi_instance == 'true' %} %i{% endif %} +ExecStart=/usr/local/bin/{{docker_container_name}}.sh wait{% if multi_instance == 'true' %} %i{% endif %} +ExecStop=/usr/local/bin/{{docker_container_name}}.sh stop{% if multi_instance == 'true' %} %i{% endif %} RestartSec=30 [Install] diff --git a/files/build_templates/snmp.service.j2 b/files/build_templates/snmp.service.j2 index b27ac347007b..5c753dd651eb 100644 --- a/files/build_templates/snmp.service.j2 +++ b/files/build_templates/snmp.service.j2 @@ -10,7 +10,7 @@ StartLimitIntervalSec=1200 StartLimitBurst=3 [Service] -ExecStartPre=/usr/bin/{{docker_container_name}}.sh start -ExecStart=/usr/bin/{{docker_container_name}}.sh wait -ExecStop=/usr/bin/{{docker_container_name}}.sh stop +ExecStartPre=/usr/local/bin/{{docker_container_name}}.sh start +ExecStart=/usr/local/bin/{{docker_container_name}}.sh wait +ExecStop=/usr/local/bin/{{docker_container_name}}.sh stop RestartSec=30 diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 511f54fd3997..08098b9c13ed 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -465,7 +465,7 @@ sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip3 install watchd {% if include_kubernetes == "y" %} # Point to kubelet to /etc/resolv.conf # -echo 'KUBELET_EXTRA_ARGS="--resolv-conf=/etc/resolv.conf"' | sudo tee -a $FILESYSTEM_ROOT/etc/default/kubelet +echo 'KUBELET_EXTRA_ARGS="--resolv-conf=/etc/resolv.conf --cgroup-driver=cgroupfs --node-ip=::"' | sudo tee -a $FILESYSTEM_ROOT/etc/default/kubelet # Copy Flannel conf file into sonic-templates # @@ -859,6 +859,10 @@ sudo LANG=C cp $SCRIPTS_DIR/bgp.sh $FILESYSTEM_ROOT/usr/local/bin/bgp.sh sudo LANG=C cp $SCRIPTS_DIR/teamd.sh $FILESYSTEM_ROOT/usr/local/bin/teamd.sh sudo LANG=C cp $SCRIPTS_DIR/lldp.sh $FILESYSTEM_ROOT/usr/local/bin/lldp.sh sudo LANG=C cp $SCRIPTS_DIR/radv.sh $FILESYSTEM_ROOT/usr/local/bin/radv.sh +sudo LANG=C cp $SCRIPTS_DIR/database.sh $FILESYSTEM_ROOT/usr/local/bin/database.sh +sudo LANG=C cp $SCRIPTS_DIR/snmp.sh $FILESYSTEM_ROOT/usr/local/bin/snmp.sh +sudo LANG=C cp $SCRIPTS_DIR/telemetry.sh $FILESYSTEM_ROOT/usr/local/bin/telemetry.sh +sudo LANG=C cp $SCRIPTS_DIR/mgmt-framework.sh $FILESYSTEM_ROOT/usr/local/bin/mgmt-framework.sh sudo LANG=C cp $SCRIPTS_DIR/asic_status.sh $FILESYSTEM_ROOT/usr/local/bin/asic_status.sh sudo LANG=C cp $SCRIPTS_DIR/asic_status.py $FILESYSTEM_ROOT/usr/local/bin/asic_status.py diff --git a/files/build_templates/telemetry.service.j2 b/files/build_templates/telemetry.service.j2 index 33affa62a748..ebdd484dc877 100644 --- a/files/build_templates/telemetry.service.j2 +++ b/files/build_templates/telemetry.service.j2 @@ -10,7 +10,7 @@ StartLimitBurst=3 [Service] User={{ sonicadmin_user }} -ExecStartPre=/usr/bin/{{docker_container_name}}.sh start -ExecStart=/usr/bin/{{docker_container_name}}.sh wait -ExecStop=/usr/bin/{{docker_container_name}}.sh stop +ExecStartPre=/usr/local/bin/{{docker_container_name}}.sh start +ExecStart=/usr/local/bin/{{docker_container_name}}.sh wait +ExecStop=/usr/local/bin/{{docker_container_name}}.sh stop RestartSec=30 diff --git a/files/image_config/environment/motd b/files/image_config/environment/motd index 8562e330fe2c..0d857e5c5f94 100644 --- a/files/image_config/environment/motd +++ b/files/image_config/environment/motd @@ -10,5 +10,5 @@ You are on Unauthorized access and/or use are prohibited. All access and/or use are subject to monitoring. -Help: http://azure.github.io/SONiC/ +Help: https://sonic-net.github.io/SONiC/ diff --git a/files/scripts/database.sh b/files/scripts/database.sh new file mode 120000 index 000000000000..ce97295f0364 --- /dev/null +++ b/files/scripts/database.sh @@ -0,0 +1 @@ +service_mgmt.sh \ No newline at end of file diff --git a/files/scripts/mgmt-framework.sh b/files/scripts/mgmt-framework.sh new file mode 120000 index 000000000000..ce97295f0364 --- /dev/null +++ b/files/scripts/mgmt-framework.sh @@ -0,0 +1 @@ +service_mgmt.sh \ No newline at end of file diff --git a/files/scripts/radv.sh b/files/scripts/radv.sh deleted file mode 100755 index 1047808e4e44..000000000000 --- a/files/scripts/radv.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash - -function debug() -{ - /usr/bin/logger $1 - /bin/echo `date` "- $1" >> ${DEBUGLOG} -} - -function check_warm_boot() -{ - SYSTEM_WARM_START=`$SONIC_DB_CLI STATE_DB hget "WARM_RESTART_ENABLE_TABLE|system" enable` - SERVICE_WARM_START=`$SONIC_DB_CLI STATE_DB hget "WARM_RESTART_ENABLE_TABLE|${SERVICE}" enable` - if [[ x"$SYSTEM_WARM_START" == x"true" ]] || [[ x"$SERVICE_WARM_START" == x"true" ]]; then - WARM_BOOT="true" - else - WARM_BOOT="false" - fi -} - -function check_fast_boot () -{ - if [[ $($SONIC_DB_CLI STATE_DB GET "FAST_REBOOT|system") == "1" ]]; then - FAST_BOOT="true" - else - FAST_BOOT="false" - fi -} - -start() { - debug "Starting ${SERVICE}$DEV service..." - - check_warm_boot - check_fast_boot - debug "Warm boot flag: ${SERVICE}$DEV ${WARM_BOOT}." - debug "Fast boot flag: ${SERVICE}$DEV ${FAST_BOOT}." - - # start service docker - /usr/bin/${SERVICE}.sh start $DEV - debug "Started ${SERVICE}$DEV service..." -} - -wait() { - /usr/bin/${SERVICE}.sh wait $DEV -} - -stop() { - debug "Stopping ${SERVICE}$DEV service..." - - check_warm_boot - check_fast_boot - debug "Warm boot flag: ${SERVICE}$DEV ${WARM_BOOT}." - debug "Fast boot flag: ${SERVICE}$DEV ${FAST_BOOT}." - - # For WARM/FAST boot do not perform service stop - if [[ x"$WARM_BOOT" != x"true" ]] && [[ x"$FAST_BOOT" != x"true" ]]; then - /usr/bin/${SERVICE}.sh stop $DEV - debug "Stopped ${SERVICE}$DEV service..." - else - debug "Killing Docker radv..." - /usr/bin/docker kill radv &> /dev/null || debug "Docker radv is not running ($?) ..." - fi -} - -DEV=$2 - -SERVICE="radv" -DEBUGLOG="/tmp/radv-debug$DEV.log" -NAMESPACE_PREFIX="asic" -if [ "$DEV" ]; then - NET_NS="$NAMESPACE_PREFIX$DEV" #name of the network namespace - SONIC_DB_CLI="sonic-db-cli -n $NET_NS" -else - SONIC_DB_CLI="sonic-db-cli" -fi - -case "$1" in - start|wait|stop) - $1 - ;; - *) - echo "Usage: $0 {start|wait|stop}" - exit 1 - ;; -esac diff --git a/files/scripts/radv.sh b/files/scripts/radv.sh new file mode 120000 index 000000000000..ce97295f0364 --- /dev/null +++ b/files/scripts/radv.sh @@ -0,0 +1 @@ +service_mgmt.sh \ No newline at end of file diff --git a/files/scripts/service_mgmt.sh b/files/scripts/service_mgmt.sh new file mode 100755 index 000000000000..d400c8472246 --- /dev/null +++ b/files/scripts/service_mgmt.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +function debug() +{ + /usr/bin/logger $1 + /bin/echo `date` "- $1" >> ${DEBUGLOG} +} + +function check_warm_boot() +{ + SYSTEM_WARM_START=`$SONIC_DB_CLI STATE_DB hget "WARM_RESTART_ENABLE_TABLE|system" enable` + SERVICE_WARM_START=`$SONIC_DB_CLI STATE_DB hget "WARM_RESTART_ENABLE_TABLE|${SERVICE}" enable` + if [[ x"$SYSTEM_WARM_START" == x"true" ]] || [[ x"$SERVICE_WARM_START" == x"true" ]]; then + WARM_BOOT="true" + else + WARM_BOOT="false" + fi +} + +function check_fast_boot () +{ + if [[ $($SONIC_DB_CLI STATE_DB GET "FAST_REBOOT|system") == "1" ]]; then + FAST_BOOT="true" + else + FAST_BOOT="false" + fi +} + +start() { + debug "Starting ${SERVICE}$DEV service..." + + # start service docker + /usr/bin/${SERVICE}.sh start $DEV + debug "Started ${SERVICE}$DEV service..." +} + +wait() { + /usr/bin/${SERVICE}.sh wait $DEV +} + +stop() { + debug "Stopping ${SERVICE}$DEV service..." + + check_warm_boot + check_fast_boot + debug "Warm boot flag: ${SERVICE}$DEV ${WARM_BOOT}." + debug "Fast boot flag: ${SERVICE}$DEV ${FAST_BOOT}." + + # For WARM/FAST boot do not perform service stop + if [[ x"$WARM_BOOT" != x"true" ]] && [[ x"$FAST_BOOT" != x"true" ]]; then + /usr/bin/${SERVICE}.sh stop $DEV + debug "Stopped ${SERVICE}$DEV service..." + else + debug "Killing Docker ${SERVICE}${DEV}..." + /usr/bin/${SERVICE}.sh kill $DEV + fi +} + +DEV=$2 + +SCRIPT_NAME=$(basename -- "$0") +SERVICE="${SCRIPT_NAME%.*}" +DEBUGLOG="/tmp/$SERVICE-debug$DEV.log" +NAMESPACE_PREFIX="asic" +if [ "$DEV" ]; then + NET_NS="$NAMESPACE_PREFIX$DEV" #name of the network namespace + SONIC_DB_CLI="sonic-db-cli -n $NET_NS" +else + SONIC_DB_CLI="sonic-db-cli" +fi + +case "$1" in + start|wait|stop) + $1 + ;; + *) + echo "Usage: $0 {start|wait|stop}" + exit 1 + ;; +esac diff --git a/files/scripts/snmp.sh b/files/scripts/snmp.sh new file mode 120000 index 000000000000..ce97295f0364 --- /dev/null +++ b/files/scripts/snmp.sh @@ -0,0 +1 @@ +service_mgmt.sh \ No newline at end of file diff --git a/files/scripts/telemetry.sh b/files/scripts/telemetry.sh new file mode 120000 index 000000000000..ce97295f0364 --- /dev/null +++ b/files/scripts/telemetry.sh @@ -0,0 +1 @@ +service_mgmt.sh \ No newline at end of file diff --git a/platform/barefoot/sonic-platform-modules-arista b/platform/barefoot/sonic-platform-modules-arista index b65a69a9e1c2..11180c37fa17 160000 --- a/platform/barefoot/sonic-platform-modules-arista +++ b/platform/barefoot/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit b65a69a9e1c2c876ba5210ce8b2a1cc9b5c8b18f +Subproject commit 11180c37fa17421afdeef346b3896552872a2721 diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/chassis.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/chassis.py index 6d0e8b8c120c..1041561db423 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/chassis.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/chassis.py @@ -13,8 +13,8 @@ from sonic_platform.psu import psu_list_get from sonic_platform.fan_drawer import fan_drawer_list_get from sonic_platform.thermal import thermal_list_get - from eeprom import Eeprom - from platform_utils import file_create + from sonic_platform.platform_utils import file_create + from sonic_platform.eeprom import Eeprom from sonic_platform.platform_thrift_client import pltfm_mgr_ready from sonic_platform.platform_thrift_client import thrift_try @@ -40,7 +40,10 @@ class Chassis(ChassisBase): def __init__(self): ChassisBase.__init__(self) - self.__eeprom = None + self._eeprom = Eeprom() + self.__tlv_bin_eeprom = self._eeprom.get_raw_data() + self.__tlv_dict_eeprom = self._eeprom.get_data() + self.__fan_drawers = None self.__fan_list = None self.__thermals = None @@ -57,16 +60,6 @@ def __init__(self): file_create(config_dict['handlers']['file']['filename'], '646') logging.config.dictConfig(config_dict) - @property - def _eeprom(self): - if self.__eeprom is None: - self.__eeprom = Eeprom() - return self.__eeprom - - @_eeprom.setter - def _eeprom(self, value): - pass - @property def _fan_drawer_list(self): if self.__fan_drawers is None: @@ -152,7 +145,7 @@ def get_name(self): Returns: string: The name of the chassis """ - return self._eeprom.modelstr() + return self._eeprom.modelstr(self.__tlv_bin_eeprom) def get_presence(self): """ @@ -168,7 +161,7 @@ def get_model(self): Returns: string: Model/part number of chassis """ - return self._eeprom.part_number_str() + return self._eeprom.part_number_str(self.__tlv_bin_eeprom) def get_serial(self): """ @@ -176,7 +169,7 @@ def get_serial(self): Returns: string: Serial number of chassis """ - return self._eeprom.serial_number_str() + return self._eeprom.serial_number_str(self.__tlv_bin_eeprom) def get_revision(self): """ @@ -184,7 +177,8 @@ def get_revision(self): Returns: string: Revision number of chassis """ - return self._eeprom.revision_str() + return self.__tlv_dict_eeprom.get( + "0x{:X}".format(Eeprom._TLV_CODE_LABEL_REVISION), 'N/A') def get_sfp(self, index): """ @@ -225,7 +219,7 @@ def get_base_mac(self): A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ - return self._eeprom.base_mac_addr() + return self._eeprom.base_mac_addr(self.__tlv_bin_eeprom) def get_system_eeprom_info(self): """ @@ -236,7 +230,7 @@ def get_system_eeprom_info(self): OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ - return self._eeprom.system_eeprom_info() + return self.__tlv_dict_eeprom def __get_transceiver_change_event(self, timeout=0): forever = False diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/component.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/component.py index 47a0993bf3e5..a7f236cb42a4 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/component.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/component.py @@ -6,6 +6,7 @@ import json from collections import OrderedDict from sonic_py_common import device_info + from platform_utils import limit_execution_time except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -24,6 +25,7 @@ def get_bios_version(): except subprocess.CalledProcessError as e: raise RuntimeError("Failed to get BIOS version") +@limit_execution_time(1) def get_bmc_version(): """ Retrieves the firmware version of the BMC diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/eeprom.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/eeprom.py index 2335c02863d9..4b5c1e3051fb 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/eeprom.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/eeprom.py @@ -2,7 +2,8 @@ import os import sys import datetime - import re + import logging + import logging.config sys.path.append(os.path.dirname(__file__)) @@ -13,13 +14,15 @@ from sonic_platform_base.sonic_eeprom import eeprom_base from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo - from platform_utils import file_create - from platform_thrift_client import thrift_try + from sonic_py_common import device_info + + from sonic_platform.platform_thrift_client import thrift_try + from sonic_platform.platform_utils import file_create + except ImportError as e: raise ImportError (str(e) + "- required module not found") - _platform_eeprom_map = { "prod_name" : ("Product Name", "0x21", 12), "odm_pcba_part_num" : ("Part Number", "0x22", 13), @@ -44,25 +47,55 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): def __init__(self): file_create(_EEPROM_SYMLINK, '646') file_create(_EEPROM_STATUS, '646') - with open(_EEPROM_STATUS, 'w') as f: - f.write("initializing..") + super(Eeprom, self).__init__(_EEPROM_SYMLINK, 0, _EEPROM_STATUS, True) - self.eeprom_path = _EEPROM_SYMLINK - super(Eeprom, self).__init__(self.eeprom_path, 0, _EEPROM_STATUS, True) - - def sys_eeprom_get(client): - return client.pltfm_mgr.pltfm_mgr_sys_eeprom_get() + self._eeprom_bin = bytearray() + self.report_status("initializing..") try: - platform_eeprom = thrift_try(sys_eeprom_get) - except Exception: - raise RuntimeError("eeprom.py: Initialization failed") + try: + if device_info.get_platform() in ["x86_64-accton_as9516_32d-r0", + "x86_64-accton_as9516bf_32d-r0"]: + def tlv_eeprom_get(client): + return client.pltfm_mgr.pltfm_mgr_tlv_eeprom_get() + try: + self._eeprom_bin = bytearray.fromhex( + thrift_try(tlv_eeprom_get, 1).raw_content_hex) + except TApplicationException as e: + raise RuntimeError("api is not supported") + except Exception as e: + self._eeprom_bin = bytearray.fromhex( + thrift_try(tlv_eeprom_get).raw_content_hex) + else: + raise RuntimeError("platform is not supported") + + except RuntimeError as e: + logging.warning("Tlv eeprom fetching failed: %s, using OpenBMC" % (str(e))) + + def sys_eeprom_get(client): + return client.pltfm_mgr.pltfm_mgr_sys_eeprom_get() + + eeprom_params = self.platfrom_eeprom_to_params(thrift_try(sys_eeprom_get)) + stdout_stream = sys.stdout + sys.stdout = open(os.devnull, 'w') + self._eeprom_bin = self.set_eeprom(self._eeprom_bin, [eeprom_params]) + sys.stdout.close() + sys.stdout = stdout_stream + try: + self.write_eeprom(self._eeprom_bin) + self.report_status("ok") + except IOError as e: + logging.error("Failed to write eeprom: %s" % (str(e))) - self.__eeprom_init(platform_eeprom) + except Exception as e: + logging.error("eeprom.py: Initialization failed: %s" % (str(e))) + raise RuntimeError("eeprom.py: Initialization failed: %s" % (str(e))) - def __eeprom_init(self, platform_eeprom): - with open(_EEPROM_STATUS, 'w') as f: - f.write("ok") + self._system_eeprom_info = dict() + visitor = EepromContentVisitor(self._system_eeprom_info) + self.visit_eeprom(self._eeprom_bin, visitor) + @staticmethod + def platfrom_eeprom_to_params(platform_eeprom): eeprom_params = "" for attr, val in platform_eeprom.__dict__.items(): if val is None: @@ -86,57 +119,41 @@ def __eeprom_init(self, platform_eeprom): if len(eeprom_params) > 0: eeprom_params += "," eeprom_params += "{0:s}={1:s}".format(elem[1], value) + return eeprom_params - orig_stdout = sys.stdout - sys.stdout = StringIO() - try: - eeprom_data = eeprom_tlvinfo.TlvInfoDecoder.set_eeprom(self, "", [eeprom_params]) - finally: - decode_output = sys.stdout.getvalue() - sys.stdout = orig_stdout - - eeprom_base.EepromDecoder.write_eeprom(self, eeprom_data) - self.__eeprom_tlv_dict = self.__parse_output(decode_output) + def get_data(self): + return self._system_eeprom_info - def __parse_output(self, decode_output): - EEPROM_DECODE_HEADLINES = 6 - lines = decode_output.replace('\0', '').split('\n') - lines = lines[EEPROM_DECODE_HEADLINES:] - res = dict() - - for line in lines: - try: - # match whitespace-separated tag hex, length and value (value is mathced with its whitespaces) - match = re.search('(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+[\s]*[\S]*)', line) - if match is not None: - code = match.group(1) - value = match.group(3).rstrip('\0') - res[code] = value - except Exception: - pass - return res - - def __tlv_get(self, code): - return self.__eeprom_tlv_dict.get("0x{:X}".format(code), 'N/A') - - def system_eeprom_info(self): - return self.__eeprom_tlv_dict - - def serial_number_str(self): - return self.__tlv_get(self._TLV_CODE_SERIAL_NUMBER) - - def serial_str(self): - return self.serial_number_str() - - def base_mac_addr(self): - return self.__tlv_get(self._TLV_CODE_MAC_BASE) - - def part_number_str(self): - return self.__tlv_get(self._TLV_CODE_PART_NUMBER) - - def modelstr(self): - return self.__tlv_get(self._TLV_CODE_PRODUCT_NAME) - - def revision_str(self): - return self.__tlv_get(self._TLV_CODE_LABEL_REVISION) + def get_raw_data(self): + return self._eeprom_bin + def report_status(self, status): + status_file = None + try: + status_file = open(_EEPROM_STATUS, "w") + status_file.write(status) + except IOError as e: + logging.error("Failed to report state: %s" % (str(e))) + finally: + if status_file is not None: + status_file.close() + +class EepromContentVisitor(eeprom_tlvinfo.EepromDefaultVisitor): + def __init__(self, content_dict): + self.content_dict = content_dict + + def visit_tlv(self, name, code, length, value): + if code != Eeprom._TLV_CODE_VENDOR_EXT: + self.content_dict["0x{:X}".format(code)] = value.rstrip('\0') + else: + if value: + value = value.rstrip('\0') + if value: + code = "0x{:X}".format(code) + if code not in self.content_dict: + self.content_dict[code] = [value] + else: + self.content_dict[code].append(value) + + def set_error(self, error): + logging.error("EepromContentVisitor error: %s" % (str(error))) diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/platform_thrift_client.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/platform_thrift_client.py index dff16577de74..8490d132a2df 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/platform_thrift_client.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/platform_thrift_client.py @@ -1,12 +1,10 @@ #!/usr/bin/env python try: - import os - import sys import time - import importlib - sys.path.append(os.path.dirname(__file__)) + from sonic_platform.pltfm_mgr_rpc.pltfm_mgr_rpc import Client + from sonic_platform.pltfm_mgr_rpc.pltfm_mgr_rpc import InvalidPltfmMgrOperation from thrift.transport import TSocket from thrift.transport import TTransport @@ -25,9 +23,8 @@ def open(self): self.transport = TTransport.TBufferedTransport(self.transport) bprotocol = TBinaryProtocol.TBinaryProtocol(self.transport) - self.pltfm_mgr_module = importlib.import_module(".".join(["pltfm_mgr_rpc", "pltfm_mgr_rpc"])) pltfm_mgr_protocol = TMultiplexedProtocol.TMultiplexedProtocol(bprotocol, "pltfm_mgr_rpc") - self.pltfm_mgr = self.pltfm_mgr_module.Client(pltfm_mgr_protocol) + self.pltfm_mgr = Client(pltfm_mgr_protocol) self.transport.open() return self @@ -59,7 +56,7 @@ def pltfm_mgr_try(func, default=None, thrift_attempts=35): def pm_cb_run(client): try: return (None, func(client.pltfm_mgr)) - except client.pltfm_mgr_module.InvalidPltfmMgrOperation as ouch: + except InvalidPltfmMgrOperation as ouch: return (ouch.code, default) return thrift_try(pm_cb_run) diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/platform_utils.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/platform_utils.py index 81e78ee01041..2f7b5aecb6d0 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/platform_utils.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/platform_utils.py @@ -3,11 +3,19 @@ try: import os import subprocess + import signal + from functools import wraps except ImportError as e: raise ImportError(str(e) + "- required module not found") def file_create(path, mode=None): + """ + Ensure that file is created with the appropriate permissions + Args: + path: full path of a file + mode: file permission in octal representation + """ def run_cmd(cmd): if os.geteuid() != 0: cmd.insert(0, 'sudo') @@ -18,5 +26,55 @@ def run_cmd(cmd): run_cmd(['mkdir', '-p', file_path]) if not os.path.isfile(path): run_cmd(['touch', path]) - if (mode is not None): + if (mode is not None): run_cmd(['chmod', mode, path]) + +def cancel_on_sigterm(func): + """ + Wrapper for a function which has to be cancel on SIGTERM + """ + @wraps(func) + def wrapper(*args, **kwargs): + def handler(sig, frame): + if sigterm_handler: + sigterm_handler(sig, frame) + raise Exception("Canceling {}() execution...".format(func.__name__)) + + sigterm_handler = signal.getsignal(signal.SIGTERM) + signal.signal(signal.SIGTERM, handler) + result = None + try: + result = func(*args, **kwargs) + finally: + signal.signal(signal.SIGTERM, sigterm_handler) + return result + return wrapper + +def limit_execution_time(execution_time_secs: int): + """ + Wrapper for a function whose execution time must be limited + Args: + execution_time_secs: maximum execution time in seconds, + after which the function execution will be stopped + """ + def wrapper(func): + @wraps(func) + def execution_func(*args, **kwargs): + def handler(sig, frame): + if sigalrm_handler: + sigalrm_handler(sig, frame) + raise Exception("Canceling {}() execution...".format(func.__name__)) + + sigalrm_handler = signal.getsignal(signal.SIGALRM) + signal.signal(signal.SIGALRM, handler) + signal.alarm(execution_time_secs) + result = None + try: + result = func(*args, **kwargs) + finally: + signal.alarm(0) + + return result + return execution_func + return wrapper + diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/pltfm_mgr_rpc/pltfm_mgr_rpc.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/pltfm_mgr_rpc/pltfm_mgr_rpc.py index 0fa03d58b31a..b671be1be313 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/pltfm_mgr_rpc/pltfm_mgr_rpc.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/pltfm_mgr_rpc/pltfm_mgr_rpc.py @@ -33,6 +33,9 @@ def pltfm_mgr_sys_tmp_get(self): def pltfm_mgr_sys_eeprom_get(self): pass + def pltfm_mgr_tlv_eeprom_get(self): + pass + def pltfm_mgr_pwr_supply_present_get(self, ps_num): """ Parameters: @@ -403,6 +406,34 @@ def recv_pltfm_mgr_sys_eeprom_get(self): raise result.ouch raise TApplicationException(TApplicationException.MISSING_RESULT, "pltfm_mgr_sys_eeprom_get failed: unknown result") + def pltfm_mgr_tlv_eeprom_get(self): + self.send_pltfm_mgr_tlv_eeprom_get() + return self.recv_pltfm_mgr_tlv_eeprom_get() + + def send_pltfm_mgr_tlv_eeprom_get(self): + self._oprot.writeMessageBegin('pltfm_mgr_tlv_eeprom_get', TMessageType.CALL, self._seqid) + args = pltfm_mgr_tlv_eeprom_get_args() + args.write(self._oprot) + self._oprot.writeMessageEnd() + self._oprot.trans.flush() + + def recv_pltfm_mgr_tlv_eeprom_get(self): + iprot = self._iprot + (fname, mtype, rseqid) = iprot.readMessageBegin() + if mtype == TMessageType.EXCEPTION: + x = TApplicationException() + x.read(iprot) + iprot.readMessageEnd() + raise x + result = pltfm_mgr_tlv_eeprom_get_result() + result.read(iprot) + iprot.readMessageEnd() + if result.success is not None: + return result.success + if result.ouch is not None: + raise result.ouch + raise TApplicationException(TApplicationException.MISSING_RESULT, "pltfm_mgr_tlv_eeprom_get failed: unknown result") + def pltfm_mgr_pwr_supply_present_get(self, ps_num): """ Parameters: @@ -1579,6 +1610,7 @@ def __init__(self, handler): self._processMap["pltfm_mgr_dummy"] = Processor.process_pltfm_mgr_dummy self._processMap["pltfm_mgr_sys_tmp_get"] = Processor.process_pltfm_mgr_sys_tmp_get self._processMap["pltfm_mgr_sys_eeprom_get"] = Processor.process_pltfm_mgr_sys_eeprom_get + self._processMap["pltfm_mgr_tlv_eeprom_get"] = Processor.process_pltfm_mgr_tlv_eeprom_get self._processMap["pltfm_mgr_pwr_supply_present_get"] = Processor.process_pltfm_mgr_pwr_supply_present_get self._processMap["pltfm_mgr_pwr_supply_info_get"] = Processor.process_pltfm_mgr_pwr_supply_info_get self._processMap["pltfm_mgr_pwr_rail_info_get"] = Processor.process_pltfm_mgr_pwr_rail_info_get @@ -1710,6 +1742,32 @@ def process_pltfm_mgr_sys_eeprom_get(self, seqid, iprot, oprot): oprot.writeMessageEnd() oprot.trans.flush() + def process_pltfm_mgr_tlv_eeprom_get(self, seqid, iprot, oprot): + args = pltfm_mgr_tlv_eeprom_get_args() + args.read(iprot) + iprot.readMessageEnd() + result = pltfm_mgr_tlv_eeprom_get_result() + try: + result.success = self._handler.pltfm_mgr_tlv_eeprom_get() + msg_type = TMessageType.REPLY + except TTransport.TTransportException: + raise + except InvalidPltfmMgrOperation as ouch: + msg_type = TMessageType.REPLY + result.ouch = ouch + except TApplicationException as ex: + logging.exception('TApplication exception in handler') + msg_type = TMessageType.EXCEPTION + result = ex + except Exception: + logging.exception('Unexpected exception in handler') + msg_type = TMessageType.EXCEPTION + result = TApplicationException(TApplicationException.INTERNAL_ERROR, 'Internal error') + oprot.writeMessageBegin("pltfm_mgr_tlv_eeprom_get", msg_type, seqid) + result.write(oprot) + oprot.writeMessageEnd() + oprot.trans.flush() + def process_pltfm_mgr_pwr_supply_present_get(self, seqid, iprot, oprot): args = pltfm_mgr_pwr_supply_present_get_args() args.read(iprot) @@ -2954,6 +3012,123 @@ def __ne__(self, other): ) +class pltfm_mgr_tlv_eeprom_get_args(object): + + + def read(self, iprot): + if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None: + iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec]) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot._fast_encode is not None and self.thrift_spec is not None: + oprot.trans.write(oprot._fast_encode(self, [self.__class__, self.thrift_spec])) + return + oprot.writeStructBegin('pltfm_mgr_tlv_eeprom_get_args') + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.items()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) +all_structs.append(pltfm_mgr_tlv_eeprom_get_args) +pltfm_mgr_tlv_eeprom_get_args.thrift_spec = ( +) + + +class pltfm_mgr_tlv_eeprom_get_result(object): + """ + Attributes: + - success + - ouch + + """ + + + def __init__(self, success=None, ouch=None,): + self.success = success + self.ouch = ouch + + def read(self, iprot): + if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None: + iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec]) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 0: + if ftype == TType.STRUCT: + self.success = pltfm_mgr_tlv_sys_eeprom_t() + self.success.read(iprot) + else: + iprot.skip(ftype) + elif fid == 1: + if ftype == TType.STRUCT: + self.ouch = InvalidPltfmMgrOperation.read(iprot) + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot._fast_encode is not None and self.thrift_spec is not None: + oprot.trans.write(oprot._fast_encode(self, [self.__class__, self.thrift_spec])) + return + oprot.writeStructBegin('pltfm_mgr_tlv_eeprom_get_result') + if self.success is not None: + oprot.writeFieldBegin('success', TType.STRUCT, 0) + self.success.write(oprot) + oprot.writeFieldEnd() + if self.ouch is not None: + oprot.writeFieldBegin('ouch', TType.STRUCT, 1) + self.ouch.write(oprot) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.items()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) +all_structs.append(pltfm_mgr_tlv_eeprom_get_result) +pltfm_mgr_tlv_eeprom_get_result.thrift_spec = ( + (0, TType.STRUCT, 'success', [pltfm_mgr_tlv_sys_eeprom_t, None], None, ), # 0 + (1, TType.STRUCT, 'ouch', [InvalidPltfmMgrOperation, None], None, ), # 1 +) + + class pltfm_mgr_pwr_supply_present_get_args(object): """ Attributes: diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/pltfm_mgr_rpc/ttypes.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/pltfm_mgr_rpc/ttypes.py index 501596941664..ad686b888029 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/pltfm_mgr_rpc/ttypes.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/pltfm_mgr_rpc/ttypes.py @@ -16,24 +16,6 @@ all_structs = [] -class qsfp_eeprom_page_t(object): - PAGE0_LOWER = 0 - PAGE0_UPPER = 1 - PAGE3 = 2 - - _VALUES_TO_NAMES = { - 0: "PAGE0_LOWER", - 1: "PAGE0_UPPER", - 2: "PAGE3", - } - - _NAMES_TO_VALUES = { - "PAGE0_LOWER": 0, - "PAGE0_UPPER": 1, - "PAGE3": 2, - } - - class pltfm_mgr_sys_tmp_t(object): """ Attributes: @@ -478,6 +460,63 @@ def __ne__(self, other): return not (self == other) +class pltfm_mgr_tlv_sys_eeprom_t(object): + """ + Attributes: + - raw_content_hex + + """ + + + def __init__(self, raw_content_hex=None,): + self.raw_content_hex = raw_content_hex + + def read(self, iprot): + if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None: + iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec]) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.STRING: + self.raw_content_hex = iprot.readString().decode('utf-8', errors='replace') if sys.version_info[0] == 2 else iprot.readString() + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot._fast_encode is not None and self.thrift_spec is not None: + oprot.trans.write(oprot._fast_encode(self, [self.__class__, self.thrift_spec])) + return + oprot.writeStructBegin('pltfm_mgr_tlv_sys_eeprom_t') + if self.raw_content_hex is not None: + oprot.writeFieldBegin('raw_content_hex', TType.STRING, 1) + oprot.writeString(self.raw_content_hex.encode('utf-8') if sys.version_info[0] == 2 else self.raw_content_hex) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.items()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + + class pltfm_mgr_pwr_supply_info_t(object): """ Attributes: @@ -1398,6 +1437,11 @@ def __ne__(self, other): (21, TType.STRING, 'location', 'UTF8', None, ), # 21 (22, TType.I16, 'crc8', None, None, ), # 22 ) +all_structs.append(pltfm_mgr_tlv_sys_eeprom_t) +pltfm_mgr_tlv_sys_eeprom_t.thrift_spec = ( + None, # 0 + (1, TType.STRING, 'raw_content_hex', 'UTF8', None, ), # 1 +) all_structs.append(pltfm_mgr_pwr_supply_info_t) pltfm_mgr_pwr_supply_info_t.thrift_spec = ( None, # 0 diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/psu.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/psu.py index fb9bce50e071..fbd83d6496ae 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/psu.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/psu.py @@ -4,18 +4,26 @@ import os import sys import time + import signal + import syslog sys.path.append(os.path.dirname(__file__)) from .platform_thrift_client import thrift_try from sonic_platform_base.psu_base import PsuBase + from platform_utils import cancel_on_sigterm + except ImportError as e: raise ImportError (str(e) + "- required module not found") class Psu(PsuBase): """Platform-specific PSU class""" + sigterm = False + sigterm_default_handler = None + cls_inited = False + def __init__(self, index): PsuBase.__init__(self) self.__index = index @@ -24,6 +32,21 @@ def __init__(self, index): # STUB IMPLEMENTATION self.color = "" + syslog.syslog(syslog.LOG_INFO, "Created PSU #{} instance".format(self.__index)) + if not Psu.cls_inited: + Psu.sigterm_default_handler = signal.getsignal(signal.SIGTERM) + signal.signal(signal.SIGTERM, Psu.signal_handler) + if Psu.sigterm_default_handler: + syslog.syslog(syslog.LOG_INFO, "Default SIGTERM handler overridden!!") + Psu.cls_inited = True + + @classmethod + def signal_handler(cls, sig, frame): + if cls.sigterm_default_handler: + cls.sigterm_default_handler(sig, frame) + syslog.syslog(syslog.LOG_INFO, "Canceling PSU platform API calls...") + cls.sigterm = True + ''' Units of returned info object values: vin - V @@ -33,20 +56,23 @@ def __init__(self, index): fspeed - RPM ''' def __info_get(self): + @cancel_on_sigterm def psu_info_get(client): return client.pltfm_mgr.pltfm_mgr_pwr_supply_info_get(self.__index) # Update cache once per 2 seconds - if self.__ts + 2 < time.time(): + if self.__ts + 2 < time.time() and not Psu.sigterm: self.__info = None try: self.__info = thrift_try(psu_info_get, attempts=1) + except Exception as e: + if "Canceling" in str(e): + syslog.syslog(syslog.LOG_INFO, "{}".format(e)) finally: self.__ts = time.time() return self.__info return self.__info - @staticmethod def get_num_psus(): """ diff --git a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/sfp.py b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/sfp.py index f5d800b749c9..6a5534d8ba6b 100644 --- a/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/sfp.py +++ b/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/sfp.py @@ -11,29 +11,38 @@ SFP_TYPE = "SFP" QSFP_TYPE = "QSFP" QSFP_DD_TYPE = "QSFP_DD" +EEPROM_PAGE_SIZE = 128 +try: + from thrift.Thrift import TApplicationException + + def cached_num_bytes_get(client): + return client.pltfm_mgr.pltfm_mgr_qsfp_cached_num_bytes_get(1, 0, 0, 0) + thrift_try(cached_num_bytes_get, 1) + EEPROM_CACHED_API_SUPPORT = True +except TApplicationException as e: + EEPROM_CACHED_API_SUPPORT = False class Sfp(SfpOptoeBase): """ BFN Platform-specific SFP class """ - SFP_EEPROM_PATH = "/var/run/platform/sfp/" - def __init__(self, port_num): SfpOptoeBase.__init__(self) self.index = port_num self.port_num = port_num self.sfp_type = QSFP_TYPE + self.SFP_EEPROM_PATH = "/var/run/platform/sfp/" - if not os.path.exists(self.SFP_EEPROM_PATH): - try: - os.makedirs(self.SFP_EEPROM_PATH) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - self.eeprom_path = self.SFP_EEPROM_PATH + "sfp{}-eeprom-cache".format(self.index) + if not EEPROM_CACHED_API_SUPPORT: + if not os.path.exists(self.SFP_EEPROM_PATH): + try: + os.makedirs(self.SFP_EEPROM_PATH) + except OSError as e: + if e.errno != errno.EEXIST: + raise + self.eeprom_path = self.SFP_EEPROM_PATH + "sfp{}-eeprom-cache".format(self.index) def get_presence(self): """ @@ -47,7 +56,7 @@ def qsfp_presence_get(client): try: presence = thrift_try(qsfp_presence_get) except Exception as e: - print( e.__doc__) + print(e.__doc__) print(e.message) return presence @@ -75,14 +84,31 @@ def get_eeprom_path(self): def qsfp_info_get(client): return client.pltfm_mgr.pltfm_mgr_qsfp_info_get(self.index) - if self.get_presence(): - eeprom_hex = thrift_try(qsfp_info_get) - eeprom_raw = bytearray.fromhex(eeprom_hex) - with open(self.eeprom_path, 'wb') as fp: - fp.write(eeprom_raw) - return self.eeprom_path + eeprom_hex = thrift_try(qsfp_info_get) + eeprom_raw = bytearray.fromhex(eeprom_hex) + with open(self.eeprom_path, 'wb') as fp: + fp.write(eeprom_raw) + return self.eeprom_path + + def read_eeprom(self, offset, num_bytes): + if not self.get_presence(): + return None + + if not EEPROM_CACHED_API_SUPPORT: + return super().read_eeprom(offset, num_bytes) + + def cached_num_bytes_get(page, offset, num_bytes): + def qsfp_cached_num_bytes_get(client): + return client.pltfm_mgr.pltfm_mgr_qsfp_cached_num_bytes_get(self.index, page, offset, num_bytes) + return bytearray.fromhex(thrift_try(qsfp_cached_num_bytes_get)) + + page_offset = offset % EEPROM_PAGE_SIZE + if page_offset + num_bytes > EEPROM_PAGE_SIZE: + curr_page_num_bytes_left = EEPROM_PAGE_SIZE - page_offset + curr_page_bytes = cached_num_bytes_get(offset // EEPROM_PAGE_SIZE, page_offset, curr_page_num_bytes_left) + return curr_page_bytes + self.read_eeprom(offset + curr_page_num_bytes_left, num_bytes - curr_page_num_bytes_left) - return None + return cached_num_bytes_get(offset // EEPROM_PAGE_SIZE, page_offset, num_bytes) def write_eeprom(self, offset, num_bytes, write_buffer): # Not supported at the moment diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index bde6b9da0ecc..59a3259c9929 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -69,6 +69,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE) \ $(ALPHANETWORKS_SNH60B0_640F_PLATFORM_MODULE) \ $(ALPHANETWORKS_SNJ60D0_320F_PLATFORM_MODULE) \ + $(ALPHANETWORKS_BES2348T_PLATFORM_MODULE) \ $(BRCM_XLR_GTS_PLATFORM_MODULE) \ $(DELTA_AG9032V2A_PLATFORM_MODULE) \ $(JUNIPER_QFX5210_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-alphanetworks.mk b/platform/broadcom/platform-modules-alphanetworks.mk index cdfd4683723e..03b7298b2ffc 100644 --- a/platform/broadcom/platform-modules-alphanetworks.mk +++ b/platform/broadcom/platform-modules-alphanetworks.mk @@ -3,10 +3,12 @@ ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE_VERSION = 1.0 ALPHANETWORKS_SNH60B0_640F_PLATFORM_MODULE_VERSION = 1.0 ALPHANETWORKS_SNJ60D0_320F_PLATFORM_MODULE_VERSION = 1.0 +ALPHANETWORKS_BES2348T_PLATFORM_MODULE_VERSION = 1.0 export ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE_VERSION export ALPHANETWORKS_SNH60B0_640F_PLATFORM_MODULE_VERSION export ALPHANETWORKS_SNJ60D0_320F_PLATFORM_MODULE_VERSION +export ALPHANETWORKS_BES2348T_PLATFORM_MODULE_VERSION ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE = sonic-platform-alphanetworks-snh60a0-320fv2_$(ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE_VERSION)_amd64.deb $(ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-alphanetworks @@ -22,4 +24,7 @@ ALPHANETWORKS_SNJ60D0_320F_PLATFORM_MODULE = sonic-platform-alphanetworks-snj60d $(ALPHANETWORKS_SNJ60D0_320F_PLATFORM_MODULE)_PLATFORM = x86_64-alphanetworks_snj60d0_320f-r0 $(eval $(call add_extra_package,$(ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE),$(ALPHANETWORKS_SNJ60D0_320F_PLATFORM_MODULE))) +ALPHANETWORKS_BES2348T_PLATFORM_MODULE = sonic-platform-alphanetworks-bes2348t_$(ALPHANETWORKS_BES2348T_PLATFORM_MODULE_VERSION)_amd64.deb +$(ALPHANETWORKS_BES2348T_PLATFORM_MODULE)_PLATFORM = x86_64-alphanetworks_bes2348t-r0 +$(eval $(call add_extra_package,$(ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE),$(ALPHANETWORKS_BES2348T_PLATFORM_MODULE))) diff --git a/platform/broadcom/rules.mk b/platform/broadcom/rules.mk index c7c7381b9735..d946d04cc1d8 100644 --- a/platform/broadcom/rules.mk +++ b/platform/broadcom/rules.mk @@ -5,7 +5,7 @@ include $(PLATFORM_PATH)/platform-modules-dell.mk include $(PLATFORM_PATH)/platform-modules-arista.mk #include $(PLATFORM_PATH)/platform-modules-ingrasys.mk include $(PLATFORM_PATH)/platform-modules-accton.mk -#include $(PLATFORM_PATH)/platform-modules-alphanetworks.mk +include $(PLATFORM_PATH)/platform-modules-alphanetworks.mk #include $(PLATFORM_PATH)/platform-modules-inventec.mk include $(PLATFORM_PATH)/platform-modules-cel.mk #include $(PLATFORM_PATH)/platform-modules-delta.mk diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/Makefile b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/Makefile new file mode 100644 index 000000000000..9570c728a7f2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/Makefile @@ -0,0 +1,3 @@ +obj-m:=bes2348t_onie_eeprom.o pddf_custom_psu.o +CFLAGS_pddf_custom_psu.o := -I$(M)/../../../../pddf/i2c/modules/include +KBUILD_EXTRA_SYMBOLS := $(M)/../../../../pddf/i2c/Module.symvers.PDDF diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/bes2348t_onie_eeprom.c b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/bes2348t_onie_eeprom.c new file mode 100644 index 000000000000..abb77938cdf4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/bes2348t_onie_eeprom.c @@ -0,0 +1,208 @@ +/* + * A driver for alphanetworks_bes2348t ONIE EEPROM + * + * Copyright (C) 2020 Alphanetworks Technology Corporation. + * Robin Chen + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * see + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define EEPROM_SIZE 256 + +static ssize_t onie_read(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t onie_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); + +/* Each client has this additional data + */ + +struct bes2348t_onie_eeprom_data +{ + struct mutex update_lock; + unsigned char onie_eeprom[EEPROM_SIZE]; +}; + + +/* Addresses scanned for bes2348t_onie_eeprom */ +static const unsigned short normal_i2c[] = { 0x56, I2C_CLIENT_END }; + +enum bes2348t_onie_eeprom_sysfs_attributes { + ONIE_RW, +}; + +static SENSOR_DEVICE_ATTR(eeprom, (0660), onie_read, onie_write, ONIE_RW); + +static struct attribute *bes2348t_onie_attributes[] = { + &sensor_dev_attr_eeprom.dev_attr.attr, + NULL +}; + +static const struct attribute_group bes2348t_onie_group = { + .attrs = bes2348t_onie_attributes, +}; + + +static ssize_t onie_read(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0, res = 0; + u8 command; + __u8 read_write; + unsigned short offset = 0; + union i2c_smbus_data temp; + struct i2c_client *client = to_i2c_client(dev); + struct bes2348t_onie_eeprom_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + read_write = I2C_SMBUS_WRITE; + offset = offset & 0x3fff; + temp.byte = (u8)offset; + res = i2c_smbus_xfer(client->adapter, client->addr, client->flags=0, + read_write, 0, 2, &temp); + res = i2c_smbus_xfer(client->adapter, client->addr, client->flags=0, + read_write, 0, 2, &temp); + for( offset=0 ; offset < EEPROM_SIZE ; ++offset ) + { + read_write = I2C_SMBUS_READ; + res = i2c_smbus_xfer(client->adapter, client->addr, client->flags=0, + read_write, 0, 1, &temp); + if (!res) + { + data->onie_eeprom[offset] = temp.byte; + } + } + memcpy(buf, data->onie_eeprom, EEPROM_SIZE); + + mutex_unlock(&data->update_lock); + + return EEPROM_SIZE; +} + +static ssize_t onie_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + int error, write, command, read; + + error = kstrtoint(buf, 10, &write); + if (error) + return error; + + if (write < 0 || write > 255) + return -EINVAL; + + /* Not support yet */ + + return count; +} + +static int onie_eeprom_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct bes2348t_onie_eeprom_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct bes2348t_onie_eeprom_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &bes2348t_onie_group); + if (status) { + goto exit_free; + } + + return 0; + +exit_free: + kfree(data); +exit: + return status; +} + +static int onie_eeprom_remove(struct i2c_client *client) +{ + struct bes2348t_onie_eeprom_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &bes2348t_onie_group); + kfree(data); + + return 0; +} + +static const struct i2c_device_id onie_eeprom_id[] = { + { "bes2348t_eeprom", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, onie_eeprom_id); + +static struct i2c_driver onie_eeprom_driver = { + .driver = { + .name = "bes2348t_eeprom", + }, + .probe = onie_eeprom_probe, + .remove = onie_eeprom_remove, + .id_table = onie_eeprom_id, + .address_list = normal_i2c, +}; + + +static int __init onie_eeprom_init(void) +{ + return i2c_add_driver(&onie_eeprom_driver); +} + +static void __exit onie_eeprom_exit(void) + +{ + i2c_del_driver(&onie_eeprom_driver); +} + +module_init(onie_eeprom_init); +module_exit(onie_eeprom_exit); + +MODULE_AUTHOR("Alpha-SID6"); +MODULE_DESCRIPTION("ONIE EEPROM Driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/pddf_custom_psu.c b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/pddf_custom_psu.c new file mode 100644 index 000000000000..8fd7f8f52b13 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/modules/pddf_custom_psu.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_psu_defs.h" + +#define PSU_REG_VOUT_MODE 0x20 +#define PSU_REG_READ_VOUT 0x8b + +ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *da, char *buf); +extern PSU_SYSFS_ATTR_DATA access_psu_v_out; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +static u8 psu_get_vout_mode(struct i2c_client *client) +{ + u8 status = 0, retry = 10; + uint8_t offset = PSU_REG_VOUT_MODE; + + while (retry) { + status = i2c_smbus_read_byte_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + printk(KERN_ERR "%s: Get PSU Vout mode failed\n", __func__); + return 0; + } + else + { + /*printk(KERN_ERR "%s: vout_mode reg value 0x%x\n", __func__, status);*/ + return status; + } +} + +static u16 psu_get_v_out(struct i2c_client *client) +{ + u16 status = 0, retry = 10; + uint8_t offset = PSU_REG_READ_VOUT; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + printk(KERN_ERR "%s: Get PSU Vout failed\n", __func__); + return 0; + } + else + { + /*printk(KERN_ERR "%s: vout reg value 0x%x\n", __func__, status);*/ + return status; + } +} + +ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int exponent, mantissa; + int multiplier = 1000; + + u16 value = psu_get_v_out(client); + u8 vout_mode = psu_get_vout_mode(client); + + if ((vout_mode >> 5) == 0) + exponent = two_complement_to_int(vout_mode & 0x1f, 5, 0x1f); + else + { + /*printk(KERN_ERR "%s: Only support linear mode for vout mode\n", __func__);*/ + exponent = 0; + } + mantissa = value; + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier); + else + return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + + + +static int __init pddf_custom_psu_init(void) +{ + access_psu_v_out.show = pddf_show_custom_psu_v_out; + access_psu_v_out.do_get = NULL; + return 0; +} + +static void __exit pddf_custom_psu_exit(void) +{ + return; +} + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("pddf custom psu api"); +MODULE_LICENSE("GPL"); + +module_init(pddf_custom_psu_init); +module_exit(pddf_custom_psu_exit); diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/__init__.py new file mode 100644 index 000000000000..f0201e717796 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +# All the derived classes for PDDF +__all__ = ["platform", "chassis", "sfp", "psu", "thermal"] +from . import platform diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/chassis.py new file mode 100644 index 000000000000..a841bd3fffff --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/chassis.py @@ -0,0 +1,133 @@ +############################################################################# +# PDDF +# Module contains an implementation of SONiC Chassis API +# +############################################################################# + +try: + import sys + import time + from sonic_platform_pddf_base.pddf_chassis import PddfChassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(PddfChassis): + """ + PDDF Platform-specific Chassis class + """ + + SYSLED_DEV_NAME = "SYS_LED" + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfChassis.__init__(self, pddf_data, pddf_plugin_data) + self.sfp_state = [] + + # Provide the functions/variables below for which implementation is to be overwritten + + def get_sfp(self, index): + """ + Retrieves sfp represented by (0-based) index + Args: + index: An integer, the index (0-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 0. + For example, 0 for Ethernet0, 1 for Ethernet4 and so on. + Returns: + An object derived from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The 'index' starts from 1 for this platform + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_serial_number(self): + return self.get_serial() + + def initizalize_system_led(self): + return True + + def get_status_led(self): + return self.pddf_obj.get_system_led_color(self.SYSLED_DEV_NAME) + + def set_status_led(self, color): + return self.pddf_obj.set_system_led_color(self.SYSLED_DEV_NAME, color) + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + + Args: + timeout: Timeout in milliseconds (optional). If timeout == 0, + this method will block until a change is detected. + + Returns: + (bool, dict): + - True if call successful, False if not; + - A nested dictionary where key is a device type, + value is a dictionary with key:value pairs in the format of + {'device_id':'device_event'}, + where device_id is the device ID for this device and + device_event, + status='1' represents device inserted, + status='0' represents device removed. + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} + indicates that fan 0 has been removed, fan 2 + has been inserted and sfp 11 has been removed. + Specifically for SFP event, besides SFP plug in and plug out, + there are some other error event could be raised from SFP, when + these error happened, SFP eeprom will not be avalaible, XCVRD shall + stop to read eeprom before SFP recovered from error status. + status='2' I2C bus stuck, + status='3' Bad eeprom, + status='4' Unsupported cable, + status='5' High Temperature, + status='6' Bad cable. + """ + change_event_dict = {"sfp": {}} + sfp_status, sfp_change_dict = self.get_transceiver_change_event(timeout) + change_event_dict["sfp"] = sfp_change_dict + if sfp_status is True: + return True, change_event_dict + + return False, {} + + def get_transceiver_change_event(self, timeout=0): + start_time = time.time() + # SFP status definition from xcvrd + SFP_STATUS_INSERTED = '1' + SFP_STATUS_REMOVED = '0' + + timeout = (timeout/1000) + end_time = start_time + timeout + while (timeout >= 0): + new_sfp_state = [] + change_dict = {} + for index in range(self.get_num_sfps()): + # get current status + state = self._sfp_list[index].get_presence() + new_sfp_state.append(state) + + port_index = self._sfp_list[index].port_index + if self.sfp_state == []: + change_dict[port_index] = SFP_STATUS_INSERTED if state == True else SFP_STATUS_REMOVED + elif state != self.sfp_state[index]: + change_dict[port_index] = SFP_STATUS_INSERTED if state == True else SFP_STATUS_REMOVED + + self.sfp_state = new_sfp_state + current_time = time.time() + + if bool(change_dict): + return True, change_dict + elif timeout == 0 or current_time < end_time: + time.sleep(1) + continue + else: + return True, {} + + return False, {} diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/eeprom.py new file mode 100644 index 000000000000..78a9cbc48e46 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/eeprom.py @@ -0,0 +1,14 @@ +try: + from sonic_platform_pddf_base.pddf_eeprom import PddfEeprom +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(PddfEeprom): + + _TLV_DISPLAY_VENDOR_EXT = True + + def __init__(self, pddf_data=None, pddf_plugin_data=None): + PddfEeprom.__init__(self, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/fan.py new file mode 100644 index 000000000000..dd4da7dd8f0e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/fan.py @@ -0,0 +1,55 @@ +try: + from sonic_platform_pddf_base.pddf_fan import PddfFan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Fan(PddfFan): + """PDDF Platform-Specific Fan class""" + + def __init__(self, tray_idx, fan_idx=0, pddf_data=None, pddf_plugin_data=None, is_psu_fan=False, psu_index=0): + # idx is 0-based + PddfFan.__init__(self, tray_idx, fan_idx, pddf_data, pddf_plugin_data, is_psu_fan, psu_index) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + if self.is_psu_fan: + direction = self.FAN_DIRECTION_EXHAUST + + else: + idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index + attr = "fan" + str(idx) + "_direction" + output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr) + if not output: + return False + + mode = output['mode'] + val = output['status'] + + val = val.rstrip() + vmap = self.plugin_data['FAN']['direction'][mode]['valmap'] + if val in vmap: + direction = vmap[val] + else: + direction = val + + return direction + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + # Fix the speed vairance to 20 percent. If it changes based on platforms, overwrite + # this value in derived pddf fan class + return 20 diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..c4b3cdfe5f18 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/fan_drawer.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + + +try: + from sonic_platform_pddf_base.pddf_fan_drawer import PddfFanDrawer +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(PddfFanDrawer): + """PDDF Platform-Specific Fan-Drawer class""" + + def __init__(self, tray_idx, pddf_data=None, pddf_plugin_data=None): + # idx is 0-based + PddfFanDrawer.__init__(self, tray_idx, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/platform.py new file mode 100644 index 000000000000..8595e80692df --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/platform.py @@ -0,0 +1,23 @@ +############################################################################# +# PDDF +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + + +try: + from sonic_platform_pddf_base.pddf_platform import PddfPlatform +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PddfPlatform): + """ + PDDF Platform-Specific Platform Class + """ + + def __init__(self): + PddfPlatform.__init__(self) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/psu.py new file mode 100644 index 000000000000..6b3f0a309b7d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/psu.py @@ -0,0 +1,35 @@ +try: + from sonic_platform_pddf_base.pddf_psu import PddfPsu +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Psu(PddfPsu): + """PDDF Platform-Specific PSU class""" + + PLATFORM_PSU_CAPACITY = 550 + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfPsu.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + return (self.PLATFORM_PSU_CAPACITY) + + def get_type(self): + """ + Gets the type of the PSU + + Returns: + A string, the type of PSU (AC/DC) + """ + ptype = "AC" + + # Currently the platform supports only AC type of PSUs + return ptype diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/sfp.py new file mode 100644 index 000000000000..48b0e5f19d08 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/sfp.py @@ -0,0 +1,22 @@ +try: + from sonic_platform_pddf_base.pddf_sfp import PddfSfp +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +class Sfp(PddfSfp): + """ + PDDF Platform-Specific Sfp class + """ + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + PddfSfp.__init__(self, index, pddf_data, pddf_plugin_data) + + # Provide the functions/variables below for which implementation is to be overwritten + + @property + def port_type(self): + type = self.PORT_TYPE_NONE + if self.port_index in range(49, 53): + type = self.PORT_TYPE_SFP + return type diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/thermal.py new file mode 100644 index 000000000000..d193d9606ec2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/thermal.py @@ -0,0 +1,26 @@ +try: + import os + from sonic_platform_pddf_base.pddf_thermal import PddfThermal +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + + +class Thermal(PddfThermal): + """PDDF Platform-Specific Thermal class""" + + def __init__(self, index, pddf_data=None, pddf_plugin_data=None, is_psu_thermal=False, psu_index=0): + PddfThermal.__init__(self, index, pddf_data, pddf_plugin_data, is_psu_thermal, psu_index) + + # Provide the functions/variables below for which implementation is to be overwritten + + def get_cpu_temperature(self): + dev_path = "/sys/devices/platform/coretemp.0/hwmon/" + hwmon_node = os.listdir(dev_path)[0] + node = dev_path + hwmon_node + '/temp1_input' + try: + with open(node, 'r') as fp: + temp = float(fp.read()) / 1000 + except IOError: + return None + return temp diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/watchdog.py new file mode 100644 index 000000000000..90b5ee352c08 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform/watchdog.py @@ -0,0 +1,14 @@ +try: + from sonic_platform_pddf_base.pddf_watchdog import PddfWatchdog +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + + +class Watchdog(PddfWatchdog): + """PDDF Platform-Specific Watchdog Class""" + + def __init__(self): + PddfWatchdog.__init__(self) + + # Provide the functions/variables below for which implementation is to be overwritten diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform_setup.py new file mode 100644 index 000000000000..21abdb1c7ac0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/pddf/sonic_platform_setup.py @@ -0,0 +1,27 @@ +import os +from setuptools import setup +os.listdir + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Alpha Platforms based on PDDF', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/service/bes2348t-thermal-shutdown.service b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/service/bes2348t-thermal-shutdown.service new file mode 100644 index 000000000000..abeb9c56a6e5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/service/bes2348t-thermal-shutdown.service @@ -0,0 +1,16 @@ +[Unit] +Description=Alphanetworks BES2348T Platform Thermal Shutdown service +Before=pmon.service +After=pddf-platform-init.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/alphanetworks_bes2348t_thermal_shutdown.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/service/pddf-platform-init.service b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/service/pddf-platform-init.service new file mode 120000 index 000000000000..0fd9f25b6c5e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/service/pddf-platform-init.service @@ -0,0 +1 @@ +../../../../pddf/i2c/service/pddf-platform-init.service \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/utils/alphanetworks_bes2348t_thermal_shutdown.py b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/utils/alphanetworks_bes2348t_thermal_shutdown.py new file mode 100755 index 000000000000..958850b40a1d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/utils/alphanetworks_bes2348t_thermal_shutdown.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +try: + import subprocess + import re + import time + from sonic_platform import platform + from sonic_py_common import logger +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +sonic_logger = logger.Logger('thermal_shutdown') + +# Thermal Shutdown +# CPU Board +# Core>=80 +# TMP75_2(0x4F)>=80 +# Main board +# TMP75_0(0x48)>=80 +# TMP75_1(0x49)>=80 +# ASIC maximum peak temperature>=108 + +def power_off_device(): + command = "sync" + subprocess.getstatusoutput(command) + time.sleep(3) + command = "ipmitool chassis power off" + subprocess.getstatusoutput(command) + +def get_asic_temperature(): + command = "bcmcmd \"show temp\" | grep \"maximum peak temperature\"" + status, output = subprocess.getstatusoutput(command) + if status: + sonic_logger.log_warning("Failed to get asic temperature.") + return 0 + + temperature = [float(s) for s in re.findall(r'-?\d+\.?\d*', output)] + return temperature[0] + + +class thermal_shutdown_monitor(object): + # Critical temperatures + CRIT_CPU_TEMPERATURE = 80 + CRIT_ASIC_TEMPERATURE = 108 + CRIT_THERMAL_TEMPERATURE = 80 + CRIT_THERMAL_NAME = "TMP75" + + def monitor(self): + global platform_chassis + + # Check asic temperature + asic_temperature = get_asic_temperature() + if asic_temperature >= self.CRIT_ASIC_TEMPERATURE: + sonic_logger.log_warning("ASIC temperature {} is over critical ASIC temperature {}, shutdown device.".format( + asic_temperature, self.CRIT_ASIC_TEMPERATURE)) + power_off_device() + return True + + # Check cpu temperature + cpu_temperature = platform_chassis.get_thermal(0).get_cpu_temperature() + if cpu_temperature >= self.CRIT_CPU_TEMPERATURE: + sonic_logger.log_warning("CPU temperature {} is over critial CPU temperature {}, shutdown device.".format( + cpu_temperature, self.CRIT_CPU_TEMPERATURE)) + power_off_device() + return True + + # Check thermal temperature + for thermal in platform_chassis.get_all_thermals(): + if self.CRIT_THERMAL_NAME in thermal.get_name(): + thermal_temperature = thermal.get_temperature() + if thermal_temperature >= self.CRIT_THERMAL_TEMPERATURE: + sonic_logger.log_warning("Thermal {} temperature {} is over critial thermal temperature {}, shutdown device.".format( + thermal.get_name(), thermal_temperature, self.CRIT_THERMAL_TEMPERATURE)) + power_off_device() + return True + return True + + +def main(): + global platform_chassis + platform_chassis = platform.Platform().get_chassis() + + # thermal shutdown monitor + monitor = thermal_shutdown_monitor() + POLL_INTERVAL=30 + + # start monitor + while True: + monitor.monitor() + time.sleep(POLL_INTERVAL) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/utils/pddf_post_device_create.sh b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/utils/pddf_post_device_create.sh new file mode 100755 index 000000000000..e31982fa2640 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/bes2348t/utils/pddf_post_device_create.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# bes2348t post device creation script +echo "Disable SFP28 PORT49 TX disable" +echo 0 > /sys/class/gpio/gpio480/value + +echo "Disable SFP28 PORT50 TX disable" +echo 0 > /sys/class/gpio/gpio484/value + +echo "Disable SFP28 PORT51 TX disable" +echo 0 > /sys/class/gpio/gpio488/value + +echo "Disable SFP28 PORT52 TX disable" +echo 0 > /sys/class/gpio/gpio492/value + +set_pca_mux_idle_disconnect() +{ + echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state >& /dev/null + if [ $? -ne 0 ]; then + echo Fail to set pca954x mux idle disconnect + exit 2 + fi +} + +set_pca_mux_idle_disconnect diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/changelog b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/changelog index 5088e8217a2c..2c27ec7072bc 100644 --- a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/changelog +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/changelog @@ -1,6 +1,6 @@ sonic-alphanetworks-platform-modules (1.0) unstable; urgency=low - * Add support for SNH60A0-320FV2, SNH60B0_640F, and SNJ60D0_320F. + * Add support for SNH60A0-320FV2, SNH60B0_640F, SNJ60D0_320F, and SCG60D0-484T. - -- Alphanetworks Tue, 14 Sep 2021 14:50:08 +0800 + -- Alphanetworks Thu, 26 May 2022 14:50:08 +0800 diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/control b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/control index 0daf71e1dade..e146005eee06 100644 --- a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/control +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/control @@ -7,16 +7,20 @@ Standards-Version: 3.9.3 Package: sonic-platform-alphanetworks-snh60a0-320fv2 Architecture: amd64 -Depends: linux-image-4.19.0-12-2-amd64-unsigned +Depends: linux-image-5.10.0-12-2-amd64-unsigned Description: kernel modules for platform devices such as fan, led, sfp Package: sonic-platform-alphanetworks-snh60b0-640f Architecture: amd64 -Depends: linux-image-4.19.0-12-2-amd64-unsigned +Depends: linux-image-5.10.0-12-2-amd64-unsigned Description: kernel modules for platform devices such as fan, led, sfp Package: sonic-platform-alphanetworks-snj60d0-320f Architecture: amd64 -Depends: linux-image-4.19.0-12-2-amd64-unsigned +Depends: linux-image-5.10.0-12-2-amd64-unsigned Description: kernel modules for platform devices such as fan, led, sfp +Package: sonic-platform-alphanetworks-bes2348t +Architecture: amd64 +Depends: linux-image-5.10.0-12-2-amd64-unsigned +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/rules b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/rules old mode 100644 new mode 100755 index d863ef137736..5b8646b169bc --- a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/rules +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/rules @@ -13,13 +13,13 @@ include /usr/share/dpkg/pkg-info.mk export INSTALL_MOD_DIR:=extra -PYTHON ?= python2 +PYTHON3 ?= python3 PACKAGE_PRE_NAME := sonic-platform-alphanetworks KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= snh60a0-320fv2 snh60b0-640f snj60d0-320f +MODULE_DIRS:= snh60a0-320fv2 snh60b0-640f snj60d0-320f bes2348t MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service @@ -39,11 +39,15 @@ build: (for mod in $(MODULE_DIRS); do \ make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ cd $(MOD_SRC_DIR)/$${mod}; \ - $(PYTHON) setup.py build; \ - $(PYTHON) setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/utils; \ - if [ $$mod = "snj60d0-320f" ]; then \ - python3 setup.py build; \ - python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/utils; \ + if [ -f setup.py ]; then \ + $(PYTHON3) setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ + fi; \ + if [ -d $(MOD_SRC_DIR)/$${mod}/pddf ]; then \ + cd $(MOD_SRC_DIR)/$${mod}/pddf; \ + if [ -f sonic_platform_setup.py ]; then \ + $(PYTHON3) sonic_platform_setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/pddf; \ + echo "Finished makig pddf whl package for $$mod"; \ + fi; \ fi; \ cd $(MOD_SRC_DIR); \ done) @@ -68,17 +72,13 @@ binary-indep: (for mod in $(MODULE_DIRS); do \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} usr/local/bin; \ - platform_name=`echo $${mod} | sed "s/-/_/g"`; \ - dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} usr/share/sonic/device/x86_64-alphanetworks_$${platform_name}-r0; \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} lib/systemd/system; \ cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ - cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/*.py debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ - cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/*.whl debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/share/sonic/device/x86_64-alphanetworks_$${platform_name}-r0; \ + cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ cd $(MOD_SRC_DIR)/$${mod}; \ - $(PYTHON) setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ - if [ $$mod = "snj60d0-320f" ]; then \ - python3 setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ + if [ -f setup.py ]; then \ + $(PYTHON3) setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ fi; \ cd $(MOD_SRC_DIR); \ done) diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/sonic-platform-alphanetworks-bes2348t.install b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/sonic-platform-alphanetworks-bes2348t.install new file mode 100644 index 000000000000..311dfb0ba9b3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/sonic-platform-alphanetworks-bes2348t.install @@ -0,0 +1 @@ +bes2348t/pddf/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-alphanetworks_bes2348t-r0/pddf diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/sonic-platform-alphanetworks-snj60d0-320f.install b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/sonic-platform-alphanetworks-snj60d0-320f.install new file mode 100644 index 000000000000..1d97d539eef4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/sonic-platform-alphanetworks-snj60d0-320f.install @@ -0,0 +1 @@ +snj60d0-320f/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-alphanetworks_snj60d0_320f-r0 diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index b65a69a9e1c2..11180c37fa17 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit b65a69a9e1c2c876ba5210ce8b2a1cc9b5c8b18f +Subproject commit 11180c37fa17421afdeef346b3896552872a2721 diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init index 07a6542109b5..3f6358bf4ab4 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init @@ -11,6 +11,26 @@ # Short-Description: Setup Haliburton board. ### END INIT INFO +setup_swap () { + SWAPFILE=/host/myswapfile + + if [ ! -f $SWAPFILE ]; then + availspace=`df -h --output=avail /host | sed '1d;s/\s//g;s/[^0-9].*//g'` + diff=$(( availspace - 2*$1 )) + if [ $diff -gt 0 ]; then + fallocate -l ${1}G $SWAPFILE + chmod 600 $SWAPFILE + echo "swap file created successfully" + else + echo "not enough disk space to turn on swap." + return + fi + fi + mkswap $SWAPFILE + swapon $SWAPFILE + echo "swap on successfully" +} + case "$1" in start) echo -n "Setting up board... " @@ -74,6 +94,8 @@ start) /bin/sh /usr/local/bin/platform_api_mgnt.sh init + setup_swap 2 + echo "done." ;; diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index f6beeb990bd7..92aed0663311 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -27,17 +27,17 @@ else FW_FROM_URL = n endif -MLNX_SPC_FW_VERSION = 13.2010.2318 +MLNX_SPC_FW_VERSION = 13.2010.3170 MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa $(MLNX_SPC_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC_FW_FILE) -MLNX_SPC2_FW_VERSION = 29.2010.2318 +MLNX_SPC2_FW_VERSION = 29.2010.3170 MLNX_SPC2_FW_FILE = fw-SPC2-rel-$(subst .,_,$(MLNX_SPC2_FW_VERSION))-EVB.mfa $(MLNX_SPC2_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC2_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC2_FW_FILE) -MLNX_SPC3_FW_VERSION = 30.2010.2318 +MLNX_SPC3_FW_VERSION = 30.2010.3170 MLNX_SPC3_FW_FILE = fw-SPC3-rel-$(subst .,_,$(MLNX_SPC3_FW_VERSION))-EVB.mfa $(MLNX_SPC3_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC3_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC3_FW_FILE) diff --git a/platform/mellanox/mft.mk b/platform/mellanox/mft.mk index eb702a85a1d1..047e87b09086 100644 --- a/platform/mellanox/mft.mk +++ b/platform/mellanox/mft.mk @@ -16,8 +16,8 @@ # # Mellanox SAI -MFT_VERSION = 4.20.0 -MFT_REVISION = 34 +MFT_VERSION = 4.21.0 +MFT_REVISION = 100 export MFT_VERSION MFT_REVISION diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index b9fa2593174c..96a7b9e2315a 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -123,7 +123,7 @@ def __del__(self): if self._sfp_list: if self.sfp_module.SFP.shared_sdk_handle: - self.sfp_module.deinitialize_sdk_handle(sfp_module.SFP.shared_sdk_handle) + self.sfp_module.deinitialize_sdk_handle(self.sfp_module.SFP.shared_sdk_handle) @property def RJ45_port_list(self): diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index 617b4f33d636..d35b869e9a29 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -755,6 +755,38 @@ def get_error_description(self): error_description = "Unknow SFP module status ({})".format(oper_status) return error_description + def get_rx_los(self): + """Accessing rx los is not supproted, return all False + + Returns: + list: [False] * channels + """ + api = self.get_xcvr_api() + return [False] * api.NUM_CHANNELS if api else None + + def get_tx_fault(self): + """Accessing tx fault is not supproted, return all False + + Returns: + list: [False] * channels + """ + api = self.get_xcvr_api() + return [False] * api.NUM_CHANNELS if api else None + + def get_xcvr_api(self): + """ + Retrieves the XcvrApi associated with this SFP + + Returns: + An object derived from XcvrApi that corresponds to the SFP + """ + if self._xcvr_api is None: + self.refresh_xcvr_api() + if self._xcvr_api is not None: + self._xcvr_api.get_rx_los = self.get_rx_los + self._xcvr_api.get_tx_fault = self.get_tx_fault + return self._xcvr_api + class RJ45Port(NvidiaSFPCommon): """class derived from SFP, representing RJ45 ports""" diff --git a/platform/mellanox/mlnx-platform-api/tests/input_platform/__init__.py b/platform/mellanox/mlnx-platform-api/tests/input_platform/__init__.py index e69de29bb2d1..07ebf17a113e 100644 --- a/platform/mellanox/mlnx-platform-api/tests/input_platform/__init__.py +++ b/platform/mellanox/mlnx-platform-api/tests/input_platform/__init__.py @@ -0,0 +1,16 @@ +# +# Copyright (c) 2017-2022 NVIDIA CORPORATION & AFFILIATES. +# Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/platform/mellanox/mlnx-platform-api/tests/input_platform/output_sfp.py b/platform/mellanox/mlnx-platform-api/tests/input_platform/output_sfp.py index 20a09d1b54f6..170b0246430f 100644 --- a/platform/mellanox/mlnx-platform-api/tests/input_platform/output_sfp.py +++ b/platform/mellanox/mlnx-platform-api/tests/input_platform/output_sfp.py @@ -1,3 +1,20 @@ +# +# Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. +# Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + """ module holding the correct values for the sfp_test.py """ diff --git a/platform/mellanox/mlnx-platform-api/tests/test_sfp.py b/platform/mellanox/mlnx-platform-api/tests/test_sfp.py index f599e0241d25..b72a5f3ed4aa 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_sfp.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_sfp.py @@ -119,3 +119,17 @@ def test_is_port_admin_status_up(self, mock_port_status): mock_port_status.return_value = (0, False) assert not SFP.is_port_admin_status_up(None, None) + + @mock.patch('sonic_platform.sfp.SFP.get_xcvr_api') + def test_dummy_apis(self, mock_get_xcvr_api): + mock_api = mock.MagicMock() + mock_api.NUM_CHANNELS = 4 + mock_get_xcvr_api.return_value = mock_api + + sfp = SFP(0) + assert sfp.get_rx_los() == [False] * 4 + assert sfp.get_tx_fault() == [False] * 4 + + mock_get_xcvr_api.return_value = None + assert sfp.get_rx_los() is None + assert sfp.get_tx_fault() is None diff --git a/platform/mellanox/mlnx-sai.mk b/platform/mellanox/mlnx-sai.mk index 6eaa1dcf80b4..90ca7430b0ad 100644 --- a/platform/mellanox/mlnx-sai.mk +++ b/platform/mellanox/mlnx-sai.mk @@ -1,6 +1,6 @@ # Mellanox SAI -MLNX_SAI_VERSION = SAIRel1.21.2.0 +MLNX_SAI_VERSION = SAIBuild2205.22.1.19 export MLNX_SAI_VERSION diff --git a/platform/mellanox/mlnx-sai/SAI-Implementation b/platform/mellanox/mlnx-sai/SAI-Implementation index f9a21df71363..82274ffaef77 160000 --- a/platform/mellanox/mlnx-sai/SAI-Implementation +++ b/platform/mellanox/mlnx-sai/SAI-Implementation @@ -1 +1 @@ -Subproject commit f9a21df713636fe648b8bb190698e4494a0f5239 +Subproject commit 82274ffaef7748120b7657362f7875fb7d6e6f5f diff --git a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers index 7d4071a89f34..8b1f1c0f1164 160000 --- a/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers +++ b/platform/mellanox/sdk-src/sx-kernel/Switch-SDK-drivers @@ -1 +1 @@ -Subproject commit 7d4071a89f34dc1dce4a9e832a0fd27c26acb485 +Subproject commit 8b1f1c0f11647749f79ebc4e823c157513067412 diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index ad60fd1fa045..5a6864bc1e4a 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -16,7 +16,7 @@ # MLNX_SDK_BASE_PATH = $(PLATFORM_PATH)/sdk-src/sx-kernel/Switch-SDK-drivers/bin/ MLNX_SDK_PKG_BASE_PATH = $(MLNX_SDK_BASE_PATH)/$(BLDENV)/$(CONFIGURED_ARCH)/ -MLNX_SDK_VERSION = 4.5.2318 +MLNX_SDK_VERSION = 4.5.3168 MLNX_SDK_ISSU_VERSION = 101 MLNX_SDK_DEB_VERSION = $(subst -,.,$(subst _,.,$(MLNX_SDK_VERSION))) diff --git a/platform/mellanox/zero_profiles.j2 b/platform/mellanox/zero_profiles.j2 index a953c18409b2..007f19c83a0a 100644 --- a/platform/mellanox/zero_profiles.j2 +++ b/platform/mellanox/zero_profiles.j2 @@ -1,3 +1,20 @@ +{# + Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. + Apache-2.0 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +#} + [ { "BUFFER_POOL_TABLE:ingress_zero_pool": { diff --git a/platform/vs/sonic-gns3a.sh b/platform/vs/sonic-gns3a.sh index 41e39cd8686a..2a772ce5a332 100644 --- a/platform/vs/sonic-gns3a.sh +++ b/platform/vs/sonic-gns3a.sh @@ -41,9 +41,9 @@ echo " \"category\": \"router\", \"description\": \"SONiC Virtual Switch/Router\", \"vendor_name\": \"SONiC\", - \"vendor_url\": \"https://azure.github.io/SONiC/\", + \"vendor_url\": \"https://sonic-net.github.io/SONiC/\", \"product_name\": \"SONiC\", - \"product_url\": \"https://azure.github.io/SONiC/\", + \"product_url\": \"https://sonic-net.github.io/SONiC/\", \"registry_version\": 3, \"status\": \"experimental\", \"maintainer\": \"SONiC\", diff --git a/rules/config b/rules/config index 380b28bc7cd5..888c470cdee2 100644 --- a/rules/config +++ b/rules/config @@ -156,9 +156,9 @@ INCLUDE_P4RT = n # ENABLE_AUTO_TECH_SUPPORT - Enable the configuration for event-driven techsupport & coredump mgmt feature ENABLE_AUTO_TECH_SUPPORT = y -# TELEMETRY_WRITABLE - Enable write/config operations via the gNMI interface. +# ENABLE_TRANSLIB_WRITE - Enable translib write/config operations via the gNMI interface. # Uncomment to enable: -# TELEMETRY_WRITABLE = y +# ENABLE_TRANSLIB_WRITE = y # INCLUDE_MACSEC - build docker-macsec for macsec support INCLUDE_MACSEC = y diff --git a/rules/swss-common.mk b/rules/swss-common.mk index 9ab49b672b6c..d2c4390ef4ff 100644 --- a/rules/swss-common.mk +++ b/rules/swss-common.mk @@ -9,9 +9,9 @@ $(LIBSWSSCOMMON)_VERSION = $(LIBSWSSCOMMON_VERSION) $(LIBSWSSCOMMON)_NAME = $(LIBSWSSCOMMON_NAME) $(LIBSWSSCOMMON)_DEPENDS += $(LIBHIREDIS_DEV) $(LIBNL3_DEV) $(LIBNL_GENL3_DEV) \ $(LIBNL_ROUTE3_DEV) $(LIBNL_NF3_DEV) \ - $(LIBNL_CLI_DEV) + $(LIBNL_CLI_DEV) $(LIBYANG_DEV) $(LIBYANG) $(LIBSWSSCOMMON)_RDEPENDS += $(LIBHIREDIS) $(LIBNL3) $(LIBNL_GENL3) \ - $(LIBNL_ROUTE3) $(LIBNL_NF3) $(LIBNL_CLI) + $(LIBNL_ROUTE3) $(LIBNL_NF3) $(LIBNL_CLI) $(LIBYANG) SONIC_DPKG_DEBS += $(LIBSWSSCOMMON) LIBSWSSCOMMON_DEV = $(LIBSWSSCOMMON_NAME)-dev_$(LIBSWSSCOMMON_VERSION)_$(CONFIGURED_ARCH).deb diff --git a/scripts/build_kvm_image.sh b/scripts/build_kvm_image.sh index 44009ed013f4..f3936a548299 100755 --- a/scripts/build_kvm_image.sh +++ b/scripts/build_kvm_image.sh @@ -49,6 +49,19 @@ prepare_installer_disk() umount $tmpdir } +wait_kvm_ready() +{ + local count=30 + local waiting_in_seconds=2.0 + for ((i=1; i<=$count; i++)); do + sleep $waiting_in_seconds + echo "$(date) [$i/$count] waiting for the port $KVM_PORT ready" + if netstat -l | grep -q ":$KVM_PORT"; then + break + fi + done +} + apt-get install -y net-tools create_disk prepare_installer_disk @@ -86,7 +99,7 @@ echo "Installing SONiC" kvm_pid=$! -sleep 2.0 +wait_kvm_ready [ -d "/proc/$kvm_pid" ] || { echo "ERROR: kvm died." @@ -114,7 +127,7 @@ echo "Booting up SONiC" kvm_pid=$! -sleep 2.0 +wait_kvm_ready [ -d "/proc/$kvm_pid" ] || { echo "ERROR: kvm died." diff --git a/slave.mk b/slave.mk index d0184445cd1f..c521b3807356 100644 --- a/slave.mk +++ b/slave.mk @@ -391,7 +391,7 @@ $(info "INCLUDE_MUX" : "$(INCLUDE_MUX)") $(info "INCLUDE_BOOTCHART : "$(INCLUDE_BOOTCHART)") $(info "ENABLE_BOOTCHART : "$(ENABLE_BOOTCHART)") $(info "ENABLE_FIPS_FEATURE" : "$(ENABLE_FIPS_FEATURE)") -$(info "TELEMETRY_WRITABLE" : "$(TELEMETRY_WRITABLE)") +$(info "ENABLE_TRANSLIB_WRITE" : "$(ENABLE_TRANSLIB_WRITE)") $(info "ENABLE_AUTO_TECH_SUPPORT" : "$(ENABLE_AUTO_TECH_SUPPORT)") $(info "PDDF_SUPPORT" : "$(PDDF_SUPPORT)") $(info "MULTIARCH_QEMU_ENVIRON" : "$(MULTIARCH_QEMU_ENVIRON)") diff --git a/src/ifupdown2/patch/0003-Fix-the-return-value-of-utils._execute_subprocess-me.patch b/src/ifupdown2/patch/0003-Fix-the-return-value-of-utils._execute_subprocess-me.patch new file mode 100644 index 000000000000..39cd481099ca --- /dev/null +++ b/src/ifupdown2/patch/0003-Fix-the-return-value-of-utils._execute_subprocess-me.patch @@ -0,0 +1,21 @@ +Fix the return value of utils._execute_subprocess method for empty strings +--- + ifupdown2/ifupdown/utils.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ifupdown2/ifupdown/utils.py b/ifupdown2/ifupdown/utils.py +index d638fe9..0c5d8ce 100644 +--- a/ifupdown2/ifupdown/utils.py ++++ b/ifupdown2/ifupdown/utils.py +@@ -380,7 +380,7 @@ class utils(): + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) + +- cmd_output_string = cmd_output.decode() if cmd_output else cmd_output ++ cmd_output_string = cmd_output.decode() if cmd_output is not None else cmd_output + + if cmd_returncode != 0: + raise Exception(cls._format_error(cmd, +-- +2.14.1 + diff --git a/src/ifupdown2/patch/series b/src/ifupdown2/patch/series index c4e412bbe83f..7d0fa15ded61 100644 --- a/src/ifupdown2/patch/series +++ b/src/ifupdown2/patch/series @@ -1,2 +1,3 @@ 0001-fix-broadcast-addr-encoding.patch 0002-disable-checks-when-using-no-wait.patch +0003-Fix-the-return-value-of-utils._execute_subprocess-me.patch diff --git a/src/isc-dhcp/patch/0013-Fix-dhcrelay-agent-option-buffer-pointer-logic.patch b/src/isc-dhcp/patch/0013-Fix-dhcrelay-agent-option-buffer-pointer-logic.patch new file mode 100644 index 000000000000..051b58966cae --- /dev/null +++ b/src/isc-dhcp/patch/0013-Fix-dhcrelay-agent-option-buffer-pointer-logic.patch @@ -0,0 +1,53 @@ +From 0a2f9a62bceb90b0d30461add2e25c4ce7a24547 Mon Sep 17 00:00:00 2001 +From: Thomas Markwalder +Date: Fri, 20 Dec 2019 10:11:54 -0500 +Subject: [PATCH] [#71] Fix dhcrelay agent option buffer pointer logic + +relay/dhcrelay.c + strip_relay_agent_options() + strip_relay_agent_options() + - corrected buffer pointer logic + +--- + relay/dhcrelay.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c +index 896e1e2e..980dacae 100644 +--- a/relay/dhcrelay.c ++++ b/relay/dhcrelay.c +@@ -1238,8 +1238,13 @@ strip_relay_agent_options(struct interface_info *in, + return (0); + + if (sp != op) { +- memmove(sp, op, op[1] + 2); +- sp += op[1] + 2; ++ size_t mlen = op[1] + 2; ++ memmove(sp, op, mlen); ++ sp += mlen; ++ if (sp > max) { ++ return (0); ++ } ++ + op = nextop; + } else + op = sp = nextop; +@@ -1620,8 +1620,13 @@ add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet, + end_pad = NULL; + + if (sp != op) { +- memmove(sp, op, op[1] + 2); +- sp += op[1] + 2; ++ size_t mlen = op[1] + 2; ++ memmove(sp, op, mlen); ++ sp += mlen; ++ if (sp > max) { ++ return (0); ++ } ++ + op = nextop; + } else + op = sp = nextop; +-- +2.17.1 + diff --git a/src/isc-dhcp/patch/series b/src/isc-dhcp/patch/series index 5397aa0c6e06..b9efee0192f5 100644 --- a/src/isc-dhcp/patch/series +++ b/src/isc-dhcp/patch/series @@ -11,3 +11,4 @@ 0010-Bugfix-correctly-set-interface-netmask.patch 0011-dhcp-relay-Prevent-Buffer-Overrun.patch 0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch +0013-Fix-dhcrelay-agent-option-buffer-pointer-logic.patch diff --git a/src/sonic-config-engine/redis_bcc.py b/src/sonic-config-engine/redis_bcc.py deleted file mode 100644 index c9d3ebca239f..000000000000 --- a/src/sonic-config-engine/redis_bcc.py +++ /dev/null @@ -1,29 +0,0 @@ -import jinja2 - -from base64 import b64encode, b64decode - -class RedisBytecodeCache(jinja2.BytecodeCache): - """ A bytecode cache for jinja2 template that stores bytecode in Redis """ - - REDIS_HASH = 'JINJA2_CACHE' - - def __init__(self, client): - self._client = client - try: - self._client.connect(self._client.LOGLEVEL_DB, retry_on=False) - except Exception: - self._client = None - - def load_bytecode(self, bucket): - if self._client is None: - return - code = self._client.get(self._client.LOGLEVEL_DB, self.REDIS_HASH, bucket.key) - if code is not None: - bucket.bytecode_from_string(b64decode(code.encode())) - - def dump_bytecode(self, bucket): - if self._client is None: - return - self._client.set(self._client.LOGLEVEL_DB, self.REDIS_HASH, - bucket.key, b64encode(bucket.bytecode_to_string()).decode()) - diff --git a/src/sonic-config-engine/setup.py b/src/sonic-config-engine/setup.py index aa340995b60b..3f2b2a240a95 100644 --- a/src/sonic-config-engine/setup.py +++ b/src/sonic-config-engine/setup.py @@ -43,7 +43,6 @@ 'minigraph', 'openconfig_acl', 'portconfig', - 'redis_bcc', ] if sys.version_info.major == 3: # Python 3-only modules diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index ed7c3b616f3c..d5358f633dbf 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -31,10 +31,9 @@ from config_samples import generate_sample_config, get_available_config from functools import partial from minigraph import minigraph_encoder, parse_xml, parse_device_desc_xml, parse_asic_sub_role, parse_asic_switch_type from portconfig import get_port_config, get_breakout_mode -from redis_bcc import RedisBytecodeCache from sonic_py_common.multi_asic import get_asic_id_from_name, get_asic_device_id, is_multi_asic from sonic_py_common import device_info -from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector, SonicDBConfig, ConfigDBPipeConnector +from swsscommon.swsscommon import ConfigDBConnector, SonicDBConfig, ConfigDBPipeConnector PY3x = sys.version_info >= (3, 0) @@ -241,8 +240,7 @@ def _get_jinja2_env(paths): Retreive Jinj2 env used to render configuration templates """ loader = jinja2.FileSystemLoader(paths) - redis_bcc = RedisBytecodeCache(SonicV2Connector(host='127.0.0.1')) - env = jinja2.Environment(loader=loader, trim_blocks=True, bytecode_cache=redis_bcc) + env = jinja2.Environment(loader=loader, trim_blocks=True) env.filters['sort_by_port_index'] = sort_by_port_index env.filters['ipv4'] = is_ipv4 env.filters['ipv6'] = is_ipv6 diff --git a/src/sonic-ctrmgrd/ctrmgr/ctrmgrd.py b/src/sonic-ctrmgrd/ctrmgr/ctrmgrd.py index 3941a05a738a..2defb6e45387 100755 --- a/src/sonic-ctrmgrd/ctrmgr/ctrmgrd.py +++ b/src/sonic-ctrmgrd/ctrmgr/ctrmgrd.py @@ -104,10 +104,12 @@ def log_debug(m): def log_error(m): + msg = "{}: {}".format(inspect.stack()[1][3], m) syslog.syslog(syslog.LOG_ERR, msg) def log_info(m): + msg = "{}: {}".format(inspect.stack()[1][3], m) syslog.syslog(syslog.LOG_INFO, msg) diff --git a/src/sonic-ctrmgrd/ctrmgr/kube_commands.py b/src/sonic-ctrmgrd/ctrmgr/kube_commands.py index 9a6ea9ed8dff..3adea36ef12c 100755 --- a/src/sonic-ctrmgrd/ctrmgr/kube_commands.py +++ b/src/sonic-ctrmgrd/ctrmgr/kube_commands.py @@ -13,10 +13,14 @@ import syslog import tempfile import urllib.request +import base64 from urllib.parse import urlparse import yaml +import requests from sonic_py_common import device_info +from jinja2 import Template +from swsscommon import swsscommon KUBE_ADMIN_CONF = "/etc/sonic/kube_admin.conf" KUBELET_YAML = "/var/lib/kubelet/config.yaml" @@ -24,6 +28,9 @@ LOCK_FILE = "/var/lock/kube_join.lock" FLANNEL_CONF_FILE = "/usr/share/sonic/templates/kube_cni.10-flannel.conflist" CNI_DIR = "/etc/cni/net.d" +K8S_CA_URL = "https://{}:{}/api/v1/namespaces/default/configmaps/kube-root-ca.crt" +AME_CRT = "/etc/sonic/credentials/restapiserver.crt" +AME_KEY = "/etc/sonic/credentials/restapiserver.key" def log_debug(m): msg = "{}: {}".format(inspect.stack()[1][3], m) @@ -77,8 +84,7 @@ def _run_command(cmd, timeout=5): def kube_read_labels(): """ Read current labels on node and return as dict. """ - KUBECTL_GET_CMD = "kubectl --kubeconfig {} get nodes --show-labels |\ - grep {} | tr -s ' ' | cut -f6 -d' '" + KUBECTL_GET_CMD = "kubectl --kubeconfig {} get nodes {} --show-labels |tr -s ' ' | cut -f6 -d' '" labels = {} ret, out, _ = _run_command(KUBECTL_GET_CMD.format( @@ -211,6 +217,68 @@ def _download_file(server, port, insecure): log_debug("{} downloaded".format(KUBE_ADMIN_CONF)) +def _gen_cli_kubeconf(server, port, insecure): + """generate identity which can help authenticate and + authorization to k8s cluster + """ + client_kubeconfig_template = """ +apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: {{ k8s_ca }} + server: https://{{ vip }}:{{ port }} + name: kubernetes +contexts: +- context: + cluster: kubernetes + user: user + name: user@kubernetes +current-context: user@kubernetes +kind: Config +preferences: {} +users: +- name: user + user: + client-certificate-data: {{ ame_crt }} + client-key-data: {{ ame_key }} + """ + if insecure: + r = requests.get(K8S_CA_URL.format(server, port), cert=(AME_CRT, AME_KEY), verify=False) + else: + r = requests.get(K8S_CA_URL.format(server, port), cert=(AME_CRT, AME_KEY)) + if not r.ok: + raise requests.RequestException("Something wrong with AME cert or something wrong about sonic role in k8s cluster") + k8s_ca = r.json()["data"]["ca.crt"] + k8s_ca_b64 = base64.b64encode(k8s_ca.encode("utf-8")).decode("utf-8") + ame_crt_raw = open(AME_CRT, "rb") + ame_crt_b64 = base64.b64encode(ame_crt_raw.read()).decode("utf-8") + ame_key_raw = open(AME_KEY, "rb") + ame_key_b64 = base64.b64encode(ame_key_raw.read()).decode("utf-8") + client_kubeconfig_template_j2 = Template(client_kubeconfig_template) + client_kubeconfig = client_kubeconfig_template_j2.render( + k8s_ca=k8s_ca_b64, vip=server, port=port, ame_crt=ame_crt_b64, ame_key=ame_key_b64) + (h, fname) = tempfile.mkstemp(suffix="_kube_join") + os.write(h, client_kubeconfig.encode("utf-8")) + os.close(h) + log_debug("Downloaded = {}".format(fname)) + + shutil.copyfile(fname, KUBE_ADMIN_CONF) + + log_debug("{} downloaded".format(KUBE_ADMIN_CONF)) + + +def _get_local_ipv6(): + try: + config_db = swsscommon.DBConnector("CONFIG_DB", 0) + mgmt_ip_data = swsscommon.Table(config_db, 'MGMT_INTERFACE') + for key in mgmt_ip_data.getKeys(): + if key.find(":") >= 0: + return key.split("|")[1].split("/")[0] + raise IOError("IPV6 not find from MGMT_INTERFACE table") + except Exception as e: + raise IOError(str(e)) + + def _troubleshoot_tips(): """ log troubleshoot tips which could be handy, when in trouble with join @@ -264,12 +332,14 @@ def _do_reset(pending_join = False): def _do_join(server, port, insecure): - KUBEADM_JOIN_CMD = "kubeadm join --discovery-file {} --node-name {}" + KUBEADM_JOIN_CMD = "kubeadm join --discovery-file {} --node-name {} --apiserver-advertise-address {}" err = "" out = "" ret = 0 try: - _download_file(server, port, insecure) + local_ipv6 = _get_local_ipv6() + #_download_file(server, port, insecure) + _gen_cli_kubeconf(server, port, insecure) _do_reset(True) _run_command("modprobe br_netfilter") # Copy flannel.conf @@ -279,11 +349,11 @@ def _do_join(server, port, insecure): if ret == 0: (ret, out, err) = _run_command(KUBEADM_JOIN_CMD.format( - KUBE_ADMIN_CONF, get_device_name()), timeout=60) + KUBE_ADMIN_CONF, get_device_name(), local_ipv6), timeout=60) log_debug("ret = {}".format(ret)) except IOError as e: - err = "Download failed: {}".format(str(e)) + err = "Join failed: {}".format(str(e)) ret = -1 out = "" diff --git a/src/sonic-ctrmgrd/tests/common_test.py b/src/sonic-ctrmgrd/tests/common_test.py index 6e9763962bde..9283e3ad258e 100755 --- a/src/sonic-ctrmgrd/tests/common_test.py +++ b/src/sonic-ctrmgrd/tests/common_test.py @@ -9,6 +9,7 @@ CONFIG_DB_NO = 4 STATE_DB_NO = 6 FEATURE_TABLE = "FEATURE" +MGMT_INTERFACE_TABLE = "MGMT_INTERFACE" KUBE_LABEL_TABLE = "KUBE_LABELS" KUBE_LABEL_SET_KEY = "SET" @@ -41,6 +42,7 @@ IMAGE_TAG = "image_tag" FAIL_LOCK = "fail_lock" DO_JOIN = "do_join" +REQ = "req" # subproc key words @@ -643,8 +645,27 @@ def mock_subproc_side_effect(cmd, shell=False, stdout=None, stderr=None): return mock_proc(cmd, index) -def set_kube_mock(mock_subproc): +class mock_reqget: + def __init__(self): + self.ok = True + + def json(self): + return current_test_data.get(REQ, "") + + +def mock_reqget_side_effect(url, cert, verify=True): + return mock_reqget() + + +def set_kube_mock(mock_subproc, mock_table=None, mock_conn=None, mock_reqget=None): mock_subproc.side_effect = mock_subproc_side_effect + if mock_table != None: + mock_table.side_effect = table_side_effect + if mock_conn != None: + mock_conn.side_effect = conn_side_effect + if mock_reqget != None: + mock_reqget.side_effect = mock_reqget_side_effect + def create_remote_ctr_config_json(): str_conf = '\ diff --git a/src/sonic-ctrmgrd/tests/kube_commands_test.py b/src/sonic-ctrmgrd/tests/kube_commands_test.py index 637802ab1d9f..d8e0939efb85 100755 --- a/src/sonic-ctrmgrd/tests/kube_commands_test.py +++ b/src/sonic-ctrmgrd/tests/kube_commands_test.py @@ -15,6 +15,8 @@ KUBE_ADMIN_CONF = "/tmp/kube_admin.conf" FLANNEL_CONF_FILE = "/tmp/flannel.conf" CNI_DIR = "/tmp/cni/net.d" +AME_CRT = "/tmp/restapiserver.crt" +AME_KEY = "/tmp/restapiserver.key" # kube_commands test cases # NOTE: Ensure state-db entry is complete in PRE as we need to @@ -25,8 +27,7 @@ common_test.DESCR: "read labels", common_test.RETVAL: 0, common_test.PROC_CMD: ["\ -kubectl --kubeconfig {} get nodes --show-labels |\ - grep none | tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF)], +kubectl --kubeconfig {} get nodes none --show-labels |tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF)], common_test.PROC_OUT: ["foo=bar,hello=world"], common_test.POST: { "foo": "bar", @@ -39,8 +40,7 @@ common_test.TRIGGER_THROW: True, common_test.RETVAL: -1, common_test.PROC_CMD: ["\ -kubectl --kubeconfig {} get nodes --show-labels |\ - grep none | tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF)], +kubectl --kubeconfig {} get nodes none --show-labels |tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF)], common_test.POST: { }, common_test.PROC_KILLED: 1 @@ -49,8 +49,7 @@ common_test.DESCR: "read labels fail", common_test.RETVAL: -1, common_test.PROC_CMD: ["\ -kubectl --kubeconfig {} get nodes --show-labels |\ - grep none | tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF)], +kubectl --kubeconfig {} get nodes none --show-labels |tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF)], common_test.PROC_OUT: [""], common_test.PROC_ERR: ["command failed"], common_test.POST: { @@ -65,8 +64,7 @@ common_test.RETVAL: 0, common_test.ARGS: { "foo": "bar", "hello": "World!", "test": "ok" }, common_test.PROC_CMD: [ -"kubectl --kubeconfig {} get nodes --show-labels |\ - grep none | tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF), +"kubectl --kubeconfig {} get nodes none --show-labels |tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF), "kubectl --kubeconfig {} label --overwrite nodes none hello-".format( KUBE_ADMIN_CONF), "kubectl --kubeconfig {} label --overwrite nodes none hello=World! test=ok".format( @@ -79,8 +77,7 @@ common_test.RETVAL: 0, common_test.ARGS: { "foo": "bar", "hello": "world" }, common_test.PROC_CMD: [ -"kubectl --kubeconfig {} get nodes --show-labels |\ - grep none | tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF) +"kubectl --kubeconfig {} get nodes none --show-labels |tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF) ], common_test.PROC_OUT: ["foo=bar,hello=world"] }, @@ -90,8 +87,7 @@ common_test.ARGS: { "any": "thing" }, common_test.RETVAL: -1, common_test.PROC_CMD: [ -"kubectl --kubeconfig {} get nodes --show-labels |\ - grep none | tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF) +"kubectl --kubeconfig {} get nodes none --show-labels |tr -s ' ' | cut -f6 -d' '".format(KUBE_ADMIN_CONF) ], common_test.PROC_ERR: ["read failed"] } @@ -114,10 +110,22 @@ "mkdir -p {}".format(CNI_DIR), "cp {} {}".format(FLANNEL_CONF_FILE, CNI_DIR), "systemctl start kubelet", - "kubeadm join --discovery-file {} --node-name none".format( + "kubeadm join --discovery-file {} --node-name none --apiserver-advertise-address FC00:2::32".format( KUBE_ADMIN_CONF) ], - common_test.PROC_RUN: [True, True] + common_test.PROC_RUN: [True, True], + common_test.PRE: { + common_test.CONFIG_DB_NO: { + common_test.MGMT_INTERFACE_TABLE: { + "eth0|FC00:2::32/64": { + "gwaddr": "fc00:2::1" + } + } + } + }, + common_test.REQ: { + "data": {"ca.crt": "test"} + } }, 1: { common_test.DESCR: "Regular secure join", @@ -135,10 +143,22 @@ "mkdir -p {}".format(CNI_DIR), "cp {} {}".format(FLANNEL_CONF_FILE, CNI_DIR), "systemctl start kubelet", - "kubeadm join --discovery-file {} --node-name none".format( + "kubeadm join --discovery-file {} --node-name none --apiserver-advertise-address FC00:2::32".format( KUBE_ADMIN_CONF) ], - common_test.PROC_RUN: [True, True] + common_test.PROC_RUN: [True, True], + common_test.PRE: { + common_test.CONFIG_DB_NO: { + common_test.MGMT_INTERFACE_TABLE: { + "eth0|FC00:2::32/64": { + "gwaddr": "fc00:2::1" + } + } + } + }, + common_test.REQ: { + "data": {"ca.crt": "test"} + } }, 2: { common_test.DESCR: "Skip join as already connected", @@ -228,11 +248,17 @@ def init(self): s.close() with open(FLANNEL_CONF_FILE, "w") as s: s.close() + with open(AME_CRT, "w") as s: + s.close() + with open(AME_KEY, "w") as s: + s.close() kube_commands.KUBELET_YAML = kubelet_yaml kube_commands.CNI_DIR = CNI_DIR kube_commands.FLANNEL_CONF_FILE = FLANNEL_CONF_FILE kube_commands.SERVER_ADMIN_URL = "file://{}".format(self.admin_conf_file) kube_commands.KUBE_ADMIN_CONF = KUBE_ADMIN_CONF + kube_commands.AME_CRT = AME_CRT + kube_commands.AME_KEY = AME_KEY @patch("kube_commands.subprocess.Popen") @@ -295,11 +321,13 @@ def test_write_labels(self, mock_subproc): json.dumps(labels, indent=4))) assert False - + @patch("kube_commands.requests.get") + @patch("kube_commands.swsscommon.DBConnector") + @patch("kube_commands.swsscommon.Table") @patch("kube_commands.subprocess.Popen") - def test_join(self, mock_subproc): + def test_join(self, mock_subproc, mock_table, mock_conn, mock_reqget): self.init() - common_test.set_kube_mock(mock_subproc) + common_test.set_kube_mock(mock_subproc, mock_table, mock_conn, mock_reqget) for (i, ct_data) in join_test_data.items(): lock_file = "" diff --git a/src/sonic-device-data/README.md b/src/sonic-device-data/README.md index e8ccad58b819..d9d403758a86 100644 --- a/src/sonic-device-data/README.md +++ b/src/sonic-device-data/README.md @@ -1,4 +1,4 @@ # sonic-device-data Device-specific data for the SONiC project -See the [SONiC Website](http://azure.github.io/SONiC/) for more information about the SONiC project. +See the [SONiC Website](https://sonic-net.github.io/SONiC/) for more information about the SONiC project. diff --git a/src/sonic-gnmi b/src/sonic-gnmi index 14f91214fe2b..437fc357fd95 160000 --- a/src/sonic-gnmi +++ b/src/sonic-gnmi @@ -1 +1 @@ -Subproject commit 14f91214fe2b4ba7575bffff58989dbf7df71c48 +Subproject commit 437fc357fd95a0b25715b8ab869b8cf8a7a22681 diff --git a/src/sonic-host-services-data/README.md b/src/sonic-host-services-data/README.md index 93af66a83d6b..0b9e714932d2 100644 --- a/src/sonic-host-services-data/README.md +++ b/src/sonic-host-services-data/README.md @@ -16,4 +16,4 @@ dpkg-buildpackage -rfakeroot -Tclean --- -See the [SONiC Website](http://azure.github.io/SONiC/) for more information about the SONiC project. +See the [SONiC Website](https://sonic-net.github.io/SONiC/) for more information about the SONiC project. diff --git a/src/sonic-py-common/setup.py b/src/sonic-py-common/setup.py index f12c0d83cb77..144cf61f52c4 100644 --- a/src/sonic-py-common/setup.py +++ b/src/sonic-py-common/setup.py @@ -27,6 +27,12 @@ 'pytest', 'mock==3.0.5' # For python 2. Version >=4.0.0 drops support for py2 ], + entry_points={ + 'console_scripts': [ + 'sonic-db-load = sonic_py_common.sonic_db_dump_load:sonic_db_dump_load', + 'sonic-db-dump = sonic_py_common.sonic_db_dump_load:sonic_db_dump_load', + ], + }, classifiers=[ 'Intended Audience :: Developers', 'Operating System :: Linux', diff --git a/src/sonic-py-common/sonic_py_common/general.py b/src/sonic-py-common/sonic_py_common/general.py index 9e04f3e214ee..4fea165de9fb 100644 --- a/src/sonic-py-common/sonic_py_common/general.py +++ b/src/sonic-py-common/sonic_py_common/general.py @@ -1,4 +1,5 @@ import sys +from subprocess import Popen, STDOUT, PIPE, CalledProcessError, check_output def load_module_from_source(module_name, file_path): @@ -23,3 +24,70 @@ def load_module_from_source(module_name, file_path): sys.modules[module_name] = module return module + + +def getstatusoutput_noshell(cmd): + """ + This function implements getstatusoutput API from subprocess module + but using shell=False to prevent shell injection. + Ref: https://github.com/python/cpython/blob/3.10/Lib/subprocess.py#L602 + """ + try: + output = check_output(cmd, universal_newlines=True, stderr=STDOUT) + exitcode = 0 + except CalledProcessError as ex: + output = ex.output + exitcode = ex.returncode + if output[-1:] == '\n': + output = output[:-1] + return exitcode, output + + +def getstatusoutput_noshell_pipe(cmd0, *args): + """ + This function implements getstatusoutput API from subprocess module + but using shell=False to prevent shell injection. Input command + includes two or more commands connected by shell pipe(s). + """ + popens = [Popen(cmd0, stdout=PIPE, universal_newlines=True)] + i = 0 + while i < len(args): + popens.append(Popen(args[i], stdin=popens[i].stdout, stdout=PIPE, universal_newlines=True)) + popens[i].stdout.close() + i += 1 + output = popens[-1].communicate()[0] + if output[-1:] == '\n': + output = output[:-1] + + exitcodes = [0] * len(popens) + while popens: + last = popens.pop(-1) + exitcodes[len(popens)] = last.wait() + + return (exitcodes, output) + + +def check_output_pipe(cmd0, *args): + """ + This function implements check_output API from subprocess module. + Input command includes two or more commands connected by shell pipe(s) + """ + popens = [Popen(cmd0, stdout=PIPE, universal_newlines=True)] + i = 0 + while i < len(args): + popens.append(Popen(args[i], stdin=popens[i].stdout, stdout=PIPE, universal_newlines=True)) + popens[i].stdout.close() + i += 1 + output = popens[-1].communicate()[0] + + i = 0 + args_list = [cmd0] + list(args) + while popens: + current = popens.pop(0) + exitcode = current.wait() + if exitcode != 0: + raise CalledProcessError(returncode=exitcode, cmd=args_list[i], output=current.stdout) + i += 1 + + return output + diff --git a/src/sonic-py-common/sonic_py_common/sonic_db_dump_load.py b/src/sonic-py-common/sonic_py_common/sonic_db_dump_load.py new file mode 100755 index 000000000000..126dd2bc112e --- /dev/null +++ b/src/sonic-py-common/sonic_py_common/sonic_db_dump_load.py @@ -0,0 +1,139 @@ +## ref: https://github.com/p/redis-dump-load/blob/7bbdb1eaea0a51ed4758d3ce6ca01d497a4e7429/redisdl.py + +def sonic_db_dump_load(): + import optparse + import os.path + import re + import sys + from redisdl import dump, load + from swsscommon.swsscommon import SonicDBConfig + + DUMP = 1 + LOAD = 2 + + def options_to_kwargs(options): + args = {} + if options.password: + args['password'] = options.password + if options.encoding: + args['encoding'] = options.encoding + # dump only + if hasattr(options, 'pretty') and options.pretty: + args['pretty'] = True + if hasattr(options, 'keys') and options.keys: + args['keys'] = options.keys + # load only + if hasattr(options, 'use_expireat') and options.use_expireat: + args['use_expireat'] = True + if hasattr(options, 'empty') and options.empty: + args['empty'] = True + if hasattr(options, 'backend') and options.backend: + args['streaming_backend'] = options.backend + if hasattr(options, 'dbname') and options.dbname: + if options.conntype == 'tcp': + args['host'] = SonicDBConfig.getDbHostname(options.dbname) + args['port'] = SonicDBConfig.getDbPort(options.dbname) + args['db'] = SonicDBConfig.getDbId(options.dbname) + args['unix_socket_path'] = None + elif options.conntype == "unix_socket": + args['host'] = None + args['port'] = None + args['db'] = SonicDBConfig.getDbId(options.dbname) + args['unix_socket_path'] = SonicDBConfig.getDbSock(options.dbname) + else: + raise TypeError('redis connection type is tcp or unix_socket') + + return args + + def do_dump(options): + if options.output: + output = open(options.output, 'w') + else: + output = sys.stdout + + kwargs = options_to_kwargs(options) + dump(output, **kwargs) + + if options.output: + output.close() + + def do_load(options, args): + if len(args) > 0: + input = open(args[0], 'rb') + else: + input = sys.stdin + + kwargs = options_to_kwargs(options) + load(input, **kwargs) + + if len(args) > 0: + input.close() + + script_name = os.path.basename(sys.argv[0]) + if re.search(r'load(?:$|\.)', script_name): + action = help = LOAD + elif re.search(r'dump(?:$|\.)', script_name): + action = help = DUMP + else: + # default is dump, however if dump is specifically requested + # we don't show help text for toggling between dumping and loading + action = DUMP + help = None + + if help == LOAD: + usage = "Usage: %prog [options] [FILE]" + usage += "\n\nLoad data from FILE (which must be a JSON dump previously created" + usage += "\nby redisdl) into specified or default redis." + usage += "\n\nIf FILE is omitted standard input is read." + elif help == DUMP: + usage = "Usage: %prog [options]" + usage += "\n\nDump data from specified or default redis." + usage += "\n\nIf no output file is specified, dump to standard output." + else: + usage = "Usage: %prog [options]" + usage += "\n %prog -l [options] [FILE]" + usage += "\n\nDump data from redis or load data into redis." + usage += "\n\nIf input or output file is specified, dump to standard output and load" + usage += "\nfrom standard input." + parser = optparse.OptionParser(usage=usage) + parser.add_option('-w', '--password', help='connect with PASSWORD') + if help == DUMP: + parser.add_option('-n', '--dbname', help='dump DATABASE (APPL_DB/ASIC_DB...)') + parser.add_option('-t', '--conntype', help='indicate redis connection type (tcp[default] or unix_socket)', default='tcp') + parser.add_option('-k', '--keys', help='dump only keys matching specified glob-style pattern') + parser.add_option('-o', '--output', help='write to OUTPUT instead of stdout') + parser.add_option('-y', '--pretty', help='split output on multiple lines and indent it', action='store_true') + parser.add_option('-E', '--encoding', help='set encoding to use while decoding data from redis', default='utf-8') + elif help == LOAD: + parser.add_option('-n', '--dbname', help='dump DATABASE (APPL_DB/ASIC_DB...)') + parser.add_option('-t', '--conntype', help='indicate redis connection type (tcp[default] or unix_socket)', default='tcp') + parser.add_option('-e', '--empty', help='delete all keys in destination db prior to loading', action='store_true') + parser.add_option('-E', '--encoding', help='set encoding to use while encoding data to redis', default='utf-8') + parser.add_option('-B', '--backend', help='use specified streaming backend') + parser.add_option('-A', '--use-expireat', help='use EXPIREAT rather than TTL/EXPIRE', action='store_true') + else: + parser.add_option('-l', '--load', help='load data into redis (default is to dump data from redis)', action='store_true') + parser.add_option('-n', '--dbname', help='dump DATABASE (APPL_DB/ASIC_DB/COUNTERS_DB/LOGLEVEL_DB/CONFIG_DB...)') + parser.add_option('-t', '--conntype', help='indicate redis connection type (tcp[default] or unix_socket)', default='tcp') + parser.add_option('-k', '--keys', help='dump only keys matching specified glob-style pattern') + parser.add_option('-o', '--output', help='write to OUTPUT instead of stdout (dump mode only)') + parser.add_option('-y', '--pretty', help='split output on multiple lines and indent it (dump mode only)', action='store_true') + parser.add_option('-e', '--empty', help='delete all keys in destination db prior to loading (load mode only)', action='store_true') + parser.add_option('-E', '--encoding', help='set encoding to use while decoding data from redis', default='utf-8') + parser.add_option('-A', '--use-expireat', help='use EXPIREAT rather than TTL/EXPIRE', action='store_true') + parser.add_option('-B', '--backend', help='use specified streaming backend (load mode only)') + options, args = parser.parse_args() + + if hasattr(options, 'load') and options.load: + action = LOAD + + if action == DUMP: + if len(args) > 0: + parser.print_help() + exit(4) + do_dump(options) + else: + if len(args) > 1: + parser.print_help() + exit(4) + do_load(options, args) diff --git a/src/sonic-py-common/tests/test_general.py b/src/sonic-py-common/tests/test_general.py new file mode 100644 index 000000000000..a395cf9aeb6b --- /dev/null +++ b/src/sonic-py-common/tests/test_general.py @@ -0,0 +1,31 @@ +import sys +import pytest +import subprocess +from sonic_py_common.general import getstatusoutput_noshell, getstatusoutput_noshell_pipe, check_output_pipe + + +def test_getstatusoutput_noshell(tmp_path): + exitcode, output = getstatusoutput_noshell(['echo', 'sonic']) + assert (exitcode, output) == (0, 'sonic') + + exitcode, output = getstatusoutput_noshell([sys.executable, "-c", "import sys; sys.exit(6)"]) + assert exitcode != 0 + +def test_getstatusoutput_noshell_pipe(): + exitcode, output = getstatusoutput_noshell_pipe(['echo', 'sonic'], ['awk', '{print $1}']) + assert (exitcode, output) == ([0, 0], 'sonic') + + exitcode, output = getstatusoutput_noshell_pipe([sys.executable, "-c", "import sys; sys.exit(6)"], [sys.executable, "-c", "import sys; sys.exit(8)"]) + assert exitcode == [6, 8] + +def test_check_output_pipe(): + output = check_output_pipe(['echo', 'sonic'], ['awk', '{print $1}']) + assert output == 'sonic\n' + + with pytest.raises(subprocess.CalledProcessError) as e: + check_output_pipe([sys.executable, "-c", "import sys; sys.exit(6)"], [sys.executable, "-c", "import sys; sys.exit(0)"]) + assert e.returncode == [6, 0] + + with pytest.raises(subprocess.CalledProcessError) as e: + check_output_pipe([sys.executable, "-c", "import sys; sys.exit(0)"], [sys.executable, "-c", "import sys; sys.exit(6)"]) + assert e.returncode == [0, 6] diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 854d54e07fd8..228e37c5e996 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 854d54e07fd8eeff9cae0410e8e7f04d6385400b +Subproject commit 228e37c5e9968278280202ba77cb85714ba2d8fa diff --git a/src/sonic-utilities b/src/sonic-utilities index 3af8ba4acc2b..0a7557bd9162 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit 3af8ba4acc2bbc77d17be0d67943703021c7d1e1 +Subproject commit 0a7557bd9162eae40f5d4c4f6fbab92dbad7204b diff --git a/src/system-health/health_checker/service_checker.py b/src/system-health/health_checker/service_checker.py index 33eeb4dfb707..674ad9944280 100644 --- a/src/system-health/health_checker/service_checker.py +++ b/src/system-health/health_checker/service_checker.py @@ -127,11 +127,11 @@ def get_critical_process_list_from_file(self, container, critical_processes_file self.bad_containers.add(container) logger.log_error('Invalid syntax in critical_processes file of {}'.format(container)) continue - - identifier_key = match.group(2).strip() - identifier_value = match.group(3).strip() - if identifier_key == "program" and identifier_value: - critical_process_list.append(identifier_value) + if match.group(1) is not None: + identifier_key = match.group(2).strip() + identifier_value = match.group(3).strip() + if identifier_key == "program" and identifier_value: + critical_process_list.append(identifier_value) return critical_process_list