support executing the farm with obfarm
This commit is contained in:
		
							
								
								
									
										9
									
								
								.github/obfarm/Dockerfile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.github/obfarm/Dockerfile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
# Container image that runs your code
 | 
			
		||||
FROM python:3.6
 | 
			
		||||
 | 
			
		||||
RUN pip3 install requests -i https://mirrors.aliyun.com/pypi/simple/
 | 
			
		||||
# Copies your code file from your action repository to the filesystem path `/` of the container
 | 
			
		||||
COPY obfarm.py /obfarm.py
 | 
			
		||||
 | 
			
		||||
# Code file to execute when the docker container starts up (`entrypoint.sh`)
 | 
			
		||||
ENTRYPOINT ["python3", "-u", "/obfarm.py"]
 | 
			
		||||
							
								
								
									
										26
									
								
								.github/obfarm/action.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								.github/obfarm/action.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
# action.yml
 | 
			
		||||
name: 'call OB Farm to run task'
 | 
			
		||||
description: ''
 | 
			
		||||
inputs:
 | 
			
		||||
  pipeline_id:
 | 
			
		||||
    description: 'pipeline_id'
 | 
			
		||||
    required: true
 | 
			
		||||
  project:
 | 
			
		||||
    description: 'project'
 | 
			
		||||
    required: true
 | 
			
		||||
  timeout:
 | 
			
		||||
    description: 'timeout'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: '3600'
 | 
			
		||||
outputs:
 | 
			
		||||
  success:
 | 
			
		||||
    description: 'the status for the task'
 | 
			
		||||
runs:
 | 
			
		||||
  using: 'docker'
 | 
			
		||||
  image: 'Dockerfile'
 | 
			
		||||
  args:
 | 
			
		||||
    - ${{ inputs.pipeline_id }}
 | 
			
		||||
    - ${{ inputs.project }}
 | 
			
		||||
    - ${{ inputs.timeout }}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										188
									
								
								.github/obfarm/obfarm.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								.github/obfarm/obfarm.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,188 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
import copy
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import traceback
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import requests
 | 
			
		||||
from enum import Enum
 | 
			
		||||
from http import HTTPStatus
 | 
			
		||||
 | 
			
		||||
OUTPUT = {}
 | 
			
		||||
RESULT_FILE_KEY = "farm/ob_results/"
 | 
			
		||||
