- hosts: all
  tasks:
    # Borrowed from devstack tasks but we want it early.
    - name: Ensure {{ ansible_user_dir }}/logs exists
      become: true
      file:
        path: "{{ ansible_user_dir }}/logs"
        state: directory
        owner: "{{ ansible_user }}"
    - name: start placement
      args:
        chdir: "{{ ansible_user_dir }}/src/opendev.org/openstack/placement"
      shell:
        executable: /bin/bash
        cmd: |
          set -x
          # TODO(cdent): Presumably ansible can do this, perhaps with 'package'.
          # create database
          sudo debconf-set-selections <<MYSQL_PRESEED
          mysql-server mysql-server/root_password password secret
          mysql-server mysql-server/root_password_again password secret
          mysql-server mysql-server/start_on_boot boolean true
          MYSQL_PRESEED
          sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev jq
          sudo mysql -uroot -psecret -e "DROP DATABASE IF EXISTS placement;"
          sudo mysql -uroot -psecret -e "CREATE DATABASE placement CHARACTER SET utf8;"
          sudo mysql -uroot -psecret -e "GRANT ALL PRIVILEGES ON placement.* TO 'root'@'%' identified by 'secret';"
          python -m virtualenv -p python3 .placement
          . .placement/bin/activate
          pip install . PyMySQL uwsgi
          # set config via environment
          export OS_PLACEMENT_DATABASE__CONNECTION=mysql+pymysql://root:secret@127.0.0.1/placement?charset=utf8
          export OS_PLACEMENT_DATABASE__MAX_POOL_SIZE=25
          export OS_PLACEMENT_DATABASE__MAX_OVERFLOW=100
          export OS_PLACEMENT_DATABASE__SYNC_ON_STARTUP=True
          # Increase our chances of allocating to different providers.
          export OS_PLACEMENT_PLACEMENT__RANDOMIZE_ALLOCATION_CANDIDATES=True
          export OS_DEFAULT__DEBUG=True
          export OS_API__AUTH_STRATEGY=noauth2
          uwsgi --http :8000 --wsgi-file .placement/bin/placement-api --daemonize {{ ansible_user_dir }}/logs/placement-api.log --processes 5 --threads 25
    - name: placement performance
      args:
        chdir: "{{ ansible_user_dir }}/src/opendev.org/openstack/placement"
      shell:
        executable: /bin/bash
        # TODO(cdent): Change this task to a role?
        cmd: |
          set -x
          # Do some performance related information gathering for placement.
          EXPLANATION="
          This output combines output from placeload with timing information
          gathered via curl. The placeload output is the current maximum
          microversion of placement followed by an encoded representation of
          what it has done. Lowercase 'r', 'i', 'a', and 't' indicate successful
          creation of a resource provider and setting inventory, aggregates, and
          traits on that resource provider.

          If there are upper case versions of any of those letters, a failure
          happened for a single request. The letter will be followed by the
          HTTP status code and the resource provider uuid. These can be used
          to find the relevant entry in logs/screen-placement-api.txt.gz.

          Note that placeload does not exit with an error code when this
          happens. It merely reports and moves on. Under correct circumstances
          the right output is a long string of 4000 characters containing
          'r', 'i', 'a', 't' in random order (because async).

          After that are three aggregate uuids, timing information for the
          placeload run, and then timing information for two identical curl
          requests for allocation candidates.

          If no timed requests are present it means that the expected number
          of resource providers were not created. At this time, only resource
          providers are counted, not whether they have the correct inventory,
          aggregates, or traits.

          "

          # This aggregate uuid is a static value in placeload.
          AGGREGATE="14a5c8a3-5a99-4e8f-88be-00d85fcb1c17"
          TRAIT="HW_CPU_X86_AVX2"
          PLACEMENT_QUERY="resources=VCPU:1,DISK_GB:10,MEMORY_MB:256&member_of=${AGGREGATE}&required=${TRAIT}"
          PLACEMENT_URL="http://localhost:8000"


          LOG=placement-perf.txt
          LOG_DEST={{ ansible_user_dir }}/logs
          COUNT=1000

          trap "sudo cp -p $LOG $LOG_DEST" EXIT

          function time_candidates {
              (
                  echo "##### TIMING GET /allocation_candidates?${PLACEMENT_QUERY} twice"
                  time curl -s -H 'x-auth-token: admin' -H 'openstack-api-version: placement latest' "${PLACEMENT_URL}/allocation_candidates?${PLACEMENT_QUERY}" > /dev/null
                  time curl -s -H 'x-auth-token: admin' -H 'openstack-api-version: placement latest' "${PLACEMENT_URL}/allocation_candidates?${PLACEMENT_QUERY}" > /dev/null
              ) 2>&1 | tee -a $LOG
          }

          function write_allocation {
              # Take the first allocation request and send it back as a well-formed allocation
              curl -s -H 'x-auth-token: admin' -H 'openstack-api-version: placement latest' "${PLACEMENT_URL}/allocation_candidates?${PLACEMENT_QUERY}&limit=5" \
                  | jq --arg proj $(uuidgen) --arg user $(uuidgen) '.allocation_requests[0] + {consumer_generation: null, project_id: $proj, user_id: $user}' \
                  | curl -s -H 'x-auth-token: admin' -H 'content-type: application/json' -H 'openstack-api-version: placement latest' \
                      -X PUT -d @- "${PLACEMENT_URL}/allocations/$(uuidgen)"
          }

          function load_candidates {
              time_candidates
              for iter in {1..99}; do
                echo "##### Writing allocation ${iter}" | tee -a $LOG
                write_allocation
                time_candidates
              done
          }

          function check_placement {
              local rp_count
              local code
              code=0

              python -m virtualenv -p python3 .placeload
              . .placeload/bin/activate

              # install placeload
              pip install 'placeload==0.3.0'

              set +x
              # load with placeload
              (
                  echo "$EXPLANATION"
                  # preheat the aggregates to avoid https://bugs.launchpad.net/nova/+bug/1804453
                  placeload $PLACEMENT_URL 10
                  echo "##### TIMING placeload creating $COUNT resource providers with inventory, aggregates and traits."
                  time placeload $PLACEMENT_URL $COUNT
              ) 2>&1 | tee -a $LOG
              rp_count=$(curl -H 'x-auth-token: admin' ${PLACEMENT_URL}/resource_providers |json_pp|grep -c '"name"')
              # Skip curl and note if we failed to create the required number of rps
              if [[ $rp_count -ge $COUNT ]]; then
                load_candidates
              else
                  (
                      echo "Unable to create expected number of resource providers. Expected: ${COUNT}, Got: $rp_count"
                      echo "See job-output.txt.gz and logs/screen-placement-api.txt.gz for additional detail."
                  ) | tee -a $LOG
                  code=1
              fi
              set -x
              deactivate
              exit $code
          }

          check_placement