mirror of
https://github.com/actions/runner.git
synced 2025-12-10 04:06:57 +00:00
Compare commits
33 Commits
v2.289.0
...
users/tihu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c645de9aee | ||
|
|
0e4f76ec4e | ||
|
|
af18df4621 | ||
|
|
5215d95637 | ||
|
|
e750eb7e38 | ||
|
|
ca1f621077 | ||
|
|
80d0b58f3c | ||
|
|
11ff2be7e9 | ||
|
|
3ce763338d | ||
|
|
a45c0278e6 | ||
|
|
658d36c1bc | ||
|
|
ca3b803237 | ||
|
|
4fa691f73e | ||
|
|
dfcfae49e5 | ||
|
|
1235dc1cea | ||
|
|
cc0d0bed90 | ||
|
|
0fac863568 | ||
|
|
42e7359f5c | ||
|
|
5639175ecb | ||
|
|
7128998d77 | ||
|
|
f37e9f80a6 | ||
|
|
0fa08423d2 | ||
|
|
029106a1dc | ||
|
|
493a2a0bf7 | ||
|
|
43f983486e | ||
|
|
f6053b616c | ||
|
|
4f4608b710 | ||
|
|
28686c40d2 | ||
|
|
ce1679bb6f | ||
|
|
0a7611b0b5 | ||
|
|
b3fee33a92 | ||
|
|
d83ef5549e | ||
|
|
fe6719d120 |
74
job.yml
Normal file
74
job.yml
Normal file
@@ -0,0 +1,74 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: pod-admin
|
||||
namespace: default
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "pods/log", "pods/attach", "pods/exec"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: default-pod-admin
|
||||
namespace: default
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: pod-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
namespace: default
|
||||
name: actions-runners
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
# hostNetwork: true
|
||||
volumes:
|
||||
- name: runner-working
|
||||
emptyDir: {}
|
||||
containers:
|
||||
- name: k8srunner
|
||||
image: huangtingluo/kube-runner:v0
|
||||
imagePullPolicy: Always
|
||||
volumeMounts:
|
||||
- mountPath: /actions-runner/_work
|
||||
name: runner-working
|
||||
env:
|
||||
- name: GITHUB_PAT
|
||||
value: ghp_
|
||||
- name: RUNNER_CONFIG_URL
|
||||
value: https://github.com/bbq-beets/ting-test
|
||||
- name: K8S_NODE_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: spec.nodeName
|
||||
- name: K8S_POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: K8S_POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: K8S_POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
- name: K8S_POD_SERVICE_ACCOUNT
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: spec.serviceAccountName
|
||||
restartPolicy: Never
|
||||
backoffLimit: 1
|
||||
completions: 1
|
||||
parallelism: 1
|
||||
78
src/Dockerfile
Normal file
78
src/Dockerfile
Normal file
@@ -0,0 +1,78 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:3.1 AS Build
|
||||
|
||||
# ENV RUNNER_CONFIG_URL=""
|
||||
# ENV GITHUB_PAT=""
|
||||
# ENV RUNNER_NAME=""
|
||||
# ENV RUNNER_GROUP=""
|
||||
# ENV RUNNER_LABELS=""
|
||||
# ENV GITHUB_RUNNER_SCOPE=""
|
||||
# ENV GITHUB_SERVER_URL=""
|
||||
# ENV GITHUB_API_URL=""
|
||||
# ENV K8S_HOST_IP=""
|
||||
|
||||
RUN apt-get update --fix-missing \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
# jq \
|
||||
# git \
|
||||
apt-utils \
|
||||
apt-transport-https \
|
||||
unzip \
|
||||
net-tools\
|
||||
gnupg2\
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install kubectl
|
||||
# RUN curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
|
||||
# echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list && \
|
||||
# apt-get update && apt-get -y install --no-install-recommends kubectl
|
||||
|
||||
# Install docker
|
||||
# RUN curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
# RUN sh get-docker.sh
|
||||
|
||||
# Allow runner to run as root
|
||||
# ENV RUNNER_ALLOW_RUNASROOT=1
|
||||
|
||||
# Directory for runner to operate in
|
||||
RUN mkdir /actions-runner
|
||||
RUN mkdir /actions-runner/src
|
||||
WORKDIR /actions-runner/src
|
||||
|
||||
COPY ./ /actions-runner/src
|
||||
|
||||
RUN /actions-runner/src/dev.sh l
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1
|
||||
|
||||
ENV RUNNER_CONFIG_URL=""
|
||||
ENV GITHUB_PAT=""
|
||||
|
||||
RUN apt-get update --fix-missing \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
# jq \
|
||||
# git \
|
||||
# apt-utils \
|
||||
# apt-transport-https \
|
||||
# unzip \
|
||||
# net-tools\
|
||||
gnupg2\
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install kubectl
|
||||
RUN curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
|
||||
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list && \
|
||||
apt-get update && apt-get -y install --no-install-recommends kubectl
|
||||
|
||||
|
||||
# Allow runner to run as root
|
||||
ENV RUNNER_ALLOW_RUNASROOT=1
|
||||
|
||||
# Directory for runner to operate in
|
||||
RUN mkdir /actions-runner
|
||||
WORKDIR /actions-runner
|
||||
COPY --from=Build /actions-runner/_layout /actions-runner
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"plugins": ["jest", "@typescript-eslint"],
|
||||
"extends": ["plugin:github/es6"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"eslint-comments/no-use": "off",
|
||||
"import/no-namespace": "off",
|
||||
"no-console": "off",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/ban-ts-ignore": "error",
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/camelcase": "error",
|
||||
"@typescript-eslint/class-name-casing": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
|
||||
"@typescript-eslint/no-array-constructor": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-inferrable-types": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-object-literal-type-assertion": "error",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
"@typescript-eslint/no-var-requires": "error",
|
||||
"@typescript-eslint/prefer-for-of": "warn",
|
||||
"@typescript-eslint/prefer-function-type": "warn",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-interface": "error",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async": "error",
|
||||
"@typescript-eslint/require-array-sort-compare": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "error",
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error", "never"],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest/globals": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
To update kubeInnerHandler under `Misc/layoutbin` run `npm install && npm run all`
|
||||
6034
src/Misc/containerEngineHandlers/kubeInnerHandler/package-lock.json
generated
Normal file
6034
src/Misc/containerEngineHandlers/kubeInnerHandler/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "kubeInnerHandler",
|
||||
"version": "1.0.0",
|
||||
"description": "GitHub Actions",
|
||||
"main": "lib/kubeInnerHandler.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"pack": "ncc build -o ../../layoutbin/kubeInnerHandler",
|
||||
"all": "npm run build && npm run format && npm run lint && npm run pack"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/runner.git"
|
||||
},
|
||||
"keywords": [
|
||||
"actions"
|
||||
],
|
||||
"author": "GitHub Actions",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/exec": "^1.1.0",
|
||||
"@actions/core": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.7.12",
|
||||
"@typescript-eslint/parser": "^2.8.0",
|
||||
"@zeit/ncc": "^0.20.5",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-github": "^2.0.0",
|
||||
"prettier": "^1.19.1",
|
||||
"typescript": "^3.6.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import * as exec from '@actions/exec'
|
||||
import * as core from '@actions/core'
|
||||
import * as events from 'events'
|
||||
import * as readline from 'readline'
|
||||
|
||||
async function run(): Promise<void> {
|
||||
let input = ''
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin
|
||||
})
|
||||
|
||||
rl.on('line', line => {
|
||||
core.debug(`Line from STDIN: ${line}`)
|
||||
input = line
|
||||
})
|
||||
|
||||
await events.once(rl, 'close')
|
||||
|
||||
core.debug(input)
|
||||
|
||||
const execInput = JSON.parse(input)
|
||||
core.debug(JSON.stringify(execInput))
|
||||
|
||||
// podman exec -i --workdir /__w/canary/canary
|
||||
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
|
||||
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
|
||||
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
|
||||
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
|
||||
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
|
||||
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
|
||||
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
|
||||
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
|
||||
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
|
||||
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
|
||||
|
||||
const execArgs = []
|
||||
const args = (<string>execInput.arguments).split(' ')
|
||||
core.debug(JSON.stringify(args))
|
||||
execArgs.push(...args)
|
||||
|
||||
core.debug(JSON.stringify(execArgs))
|
||||
|
||||
await exec.exec(execInput.fileName, execArgs, {
|
||||
env: execInput.environmentVariables
|
||||
})
|
||||
}
|
||||
|
||||
run()
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
||||
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"plugins": ["jest", "@typescript-eslint"],
|
||||
"extends": ["plugin:github/es6"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"eslint-comments/no-use": "off",
|
||||
"import/no-namespace": "off",
|
||||
"no-console": "off",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/ban-ts-ignore": "error",
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/camelcase": "error",
|
||||
"@typescript-eslint/class-name-casing": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
|
||||
"@typescript-eslint/no-array-constructor": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-inferrable-types": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-object-literal-type-assertion": "error",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
"@typescript-eslint/no-var-requires": "error",
|
||||
"@typescript-eslint/prefer-for-of": "warn",
|
||||
"@typescript-eslint/prefer-function-type": "warn",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-interface": "error",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async": "error",
|
||||
"@typescript-eslint/require-array-sort-compare": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "error",
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error", "never"],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest/globals": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
To update kubectlHandler under `Misc/layoutbin` run `npm install && npm run all`
|
||||
6034
src/Misc/containerEngineHandlers/kubectlHandler/package-lock.json
generated
Normal file
6034
src/Misc/containerEngineHandlers/kubectlHandler/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
36
src/Misc/containerEngineHandlers/kubectlHandler/package.json
Normal file
36
src/Misc/containerEngineHandlers/kubectlHandler/package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "kubectlHandler",
|
||||
"version": "1.0.0",
|
||||
"description": "GitHub Actions",
|
||||
"main": "lib/kubectlHandler.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"pack": "ncc build -o ../../layoutbin/kubectlHandler",
|
||||
"all": "npm run build && npm run format && npm run lint && npm run pack"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/runner.git"
|
||||
},
|
||||
"keywords": [
|
||||
"actions"
|
||||
],
|
||||
"author": "GitHub Actions",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/exec": "^1.1.0",
|
||||
"@actions/core": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.7.12",
|
||||
"@typescript-eslint/parser": "^2.8.0",
|
||||
"@zeit/ncc": "^0.20.5",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-github": "^2.0.0",
|
||||
"prettier": "^1.19.1",
|
||||
"typescript": "^3.6.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
import * as exec from '@actions/exec'
|
||||
import * as core from '@actions/core'
|
||||
import * as events from 'events'
|
||||
import * as readline from 'readline'
|
||||
|
||||
async function run(): Promise<void> {
|
||||
let input = ''
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin
|
||||
})
|
||||
|
||||
rl.on('line', line => {
|
||||
core.debug(`Line from STDIN: ${line}`)
|
||||
input = line
|
||||
})
|
||||
|
||||
await events.once(rl, 'close')
|
||||
|
||||
core.debug(input)
|
||||
|
||||
const inputJson = JSON.parse(input)
|
||||
core.debug(JSON.stringify(inputJson))
|
||||
|
||||
const command = inputJson.command
|
||||
if (command === 'Create') {
|
||||
const creationInput = inputJson.creationInput
|
||||
core.debug(JSON.stringify(creationInput))
|
||||
const containers = creationInput.containers
|
||||
const jobContainer = containers[0]
|
||||
|
||||
// const networkName = 'actions_podman_network'
|
||||
// // podman network create {network} -> track and return `network` for ${{job.container.network}}
|
||||
// await exec.exec('podman', ['network', 'create', networkName])
|
||||
|
||||
const containerImage = `${jobContainer.containerImage}`
|
||||
// podman pull docker.io/library/{image}
|
||||
// await exec.exec('podman', ['pull', containerImage])
|
||||
|
||||
// kubectl run e088c842be1f46b394212618408aaba0_node1016jessie_6196c9
|
||||
// --image=node:10.16-jessie
|
||||
// -- tail -f /dev/null
|
||||
const runArgs = ['run', 'job-container']
|
||||
// runArgs.push(`--workdir=${jobContainer.containerWorkDirectory}`)
|
||||
// runArgs.push(`--network=${networkName}`)
|
||||
|
||||
// for (const mountVolume of jobContainer.mountVolumes) {
|
||||
// runArgs.push(
|
||||
// `-v=${mountVolume.sourceVolumePath}:${mountVolume.targetVolumePath}`
|
||||
// )
|
||||
// }
|
||||
runArgs.push(`--image=${containerImage}`)
|
||||
runArgs.push(`--`)
|
||||
runArgs.push(`tail`)
|
||||
runArgs.push(`-f`)
|
||||
runArgs.push(`/dev/null`)
|
||||
|
||||
core.debug(JSON.stringify(runArgs))
|
||||
|
||||
// const containerId = await exec.getExecOutput('podman', [
|
||||
// 'create',
|
||||
// // `--workdir ${jobContainer.containerWorkDirectory}`,
|
||||
// `--network=${networkName}`,
|
||||
// // `-v=/Users/ting/Desktop/runner/_layout/_work:/__w`,
|
||||
// `--entrypoint=${jobContainer.containerEntryPoint}`,
|
||||
// `${containerImage}`,
|
||||
// `${jobContainer.containerEntryPointArgs}`
|
||||
// ])
|
||||
|
||||
await exec.exec('kubectl', runArgs)
|
||||
|
||||
// get PATH inside the container
|
||||
|
||||
const waitArgs = ['wait', '--for=condition=Ready', 'pod/job-container']
|
||||
await exec.exec('kubectl', waitArgs)
|
||||
|
||||
// output containerId for ${{job.container.id}}
|
||||
|
||||
// copy over node.js
|
||||
const cpNodeArgs = [
|
||||
'cp',
|
||||
'/actions-runner/externals/node12/bin',
|
||||
'job-container:/__runner_util/'
|
||||
]
|
||||
await exec.exec('kubectl', cpNodeArgs)
|
||||
|
||||
// copy over innerhandler
|
||||
const cpKubeInnerArgs = [
|
||||
'cp',
|
||||
'/actions-runner/bin/kubeInnerHandler',
|
||||
'job-container:/__runner_util/kubeInnerHandler'
|
||||
]
|
||||
await exec.exec('kubectl', cpKubeInnerArgs)
|
||||
|
||||
// copy over _work
|
||||
const cpWorkArgs = ['cp', '/actions-runner/_work', 'job-container:/__w/']
|
||||
await exec.exec('kubectl', cpWorkArgs)
|
||||
|
||||
const creationOutput = {
|
||||
JobContainerId: 'job-container',
|
||||
Network: 'job-container'
|
||||
}
|
||||
|
||||
const output = JSON.stringify({CreationOutput: creationOutput})
|
||||
core.debug(output)
|
||||
|
||||
process.stderr.write(
|
||||
`___CONTAINER_ENGINE_HANDLER_OUTPUT___${output}___CONTAINER_ENGINE_HANDLER_OUTPUT___`
|
||||
)
|
||||
} else if (command === 'Remove') {
|
||||
const removeInput = inputJson.removeInput
|
||||
core.debug(JSON.stringify(removeInput))
|
||||
// const jobContainerId = removeInput.jobContainerId
|
||||
|
||||
// await exec.exec('kubectl', ['delete', 'pod', jobContainerId, '--force'])
|
||||
// await exec.exec('podman', ['network', 'rm', '-f', network])
|
||||
} else if (command === 'Exec') {
|
||||
const execInput = inputJson.execInput
|
||||
core.debug(JSON.stringify(execInput))
|
||||
|
||||
// podman exec -i --workdir /__w/canary/canary
|
||||
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
|
||||
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
|
||||
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
|
||||
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
|
||||
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
|
||||
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
|
||||
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
|
||||
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
|
||||
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
|
||||
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
|
||||
|
||||
const cpTempArgs = [
|
||||
'cp',
|
||||
'/actions-runner/_work/_temp',
|
||||
'job-container:/__w/'
|
||||
]
|
||||
await exec.exec('kubectl', cpTempArgs)
|
||||
|
||||
const execArgs = ['exec']
|
||||
execArgs.push(execInput.jobContainer.containerId)
|
||||
execArgs.push('-i')
|
||||
execArgs.push('-t')
|
||||
execArgs.push('--')
|
||||
execArgs.push('/__runner_util/node')
|
||||
execArgs.push('/__runner_util/kubeInnerHandler')
|
||||
|
||||
core.debug(JSON.stringify(execArgs))
|
||||
|
||||
await exec.exec('kubectl', execArgs, {
|
||||
input: Buffer.from(JSON.stringify(execInput))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
||||
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"plugins": ["jest", "@typescript-eslint"],
|
||||
"extends": ["plugin:github/es6"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"eslint-comments/no-use": "off",
|
||||
"import/no-namespace": "off",
|
||||
"no-console": "off",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/ban-ts-ignore": "error",
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/camelcase": "error",
|
||||
"@typescript-eslint/class-name-casing": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
|
||||
"@typescript-eslint/no-array-constructor": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-inferrable-types": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-object-literal-type-assertion": "error",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
"@typescript-eslint/no-var-requires": "error",
|
||||
"@typescript-eslint/prefer-for-of": "warn",
|
||||
"@typescript-eslint/prefer-function-type": "warn",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-interface": "error",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async": "error",
|
||||
"@typescript-eslint/require-array-sort-compare": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "error",
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error", "never"],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest/globals": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript"
|
||||
}
|
||||
1
src/Misc/containerEngineHandlers/podmanHandler/README.md
Normal file
1
src/Misc/containerEngineHandlers/podmanHandler/README.md
Normal file
@@ -0,0 +1 @@
|
||||
To update podmanHandler under `Misc/layoutbin` run `npm install && npm run all`
|
||||
6034
src/Misc/containerEngineHandlers/podmanHandler/package-lock.json
generated
Normal file
6034
src/Misc/containerEngineHandlers/podmanHandler/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
36
src/Misc/containerEngineHandlers/podmanHandler/package.json
Normal file
36
src/Misc/containerEngineHandlers/podmanHandler/package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "podmanHandler",
|
||||
"version": "1.0.0",
|
||||
"description": "GitHub Actions",
|
||||
"main": "lib/podmanHandler.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"pack": "ncc build -o ../../layoutbin/podmanHandler",
|
||||
"all": "npm run build && npm run format && npm run lint && npm run pack"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/runner.git"
|
||||
},
|
||||
"keywords": [
|
||||
"actions"
|
||||
],
|
||||
"author": "GitHub Actions",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/exec": "^1.1.0",
|
||||
"@actions/core": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.7.12",
|
||||
"@typescript-eslint/parser": "^2.8.0",
|
||||
"@zeit/ncc": "^0.20.5",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-github": "^2.0.0",
|
||||
"prettier": "^1.19.1",
|
||||
"typescript": "^3.6.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
import * as exec from '@actions/exec'
|
||||
import * as core from '@actions/core'
|
||||
import * as events from 'events'
|
||||
import * as readline from 'readline'
|
||||
|
||||
async function run(): Promise<void> {
|
||||
let input = ''
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin
|
||||
})
|
||||
|
||||
rl.on('line', line => {
|
||||
core.debug(`Line from STDIN: ${line}`)
|
||||
input = line
|
||||
})
|
||||
|
||||
await events.once(rl, 'close')
|
||||
|
||||
core.debug(input)
|
||||
|
||||
const inputJson = JSON.parse(input)
|
||||
core.debug(JSON.stringify(inputJson))
|
||||
|
||||
const command = inputJson.command
|
||||
if (command === 'Create') {
|
||||
const creationInput = inputJson.creationInput
|
||||
core.debug(JSON.stringify(creationInput))
|
||||
const containers = creationInput.containers
|
||||
const jobContainer = containers[0]
|
||||
|
||||
const networkName = 'actions_podman_network'
|
||||
// podman network create {network} -> track and return `network` for ${{job.container.network}}
|
||||
await exec.exec('podman', ['network', 'create', networkName])
|
||||
|
||||
const containerImage = `docker.io/library/${jobContainer.containerImage}`
|
||||
// podman pull docker.io/library/{image}
|
||||
await exec.exec('podman', ['pull', containerImage])
|
||||
|
||||
// podman create --name e088c842be1f46b394212618408aaba0_node1016jessie_6196c9
|
||||
// --label fa4e14
|
||||
// --workdir /__w/canary/canary
|
||||
// --network github_network_f98a6e1e96e74d919d814c165641cba3
|
||||
// -e "HOME=/github/home" -e GITHUB_ACTIONS=true -e CI=true
|
||||
// -v "/var/run/docker.sock":"/var/run/docker.sock"
|
||||
// -v "/home/runner/work":"/__w"
|
||||
// -v "/home/runner/runners/2.283.2/externals":"/__e":ro
|
||||
// -v "/home/runner/work/_temp":"/__w/_temp"
|
||||
// -v "/home/runner/work/_actions":"/__w/_actions"
|
||||
// -v "/opt/hostedtoolcache":"/__t"
|
||||
// -v "/home/runner/work/_temp/_github_home":"/github/home"
|
||||
// -v "/home/runner/work/_temp/_github_workflow":"/github/workflow"
|
||||
// --entrypoint "tail" node:10.16-jessie "-f" "/dev/null"
|
||||
const creatArgs = ['create']
|
||||
creatArgs.push(`--workdir=${jobContainer.containerWorkDirectory}`)
|
||||
creatArgs.push(`--network=${networkName}`)
|
||||
|
||||
for (const mountVolume of jobContainer.mountVolumes) {
|
||||
creatArgs.push(
|
||||
`-v=${mountVolume.sourceVolumePath}:${mountVolume.targetVolumePath}`
|
||||
)
|
||||
}
|
||||
|
||||
creatArgs.push(`--entrypoint=tail`)
|
||||
creatArgs.push(containerImage)
|
||||
creatArgs.push(`-f`)
|
||||
creatArgs.push(`/dev/null`)
|
||||
|
||||
core.debug(JSON.stringify(creatArgs))
|
||||
|
||||
// const containerId = await exec.getExecOutput('podman', [
|
||||
// 'create',
|
||||
// // `--workdir ${jobContainer.containerWorkDirectory}`,
|
||||
// `--network=${networkName}`,
|
||||
// // `-v=/Users/ting/Desktop/runner/_layout/_work:/__w`,
|
||||
// `--entrypoint=${jobContainer.containerEntryPoint}`,
|
||||
// `${containerImage}`,
|
||||
// `${jobContainer.containerEntryPointArgs}`
|
||||
// ])
|
||||
|
||||
const containerId = await exec.getExecOutput('podman', creatArgs)
|
||||
|
||||
core.debug(JSON.stringify(containerId))
|
||||
|
||||
// podman start {containerId}
|
||||
await exec.exec('podman', ['start', containerId.stdout.trim()])
|
||||
|
||||
// get PATH inside the container
|
||||
|
||||
// output containerId for ${{job.container.id}}
|
||||
|
||||
const creationOutput = {
|
||||
JobContainerId: containerId.stdout.trim(),
|
||||
Network: networkName
|
||||
}
|
||||
|
||||
const output = JSON.stringify({CreationOutput: creationOutput})
|
||||
core.debug(output)
|
||||
|
||||
process.stderr.write(
|
||||
`___CONTAINER_ENGINE_HANDLER_OUTPUT___${output}___CONTAINER_ENGINE_HANDLER_OUTPUT___`
|
||||
)
|
||||
} else if (command === 'Remove') {
|
||||
const removeInput = inputJson.removeInput
|
||||
core.debug(JSON.stringify(removeInput))
|
||||
const jobContainerId = removeInput.jobContainerId
|
||||
const network = removeInput.network
|
||||
|
||||
await exec.exec('podman', ['rm', '-f', jobContainerId])
|
||||
await exec.exec('podman', ['network', 'rm', '-f', network])
|
||||
} else if (command === 'Exec') {
|
||||
const execInput = inputJson.execInput
|
||||
core.debug(JSON.stringify(execInput))
|
||||
|
||||
// podman exec -i --workdir /__w/canary/canary
|
||||
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
|
||||
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
|
||||
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
|
||||
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
|
||||
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
|
||||
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
|
||||
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
|
||||
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
|
||||
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
|
||||
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
|
||||
|
||||
const execArgs = ['exec']
|
||||
execArgs.push('-i')
|
||||
execArgs.push(`--workdir=${execInput.workingDirectory}`)
|
||||
for (const envKey of execInput.environmentKeys) {
|
||||
execArgs.push(`-e=${envKey}`)
|
||||
}
|
||||
execArgs.push(execInput.jobContainer.containerId)
|
||||
execArgs.push(execInput.fileName)
|
||||
|
||||
const args = (<string>execInput.arguments).split(' ')
|
||||
core.debug(JSON.stringify(args))
|
||||
|
||||
execArgs.push(...args)
|
||||
|
||||
core.debug(JSON.stringify(execArgs))
|
||||
|
||||
await exec.exec('podman', execArgs)
|
||||
}
|
||||
|
||||
await exec.exec('podman', ['network', 'ls'])
|
||||
await exec.exec('podman', ['ps', '-a'])
|
||||
}
|
||||
|
||||
run()
|
||||
12
src/Misc/containerEngineHandlers/podmanHandler/tsconfig.json
Normal file
12
src/Misc/containerEngineHandlers/podmanHandler/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
||||
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
}
|
||||
3031
src/Misc/layoutbin/kubeInnerHandler/index.js
Normal file
3031
src/Misc/layoutbin/kubeInnerHandler/index.js
Normal file
File diff suppressed because it is too large
Load Diff
3119
src/Misc/layoutbin/kubectlHandler/index.js
Normal file
3119
src/Misc/layoutbin/kubectlHandler/index.js
Normal file
File diff suppressed because it is too large
Load Diff
49
src/Misc/layoutbin/podman-handler.js
Normal file
49
src/Misc/layoutbin/podman-handler.js
Normal file
@@ -0,0 +1,49 @@
|
||||
// Job container creation
|
||||
|
||||
// podman network create {network} -> track and return `network` for ${{job.container.network}}
|
||||
|
||||
// podman pull docker.io/library/{image}
|
||||
|
||||
// podman create --name e088c842be1f46b394212618408aaba0_node1016jessie_6196c9
|
||||
// --label fa4e14
|
||||
// --workdir /__w/canary/canary
|
||||
// --network github_network_f98a6e1e96e74d919d814c165641cba3
|
||||
// -e "HOME=/github/home" -e GITHUB_ACTIONS=true -e CI=true
|
||||
// -v "/var/run/docker.sock":"/var/run/docker.sock"
|
||||
// -v "/home/runner/work":"/__w"
|
||||
// -v "/home/runner/runners/2.283.2/externals":"/__e":ro
|
||||
// -v "/home/runner/work/_temp":"/__w/_temp"
|
||||
// -v "/home/runner/work/_actions":"/__w/_actions"
|
||||
// -v "/opt/hostedtoolcache":"/__t"
|
||||
// -v "/home/runner/work/_temp/_github_home":"/github/home"
|
||||
// -v "/home/runner/work/_temp/_github_workflow":"/github/workflow"
|
||||
// --entrypoint "tail" node:10.16-jessie "-f" "/dev/null"
|
||||
|
||||
// podman start {containerId}
|
||||
|
||||
// get PATH inside the container
|
||||
|
||||
// output containerId for ${{job.container.id}}
|
||||
|
||||
|
||||
|
||||
// Job container stop
|
||||
|
||||
// podman rm --force {containerId}
|
||||
|
||||
// podman network rm {network}
|
||||
|
||||
|
||||
// Run step
|
||||
|
||||
// podman exec -i --workdir /__w/canary/canary
|
||||
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
|
||||
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
|
||||
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
|
||||
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
|
||||
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
|
||||
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
|
||||
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
|
||||
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
|
||||
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
|
||||
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
|
||||
3110
src/Misc/layoutbin/podmanHandler/index.js
Normal file
3110
src/Misc/layoutbin/podmanHandler/index.js
Normal file
File diff suppressed because it is too large
Load Diff
68
src/Misc/layoutroot/entrypoint.sh
Executable file
68
src/Misc/layoutroot/entrypoint.sh
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
function fatal() {
|
||||
echo "error: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -n "${GITHUB_PAT:-""}" ] || fatal "GITHUB_PAT variable must be set"
|
||||
[ -n "${RUNNER_CONFIG_URL:-""}" ] || fatal "RUNNER_CONFIG_URL variable must be set"
|
||||
# [ -n "${RUNNER_NAME:-""}" ] || fatal "RUNNER_NAME variable must be set"
|
||||
|
||||
# if [ -n "${RUNNER_NAME}" ]; then
|
||||
# # Use container id to gen unique runner name if name not provide
|
||||
# CONTAINER_ID=$(cat /proc/self/cgroup | head -n 1 | tr '/' '\n' | tail -1 | cut -c1-12)
|
||||
# RUNNER_NAME="actions-runner-${CONTAINER_ID}"
|
||||
# fi
|
||||
|
||||
# if the scope has a slash, it's a repo runner
|
||||
# orgs_or_repos="orgs"
|
||||
# if [[ "$GITHUB_RUNNER_SCOPE" == *\/* ]]; then
|
||||
# orgs_or_repos="repos"
|
||||
# fi
|
||||
|
||||
# RUNNER_REG_URL="${GITHUB_SERVER_URL:=https://github.com}/${GITHUB_RUNNER_SCOPE}"
|
||||
|
||||
# echo "Runner Name : ${RUNNER_NAME}"
|
||||
echo "Registration URL : ${RUNNER_CONFIG_URL}"
|
||||
# echo "GitHub API URL : ${GITHUB_API_URL:=https://api.github.com}"
|
||||
# echo "Runner Labels : ${RUNNER_LABELS:=""}"
|
||||
|
||||
# TODO: if api url is not default, validate it ends in /api/v3
|
||||
|
||||
# RUNNER_LABELS_ARG=""
|
||||
# if [ -n "${RUNNER_LABELS}" ]; then
|
||||
# RUNNER_LABELS_ARG="--labels ${RUNNER_LABELS}"
|
||||
# fi
|
||||
|
||||
# RUNNER_GROUP_ARG=""
|
||||
# if [ -n "${RUNNER_GROUP}" ]; then
|
||||
# RUNNER_GROUP_ARG="--runnergroup ${RUNNER_GROUP}"
|
||||
# fi
|
||||
|
||||
# if [ -n "${K8S_HOST_IP}" ]; then
|
||||
# export http_proxy=http://$K8S_HOST_IP:9090
|
||||
# fi
|
||||
|
||||
# curl -v -s -X POST ${GITHUB_API_URL}/${orgs_or_repos}/${GITHUB_RUNNER_SCOPE}/actions/runners/registration-token -H "authorization: token $GITHUB_PAT" -H "accept: application/vnd.github.everest-preview+json"
|
||||
|
||||
# Generate registration token
|
||||
# RUNNER_REG_TOKEN=$(curl -s -X POST ${GITHUB_API_URL}/${orgs_or_repos}/${GITHUB_RUNNER_SCOPE}/actions/runners/registration-token -H "authorization: token $GITHUB_PAT" -H "accept: application/vnd.github.everest-preview+json" | jq -r '.token')
|
||||
|
||||
# Create the runner and configure it
|
||||
./config.sh --unattended --url $RUNNER_CONFIG_URL --pat $GITHUB_PAT --replace --ephemeral
|
||||
|
||||
# while (! docker version ); do
|
||||
# # Docker takes a few seconds to initialize
|
||||
# echo "Waiting for Docker to launch..."
|
||||
# sleep 1
|
||||
# done
|
||||
|
||||
# unset env
|
||||
unset RUNNER_CONFIG_URL
|
||||
unset GITHUB_PAT
|
||||
|
||||
# Run it
|
||||
./run.sh
|
||||
@@ -54,7 +54,7 @@ namespace GitHub.Runner.Worker.Container
|
||||
_pathMappings.Add(new PathMapping(hostContext.GetDirectory(WellKnownDirectory.Externals), "/__e"));
|
||||
if (this.IsJobContainer)
|
||||
{
|
||||
this.MountVolumes.Add(new MountVolume("/var/run/docker.sock", "/var/run/docker.sock"));
|
||||
// this.MountVolumes.Add(new MountVolume("/var/run/docker.sock", "/var/run/docker.sock"));
|
||||
}
|
||||
#endif
|
||||
if (container.Ports?.Count > 0)
|
||||
|
||||
@@ -12,9 +12,88 @@ using GitHub.Runner.Sdk;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using Microsoft.Win32;
|
||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||
using System.Threading.Channels;
|
||||
using GitHub.Services.WebApi;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace GitHub.Runner.Worker
|
||||
{
|
||||
[DataContract]
|
||||
public class ContainerEngineHandlerInput
|
||||
{
|
||||
[DataMember]
|
||||
public string Command { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public ContainersCreationInput CreationInput { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public JobContainerExecInput ExecInput { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public ContainersRemoveInput RemoveInput { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class ContainersCreationInput
|
||||
{
|
||||
[DataMember]
|
||||
public List<ContainerInfo> Containers { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class JobContainerExecInput
|
||||
{
|
||||
[DataMember]
|
||||
public ContainerInfo JobContainer { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string WorkingDirectory { get; set; }
|
||||
|
||||
|
||||
[DataMember]
|
||||
public string FileName { get; set; }
|
||||
|
||||
|
||||
[DataMember]
|
||||
public string Arguments { get; set; }
|
||||
|
||||
|
||||
[DataMember]
|
||||
public List<string> EnvironmentKeys { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public Dictionary<string, string> EnvironmentVariables { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
[DataContract]
|
||||
public class ContainersRemoveInput
|
||||
{
|
||||
[DataMember]
|
||||
public string Network { get; set; }
|
||||
[DataMember]
|
||||
public string JobContainerId { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class ContainersCreationOutput
|
||||
{
|
||||
[DataMember]
|
||||
public string Network { get; set; }
|
||||
[DataMember]
|
||||
public string JobContainerId { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class ContainerEngineHandlerOutput
|
||||
{
|
||||
[DataMember]
|
||||
public ContainersCreationOutput CreationOutput { get; set; }
|
||||
}
|
||||
|
||||
[ServiceLocator(Default = typeof(ContainerOperationProvider))]
|
||||
public interface IContainerOperationProvider : IRunnerService
|
||||
{
|
||||
@@ -24,25 +103,57 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public class ContainerOperationProvider : RunnerService, IContainerOperationProvider
|
||||
{
|
||||
private IDockerCommandManager _dockerManager;
|
||||
private IDockerCommandManager _dockerManager = null;
|
||||
|
||||
public override void Initialize(IHostContext hostContext)
|
||||
{
|
||||
base.Initialize(hostContext);
|
||||
_dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||
// _dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||
}
|
||||
|
||||
public async Task StartContainersAsync(IExecutionContext executionContext, object data)
|
||||
{
|
||||
Trace.Entering();
|
||||
if (!Constants.Runner.Platform.Equals(Constants.OSPlatform.Linux))
|
||||
{
|
||||
throw new NotSupportedException("Container operations are only supported on Linux runners");
|
||||
}
|
||||
// if (!Constants.Runner.Platform.Equals(Constants.OSPlatform.Linux))
|
||||
// {
|
||||
// throw new NotSupportedException("Container operations are only supported on Linux runners");
|
||||
// }
|
||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||
List<ContainerInfo> containers = data as List<ContainerInfo>;
|
||||
ArgUtil.NotNull(containers, nameof(containers));
|
||||
|
||||
foreach (var container in containers)
|
||||
{
|
||||
if (container.IsJobContainer)
|
||||
{
|
||||
// Configure job container - Mount workspace and tools, set up environment, and start long running process
|
||||
var githubContext = executionContext.ExpressionValues["github"] as GitHubContext;
|
||||
ArgUtil.NotNull(githubContext, nameof(githubContext));
|
||||
var workingDirectory = githubContext["workspace"] as StringContextData;
|
||||
ArgUtil.NotNullOrEmpty(workingDirectory, nameof(workingDirectory));
|
||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Work), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Work))));
|
||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals)), true));
|
||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Temp), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Temp))));
|
||||
// container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Actions), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Actions))));
|
||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Tools), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Tools))));
|
||||
|
||||
var tempHomeDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), "_github_home");
|
||||
Directory.CreateDirectory(tempHomeDirectory);
|
||||
container.MountVolumes.Add(new MountVolume(tempHomeDirectory, "/github/home"));
|
||||
container.AddPathTranslateMapping(tempHomeDirectory, "/github/home");
|
||||
container.ContainerEnvironmentVariables["HOME"] = container.TranslateToContainerPath(tempHomeDirectory);
|
||||
|
||||
var tempWorkflowDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), "_github_workflow");
|
||||
Directory.CreateDirectory(tempWorkflowDirectory);
|
||||
container.MountVolumes.Add(new MountVolume(tempWorkflowDirectory, "/github/workflow"));
|
||||
container.AddPathTranslateMapping(tempWorkflowDirectory, "/github/workflow");
|
||||
|
||||
container.ContainerWorkDirectory = container.TranslateToContainerPath(workingDirectory);
|
||||
container.ContainerEntryPoint = "tail";
|
||||
container.ContainerEntryPointArgs = "-f /dev/null";
|
||||
}
|
||||
}
|
||||
|
||||
var postJobStep = new JobExtensionRunner(runAsync: this.StopContainersAsync,
|
||||
condition: $"{PipelineTemplateConstants.Always}()",
|
||||
displayName: "Stop containers",
|
||||
@@ -51,9 +162,71 @@ namespace GitHub.Runner.Worker
|
||||
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
||||
executionContext.RegisterPostJobStep(postJobStep);
|
||||
|
||||
// Check whether we are inside a container.
|
||||
// Our container feature requires to map working directory from host to the container.
|
||||
// If we are already inside a container, we will not able to find out the real working direcotry path on the host.
|
||||
var podManHandler = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "kubectlHandler", "index.js");
|
||||
if (File.Exists(podManHandler))
|
||||
{
|
||||
var podmanInput = new ContainerEngineHandlerInput()
|
||||
{
|
||||
Command = "Create",
|
||||
CreationInput = new ContainersCreationInput()
|
||||
{
|
||||
Containers = containers
|
||||
}
|
||||
};
|
||||
|
||||
ContainerEngineHandlerOutput podmanOutput = null;
|
||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||
{
|
||||
var redirectStandardIn = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true });
|
||||
redirectStandardIn.Writer.TryWrite(JsonUtility.ToString(podmanInput));
|
||||
|
||||
processInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
||||
{
|
||||
executionContext.Output(message.Data);
|
||||
};
|
||||
|
||||
processInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
||||
{
|
||||
executionContext.Output(message.Data);
|
||||
if (podmanOutput == null && message.Data.IndexOf("___CONTAINER_ENGINE_HANDLER_OUTPUT___") >= 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
podmanOutput = JsonUtility.FromString<ContainerEngineHandlerOutput>(message.Data.Replace("___CONTAINER_ENGINE_HANDLER_OUTPUT___", ""));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
executionContext.Error(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Execute the process. Exit code 0 should always be returned.
|
||||
// A non-zero exit code indicates infrastructural failure.
|
||||
// Task failure should be communicated over STDOUT using ## commands.
|
||||
await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Bin),
|
||||
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}"),
|
||||
arguments: podManHandler,
|
||||
environment: null,
|
||||
requireExitCodeZero: false,
|
||||
outputEncoding: Encoding.UTF8,
|
||||
killProcessOnCancel: false,
|
||||
redirectStandardIn: redirectStandardIn,
|
||||
cancellationToken: executionContext.CancellationToken);
|
||||
}
|
||||
|
||||
if (podmanOutput != null)
|
||||
{
|
||||
executionContext.JobContext.Container["network"] = new StringContextData(podmanOutput.CreationOutput.Network);
|
||||
executionContext.JobContext.Container["id"] = new StringContextData(podmanOutput.CreationOutput.JobContainerId);
|
||||
executionContext.Global.Container.ContainerId = podmanOutput.CreationOutput.JobContainerId;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check whether we are inside a container.
|
||||
// Our container feature requires to map working directory from host to the container.
|
||||
// If we are already inside a container, we will not able to find out the real working direcotry path on the host.
|
||||
#if OS_WINDOWS
|
||||
// service CExecSvc is Container Execution Agent.
|
||||
ServiceController[] scServices = ServiceController.GetServices();
|
||||
@@ -62,11 +235,11 @@ namespace GitHub.Runner.Worker
|
||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||
}
|
||||
#else
|
||||
var initProcessCgroup = File.ReadLines("/proc/1/cgroup");
|
||||
if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0))
|
||||
{
|
||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||
}
|
||||
var initProcessCgroup = File.ReadLines("/proc/1/cgroup");
|
||||
if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0))
|
||||
{
|
||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OS_WINDOWS
|
||||
@@ -90,68 +263,69 @@ namespace GitHub.Runner.Worker
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check docker client/server version
|
||||
executionContext.Output("##[group]Checking docker version");
|
||||
DockerVersion dockerVersion = await _dockerManager.DockerVersion(executionContext);
|
||||
executionContext.Output("##[endgroup]");
|
||||
// Check docker client/server version
|
||||
executionContext.Output("##[group]Checking docker version");
|
||||
DockerVersion dockerVersion = await _dockerManager.DockerVersion(executionContext);
|
||||
executionContext.Output("##[endgroup]");
|
||||
|
||||
ArgUtil.NotNull(dockerVersion.ServerVersion, nameof(dockerVersion.ServerVersion));
|
||||
ArgUtil.NotNull(dockerVersion.ClientVersion, nameof(dockerVersion.ClientVersion));
|
||||
ArgUtil.NotNull(dockerVersion.ServerVersion, nameof(dockerVersion.ServerVersion));
|
||||
ArgUtil.NotNull(dockerVersion.ClientVersion, nameof(dockerVersion.ClientVersion));
|
||||
|
||||
#if OS_WINDOWS
|
||||
Version requiredDockerEngineAPIVersion = new Version(1, 30); // Docker-EE version 17.6
|
||||
#else
|
||||
Version requiredDockerEngineAPIVersion = new Version(1, 35); // Docker-CE version 17.12
|
||||
Version requiredDockerEngineAPIVersion = new Version(1, 35); // Docker-CE version 17.12
|
||||
#endif
|
||||
|
||||
if (dockerVersion.ServerVersion < requiredDockerEngineAPIVersion)
|
||||
{
|
||||
throw new NotSupportedException($"Min required docker engine API server version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') server version is '{dockerVersion.ServerVersion}'");
|
||||
}
|
||||
if (dockerVersion.ClientVersion < requiredDockerEngineAPIVersion)
|
||||
{
|
||||
throw new NotSupportedException($"Min required docker engine API client version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') client version is '{dockerVersion.ClientVersion}'");
|
||||
}
|
||||
|
||||
// Clean up containers left by previous runs
|
||||
executionContext.Output("##[group]Clean up resources from previous jobs");
|
||||
var staleContainers = await _dockerManager.DockerPS(executionContext, $"--all --quiet --no-trunc --filter \"label={_dockerManager.DockerInstanceLabel}\"");
|
||||
foreach (var staleContainer in staleContainers)
|
||||
{
|
||||
int containerRemoveExitCode = await _dockerManager.DockerRemove(executionContext, staleContainer);
|
||||
if (containerRemoveExitCode != 0)
|
||||
if (dockerVersion.ServerVersion < requiredDockerEngineAPIVersion)
|
||||
{
|
||||
executionContext.Warning($"Delete stale containers failed, docker rm fail with exit code {containerRemoveExitCode} for container {staleContainer}");
|
||||
throw new NotSupportedException($"Min required docker engine API server version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') server version is '{dockerVersion.ServerVersion}'");
|
||||
}
|
||||
if (dockerVersion.ClientVersion < requiredDockerEngineAPIVersion)
|
||||
{
|
||||
throw new NotSupportedException($"Min required docker engine API client version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') client version is '{dockerVersion.ClientVersion}'");
|
||||
}
|
||||
}
|
||||
|
||||
int networkPruneExitCode = await _dockerManager.DockerNetworkPrune(executionContext);
|
||||
if (networkPruneExitCode != 0)
|
||||
{
|
||||
executionContext.Warning($"Delete stale container networks failed, docker network prune fail with exit code {networkPruneExitCode}");
|
||||
}
|
||||
executionContext.Output("##[endgroup]");
|
||||
// Clean up containers left by previous runs
|
||||
executionContext.Output("##[group]Clean up resources from previous jobs");
|
||||
var staleContainers = await _dockerManager.DockerPS(executionContext, $"--all --quiet --no-trunc --filter \"label={_dockerManager.DockerInstanceLabel}\"");
|
||||
foreach (var staleContainer in staleContainers)
|
||||
{
|
||||
int containerRemoveExitCode = await _dockerManager.DockerRemove(executionContext, staleContainer);
|
||||
if (containerRemoveExitCode != 0)
|
||||
{
|
||||
executionContext.Warning($"Delete stale containers failed, docker rm fail with exit code {containerRemoveExitCode} for container {staleContainer}");
|
||||
}
|
||||
}
|
||||
|
||||
// Create local docker network for this job to avoid port conflict when multiple runners run on same machine.
|
||||
// All containers within a job join the same network
|
||||
executionContext.Output("##[group]Create local container network");
|
||||
var containerNetwork = $"github_network_{Guid.NewGuid().ToString("N")}";
|
||||
await CreateContainerNetworkAsync(executionContext, containerNetwork);
|
||||
executionContext.JobContext.Container["network"] = new StringContextData(containerNetwork);
|
||||
executionContext.Output("##[endgroup]");
|
||||
int networkPruneExitCode = await _dockerManager.DockerNetworkPrune(executionContext);
|
||||
if (networkPruneExitCode != 0)
|
||||
{
|
||||
executionContext.Warning($"Delete stale container networks failed, docker network prune fail with exit code {networkPruneExitCode}");
|
||||
}
|
||||
executionContext.Output("##[endgroup]");
|
||||
|
||||
foreach (var container in containers)
|
||||
{
|
||||
container.ContainerNetwork = containerNetwork;
|
||||
await StartContainerAsync(executionContext, container);
|
||||
}
|
||||
// Create local docker network for this job to avoid port conflict when multiple runners run on same machine.
|
||||
// All containers within a job join the same network
|
||||
executionContext.Output("##[group]Create local container network");
|
||||
var containerNetwork = $"github_network_{Guid.NewGuid().ToString("N")}";
|
||||
await CreateContainerNetworkAsync(executionContext, containerNetwork);
|
||||
executionContext.JobContext.Container["network"] = new StringContextData(containerNetwork);
|
||||
executionContext.Output("##[endgroup]");
|
||||
|
||||
executionContext.Output("##[group]Waiting for all services to be ready");
|
||||
foreach (var container in containers.Where(c => !c.IsJobContainer))
|
||||
{
|
||||
await ContainerHealthcheck(executionContext, container);
|
||||
foreach (var container in containers)
|
||||
{
|
||||
container.ContainerNetwork = containerNetwork;
|
||||
await StartContainerAsync(executionContext, container);
|
||||
}
|
||||
|
||||
executionContext.Output("##[group]Waiting for all services to be ready");
|
||||
foreach (var container in containers.Where(c => !c.IsJobContainer))
|
||||
{
|
||||
await ContainerHealthcheck(executionContext, container);
|
||||
}
|
||||
executionContext.Output("##[endgroup]");
|
||||
}
|
||||
executionContext.Output("##[endgroup]");
|
||||
}
|
||||
|
||||
public async Task StopContainersAsync(IExecutionContext executionContext, object data)
|
||||
@@ -162,12 +336,69 @@ namespace GitHub.Runner.Worker
|
||||
List<ContainerInfo> containers = data as List<ContainerInfo>;
|
||||
ArgUtil.NotNull(containers, nameof(containers));
|
||||
|
||||
foreach (var container in containers)
|
||||
var podManHandler = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "kubectlHandler", "index.js");
|
||||
if (File.Exists(podManHandler))
|
||||
{
|
||||
await StopContainerAsync(executionContext, container);
|
||||
var podmanInput = new ContainerEngineHandlerInput()
|
||||
{
|
||||
Command = "Remove",
|
||||
RemoveInput = new ContainersRemoveInput()
|
||||
{
|
||||
Network = executionContext.JobContext.Container["network"].ToString(),
|
||||
JobContainerId = executionContext.JobContext.Container["id"].ToString()
|
||||
}
|
||||
};
|
||||
|
||||
ContainerEngineHandlerOutput podmanOutput = null;
|
||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||
{
|
||||
var redirectStandardIn = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true });
|
||||
redirectStandardIn.Writer.TryWrite(JsonUtility.ToString(podmanInput));
|
||||
|
||||
processInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
||||
{
|
||||
executionContext.Output(message.Data);
|
||||
};
|
||||
|
||||
processInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
||||
{
|
||||
executionContext.Output(message.Data);
|
||||
if (podmanOutput == null && message.Data.IndexOf("___CONTAINER_ENGINE_HANDLER_OUTPUT___") >= 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
podmanOutput = JsonUtility.FromString<ContainerEngineHandlerOutput>(message.Data.Replace("___CONTAINER_ENGINE_HANDLER_OUTPUT___", ""));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
executionContext.Error(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Execute the process. Exit code 0 should always be returned.
|
||||
// A non-zero exit code indicates infrastructural failure.
|
||||
// Task failure should be communicated over STDOUT using ## commands.
|
||||
await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
||||
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}"),
|
||||
arguments: podManHandler,
|
||||
environment: null,
|
||||
requireExitCodeZero: false,
|
||||
outputEncoding: Encoding.UTF8,
|
||||
killProcessOnCancel: false,
|
||||
redirectStandardIn: redirectStandardIn,
|
||||
cancellationToken: executionContext.CancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var container in containers)
|
||||
{
|
||||
await StopContainerAsync(executionContext, container);
|
||||
}
|
||||
// Remove the container network
|
||||
await RemoveContainerNetworkAsync(executionContext, containers.First().ContainerNetwork);
|
||||
}
|
||||
// Remove the container network
|
||||
await RemoveContainerNetworkAsync(executionContext, containers.First().ContainerNetwork);
|
||||
}
|
||||
|
||||
private async Task StartContainerAsync(IExecutionContext executionContext, ContainerInfo container)
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace GitHub.Runner.Worker
|
||||
"job",
|
||||
"path",
|
||||
"ref",
|
||||
"ref_name",
|
||||
"ref_protected",
|
||||
"ref_type",
|
||||
"repository",
|
||||
"repository_owner",
|
||||
"retention_days",
|
||||
@@ -39,9 +42,16 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
foreach (var data in this)
|
||||
{
|
||||
if (_contextEnvAllowlist.Contains(data.Key) && data.Value is StringContextData value)
|
||||
if (_contextEnvAllowlist.Contains(data.Key))
|
||||
{
|
||||
yield return new KeyValuePair<string, string>($"GITHUB_{data.Key.ToUpperInvariant()}", value);
|
||||
if (data.Value is StringContextData value)
|
||||
{
|
||||
yield return new KeyValuePair<string, string>($"GITHUB_{data.Key.ToUpperInvariant()}", value);
|
||||
}
|
||||
else if (data.Value is BooleanContextData booleanValue)
|
||||
{
|
||||
yield return new KeyValuePair<string, string>($"GITHUB_{data.Key.ToUpperInvariant()}", booleanValue.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||
event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||
|
||||
IExecutionContext ExecutionContext { get; set; }
|
||||
|
||||
string ResolvePathForStepHost(string path);
|
||||
|
||||
Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext);
|
||||
@@ -53,6 +55,8 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||
|
||||
public IExecutionContext ExecutionContext { get; set; }
|
||||
|
||||
public string ResolvePathForStepHost(string path)
|
||||
{
|
||||
return path;
|
||||
@@ -99,6 +103,8 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||
|
||||
public IExecutionContext ExecutionContext { get; set; }
|
||||
|
||||
public string ResolvePathForStepHost(string path)
|
||||
{
|
||||
// make sure container exist.
|
||||
@@ -174,69 +180,138 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
ArgUtil.NotNull(Container, nameof(Container));
|
||||
ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId));
|
||||
|
||||
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||
string dockerClientPath = dockerManager.DockerPath;
|
||||
|
||||
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
|
||||
IList<string> dockerCommandArgs = new List<string>();
|
||||
dockerCommandArgs.Add($"exec");
|
||||
|
||||
// [OPTIONS]
|
||||
dockerCommandArgs.Add($"-i");
|
||||
dockerCommandArgs.Add($"--workdir {workingDirectory}");
|
||||
foreach (var env in environment)
|
||||
var podManHandler = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "kubectlHandler", "index.js");
|
||||
if (File.Exists(podManHandler))
|
||||
{
|
||||
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
||||
// the value directly in the command
|
||||
dockerCommandArgs.Add($"-e {env.Key}");
|
||||
var podmanInput = new ContainerEngineHandlerInput()
|
||||
{
|
||||
Command = "Exec",
|
||||
ExecInput = new JobContainerExecInput()
|
||||
{
|
||||
JobContainer = this.Container,
|
||||
WorkingDirectory = workingDirectory,
|
||||
FileName = fileName,
|
||||
Arguments = arguments,
|
||||
EnvironmentKeys = environment.Keys.ToList(),
|
||||
EnvironmentVariables = environment.ToDictionary(x => x.Key, y => y.Value)
|
||||
}
|
||||
};
|
||||
|
||||
// make sure all env are using container path
|
||||
foreach (var envKey in environment.Keys.ToList())
|
||||
{
|
||||
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
|
||||
}
|
||||
|
||||
// ContainerEngineHandlerOutput podmanOutput = null;
|
||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||
{
|
||||
var redirectStandardIn = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true });
|
||||
redirectStandardIn.Writer.TryWrite(JsonUtility.ToString(podmanInput));
|
||||
|
||||
// processInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
||||
// {
|
||||
// ExecutionContext.Output(message.Data);
|
||||
// };
|
||||
|
||||
// processInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
||||
// {
|
||||
// executionContext.Output(message.Data);
|
||||
// if (podmanOutput == null && message.Data.IndexOf("___CONTAINER_ENGINE_HANDLER_OUTPUT___") >= 0)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// podmanOutput = JsonUtility.FromString<ContainerEngineHandlerOutput>(message.Data.Replace("___CONTAINER_ENGINE_HANDLER_OUTPUT___", ""));
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// executionContext.Error(ex);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
processInvoker.OutputDataReceived += OutputDataReceived;
|
||||
processInvoker.ErrorDataReceived += ErrorDataReceived;
|
||||
|
||||
// Execute the process. Exit code 0 should always be returned.
|
||||
// A non-zero exit code indicates infrastructural failure.
|
||||
// Task failure should be communicated over STDOUT using ## commands.
|
||||
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
||||
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}"),
|
||||
arguments: podManHandler,
|
||||
environment: environment,
|
||||
requireExitCodeZero: requireExitCodeZero,
|
||||
outputEncoding: Encoding.UTF8,
|
||||
killProcessOnCancel: killProcessOnCancel,
|
||||
redirectStandardIn: redirectStandardIn,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(PrependPath))
|
||||
else
|
||||
{
|
||||
// Prepend tool paths to container's PATH
|
||||
var fullPath = !string.IsNullOrEmpty(Container.ContainerRuntimePath) ? $"{PrependPath}:{Container.ContainerRuntimePath}" : PrependPath;
|
||||
dockerCommandArgs.Add($"-e PATH=\"{fullPath}\"");
|
||||
}
|
||||
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||
string dockerClientPath = dockerManager.DockerPath;
|
||||
|
||||
// CONTAINER
|
||||
dockerCommandArgs.Add($"{Container.ContainerId}");
|
||||
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
|
||||
IList<string> dockerCommandArgs = new List<string>();
|
||||
dockerCommandArgs.Add($"exec");
|
||||
|
||||
// COMMAND
|
||||
dockerCommandArgs.Add(fileName);
|
||||
// [OPTIONS]
|
||||
dockerCommandArgs.Add($"-i");
|
||||
dockerCommandArgs.Add($"--workdir {workingDirectory}");
|
||||
foreach (var env in environment)
|
||||
{
|
||||
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
||||
// the value directly in the command
|
||||
dockerCommandArgs.Add($"-e {env.Key}");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(PrependPath))
|
||||
{
|
||||
// Prepend tool paths to container's PATH
|
||||
var fullPath = !string.IsNullOrEmpty(Container.ContainerRuntimePath) ? $"{PrependPath}:{Container.ContainerRuntimePath}" : PrependPath;
|
||||
dockerCommandArgs.Add($"-e PATH=\"{fullPath}\"");
|
||||
}
|
||||
|
||||
// [ARG...]
|
||||
dockerCommandArgs.Add(arguments);
|
||||
// CONTAINER
|
||||
dockerCommandArgs.Add($"{Container.ContainerId}");
|
||||
|
||||
string dockerCommandArgstring = string.Join(" ", dockerCommandArgs);
|
||||
// COMMAND
|
||||
dockerCommandArgs.Add(fileName);
|
||||
|
||||
// make sure all env are using container path
|
||||
foreach (var envKey in environment.Keys.ToList())
|
||||
{
|
||||
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
|
||||
}
|
||||
// [ARG...]
|
||||
dockerCommandArgs.Add(arguments);
|
||||
|
||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||
{
|
||||
processInvoker.OutputDataReceived += OutputDataReceived;
|
||||
processInvoker.ErrorDataReceived += ErrorDataReceived;
|
||||
string dockerCommandArgstring = string.Join(" ", dockerCommandArgs);
|
||||
|
||||
// make sure all env are using container path
|
||||
foreach (var envKey in environment.Keys.ToList())
|
||||
{
|
||||
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
|
||||
}
|
||||
|
||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||
{
|
||||
processInvoker.OutputDataReceived += OutputDataReceived;
|
||||
processInvoker.ErrorDataReceived += ErrorDataReceived;
|
||||
|
||||
#if OS_WINDOWS
|
||||
// It appears that node.exe outputs UTF8 when not in TTY mode.
|
||||
outputEncoding = Encoding.UTF8;
|
||||
#else
|
||||
// Let .NET choose the default.
|
||||
outputEncoding = null;
|
||||
// Let .NET choose the default.
|
||||
outputEncoding = null;
|
||||
#endif
|
||||
|
||||
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
||||
fileName: dockerClientPath,
|
||||
arguments: dockerCommandArgstring,
|
||||
environment: environment,
|
||||
requireExitCodeZero: requireExitCodeZero,
|
||||
outputEncoding: outputEncoding,
|
||||
killProcessOnCancel: killProcessOnCancel,
|
||||
redirectStandardIn: null,
|
||||
inheritConsoleHandler: inheritConsoleHandler,
|
||||
cancellationToken: cancellationToken);
|
||||
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
||||
fileName: dockerClientPath,
|
||||
arguments: dockerCommandArgstring,
|
||||
environment: environment,
|
||||
requireExitCodeZero: requireExitCodeZero,
|
||||
outputEncoding: outputEncoding,
|
||||
killProcessOnCancel: killProcessOnCancel,
|
||||
redirectStandardIn: null,
|
||||
inheritConsoleHandler: inheritConsoleHandler,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="GenerateConstant">
|
||||
<Exec Command="git rev-parse HEAD" ConsoleToMSBuild="true">
|
||||
<!-- <Exec Command="git rev-parse HEAD" ConsoleToMSBuild="true">
|
||||
<Output TaskParameter="ConsoleOutput" PropertyName="GitInfoCommitHash" />
|
||||
</Exec>
|
||||
<Message Text="Building $(Product): $(GitInfoCommitHash) --- $(PackageRuntime)" Importance="high"/>
|
||||
</Exec> -->
|
||||
<Message Text="Building $(Product): --- $(PackageRuntime)" Importance="high"/>
|
||||
|
||||
<ItemGroup>
|
||||
<BuildConstants Include="namespace GitHub.Runner.Sdk"/>
|
||||
@@ -14,7 +14,7 @@
|
||||
<BuildConstants Include="%20%20%20%20{"/>
|
||||
<BuildConstants Include="%20%20%20%20%20%20%20%20public static class Source"/>
|
||||
<BuildConstants Include="%20%20%20%20%20%20%20%20{"/>
|
||||
<BuildConstants Include="%20%20%20%20%20%20%20%20%20%20%20%20public static readonly string CommitHash = %22$(GitInfoCommitHash)%22%3B"/>
|
||||
<BuildConstants Include="%20%20%20%20%20%20%20%20%20%20%20%20public static readonly string CommitHash = %22dfcfae49e59b6dc3c2bb5295c649b33c4b49c964%22%3B"/>
|
||||
<BuildConstants Include="%20%20%20%20%20%20%20%20}%0A"/>
|
||||
<BuildConstants Include="%20%20%20%20%20%20%20%20public static class RunnerPackage"/>
|
||||
<BuildConstants Include="%20%20%20%20%20%20%20%20{"/>
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
<WriteLinesToFile File="Runner.Sdk/BuildConstants.cs" Lines="@(BuildConstants)" Overwrite="true" />
|
||||
|
||||
<Exec Command="git update-index --assume-unchanged ./Runner.Sdk/BuildConstants.cs" ConsoleToMSBuild="true" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user