name: ovn-ci

on:
  push:
  pull_request:
    branches: [ master ]
  schedule:
    - cron: '0 */12 * * *'

env:
  GO_VERSION: "1.16.3"
  K8S_VERSION: v1.20.2
  KIND_CLUSTER_NAME: ovn
  KIND_INSTALL_INGRESS: true
  KIND_ALLOW_SYSTEM_WRITES: true
  # This skips tests tagged as Serial
  # Current Serial tests are not relevant for OVN
  PARALLEL: true

jobs:
  # separate job for parallelism
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
    - name: Check out code
      uses: actions/checkout@v2

    - name: Verify
      uses: golangci/golangci-lint-action@v2
      with:
        version: v1.33.2
        working-directory: go-controller
        args: --modules-download-mode=vendor --timeout=15m0s --verbose

  build-master:
    name: Build-master
    runs-on: ubuntu-latest
    steps:
    - name: Set up Go
      uses: actions/setup-go@v2
      with:
        go-version: ${{ env.GO_VERSION }}
      id: go

    - name: Check out code into the Go module directory - from master branch
      uses: actions/checkout@v2
      with:
        ref: master

    - name: Build - from master branch
      run: |
        set -x
        pushd go-controller
           make
           make windows
        popd

    - name: Build docker image - from master branch
      run: |
        pushd dist/images
          sudo cp -f ../../go-controller/_output/go/bin/ovn* .
          echo "ref: $(git rev-parse  --symbolic-full-name HEAD)  commit: $(git rev-parse  HEAD)" > git_info
          docker build -t ovn-daemonset-f:dev -f Dockerfile.fedora .
          mkdir _output
          docker save ovn-daemonset-f:dev > _output/image-master.tar
        popd

    - uses: actions/upload-artifact@v2
      with:
        name: test-image-master
        path: dist/images/_output/image-master.tar

  build-pr:
    name: Build-PR
    runs-on: ubuntu-latest
    steps:
    - name: Set up Go
      uses: actions/setup-go@v2
      with:
        go-version: ${{ env.GO_VERSION }}
      id: go

    - name: Check out code into the Go module directory - from current pr branch
      uses: actions/checkout@v2

    - name: Build and Test - from current pr branch
      run: |
        set -x
        pushd go-controller
           # exit early if there are gofmt issues
           make gofmt
           make
           make windows
           COVERALLS=1 CONTAINER_RUNNABLE=1 make check
        popd

    - name: Build docker image - from current pr branch
      run: |
        pushd dist/images
          sudo cp -f ../../go-controller/_output/go/bin/ovn* .
          echo "ref: $(git rev-parse  --symbolic-full-name HEAD)  commit: $(git rev-parse  HEAD)" > git_info
          docker build -t ovn-daemonset-f:pr -f Dockerfile.fedora .
          mkdir _output
          docker save ovn-daemonset-f:pr > _output/image-pr.tar
        popd

    - uses: actions/upload-artifact@v2
      with:
        name: test-image-pr
        path: dist/images/_output/image-pr.tar

    - name: Upload Junit Reports
      if: always()
      uses: actions/upload-artifact@v2
      with:
        name: junit-unit
        path: '**/_artifacts/**.xml'

    - name: Submit code coverage to Coveralls
      env:
        COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        GO111MODULE: off
      run: |
        set -x
        go get github.com/mattn/goveralls
        go get github.com/modocache/gover
        PATH=$PATH:$(go env GOPATH)/bin

        mkdir -p $(go env GOPATH)/src/github.com/ovn-org
        ln -sf $(pwd) $(go env GOPATH)/src/github.com/ovn-org/ovn-kubernetes

        gover
        goveralls -coverprofile=gover.coverprofile -service=github

  ovn-upgrade-e2e:
    name: Upgrade OVN from Master to PR branch based image
    if: github.event_name != 'schedule'
    runs-on: ubuntu-latest
    timeout-minutes: 120
    needs:
      - build-master
      - build-pr
    strategy:
      fail-fast: false
      matrix:
        gateway-mode: [local, shared]
    env:
      JOB_NAME: "Upgrade-Tests-${{ matrix.gateway-mode }}"
      OVN_HA: "false"
      KIND_IPV4_SUPPORT: "true"
      KIND_IPV6_SUPPORT: "false"
      OVN_HYBRID_OVERLAY_ENABLE: "false"
      OVN_GATEWAY_MODE: "${{ matrix.gateway-mode }}"
      OVN_MULTICAST_ENABLE:  "false"
    steps:
    - name: Set up Go
      uses: actions/setup-go@v1
      with:
        go-version: ${{ env.GO_VERSION }}
      id: go

    - name: Set up environment
      run: |
        export GOPATH=$(go env GOPATH)
        echo "GOPATH=$GOPATH" >> $GITHUB_ENV
        echo "$GOPATH/bin" >> $GITHUB_PATH

    - name: Free up disk space
      run: sudo eatmydata apt-get remove --auto-remove -y aspnetcore-* dotnet-* libmono-* mono-* msbuild php-* php7* ghc-* zulu-*

    - uses: actions/download-artifact@v2
      with:
        name: test-image-master

    - name: Disable ufw
      # For IPv6 and Dualstack, ufw (Uncomplicated Firewall) should be disabled.
      # Not needed for KIND deployments, so just disable all the time.
      run: |
        sudo ufw disable

    - name: Load docker image
      run: |
        docker load --input image-master.tar

    - name: Check out code into the Go module directory - from PR branch
      uses: actions/checkout@v2

    - name: kind setup
      run: |
        export OVN_IMAGE="ovn-daemonset-f:dev"
        make -C test install-kind

    - name: Export logs
      if: always()
      run: |
        mkdir -p /tmp/kind/logs
        kind export logs --name ${KIND_CLUSTER_NAME} --loglevel=debug /tmp/kind/logs
        set -x
        docker ps -a
        docker exec ovn-control-plane crictl images 
        docker exec ovn-worker crictl images
        docker exec ovn-worker2 crictl images 

    - name: Upload logs
      if: always()
      uses: actions/upload-artifact@v2
      with:
        name: kind-logs-${{ env.JOB_NAME }}-${{ github.run_id }}
        path: /tmp/kind/logs

    - uses: actions/download-artifact@v2
      with:
        name: test-image-pr

    - name: Load docker image
      run: |
        docker load --input image-pr.tar

    - name: ovn upgrade
      run: |
        export OVN_IMAGE="ovn-daemonset-f:pr"
        make -C test upgrade-ovn

    - name: Run E2E shard-conformance
      run: |
        make -C test shard-conformance

    - name: Export logs
      if: always()
      run: |
        mkdir -p /tmp/kind/logs-kind-pr-branch
        kind export logs --name ${KIND_CLUSTER_NAME} --loglevel=debug /tmp/kind/logs-kind-pr-branch

    - name: Upload logs
      if: always()
      uses: actions/upload-artifact@v2
      with:
        name: kind-logs-${{ env.JOB_NAME }}-${{ github.run_id }}-after-upgrade
        path: /tmp/kind/logs-kind-pr-branch

  e2e:
    name: e2e
    if: github.event_name != 'schedule'
    runs-on: ubuntu-latest
    # 30 mins for kind, 150 mins for control-plane tests, 10 minutes for all other steps
    timeout-minutes: 190
    strategy:
      fail-fast: false
      matrix:
        target:
            # hybrid-overlay = multicast-enable = emptylb-enable = false
          - "shard-conformance"
            # hybrid-overlay = multicast-enable = emptylb-enable = true
          - "control-plane"
        ha: ["HA", "noHA"]
        disable-snat-multiple-gws: ["noSnatGW", "snatGW"]
        gateway-mode: ["local", "shared"]
        second-bridge: ["2br", "1br"]
        ipfamily: ["ipv4", "ipv6", "dualstack"]
        # Example of how to exclude a fully qualified test:
        # - {"ipfamily": "ipv4"}, "ha": "HA", "gateway-mode": "shared", "target": "control-plane"}
        exclude:
         # Not currently supported but needs to be.
         - {"ipfamily": "dualstack", "target": "control-plane"}
         # Limit matrix combinations for CI. DISABLED items added to exclude list:
         - {"ipfamily": "ipv4", "ha": "HA", "gateway-mode": "local"}
         - {"ipfamily": "ipv4", "ha": "noHA", "gateway-mode": "shared"}
         - {"ipfamily": "ipv6", "ha": "noHA", "gateway-mode": "local"}
         - {"ipfamily": "ipv6", "ha": "noHA", "gateway-mode": "shared"}
         - {"ipfamily": "dualstack", "ha": "HA", "gateway-mode": "shared"}
         - {"ipfamily": "dualstack", "ha": "noHA"}
         # IPv6 multicast is supported but tests fail due to old iperf version
         # in agnhost images. Disable them for now.
         - {"ipfamily": "dualstack", "target": "control-plane"}
         - {"ipfamily": "ipv6", "target": "control-plane"}
         # No need to run disable-snat-multiple-gws with local GW mode || shard conformance
         - {"disable-snat-multiple-gws": "noSnatGW", "gateway-mode": "local"}
         - {"disable-snat-multiple-gws": "noSnatGW", "target": "shard-conformance"}
         - {"second-bridge": "2br", "gateway-mode": "local"}
         - {"second-bridge": "2br", "disable-snat-multiple-gws": "snatGW"}
         - {"second-bridge": "2br", "ha": "HA"}
         - {"second-bridge": "2br", "target": "control-plane"}
    needs: [ build-pr ]
    env:
      JOB_NAME: "${{ matrix.target }}-${{ matrix.ha }}-${{ matrix.gateway-mode }}-${{ matrix.ipfamily }}-${{ matrix.disable-snat-multiple-gws }}-${{ matrix.second-bridge }}"
      OVN_HYBRID_OVERLAY_ENABLE: "${{ matrix.target == 'control-plane' }}"
      OVN_MULTICAST_ENABLE:  "${{ matrix.target == 'control-plane' }}"
      OVN_EMPTY_LB_EVENTS: "${{ matrix.target == 'control-plane' }}"
      OVN_HA: "${{ matrix.ha == 'HA' }}"
      OVN_DISABLE_SNAT_MULTIPLE_GWS: "${{ matrix.disable-snat-multiple-gws == 'noSnatGW' }}"
      OVN_GATEWAY_MODE: "${{ matrix.gateway-mode }}"
      OVN_SECOND_BRIDGE: "${{ matrix.second-bridge == '2br' }}"
      KIND_IPV4_SUPPORT: "${{ matrix.ipfamily == 'IPv4' || matrix.ipfamily == 'dualstack' }}"
      KIND_IPV6_SUPPORT: "${{ matrix.ipfamily == 'IPv6' || matrix.ipfamily == 'dualstack' }}"
    steps:

    - name: Free up disk space
      run: sudo eatmydata apt-get remove --auto-remove -y aspnetcore-* dotnet-* libmono-* mono-* msbuild php-* php7* ghc-* zulu-*

    - name: Set up Go
      uses: actions/setup-go@v2
      with:
        go-version: ${{ env.GO_VERSION }}
      id: go

    - name: Check out code into the Go module directory
      uses: actions/checkout@v2

    - name: Set up environment
      run: |
        export GOPATH=$(go env GOPATH)
        echo "GOPATH=$GOPATH" >> $GITHUB_ENV
        echo "$GOPATH/bin" >> $GITHUB_PATH
        if [ $OVN_SECOND_BRIDGE == "true" ]; then
          echo OVN_TEST_EX_GW_NETWORK=kindexgw >> $GITHUB_ENV
          echo OVN_ENABLE_EX_GW_NETWORK_BRIDGE=true >> $GITHUB_ENV
        fi
    - name: Disable ufw
      # For IPv6 and Dualstack, ufw (Uncomplicated Firewall) should be disabled.
      # Not needed for KIND deployments, so just disable all the time.
      run: |
        sudo ufw disable
    - uses: actions/download-artifact@v2
      with:
        name: test-image-pr

    - name: Load docker image
      run: |
        docker load --input image-pr.tar
    - name: kind setup
      timeout-minutes: 30
      run: |
        export OVN_IMAGE="ovn-daemonset-f:pr"
        make -C test install-kind
    - name: Run Tests
      # e2e tests take less than 30 minutes normally, 60 should be more than enough
      # set 2 1/2 hours for control-plane tests as these might take a while
      timeout-minutes: ${{ matrix.target == 'control-plane' && 150 || 60 }}
      run: |
        make -C test ${{ matrix.target }}
    - name: Upload Junit Reports
      if: always()
      uses: actions/upload-artifact@v2
      with:
        name: kind-junit-${{ env.JOB_NAME }}-${{ github.run_id }}
        path: './test/_artifacts/*.xml'

    - name: Export logs
      if: always()
      run: |
        mkdir -p /tmp/kind/logs
        kind export logs --name ${KIND_CLUSTER_NAME} --loglevel=debug /tmp/kind/logs
    - name: Upload logs
      if: always()
      uses: actions/upload-artifact@v2
      with:
        name: kind-logs-${{ env.JOB_NAME }}-${{ github.run_id }}
        path: /tmp/kind/logs

  e2e-dual-conversion:
    name: e2e-dual-conversion
    if: github.event_name != 'schedule'
    runs-on: ubuntu-latest
    timeout-minutes: 60
    strategy:
      fail-fast: false
      matrix:
        gateway-mode: [local, shared]
    needs: [ build-pr ]
    env:
      JOB_NAME: "DualStack-conversion-${{ matrix.gateway-mode }}"
      OVN_HA: "true"
      KIND_IPV4_SUPPORT: "true"
      KIND_IPV6_SUPPORT: "false"
      OVN_HYBRID_OVERLAY_ENABLE: "false"
      OVN_GATEWAY_MODE: "${{ matrix.gateway-mode }}"
      OVN_MULTICAST_ENABLE:  "false"
    steps:

    - name: Set up Go
      uses: actions/setup-go@v2
      with:
        go-version: ${{ env.GO_VERSION }}
      id: go

    - name: Check out code into the Go module directory
      uses: actions/checkout@v2

    - name: Set up environment
      run: |
        export GOPATH=$(go env GOPATH)
        echo "GOPATH=$GOPATH" >> $GITHUB_ENV
        echo "$GOPATH/bin" >> $GITHUB_PATH
    - name: Disable ufw
      # For IPv6 and Dualstack, ufw (Uncomplicated Firewall) should be disabled.
      # Not needed for KIND deployments, so just disable all the time.
      run: |
        sudo ufw disable
    - uses: actions/download-artifact@v2
      with:
        name: test-image-pr

    - name: Load docker image
      run: |
        docker load --input image-pr.tar
    - name: kind IPv4 setup
      run: |
        export OVN_IMAGE="ovn-daemonset-f:pr"
        make -C test install-kind
    - name: Run Single-Stack Tests
      run: |
        make -C test shard-test WHAT="Networking Granular Checks"
    - name: Convert IPv4 cluster to Dual Stack
      run: |
        ./contrib/kind-dual-stack-conversion.sh
    - name: Run Dual-Stack Tests
      run: |
        KIND_IPV4_SUPPORT="true"
        KIND_IPV6_SUPPORT="true"
        make -C test shard-test WHAT="Networking Granular Checks\|DualStack"
    - name: Upload Junit Reports
      if: always()
      uses: actions/upload-artifact@v2
      with:
        name: kind-junit-${{ env.JOB_NAME }}-${{ github.run_id }}
        path: './test/_artifacts/*.xml'

    - name: Export logs
      if: always()
      run: |
        mkdir -p /tmp/kind/logs
        kind export logs --name ${KIND_CLUSTER_NAME} --loglevel=debug /tmp/kind/logs
    - name: Upload logs
      if: always()
      uses: actions/upload-artifact@v2
      with:
        name: kind-logs-${{ env.JOB_NAME }}-${{ github.run_id }}
        path: /tmp/kind/logs

  e2e-periodic:
    name: e2e-periodic
    if: github.event_name == 'schedule'
    runs-on: ubuntu-latest
    timeout-minutes: 60
    strategy:
      fail-fast: false
      matrix:
        target: ["shard-conformance"]
        ha: ["HA"]
        gateway-mode: ["local"]
        ipfamily: ["ipv4", "ipv6", "dualstack"]
    needs: [ build-pr ]
    env:
      JOB_NAME: "${{ matrix.target }}-${{ matrix.ha }}-${{ matrix.gateway-mode }}-${{ matrix.ipfamily }}"
      OVN_HA: "${{ matrix.ha == 'HA' }}"
      KIND_IPV4_SUPPORT: "${{ matrix.ipfamily == 'IPv4' || matrix.ipfamily == 'dualstack' }}"
      KIND_IPV6_SUPPORT: "${{ matrix.ipfamily == 'IPv6' || matrix.ipfamily == 'dualstack' }}"
      OVN_HYBRID_OVERLAY_ENABLE: "${{ matrix.target == 'control-plane' }}"
      OVN_GATEWAY_MODE: "${{ matrix.gateway-mode }}"
    steps:

      - name: Free up disk space
        run: sudo eatmydata apt-get remove --auto-remove -y aspnetcore-* dotnet-* libmono-* mono-* msbuild php-* php7* ghc-* zulu-*

      - name: Set up Go
        uses: actions/setup-go@v2
        with:
          go-version: ${{ env.GO_VERSION }}
        id: go

      - name: Check out code into the Go module directory
        uses: actions/checkout@v2

      - name: Set up environment
        run: |
          export GOPATH=$(go env GOPATH)
          echo "GOPATH=$GOPATH" >> $GITHUB_ENV
          echo "$GOPATH/bin" >> $GITHUB_PATH
      - name: Disable ufw
        # For IPv6 and Dualstack, ufw (Uncomplicated Firewall) should be disabled.
        # Not needed for KIND deployments, so just disable all the time.
        run: |
          sudo ufw disable
      - uses: actions/download-artifact@v2
        with:
          name: test-image-pr
      - name: Load docker image
        run: |
          docker load --input image-pr.tar
      - name: kind setup
        run: |
          export OVN_IMAGE="ovn-daemonset-f:pr"
          make -C test install-kind
      - name: Run Tests
        run: |
          make -C test ${{ matrix.target }}
      - name: Upload Junit Reports
        if: always()
        uses: actions/upload-artifact@v2
        with:
          name: kind-junit-${{ env.JOB_NAME }}-${{ github.run_id }}
          path: './test/_artifacts/*.xml'

      - name: Export logs
        if: always()
        run: |
          mkdir -p /tmp/kind/logs
          kind export logs --name ${KIND_CLUSTER_NAME} --loglevel=debug /tmp/kind/logs
      - name: Upload logs
        if: always()
        uses: actions/upload-artifact@v2
        with:
          name: kind-logs-${{ env.JOB_NAME }}-${{ github.run_id }}
          path: /tmp/kind/logs