TASK_QUEUE_FILE_KEY = "farm/ob_jobs/{}.json"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _range(start, last):
 | 
			
		||||
    def to_str(pos):
 | 
			
		||||
        if pos is None:
 | 
			
		||||
            return ''
 | 
			
		||||
        else:
 | 
			
		||||
            return str(pos)
 | 
			
		||||
 | 
			
		||||
    return to_str(start) + '-' + to_str(last)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _make_range_string(range):
 | 
			
		||||
    if range is None:
 | 
			
		||||
        return ''
 | 
			
		||||
 | 
			
		||||
    start = range[0]
 | 
			
		||||
    last = range[1]
 | 
			
		||||
 | 
			
		||||
    if start is None and last is None:
 | 
			
		||||
        return ''
 | 
			
		||||
 | 
			
		||||
    return 'bytes=' + _range(start, last)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OssProxy:
 | 
			
		||||
 | 
			
		||||
    def __init__(self, endpoint=""):
 | 
			
		||||
        self.endpoint = endpoint
 | 
			
		||||
 | 
			
		||||
    def get_object(self, key, _range=None):
 | 
			
		||||
        url = "{}/{}".format(self.endpoint, key)
 | 
			
		||||
        headers = {}
 | 
			
		||||
        if _range is not None:
 | 
			
		||||
            _range = (_range, None)
 | 
			
		||||
            headers.update({"range": _make_range_string(_range)})
 | 
			
		||||
        res = requests.get(url, headers=headers)
 | 
			
		||||
        if res.status_code < 400:
 | 
			
		||||
            result = res.content.decode()
 | 
			
		||||
            return result
 | 
			
		||||
        return ""
 | 
			
		||||
 | 
			
		||||
    def get_object_meta(self, key):
 | 
			
		||||
        url = "{}/{}".format(self.endpoint, key)
 | 
			
		||||
        headers = {}
 | 
			
		||||
        res = requests.head(url, headers=headers)
 | 
			
		||||
        return res.headers
 | 
			
		||||
 | 
			
		||||
    def exists_object(self, key):
 | 
			
		||||
        ...
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GithubProxy:
 | 
			
		||||
 | 
			
		||||
    def __init__(self, host="api.github.com"):
 | 
			
		||||
        self.host = host
 | 
			
		||||
 | 
			
		||||
    def get_job_by_id(self, project, pipeline_id):
 | 
			
		||||
        url = "https://{}/repos/{}/actions/runs/{}".format(
 | 
			
		||||
            self.host, project, pipeline_id
 | 
			
		||||
        )
 | 
			
		||||
        try:
 | 
			
		||||
            res = requests.get(
 | 
			
		||||
                url, headers={
 | 
			
		||||
                    "Accept": "application/vnd.github+json"
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
            status_code = res.status_code
 | 
			
		||||
            if status_code == HTTPStatus.NOT_FOUND:
 | 
			
		||||
                return {}
 | 
			
		||||
            return res.json()
 | 
			
		||||
        except:
 | 
			
		||||
            traceback.print_exc()
 | 
			
		||||
            return {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TaskStatusEnum(Enum):
 | 
			
		||||
    submitting = 0
 | 
			
		||||
    pending = 1
 | 
			
		||||
    running = 2
 | 
			
		||||
    stopping = 3
 | 
			
		||||
    success = 4
 | 
			
		||||
    fail = -1
 | 
			
		||||
    kill = -2
 | 
			
		||||
    timeout = -3
 | 
			
		||||
    submit_task_fail = -4
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def request(method, url, params=None, payload=None, timeout=10, data=None, without_check_status=False):
 | 
			
		||||
    params = params or {}
 | 
			
		||||
    try:
 | 
			
		||||
        response = requests.request(
 | 
			
		||||
            method,
 | 
			
		||||
            url,
 | 
			
		||||
            params=params,
 | 
			
		||||
            json=payload,
 | 
			
		||||
            data=data,
 | 
			
		||||
            timeout=timeout
 | 
			
		||||
        )
 | 
			
		||||
        if not without_check_status and response.status_code >= 300:
 | 
			
		||||
            try:
 | 
			
		||||
                msg = response.json()["msg"]
 | 
			
		||||
            except:
 | 
			
		||||
                msg = response.text
 | 
			
		||||
            print("[ERROR] MSG:{}".format(msg))
 | 
			
		||||
            exit(1)
 | 
			
		||||
        return response
 | 
			
		||||
    except Exception:
 | 
			
		||||
        import traceback
 | 
			
		||||
        traceback.print_exc()
 | 
			
		||||
        print("Please contact the management personnel for assistance !")
 | 
			
		||||
        if not without_check_status:
 | 
			
		||||
            exit(1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def monitor_tasks(oss_proxy: OssProxy, github_pipeline_id, timeout):
 | 
			
		||||
    end_time = time.time() + int(timeout)
 | 
			
		||||
    end_task = False
 | 
			
		||||
    while time.time() <= end_time:
 | 
			
		||||
        if end_task is True:
 | 
			
		||||
            pass
 | 
			
		||||
        task_data = get_task_res(oss_proxy, github_pipeline_id)
 | 
			
		||||
        if task_data:
 | 
			
		||||
            end_task = True
 | 
			
		||||
 | 
			
		||||
        time.sleep(1)
 | 
			
		||||
        if task_data is not None:
 | 
			
		||||
            task_status = int(task_data["status"])
 | 
			
		||||
            if task_status <= TaskStatusEnum.fail.value:
 | 
			
		||||
                print(TaskStatusEnum._value2member_map_[task_status])
 | 
			
		||||
                print("there is the output url: {}".format(
 | 
			
		||||
                    "https://ce-farm.oceanbase-dev.com/farm2/ci/?id={}".format(task_data["task_id"])))
 | 
			
		||||
                return False
 | 
			
		||||
            elif task_status >= TaskStatusEnum.success.value:
 | 
			
		||||
                print(TaskStatusEnum._value2member_map_[task_status])
 | 
			
		||||
                print("there is the output url: {}".format(
 | 
			
		||||
                    "https://ce-farm.oceanbase-dev.com/farm2/ci/?id={}".format(task_data["task_id"])))
 | 
			
		||||
                return True
 | 
			
		||||
 | 
			
		||||
        time.sleep(5)
 | 
			
		||||
    else:
 | 
			
		||||
        ...
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_task_res(oss_proxy: OssProxy, github_pipeline_id):
 | 
			
		||||
    try:
 | 
			
		||||
        result_key = RESULT_FILE_KEY + "{}.json".format(github_pipeline_id)
 | 
			
		||||
        origin_task_data = oss_proxy.get_object(result_key)
 | 
			
		||||
        return json.loads(origin_task_data)
 | 
			
		||||
    except:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main(pipeline_id, project, timeout):
 | 
			
		||||
    print("create a new task")
 | 
			
		||||
    print("working....")
 | 
			
		||||
    oss_proxy = OssProxy("https://obfarm-ce.oss-cn-hongkong.aliyuncs.com")
 | 
			
		||||
    github_proxy = GithubProxy()
 | 
			
		||||
    job_info = github_proxy.get_job_by_id(project, pipeline_id)
 | 
			
		||||
    attempt_number = job_info["run_attempt"]
 | 
			
		||||
    run_pipeline_id = "{}-{}".format(pipeline_id, attempt_number)
 | 
			
		||||
    result = monitor_tasks(oss_proxy, run_pipeline_id, timeout)
 | 
			
		||||
    if not result:
 | 
			
		||||
        exit(1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    print(sys.argv)
 | 
			
		||||
    if len(sys.argv) < 4:
 | 
			
		||||
        print("Missing relevant parameters !")
 | 
			
		||||
        OUTPUT.update({"success": -1})
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    main(sys.argv[1], sys.argv[2], sys.argv[3])
 | 
			
		||||
							
								
								
									
										20
									
								
								.github/workflows/farm.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.github/workflows/farm.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
name: Farm
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches: [ master,develop ]
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  farm:
 | 
			
		||||
    name: Farm
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout workspace
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
      - name: action by obfarm
 | 
			
		||||
        uses: ./.github/obfarm/
 | 
			
		||||
        id: farm
 | 
			
		||||
        with:
 | 
			
		||||
          pipeline_id: ${{ github.run_id }}
 | 
			
		||||
          project: ${{ github.repository }}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user