mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad74566952 | ||
|
|
3a3836a9b9 | ||
|
|
2ac16002a7 | ||
|
|
a79bab4b3c | ||
|
|
ff8e9f49de | ||
|
|
24845a5a01 | ||
|
|
a153170771 | ||
|
|
c5904d5da8 | ||
|
|
99b28c4143 | ||
|
|
b75246e0fe | ||
|
|
a41a9ba8c7 | ||
|
|
c18643e529 | ||
|
|
476640fd51 | ||
|
|
d05b9111c6 | ||
|
|
1d68b0448c |
1
.github/workflows/codeql.yml
vendored
1
.github/workflows/codeql.yml
vendored
@@ -2,7 +2,6 @@ name: "Code Scanning - Action"
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
pull_request:
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0'
|
- cron: '0 0 * * 0'
|
||||||
|
|
||||||
|
|||||||
335
.github/workflows/e2etest.yml
vendored
335
.github/workflows/e2etest.yml
vendored
@@ -1,335 +0,0 @@
|
|||||||
name: Runner E2E Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- releases/*
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
init:
|
|
||||||
name: Initialize workflow ☕
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
unique_runner_label: ${{steps.generator.outputs.runner_label}}
|
|
||||||
steps:
|
|
||||||
- name: Delete all runners
|
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
debug: true
|
|
||||||
script: |
|
|
||||||
var runnersResp = await github.actions.listSelfHostedRunnersForRepo({
|
|
||||||
owner: 'actions',
|
|
||||||
repo: 'runner',
|
|
||||||
per_page: '100'
|
|
||||||
});
|
|
||||||
for(var i=0; i<runnersResp.data.total_count; i++){
|
|
||||||
core.debug(JSON.stringify(runnersResp.data.runners[i]))
|
|
||||||
await github.actions.deleteSelfHostedRunnerFromRepo({
|
|
||||||
owner: 'actions',
|
|
||||||
repo: 'runner',
|
|
||||||
runner_id: runnersResp.data.runners[i].id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
github-token: ${{secrets.PAT}}
|
|
||||||
- name: Generate Unique Runner label
|
|
||||||
id: generator
|
|
||||||
run: |
|
|
||||||
label=$(openssl rand -hex 16)
|
|
||||||
echo ::set-output name=runner_label::$label
|
|
||||||
|
|
||||||
build:
|
|
||||||
name: Build runner packages 🏗 📦
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
|
||||||
include:
|
|
||||||
- runtime: linux-x64
|
|
||||||
os: ubuntu-latest
|
|
||||||
devScript: ./dev.sh
|
|
||||||
|
|
||||||
- runtime: linux-arm64
|
|
||||||
os: ubuntu-latest
|
|
||||||
devScript: ./dev.sh
|
|
||||||
|
|
||||||
- runtime: linux-arm
|
|
||||||
os: ubuntu-latest
|
|
||||||
devScript: ./dev.sh
|
|
||||||
|
|
||||||
- runtime: osx-x64
|
|
||||||
os: macOS-latest
|
|
||||||
devScript: ./dev.sh
|
|
||||||
|
|
||||||
- runtime: win-x64
|
|
||||||
os: windows-latest
|
|
||||||
devScript: ./dev
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
|
|
||||||
# Build runner layout
|
|
||||||
- name: Build & Layout Release
|
|
||||||
run: |
|
|
||||||
${{ matrix.devScript }} layout Release ${{ matrix.runtime }}
|
|
||||||
working-directory: src
|
|
||||||
|
|
||||||
# Create runner package tar.gz/zip
|
|
||||||
- name: Package Release
|
|
||||||
run: |
|
|
||||||
${{ matrix.devScript }} package Release ${{ matrix.runtime }}
|
|
||||||
working-directory: src
|
|
||||||
|
|
||||||
# Upload runner package tar.gz/zip as artifact
|
|
||||||
- name: Publish Artifact
|
|
||||||
uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: runner-package-${{ matrix.runtime }}
|
|
||||||
path: _package
|
|
||||||
|
|
||||||
dispatch_workflow:
|
|
||||||
name: Dispatch workflow to runners 🚨
|
|
||||||
needs: [init, build]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Dispatch workflow
|
|
||||||
timeout-minutes: 10
|
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
debug: true
|
|
||||||
script: |
|
|
||||||
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
|
||||||
async function dispatchWorkflow(runner) {
|
|
||||||
await github.actions.createWorkflowDispatch({
|
|
||||||
owner: 'actions',
|
|
||||||
repo: 'runner',
|
|
||||||
workflow_id: 'runner-basic-e2e-test-case.yml',
|
|
||||||
ref: 'main',
|
|
||||||
inputs: {target_runner: runner}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var runWin64 = false, runLinux64 = false, runOsx64 = false, runLinuxARM64 = false;
|
|
||||||
while (true) {
|
|
||||||
core.info(`------------- Waiting for runners to be configured --------------`)
|
|
||||||
await sleep(10000);
|
|
||||||
var runnersResp = await github.actions.listSelfHostedRunnersForRepo({owner: 'actions', repo: 'runner', per_page: '100'});
|
|
||||||
for (var i = 0; i < runnersResp.data.total_count; i++) {
|
|
||||||
core.debug(JSON.stringify(runnersResp.data.runners[i]))
|
|
||||||
var labels = runnersResp.data.runners[i].labels;
|
|
||||||
for (var j = 0; j < labels.length; j++) {
|
|
||||||
core.debug(`Comparing: ${labels[j].name} to win-x64/linux-x64/osx-x64/linux-arm64-${{ needs.init.outputs.unique_runner_label }}`)
|
|
||||||
if (labels[j].name == 'win-x64-${{needs.init.outputs.unique_runner_label}}' && runWin64 == false) {
|
|
||||||
core.info(`------------------- Windows runner is configured, queue Windows Run -------------------------`)
|
|
||||||
runWin64 = true;
|
|
||||||
await dispatchWorkflow('win-x64-${{needs.init.outputs.unique_runner_label}}');
|
|
||||||
break;
|
|
||||||
} else if (labels[j].name == 'linux-x64-${{needs.init.outputs.unique_runner_label}}' && runLinux64 == false) {
|
|
||||||
core.info(`------------------- Linux runner is configured, queue Linux Run -------------------------`)
|
|
||||||
runLinux64 = true;
|
|
||||||
await dispatchWorkflow('linux-x64-${{needs.init.outputs.unique_runner_label}}');
|
|
||||||
break;
|
|
||||||
} else if (labels[j].name == 'osx-x64-${{needs.init.outputs.unique_runner_label}}' && runOsx64 == false) {
|
|
||||||
core.info(`------------------- macOS runner is configured, queue macOS Run -------------------------`)
|
|
||||||
runOsx64 = true;
|
|
||||||
await dispatchWorkflow('osx-x64-${{needs.init.outputs.unique_runner_label}}');
|
|
||||||
break;
|
|
||||||
} else if (labels[j].name == 'linux-arm64-${{needs.init.outputs.unique_runner_label}}' && runLinuxARM64 == false) {
|
|
||||||
core.info(`------------------- Linux ARM64 runner is configured, queue Linux ARM64 Run-------------------------`)
|
|
||||||
runLinuxARM64 = true;
|
|
||||||
await dispatchWorkflow('linux-arm64-${{needs.init.outputs.unique_runner_label}}');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (runWin64 && runLinux64 && runOsx64 && runLinuxARM64) {
|
|
||||||
core.info(`--------------------- ALL runner are running jobs --------------------------`)
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
core.info(`---------- Windows running: ${runWin64} -- Linux running: ${runLinux64} -- macOS running: ${runOsx64} -- Linux ARM64 running: ${runLinuxARM64} -----------`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
github-token: ${{secrets.PAT}}
|
|
||||||
|
|
||||||
LinuxE2E:
|
|
||||||
needs: [build, init]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Download Runner
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: runner-package-linux-x64
|
|
||||||
- name: Unzip Runner Package
|
|
||||||
run: |
|
|
||||||
tar -xzf *.tar.gz
|
|
||||||
- name: Configure Runner
|
|
||||||
env:
|
|
||||||
unique_runner_name: linux-x64-${{needs.init.outputs.unique_runner_label}}
|
|
||||||
run: |
|
|
||||||
./config.sh --url ${{github.event.repository.html_url}} --unattended --name $unique_runner_name --pat ${{secrets.PAT}} --labels $unique_runner_name --replace
|
|
||||||
- name: Start Runner and Wait for Job
|
|
||||||
timeout-minutes: 5
|
|
||||||
run: |
|
|
||||||
./run.sh --once
|
|
||||||
- name: Remove Runner
|
|
||||||
if: always()
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
./config.sh remove --pat ${{secrets.PAT}}
|
|
||||||
- name: Upload Runner Logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: linux_x64_logs
|
|
||||||
path: _diag
|
|
||||||
macOSE2E:
|
|
||||||
needs: [build, init]
|
|
||||||
runs-on: macos-latest
|
|
||||||
steps:
|
|
||||||
- name: Download Runner
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: runner-package-osx-x64
|
|
||||||
- name: Unzip Runner Package
|
|
||||||
run: |
|
|
||||||
tar -xzf *.tar.gz
|
|
||||||
- name: Configure Runner
|
|
||||||
env:
|
|
||||||
unique_runner_name: osx-x64-${{needs.init.outputs.unique_runner_label}}
|
|
||||||
run: |
|
|
||||||
./config.sh --url ${{github.event.repository.html_url}} --unattended --name $unique_runner_name --pat ${{secrets.PAT}} --labels $unique_runner_name --replace
|
|
||||||
- name: Start Runner and Wait for Job
|
|
||||||
timeout-minutes: 5
|
|
||||||
run: |
|
|
||||||
./run.sh --once
|
|
||||||
- name: Remove Runner
|
|
||||||
if: always()
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
./config.sh remove --pat ${{secrets.PAT}}
|
|
||||||
- name: Upload Runner Logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: osx_x64_logs
|
|
||||||
path: _diag
|
|
||||||
|
|
||||||
ARM64E2E:
|
|
||||||
needs: [build, init]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Download Runner
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: runner-package-linux-arm64
|
|
||||||
- name: Unzip Runner Package
|
|
||||||
run: |
|
|
||||||
tar -xzf *.tar.gz
|
|
||||||
- name: Prepare QEMU
|
|
||||||
run: |
|
|
||||||
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
|
||||||
- name: Configure Runner
|
|
||||||
uses: docker://multiarch/ubuntu-core:arm64-bionic
|
|
||||||
with:
|
|
||||||
args: 'bash -c "apt-get update && apt-get install -y curl && ./bin/installdependencies.sh && ./config.sh --unattended --name $unique_runner_name --url ${{github.event.repository.html_url}} --pat ${{secrets.PAT}} --labels $unique_runner_name --replace"'
|
|
||||||
env:
|
|
||||||
RUNNER_ALLOW_RUNASROOT: 1
|
|
||||||
unique_runner_name: linux-arm64-${{needs.init.outputs.unique_runner_label}}
|
|
||||||
|
|
||||||
- name: Start Runner and Wait for Job
|
|
||||||
timeout-minutes: 5
|
|
||||||
uses: docker://multiarch/ubuntu-core:arm64-bionic
|
|
||||||
with:
|
|
||||||
args: 'bash -c "apt-get update && apt-get install -y curl git && ./bin/installdependencies.sh && ./run.sh --once"'
|
|
||||||
env:
|
|
||||||
RUNNER_ALLOW_RUNASROOT: 1
|
|
||||||
|
|
||||||
- name: Remove Runner
|
|
||||||
if: always()
|
|
||||||
continue-on-error: true
|
|
||||||
uses: docker://multiarch/ubuntu-core:arm64-bionic
|
|
||||||
with:
|
|
||||||
args: 'bash -c "apt-get update && apt-get install -y curl && ./bin/installdependencies.sh && ./config.sh remove --pat ${{secrets.PAT}}"'
|
|
||||||
env:
|
|
||||||
RUNNER_ALLOW_RUNASROOT: 1
|
|
||||||
|
|
||||||
- name: Upload Runner Logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: linux_arm64_logs
|
|
||||||
path: _diag
|
|
||||||
|
|
||||||
WindowsE2E:
|
|
||||||
needs: [build, init]
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- name: Download Runner
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: runner-package-win-x64
|
|
||||||
- name: Unzip Runner Package
|
|
||||||
run: |
|
|
||||||
Get-ChildItem *.zip | Expand-Archive -DestinationPath $PWD
|
|
||||||
- name: Configure Runner
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
config.cmd --unattended --url ${{github.event.repository.html_url}} --name %unique_runner_name% --pat ${{secrets.PAT}} --labels %unique_runner_name% --replace
|
|
||||||
env:
|
|
||||||
unique_runner_name: win-x64-${{needs.init.outputs.unique_runner_label}}
|
|
||||||
|
|
||||||
- name: Start Runner and Wait for Job
|
|
||||||
shell: cmd
|
|
||||||
timeout-minutes: 5
|
|
||||||
run: |
|
|
||||||
run.cmd --once
|
|
||||||
- name: Remove Runner
|
|
||||||
shell: cmd
|
|
||||||
if: always()
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
config.cmd remove --pat ${{secrets.PAT}}
|
|
||||||
- name: Upload Runner Logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: win_x64_logs
|
|
||||||
path: _diag
|
|
||||||
|
|
||||||
check:
|
|
||||||
name: Check runner logs 🕵️♂️
|
|
||||||
needs: [WindowsE2E, LinuxE2E, macOSE2E, ARM64E2E]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Download Linux Runner Logs
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: linux_x64_logs
|
|
||||||
path: linux_x64_logs
|
|
||||||
- name: Download macOS Runner Logs
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: osx_x64_logs
|
|
||||||
path: osx_x64_logs
|
|
||||||
- name: Download Linux ARM64 Runner Logs
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: linux_arm64_logs
|
|
||||||
path: linux_arm64_logs
|
|
||||||
- name: Download Windows Runner Logs
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: win_x64_logs
|
|
||||||
path: win_x64_logs
|
|
||||||
- name: Check Runner Logs
|
|
||||||
run: |
|
|
||||||
function failed()
|
|
||||||
{
|
|
||||||
local error=${1:-Undefined error}
|
|
||||||
echo "Failed: $error" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
grep -R "completed with result: Succeeded" ./win_x64_logs || failed "Windows Runner fail to run the job, please check logs"
|
|
||||||
grep -R "completed with result: Succeeded" ./linux_x64_logs || failed "Linux Runner fail to run the job, please check logs"
|
|
||||||
grep -R "completed with result: Succeeded" ./osx_x64_logs || failed "macOS Runner fail to run the job, please check logs"
|
|
||||||
grep -R "completed with result: Succeeded" ./linux_arm64_logs || failed "Linux ARM64 Runner fail to run the job, please check logs"
|
|
||||||
32
.github/workflows/release.yml
vendored
32
.github/workflows/release.yml
vendored
@@ -45,12 +45,6 @@ jobs:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
needs: check
|
needs: check
|
||||||
outputs:
|
|
||||||
linux-x64-sha: ${{ steps.sha.outputs.linux-x64-sha256 }}
|
|
||||||
linux-arm64-sha: ${{ steps.sha.outputs.linux-arm64-sha256 }}
|
|
||||||
linux-arm-sha: ${{ steps.sha.outputs.linux-arm-sha256 }}
|
|
||||||
win-x64-sha: ${{ steps.sha.outputs.win-x64-sha256 }}
|
|
||||||
osx-x64-sha: ${{ steps.sha.outputs.osx-x64-sha256 }}
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
||||||
@@ -107,19 +101,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: runner-packages
|
name: runner-packages
|
||||||
path: _package
|
path: _package
|
||||||
# compute shas and set as job outputs to use in release notes
|
|
||||||
- run: brew install coreutils #needed for shasum util
|
|
||||||
if: ${{ matrix.os == 'macOS-latest' }}
|
|
||||||
name: Install Dependencies for SHA Calculation (osx)
|
|
||||||
- run: |
|
|
||||||
file=$(ls)
|
|
||||||
sha=$(sha256sum $file | awk '{ print $1 }')
|
|
||||||
echo "Computed sha256: $sha for $file"
|
|
||||||
echo "::set-output name=${{matrix.runtime}}-sha256::$sha"
|
|
||||||
shell: bash
|
|
||||||
id: sha
|
|
||||||
name: Compute SHA256
|
|
||||||
working-directory: _package
|
|
||||||
release:
|
release:
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -144,15 +126,11 @@ jobs:
|
|||||||
const core = require('@actions/core')
|
const core = require('@actions/core')
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const runnerVersion = fs.readFileSync('${{ github.workspace }}/src/runnerversion', 'utf8').replace(/\n$/g, '')
|
const runnerVersion = fs.readFileSync('${{ github.workspace }}/src/runnerversion', 'utf8').replace(/\n$/g, '')
|
||||||
var releaseNote = fs.readFileSync('${{ github.workspace }}/releaseNote.md', 'utf8').replace(/<RUNNER_VERSION>/g, runnerVersion)
|
const releaseNote = fs.readFileSync('${{ github.workspace }}/releaseNote.md', 'utf8').replace(/<RUNNER_VERSION>/g, runnerVersion)
|
||||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA>/g, '${{needs.build.outputs.win-x64-sha}}')
|
|
||||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA>/g, '${{needs.build.outputs.osx-x64-sha}}')
|
|
||||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA>/g, '${{needs.build.outputs.linux-x64-sha}}')
|
|
||||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA>/g, '${{needs.build.outputs.linux-arm-sha}}')
|
|
||||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA>/g, '${{needs.build.outputs.linux-arm64-sha}}')
|
|
||||||
console.log(releaseNote)
|
console.log(releaseNote)
|
||||||
core.setOutput('version', runnerVersion);
|
core.setOutput('version', runnerVersion);
|
||||||
core.setOutput('note', releaseNote);
|
core.setOutput('note', releaseNote);
|
||||||
|
|
||||||
# Create GitHub release
|
# Create GitHub release
|
||||||
- uses: actions/create-release@master
|
- uses: actions/create-release@master
|
||||||
id: createRelease
|
id: createRelease
|
||||||
@@ -215,4 +193,4 @@ jobs:
|
|||||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
asset_path: ${{ github.workspace }}/actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_path: ${{ github.workspace }}/actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
31
.github/workflows/runner-basic-e2e-test-case.yml
vendored
31
.github/workflows/runner-basic-e2e-test-case.yml
vendored
@@ -1,31 +0,0 @@
|
|||||||
name: Runner Basics Test Case
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
target_runner:
|
|
||||||
description: 'Self-hosted runner will run the job'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on:
|
|
||||||
- self-hosted
|
|
||||||
- ${{github.event.inputs.target_runner}}
|
|
||||||
|
|
||||||
name: Runner Basic Test 🛠
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Run a one-line script
|
|
||||||
run: echo Hello, world!
|
|
||||||
- name: Run a multi-line script
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
printenv|sort
|
|
||||||
cat $GITHUB_EVENT_PATH
|
|
||||||
- name: Validate GitHub Context
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
declare -a context_vars=("GITHUB_ACTION" "GITHUB_ACTIONS" "GITHUB_REPOSITORY" "GITHUB_WORKSPACE" "GITHUB_SHA" "GITHUB_RUN_ID" "GITHUB_RUN_NUMBER")
|
|
||||||
for var in ${context_vars[@]};
|
|
||||||
do [ -z "${!var}" ] && echo "##[error]$var not found" && exit 1 || echo "$var: ${!var}"; done
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
* @actions/actions-runtime
|
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
# GitHub Actions Runner
|
# GitHub Actions Runner
|
||||||
|
|
||||||
[](https://github.com/actions/runner/actions)
|
[](https://github.com/actions/runner/actions)
|
||||||
[](https://github.com/actions/runner/actions)
|
|
||||||
|
|
||||||
The runner is the application that runs a job from a GitHub Actions workflow. It is used by GitHub Actions in the [hosted virtual environments](https://github.com/actions/virtual-environments), or you can [self-host the runner](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners) in your own environment.
|
The runner is the application that runs a job from a GitHub Actions workflow. It is used by GitHub Actions in the [hosted virtual environments](https://github.com/actions/virtual-environments), or you can [self-host the runner](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners) in your own environment.
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ These are described in detail below:
|
|||||||
- http://proxy.com
|
- http://proxy.com
|
||||||
- http://127.0.0.1:8080
|
- http://127.0.0.1:8080
|
||||||
- http://user:password@proxy.com
|
- http://user:password@proxy.com
|
||||||
- `no_proxy` a comma separated list of hosts that should not use the proxy. An optional port may be specified
|
- `no_proxy` a comma seperated list of hosts that should not use the proxy. An optional port may be specified
|
||||||
- `google.com`
|
- `google.com`
|
||||||
- `yahoo.com:443`
|
- `yahoo.com:443`
|
||||||
- `google.com,bing.com`
|
- `google.com,bing.com`
|
||||||
@@ -31,9 +31,9 @@ We won't use `http_proxy` for https traffic when `https_proxy` is not set, this
|
|||||||
Otherwise action authors and workflow users need to adjust to differences between the runner proxy convention, and tools used by their actions and scripts.
|
Otherwise action authors and workflow users need to adjust to differences between the runner proxy convention, and tools used by their actions and scripts.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Customer set `http_proxy=http://127.0.0.1:8888` and configure the runner against `https://github.com/owner/repo`, with the `https_proxy` -> `http_proxy` fallback, the runner will connect to the server without any problem. However, if a user runs `git push` to `https://github.com/owner/repo`, `git` won't use the proxy since it requires `https_proxy` to be set for any https traffic.
|
Customer set `http_proxy=http://127.0.0.1:8888` and configure the runner against `https://github.com/owner/repo`, with the `https_proxy` -> `http_proxy` fallback, the runner will connect to server without any problem. However, if user runs `git push` to `https://github.com/owner/repo`, `git` won't use the proxy since it require `https_proxy` to be set for any https traffic.
|
||||||
|
|
||||||
> `golang`, `node.js` and other dev tools from the linux community use `http_proxy` for both http and https traffic based on my research.
|
> `golang`, `node.js` and other dev tools from the linux community use `http_proxy` for both http and https traffic base on my research.
|
||||||
|
|
||||||
A majority of our users are using Linux where these variables are commonly required to be set by various programs. By reading these values, we simplify the process for self hosted runners to set up proxy, and expose it in a way users are already familiar with.
|
A majority of our users are using Linux where these variables are commonly required to be set by various programs. By reading these values, we simplify the process for self hosted runners to set up proxy, and expose it in a way users are already familiar with.
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ We will support the lowercase and uppercase variants, with lowercase taking prio
|
|||||||
|
|
||||||
### No Proxy Format
|
### No Proxy Format
|
||||||
|
|
||||||
While exact implementations are different per application on handle `no_proxy` env, most applications accept a comma separated list of hosts. Some accept wildcard characters (*). We are going to do exact case-insensitive matches, and not support wildcards at this time.
|
While exact implementations are different per application on handle `no_proxy` env, most applications accept a comma separated list of hosts. Some accept wildcard characters (*). We are going to do exact case-insentive matches, and not support wildcards at this time.
|
||||||
For example:
|
For example:
|
||||||
- example.com will match example.com, foo.example.com, foo.bar.example.com
|
- example.com will match example.com, foo.example.com, foo.bar.example.com
|
||||||
- foo.example.com will match bar.foo.example.com and foo.example.com
|
- foo.example.com will match bar.foo.example.com and foo.example.com
|
||||||
@@ -57,5 +57,5 @@ We will not support IP addresses for `no_proxy`, only hostnames.
|
|||||||
3. The runner will read from the environmental variables during config and runtime and use the provided proxy if it exists
|
3. The runner will read from the environmental variables during config and runtime and use the provided proxy if it exists
|
||||||
4. Users may need to pass these environmental variables into other applications if they do not natively take these variables
|
4. Users may need to pass these environmental variables into other applications if they do not natively take these variables
|
||||||
5. Action authors may need to update their workflows to react to the these environment variables
|
5. Action authors may need to update their workflows to react to the these environment variables
|
||||||
6. We will document the way of setting environmental variables for runners using the environment variables and how the runner uses them
|
6. We will document the way of setting environmental variables for runners using the environmental variables and how the runner uses them
|
||||||
7. Like all other secrets, users will be able to relatively easily figure out proxy password if they can modify a workflow file running on a self hosted machine
|
7. Like all other secrets, users will be able to relatively easily figure out proxy password if they can modify a workflow file running on a self hosted machine
|
||||||
@@ -34,7 +34,7 @@ A way out for rare cases where scoping is a problem.
|
|||||||
|
|
||||||
`##[remove-matcher]owner`
|
`##[remove-matcher]owner`
|
||||||
|
|
||||||
For this to be usable, the `owner` needs to be discoverable. Therefore, debug print the owner on registration.
|
For the this to be usable, the `owner` needs to be discoverable. Therefore, debug print the owner on registration.
|
||||||
|
|
||||||
### Single line matcher
|
### Single line matcher
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ Solving this problem means:
|
|||||||
- Use the `github.workspace` (where the repo is cloned on disk)
|
- Use the `github.workspace` (where the repo is cloned on disk)
|
||||||
- Match against a repository to determine the relative path within the repo
|
- Match against a repository to determine the relative path within the repo
|
||||||
|
|
||||||
This is a place where we diverge from VSCode. VSCode task configurations are specific to the local workspace (workspace root is known or can be specified). We're solving a more generic problem, so we need more information - specifically the `fromPath` property - in order to accurately root the path.
|
This is a place where we diverge from VSCode. VSCode task configuration are specific to the local workspace (workspace root is known or can be specified). We're solving a more generic problem, so we need more information - specifically the `fromPath` property - in order to accurately root the path.
|
||||||
|
|
||||||
In order to avoid creating inaccurate hyperlinks on the error issues, the agent will verify the file exists and is in the main repository. Otherwise omit the file property from the error issue and debug trace what happened.
|
In order to avoid creating inaccurate hyperlinks on the error issues, the agent will verify the file exists and is in the main repository. Otherwise omit the file property from the error issue and debug trace what happened.
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ Problem matchers are unable to interpret severity strings other than `warning` a
|
|||||||
|
|
||||||
However some tools indicate error/warning in different ways. For example `flake8` uses codes like `E100`, `W200`, and `F300` (error, warning, fatal, respectively).
|
However some tools indicate error/warning in different ways. For example `flake8` uses codes like `E100`, `W200`, and `F300` (error, warning, fatal, respectively).
|
||||||
|
|
||||||
Therefore, allow a property `severity`, sibling to `owner`, which identifies the default severity for the problem matcher. This allows two problem matchers to be registered - one for warnings and one for errors.
|
Therefore, allow a property `severity`, sibling to `owner`, which identifies the default severity for the problem matcher. This allows two problem matchers are registered - one for warnings and one for errors.
|
||||||
|
|
||||||
For example, given the following `flake8` output:
|
For example, given the following `flake8` output:
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ powershell/pwsh
|
|||||||
- Users can always opt out by not using the builtins, and providing a shell option like: `pwsh -File {0}`, or `powershell -Command "& '{0}'"`, depending on need
|
- Users can always opt out by not using the builtins, and providing a shell option like: `pwsh -File {0}`, or `powershell -Command "& '{0}'"`, depending on need
|
||||||
|
|
||||||
cmd
|
cmd
|
||||||
- There doesn't seem to be a way to fully opt in to fail-fast behavior other than writing your script to check each error code and respond accordingly, so we can't actually provide that behavior by default, it will be completely up to the user to write this behavior into their script
|
- There doesnt seem to be a way to fully opt in to fail-fast behavior other than writing your script to check each error code and respond accordingly, so we cant actually provide that behavior by default, it will be completely up to the user to write this behavior into their script
|
||||||
- cmd.exe will exit (return the error code to the runner) with the errorlevel of the last program it executed. This is internally consistent with the previous default behavior (sh, pwsh) and is the cmd.exe default, so we keep that behavior
|
- cmd.exe will exit (return the error code to the runner) with the errorlevel of the last program it executed. This is internally consistent with the previous default behavior (sh, pwsh) and is the cmd.exe default, so we keep that behavior
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ This gives us good coverage across the board for secrets and secrets with a pref
|
|||||||
|
|
||||||
However, we don't have great coverage for cases where the secret has a string appended to it before it is base64 encoded (i.e.: `base64($pass\n))`).
|
However, we don't have great coverage for cases where the secret has a string appended to it before it is base64 encoded (i.e.: `base64($pass\n))`).
|
||||||
|
|
||||||
Most notably we've seen this as a result of user error where a user accidentally appends a newline or space character before encoding their secret in base64.
|
Most notably we've seen this as a result of user error where a user accidentially appends a newline or space character before encoding their secret in base64.
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
@@ -45,4 +45,4 @@ This will result in us only revealing length or bit information when a prefix or
|
|||||||
|
|
||||||
- In the case where a secret has a prefix or suffix added before base64 encoding, we may now reveal up to 20 bits of information and the length of the original string modulo 3, rather then the original 16 bits and no length information
|
- In the case where a secret has a prefix or suffix added before base64 encoding, we may now reveal up to 20 bits of information and the length of the original string modulo 3, rather then the original 16 bits and no length information
|
||||||
- Secrets with a suffix appended before encoding will now be masked across the board. Previously it was only masked if it was a multiple of 3 characters
|
- Secrets with a suffix appended before encoding will now be masked across the board. Previously it was only masked if it was a multiple of 3 characters
|
||||||
- Performance will suffer in a negligible way
|
- Performance will suffer in a neglible way
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
|
|
||||||
# Actions Connection Check
|
|
||||||
|
|
||||||
## What is this check for?
|
|
||||||
|
|
||||||
Make sure the runner has access to actions service for GitHub.com or GitHub Enterprise Server
|
|
||||||
|
|
||||||
- For GitHub.com
|
|
||||||
- The runner needs to access https://api.github.com for downloading actions.
|
|
||||||
- The runner needs to access https://vstoken.actions.githubusercontent.com/_apis/.../ for requesting an access token.
|
|
||||||
- The runner needs to access https://pipelines.actions.githubusercontent.com/_apis/.../ for receiving workflow jobs.
|
|
||||||
- For GitHub Enterprise Server
|
|
||||||
- The runner needs to access https://myGHES.com/api/v3 for downloading actions.
|
|
||||||
- The runner needs to access https://myGHES.com/_services/vstoken/_apis/.../ for requesting an access token.
|
|
||||||
- The runner needs to access https://myGHES.com/_services/pipelines/_apis/.../ for receiving workflow jobs.
|
|
||||||
|
|
||||||
## What is checked?
|
|
||||||
|
|
||||||
- DNS lookup for api.github.com or myGHES.com using dotnet
|
|
||||||
- Ping api.github.com or myGHES.com using dotnet
|
|
||||||
- Make HTTP GET to https://api.github.com or https://myGHES.com/api/v3 using dotnet, check response headers contains `X-GitHub-Request-Id`
|
|
||||||
---
|
|
||||||
- DNS lookup for vstoken.actions.githubusercontent.com using dotnet
|
|
||||||
- Ping vstoken.actions.githubusercontent.com using dotnet
|
|
||||||
- Make HTTP GET to https://vstoken.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/vstoken/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
|
||||||
---
|
|
||||||
- DNS lookup for pipelines.actions.githubusercontent.com using dotnet
|
|
||||||
- Ping pipelines.actions.githubusercontent.com using dotnet
|
|
||||||
- Make HTTP GET to https://pipelines.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/pipelines/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
|
||||||
- Make HTTP POST to https://pipelines.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/pipelines/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
|
||||||
|
|
||||||
## How to fix the issue?
|
|
||||||
|
|
||||||
### 1. Check the common network issue
|
|
||||||
|
|
||||||
> Please check the [network doc](./network.md)
|
|
||||||
|
|
||||||
### 2. SSL certificate related issue
|
|
||||||
|
|
||||||
If you are seeing `System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.` in the log, it means the runner can't connect to Actions service due to SSL handshake failure.
|
|
||||||
> Please check the [SSL cert doc](./sslcert.md)
|
|
||||||
|
|
||||||
## Still not working?
|
|
||||||
|
|
||||||
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# Git Connection Check
|
|
||||||
|
|
||||||
## What is this check for?
|
|
||||||
|
|
||||||
Make sure `git` can access GitHub.com or your GitHub Enterprise Server.
|
|
||||||
|
|
||||||
|
|
||||||
## What is checked?
|
|
||||||
|
|
||||||
The test is done by executing
|
|
||||||
```bash
|
|
||||||
# For GitHub.com
|
|
||||||
git ls-remote --exit-code https://github.com/actions/checkout HEAD
|
|
||||||
|
|
||||||
# For GitHub Enterprise Server
|
|
||||||
git ls-remote --exit-code https://ghes.me/actions/checkout HEAD
|
|
||||||
```
|
|
||||||
|
|
||||||
The test also set environment variable `GIT_TRACE=1` and `GIT_CURL_VERBOSE=1` before running `git ls-remote`, this will make `git` to produce debug log for better debug any potential issues.
|
|
||||||
|
|
||||||
## How to fix the issue?
|
|
||||||
|
|
||||||
### 1. Check the common network issue
|
|
||||||
|
|
||||||
> Please check the [network doc](./network.md)
|
|
||||||
|
|
||||||
### 2. SSL certificate related issue
|
|
||||||
|
|
||||||
If you are seeing `SSL Certificate problem:` in the log, it means the `git` can't connect to the GitHub server due to SSL handshake failure.
|
|
||||||
> Please check the [SSL cert doc](./sslcert.md)
|
|
||||||
|
|
||||||
## Still not working?
|
|
||||||
|
|
||||||
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# Internet Connection Check
|
|
||||||
|
|
||||||
## What is this check for?
|
|
||||||
|
|
||||||
Make sure the runner has access to https://api.github.com
|
|
||||||
|
|
||||||
The runner needs to access https://api.github.com to download any actions from the marketplace.
|
|
||||||
|
|
||||||
Even the runner is configured to GitHub Enterprise Server, the runner can still download actions from GitHub.com with [GitHub Connect](https://docs.github.com/en/enterprise-server@2.22/admin/github-actions/enabling-automatic-access-to-githubcom-actions-using-github-connect)
|
|
||||||
|
|
||||||
|
|
||||||
## What is checked?
|
|
||||||
|
|
||||||
- DNS lookup for api.github.com using dotnet
|
|
||||||
- Ping api.github.com using dotnet
|
|
||||||
- Make HTTP GET to https://api.github.com using dotnet, check response headers contains `X-GitHub-Request-Id`
|
|
||||||
|
|
||||||
## How to fix the issue?
|
|
||||||
|
|
||||||
### 1. Check the common network issue
|
|
||||||
|
|
||||||
> Please check the [network doc](./network.md)
|
|
||||||
|
|
||||||
## Still not working?
|
|
||||||
|
|
||||||
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
## Common Network Related Issues
|
|
||||||
|
|
||||||
### Common things that can cause the runner to not working properly
|
|
||||||
|
|
||||||
- Bug in the runner or the dotnet framework that causes actions runner can't make Http request in a certain network environment.
|
|
||||||
|
|
||||||
- Proxy/Firewall block certain HTTP method, like it block all POST and PUT calls which the runner will use to upload logs.
|
|
||||||
|
|
||||||
- Proxy/Firewall only allows requests with certain user-agent to pass through and the actions runner user-agent is not in the allow list.
|
|
||||||
|
|
||||||
- Proxy try to decrypt and exam HTTPS traffic for security purpose but cause the actions-runner to fail to finish SSL handshake due to the lack of trusting proxy's CA.
|
|
||||||
|
|
||||||
- Proxy try to modify the HTTPS request (like add or change some http headers) and causes the request become incompatible with the Actions Service (ASP.NetCore), Ex: [Nginx](https://github.com/dotnet/aspnetcore/issues/17081)
|
|
||||||
|
|
||||||
- Firewall rules that block action runner from accessing certain hosts, ex: `*.github.com`, `*.actions.githubusercontent.com`, etc.
|
|
||||||
|
|
||||||
|
|
||||||
### Identify and solve these problems
|
|
||||||
|
|
||||||
The key is to figure out where is the problem, the network environment, or the actions runner?
|
|
||||||
|
|
||||||
Use a 3rd party tool to make the same requests as the runner did would be a good start point.
|
|
||||||
|
|
||||||
- Use `nslookup` to check DNS
|
|
||||||
- Use `ping` to check Ping
|
|
||||||
- Use `traceroute`, `tracepath`, or `tracert` to check the network route between the runner and the Actions service
|
|
||||||
- Use `curl -v` to check the network stack, good for verifying default certificate/proxy settings.
|
|
||||||
- Use `Invoke-WebRequest` from `pwsh` (`PowerShell Core`) to check the dotnet network stack, good for verifying bugs in the dotnet framework.
|
|
||||||
|
|
||||||
If the 3rd party tool is also experiencing the same error as the runner does, then you might want to contact your network administrator for help.
|
|
||||||
|
|
||||||
Otherwise, contact GitHub customer support or log an issue at https://github.com/actions/runner
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# Node.js Connection Check
|
|
||||||
|
|
||||||
## What is this check for?
|
|
||||||
|
|
||||||
Make sure the built-in node.js has access to GitHub.com or GitHub Enterprise Server.
|
|
||||||
|
|
||||||
The runner carries it's own copy of node.js executable under `<runner_root>/externals/node12/`.
|
|
||||||
|
|
||||||
All javascript base Actions will get executed by the built-in `node` at `<runner_root>/externals/node12/`.
|
|
||||||
|
|
||||||
> Not the `node` from `$PATH`
|
|
||||||
|
|
||||||
## What is checked?
|
|
||||||
|
|
||||||
- Make HTTPS GET to https://api.github.com or https://myGHES.com/api/v3 using node.js, make sure it gets 200 response code.
|
|
||||||
|
|
||||||
## How to fix the issue?
|
|
||||||
|
|
||||||
### 1. Check the common network issue
|
|
||||||
|
|
||||||
> Please check the [network doc](./network.md)
|
|
||||||
|
|
||||||
### 2. SSL certificate related issue
|
|
||||||
|
|
||||||
If you are seeing `Https request failed due to SSL cert issue` in the log, it means the `node.js` can't connect to the GitHub server due to SSL handshake failure.
|
|
||||||
> Please check the [SSL cert doc](./sslcert.md)
|
|
||||||
|
|
||||||
## Still not working?
|
|
||||||
|
|
||||||
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
## SSL Certificate Related Issues
|
|
||||||
|
|
||||||
You might run into an SSL certificate error when your GitHub Enterprise Server is using a self-signed SSL server certificate or a web proxy within your network is decrypting HTTPS traffic for a security audit.
|
|
||||||
|
|
||||||
As long as your certificate is generated properly, most of the issues should be fixed after your trust the certificate properly on the runner machine.
|
|
||||||
|
|
||||||
> Different OS might have extra requirements on SSL certificate,
|
|
||||||
> Ex: macOS requires `ExtendedKeyUsage` https://support.apple.com/en-us/HT210176
|
|
||||||
|
|
||||||
### Don't skip SSL cert validation
|
|
||||||
|
|
||||||
> !!! DO NOT SKIP SSL CERT VALIDATION !!!
|
|
||||||
> !!! IT IS A BAD SECURITY PRACTICE !!!
|
|
||||||
|
|
||||||
### Download SSL certificate chain
|
|
||||||
|
|
||||||
Depends on how your SSL server certificate gets configured, you might need to download the whole certificate chain from a machine that has trusted the SSL certificate's CA.
|
|
||||||
|
|
||||||
- Approach 1: Download certificate chain using a browser (Chrome, Firefox, IT), you can google for more example, [here is what I found](https://medium.com/@menakajain/export-download-ssl-certificate-from-server-site-url-bcfc41ea46a2)
|
|
||||||
|
|
||||||
- Approach 2: Download certificate chain using OpenSSL, you can google for more example, [here is what I found](https://superuser.com/a/176721)
|
|
||||||
|
|
||||||
- Approach 3: Ask your network administrator or the owner of the CA certificate to send you a copy of it
|
|
||||||
|
|
||||||
### Trust CA certificate for the Runner
|
|
||||||
|
|
||||||
The actions runner is a dotnet core application which will follow how dotnet load SSL CA certificates on each OS.
|
|
||||||
|
|
||||||
You can get full details documentation at [here](https://docs.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography#x509store)
|
|
||||||
|
|
||||||
In short:
|
|
||||||
- Windows: Load from Windows certificate store.
|
|
||||||
- Linux: Load from OpenSSL CA cert bundle.
|
|
||||||
- macOS: Load from macOS KeyChain.
|
|
||||||
|
|
||||||
To let the runner trusts your CA certificate, you will need to:
|
|
||||||
1. Save your SSL certificate chain which includes the root CA and all intermediate CAs into a `.pem` file.
|
|
||||||
2. Use `OpenSSL` to convert `.pem` file to a proper format for different OS, here is some [doc with sample commands](https://www.sslshopper.com/ssl-converter.html)
|
|
||||||
3. Trust CA on different OS:
|
|
||||||
- Windows: https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate
|
|
||||||
- macOS: 
|
|
||||||
- Linux: Refer to the distribution documentation
|
|
||||||
1. RedHat: https://www.redhat.com/sysadmin/ca-certificates-cli
|
|
||||||
2. Ubuntu: http://manpages.ubuntu.com/manpages/focal/man8/update-ca-certificates.8.html
|
|
||||||
3. Google search: "trust ca certificate on [linux distribution]"
|
|
||||||
4. If all approaches failed, set environment variable `SSL_CERT_FILE` to the CA bundle `.pem` file we get.
|
|
||||||
> To verity cert gets installed properly on Linux, you can try use `curl -v https://sitewithsslissue.com` and `pwsh -Command \"Invoke-WebRequest -Uri https://sitewithsslissue.com\"`
|
|
||||||
|
|
||||||
### Trust CA certificate for Git CLI
|
|
||||||
|
|
||||||
Git uses various CA bundle file depends on your operation system.
|
|
||||||
- Git packaged the CA bundle file within the Git installation on Windows
|
|
||||||
- Git use OpenSSL certificate CA bundle file on Linux and macOS
|
|
||||||
|
|
||||||
You can check where Git check CA file by running:
|
|
||||||
```bash
|
|
||||||
export GIT_CURL_VERBOSE=1
|
|
||||||
git ls-remote https://github.com/actions/runner HEAD
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see something like:
|
|
||||||
```
|
|
||||||
* Couldn't find host github.com in the .netrc file; using defaults
|
|
||||||
* Trying 140.82.114.4...
|
|
||||||
* TCP_NODELAY set
|
|
||||||
* Connected to github.com (140.82.114.4) port 443 (#0)
|
|
||||||
* ALPN, offering h2
|
|
||||||
* ALPN, offering http/1.1
|
|
||||||
* successfully set certificate verify locations:
|
|
||||||
* CAfile: /etc/ssl/cert.pem
|
|
||||||
CApath: none
|
|
||||||
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
|
|
||||||
```
|
|
||||||
This tells me `/etc/ssl/cert.pem` is where it read trusted CA certificates.
|
|
||||||
|
|
||||||
To let Git trusts your CA certificate, you will need to:
|
|
||||||
1. Save your SSL certificate chain which includes the root CA and all intermediate CAs into a `.pem` file.
|
|
||||||
2. Set `http.sslCAInfo` Git config or `GIT_SSL_CAINFO` environment variable to the full path of the `.pem` file [Git Doc](https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpsslCAInfo)
|
|
||||||
> I would recommend using `http.sslCAInfo` since it can be scope to certain hosts that need the extra trusted CA.
|
|
||||||
> Ex: `git config --global http.https://myghes.com/.sslCAInfo /extra/ca/cert.pem`
|
|
||||||
> This will make Git use the `/extra/ca/cert.pem` only when communicates with `https://myghes.com` and keep using the default CA bundle with others.
|
|
||||||
|
|
||||||
### Trust CA certificate for Node.js
|
|
||||||
|
|
||||||
Node.js has compiled a snapshot of the Mozilla CA store that is fixed at each version of Node.js' release time.
|
|
||||||
|
|
||||||
To let Node.js trusts your CA certificate, you will need to:
|
|
||||||
1. Save your SSL certificate chain which includes the root CA and all intermediate CAs into a `.pem` file.
|
|
||||||
2. Set environment variable `NODE_EXTRA_CA_CERTS` which point to the file. ex: `export NODE_EXTRA_CA_CERTS=/full/path/to/cacert.pem` or `set NODE_EXTRA_CA_CERTS=C:\full\path\to\cacert.pem`
|
|
||||||
@@ -14,7 +14,7 @@ Issues in this repository should be for the runner application. Note that the V
|
|||||||
|
|
||||||
We ask that before significant effort is put into code changes, that we have agreement on taking the change before time is invested in code changes.
|
We ask that before significant effort is put into code changes, that we have agreement on taking the change before time is invested in code changes.
|
||||||
|
|
||||||
1. Create a feature request. Once agreed we will take the enhancement
|
1. Create a feature request. Once agreed we will take the enhancment
|
||||||
2. Create an ADR to agree on the details of the change.
|
2. Create an ADR to agree on the details of the change.
|
||||||
|
|
||||||
An ADR is an Architectural Decision Record. This allows consensus on the direction forward and also serves as a record of the change and motivation. [Read more here](adrs/README.md)
|
An ADR is an Architectural Decision Record. This allows consensus on the direction forward and also serves as a record of the change and motivation. [Read more here](adrs/README.md)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 MiB |
@@ -1,16 +1,11 @@
|
|||||||
## Features
|
## Features
|
||||||
- Verify the Runner Hash during auto-upgrade before installing the new runner version (#967)
|
- N/A
|
||||||
- Support download of runners from authenticated endpoints (#920)
|
|
||||||
- Enabled tty output in Docker Actions (#916)
|
|
||||||
- Added '--check' command to verify runner connectivity (#949)
|
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
- Fix usage of /dev/null and ping in run.sh (#968)
|
- Raise error for set-env, block set node_options using `::set-env::` (#784)
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
- Updated the copy for various runner messages (#972)
|
- N/A
|
||||||
- Added the runner's OS to telemetry (#939)
|
|
||||||
- Various other telemetry improvements (#935)
|
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
@@ -72,13 +67,3 @@ tar xzf ./actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz
|
|||||||
|
|
||||||
## Using your self hosted runner
|
## Using your self hosted runner
|
||||||
For additional details about configuring, running, or shutting down the runner please check out our [product docs.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/adding-self-hosted-runners)
|
For additional details about configuring, running, or shutting down the runner please check out our [product docs.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/adding-self-hosted-runners)
|
||||||
|
|
||||||
## SHA-256 Checksums
|
|
||||||
|
|
||||||
The SHA-256 checksums for the packages included in this build are shown below:
|
|
||||||
|
|
||||||
- actions-runner-win-x64-<RUNNER_VERSION>.zip <!-- BEGIN SHA win-x64 --><WIN_X64_SHA><!-- END SHA win-x64 -->
|
|
||||||
- actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA osx-x64 --><OSX_X64_SHA><!-- END SHA osx-x64 -->
|
|
||||||
- actions-runner-linux-x64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-x64 --><LINUX_X64_SHA><!-- END SHA linux-x64 -->
|
|
||||||
- actions-runner-linux-arm64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm64 --><LINUX_ARM64_SHA><!-- END SHA linux-arm64 -->
|
|
||||||
- actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm --><LINUX_ARM_SHA><!-- END SHA linux-arm -->
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.277.0
|
2.273.6
|
||||||
|
|||||||
@@ -12,13 +12,12 @@ set -e
|
|||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# export RUNNER_CFG_PAT=<yourPAT>
|
# export RUNNER_CFG_PAT=<yourPAT>
|
||||||
# ./create-latest-svc scope [ghe_domain] [name] [user] [labels]
|
# ./create-latest-svc scope [ghe_domain] [name] [user]
|
||||||
#
|
#
|
||||||
# scope required repo (:owner/:repo) or org (:organization)
|
# scope required repo (:owner/:repo) or org (:organization)
|
||||||
# ghe_domain optional the fully qualified domain name of your GitHub Enterprise Server deployment
|
# ghe_domain optional the fully qualified domain name of your GitHub Enterprise Server deployment
|
||||||
# name optional defaults to hostname
|
# name optional defaults to hostname
|
||||||
# user optional user svc will run as. defaults to current
|
# user optional user svc will run as. defaults to current
|
||||||
# labels optional list of labels (split by comma) applied on the runner
|
|
||||||
#
|
#
|
||||||
# Notes:
|
# Notes:
|
||||||
# PATS over envvars are more secure
|
# PATS over envvars are more secure
|
||||||
@@ -31,7 +30,6 @@ runner_scope=${1}
|
|||||||
ghe_hostname=${2}
|
ghe_hostname=${2}
|
||||||
runner_name=${3:-$(hostname)}
|
runner_name=${3:-$(hostname)}
|
||||||
svc_user=${4:-$USER}
|
svc_user=${4:-$USER}
|
||||||
labels=${5}
|
|
||||||
|
|
||||||
echo "Configuring runner @ ${runner_scope}"
|
echo "Configuring runner @ ${runner_scope}"
|
||||||
sudo echo
|
sudo echo
|
||||||
@@ -132,8 +130,8 @@ fi
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Configuring ${runner_name} @ $runner_url"
|
echo "Configuring ${runner_name} @ $runner_url"
|
||||||
echo "./config.sh --unattended --url $runner_url --token *** --name $runner_name --labels $labels"
|
echo "./config.sh --unattended --url $runner_url --token *** --name $runner_name"
|
||||||
sudo -E -u ${svc_user} ./config.sh --unattended --url $runner_url --token $RUNNER_TOKEN --name $runner_name --labels $labels
|
sudo -E -u ${svc_user} ./config.sh --unattended --url $runner_url --token $RUNNER_TOKEN --name $runner_name
|
||||||
|
|
||||||
#---------------------------------------
|
#---------------------------------------
|
||||||
# Configuring as a service
|
# Configuring as a service
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
[*.cs]
|
|
||||||
charset = utf-8
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
csharp_new_line_before_else = true
|
|
||||||
csharp_new_line_before_catch = true
|
|
||||||
csharp_new_line_before_finally = true
|
|
||||||
csharp_new_line_before_open_brace = all
|
|
||||||
|
|
||||||
csharp_space_after_keywords_in_control_flow_statements = true
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 16.0.29411.138
|
VisualStudioVersion = 16.0.29411.138
|
||||||
@@ -21,11 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdk", "Sdk\Sdk.csproj", "{D
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{C932061F-F6A1-4F1E-B854-A6C6B30DC3EF}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{C932061F-F6A1-4F1E-B854-A6C6B30DC3EF}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EFB254FC-7927-445E-BA64-6676ADB309E9}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|||||||
313
src/Misc/dotnet-install.ps1
vendored
313
src/Misc/dotnet-install.ps1
vendored
@@ -23,6 +23,8 @@
|
|||||||
Default: latest
|
Default: latest
|
||||||
Represents a build version on specific channel. Possible values:
|
Represents a build version on specific channel. Possible values:
|
||||||
- latest - most latest build on specific channel
|
- latest - most latest build on specific channel
|
||||||
|
- coherent - most latest coherent build on specific channel
|
||||||
|
coherent applies only to SDK downloads
|
||||||
- 3-part version in a format A.B.C - represents specific version of build
|
- 3-part version in a format A.B.C - represents specific version of build
|
||||||
examples: 2.0.0-preview2-006120, 1.1.0
|
examples: 2.0.0-preview2-006120, 1.1.0
|
||||||
.PARAMETER InstallDir
|
.PARAMETER InstallDir
|
||||||
@@ -120,42 +122,24 @@ $VersionRegEx="/\d+\.\d+[^/]+/"
|
|||||||
$OverrideNonVersionedFiles = !$SkipNonVersionedFiles
|
$OverrideNonVersionedFiles = !$SkipNonVersionedFiles
|
||||||
|
|
||||||
function Say($str) {
|
function Say($str) {
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
Write-Host "dotnet-install: $str"
|
Write-Host "dotnet-install: $str"
|
||||||
}
|
}
|
||||||
catch {
|
catch
|
||||||
|
{
|
||||||
# Some platforms cannot utilize Write-Host (Azure Functions, for instance). Fall back to Write-Output
|
# Some platforms cannot utilize Write-Host (Azure Functions, for instance). Fall back to Write-Output
|
||||||
Write-Output "dotnet-install: $str"
|
Write-Output "dotnet-install: $str"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Say-Warning($str) {
|
|
||||||
try {
|
|
||||||
Write-Warning "dotnet-install: $str"
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
# Some platforms cannot utilize Write-Warning (Azure Functions, for instance). Fall back to Write-Output
|
|
||||||
Write-Output "dotnet-install: Warning: $str"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Writes a line with error style settings.
|
|
||||||
# Use this function to show a human-readable comment along with an exception.
|
|
||||||
function Say-Error($str) {
|
|
||||||
try {
|
|
||||||
# Write-Error is quite oververbose for the purpose of the function, let's write one line with error style settings.
|
|
||||||
$Host.UI.WriteErrorLine("dotnet-install: $str")
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Output "dotnet-install: Error: $str"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Say-Verbose($str) {
|
function Say-Verbose($str) {
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
Write-Verbose "dotnet-install: $str"
|
Write-Verbose "dotnet-install: $str"
|
||||||
}
|
}
|
||||||
catch {
|
catch
|
||||||
|
{
|
||||||
# Some platforms cannot utilize Write-Verbose (Azure Functions, for instance). Fall back to Write-Output
|
# Some platforms cannot utilize Write-Verbose (Azure Functions, for instance). Fall back to Write-Output
|
||||||
Write-Output "dotnet-install: $str"
|
Write-Output "dotnet-install: $str"
|
||||||
}
|
}
|
||||||
@@ -172,7 +156,7 @@ function Invoke-With-Retry([ScriptBlock]$ScriptBlock, [int]$MaxAttempts = 3, [in
|
|||||||
|
|
||||||
while ($true) {
|
while ($true) {
|
||||||
try {
|
try {
|
||||||
return & $ScriptBlock
|
return $ScriptBlock.Invoke()
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
$Attempts++
|
$Attempts++
|
||||||
@@ -286,41 +270,18 @@ function GetHTTPResponse([Uri] $Uri)
|
|||||||
# Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out
|
# Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out
|
||||||
# 20 minutes allows it to work over much slower connections.
|
# 20 minutes allows it to work over much slower connections.
|
||||||
$HttpClient.Timeout = New-TimeSpan -Minutes 20
|
$HttpClient.Timeout = New-TimeSpan -Minutes 20
|
||||||
$Task = $HttpClient.GetAsync("${Uri}${FeedCredential}").ConfigureAwait("false");
|
$Response = $HttpClient.GetAsync("${Uri}${FeedCredential}").Result
|
||||||
$Response = $Task.GetAwaiter().GetResult();
|
if (($Response -eq $null) -or (-not ($Response.IsSuccessStatusCode))) {
|
||||||
|
# The feed credential is potentially sensitive info. Do not log FeedCredential to console output.
|
||||||
if (($null -eq $Response) -or (-not ($Response.IsSuccessStatusCode))) {
|
$ErrorMsg = "Failed to download $Uri."
|
||||||
# The feed credential is potentially sensitive info. Do not log FeedCredential to console output.
|
if ($Response -ne $null) {
|
||||||
$DownloadException = [System.Exception] "Unable to download $Uri."
|
$ErrorMsg += " $Response"
|
||||||
|
|
||||||
if ($null -ne $Response) {
|
|
||||||
$DownloadException.Data["StatusCode"] = [int] $Response.StatusCode
|
|
||||||
$DownloadException.Data["ErrorMessage"] = "Unable to download $Uri. Returned HTTP status code: " + $DownloadException.Data["StatusCode"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw $DownloadException
|
throw $ErrorMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
return $Response
|
return $Response
|
||||||
}
|
|
||||||
catch [System.Net.Http.HttpRequestException] {
|
|
||||||
$DownloadException = [System.Exception] "Unable to download $Uri."
|
|
||||||
|
|
||||||
# Pick up the exception message and inner exceptions' messages if they exist
|
|
||||||
$CurrentException = $PSItem.Exception
|
|
||||||
$ErrorMsg = $CurrentException.Message + "`r`n"
|
|
||||||
while ($CurrentException.InnerException) {
|
|
||||||
$CurrentException = $CurrentException.InnerException
|
|
||||||
$ErrorMsg += $CurrentException.Message + "`r`n"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if there is an issue concerning TLS.
|
|
||||||
if ($ErrorMsg -like "*SSL/TLS*") {
|
|
||||||
$ErrorMsg += "Ensure that TLS 1.2 or higher is enabled to use this script.`r`n"
|
|
||||||
}
|
|
||||||
|
|
||||||
$DownloadException.Data["ErrorMessage"] = $ErrorMsg
|
|
||||||
throw $DownloadException
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if ($HttpClient -ne $null) {
|
if ($HttpClient -ne $null) {
|
||||||
@@ -330,7 +291,7 @@ function GetHTTPResponse([Uri] $Uri)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel) {
|
function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel, [bool]$Coherent) {
|
||||||
Say-Invocation $MyInvocation
|
Say-Invocation $MyInvocation
|
||||||
|
|
||||||
$VersionFileUrl = $null
|
$VersionFileUrl = $null
|
||||||
@@ -345,7 +306,12 @@ function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel) {
|
|||||||
$VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version"
|
$VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version"
|
||||||
}
|
}
|
||||||
elseif (-not $Runtime) {
|
elseif (-not $Runtime) {
|
||||||
$VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version"
|
if ($Coherent) {
|
||||||
|
$VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.coherent.version"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw "Invalid value for `$Runtime"
|
throw "Invalid value for `$Runtime"
|
||||||
@@ -354,8 +320,7 @@ function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel) {
|
|||||||
$Response = GetHTTPResponse -Uri $VersionFileUrl
|
$Response = GetHTTPResponse -Uri $VersionFileUrl
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Say-Error "Could not resolve version information."
|
throw "Could not resolve version information."
|
||||||
throw
|
|
||||||
}
|
}
|
||||||
$StringContent = $Response.Content.ReadAsStringAsync().Result
|
$StringContent = $Response.Content.ReadAsStringAsync().Result
|
||||||
|
|
||||||
@@ -381,8 +346,7 @@ function Parse-Jsonfile-For-Version([string]$JSonFile) {
|
|||||||
$JSonContent = Get-Content($JSonFile) -Raw | ConvertFrom-Json | Select-Object -expand "sdk" -ErrorAction SilentlyContinue
|
$JSonContent = Get-Content($JSonFile) -Raw | ConvertFrom-Json | Select-Object -expand "sdk" -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Say-Error "Json file unreadable: '$JSonFile'"
|
throw "Json file unreadable: '$JSonFile'"
|
||||||
throw
|
|
||||||
}
|
}
|
||||||
if ($JSonContent) {
|
if ($JSonContent) {
|
||||||
try {
|
try {
|
||||||
@@ -395,8 +359,7 @@ function Parse-Jsonfile-For-Version([string]$JSonFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Say-Error "Unable to parse the SDK node in '$JSonFile'"
|
throw "Unable to parse the SDK node in '$JSonFile'"
|
||||||
throw
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -412,12 +375,16 @@ function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$Channel,
|
|||||||
Say-Invocation $MyInvocation
|
Say-Invocation $MyInvocation
|
||||||
|
|
||||||
if (-not $JSonFile) {
|
if (-not $JSonFile) {
|
||||||
if ($Version.ToLower() -eq "latest") {
|
switch ($Version.ToLower()) {
|
||||||
$LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel
|
{ $_ -eq "latest" } {
|
||||||
return $LatestVersionInfo.Version
|
$LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $False
|
||||||
}
|
return $LatestVersionInfo.Version
|
||||||
else {
|
}
|
||||||
return $Version
|
{ $_ -eq "coherent" } {
|
||||||
|
$LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $True
|
||||||
|
return $LatestVersionInfo.Version
|
||||||
|
}
|
||||||
|
default { return $Version }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -652,23 +619,6 @@ function DownloadFile($Source, [string]$OutPath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function SafeRemoveFile($Path) {
|
|
||||||
try {
|
|
||||||
if (Test-Path $Path) {
|
|
||||||
Remove-Item $Path
|
|
||||||
Say-Verbose "The temporary file `"$Path`" was removed."
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Say-Verbose "The temporary file `"$Path`" does not exist, therefore is not removed."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Say-Warning "Failed to remove the temporary file: `"$Path`", remove it manually."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolderRelativePath) {
|
function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolderRelativePath) {
|
||||||
$BinPath = Get-Absolute-Path $(Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath)
|
$BinPath = Get-Absolute-Path $(Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath)
|
||||||
if (-Not $NoPath) {
|
if (-Not $NoPath) {
|
||||||
@@ -685,11 +635,6 @@ function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Say "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
|
|
||||||
Say "- The SDK needs to be installed without user interaction and without admin rights."
|
|
||||||
Say "- The SDK installation doesn't need to persist across multiple CI runs."
|
|
||||||
Say "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.`r`n"
|
|
||||||
|
|
||||||
$CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture
|
$CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture
|
||||||
$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -JSonFile $JSonFile
|
$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -JSonFile $JSonFile
|
||||||
$DownloadLink, $EffectiveVersion = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
|
$DownloadLink, $EffectiveVersion = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
|
||||||
@@ -723,7 +668,7 @@ if ($DryRun) {
|
|||||||
Say "NOTE: Due to finding a version manifest with this runtime, it would actually install with version '$EffectiveVersion'"
|
Say "NOTE: Due to finding a version manifest with this runtime, it would actually install with version '$EffectiveVersion'"
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Runtime -eq "dotnet") {
|
if ($Runtime -eq "dotnet") {
|
||||||
@@ -757,7 +702,7 @@ $isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -Relat
|
|||||||
if ($isAssetInstalled) {
|
if ($isAssetInstalled) {
|
||||||
Say "$assetName version $SpecificVersion is already installed."
|
Say "$assetName version $SpecificVersion is already installed."
|
||||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
|
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
|
||||||
return
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
|
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
|
||||||
@@ -765,69 +710,30 @@ New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
|
|||||||
$installDrive = $((Get-Item $InstallRoot).PSDrive.Name);
|
$installDrive = $((Get-Item $InstallRoot).PSDrive.Name);
|
||||||
$diskInfo = Get-PSDrive -Name $installDrive
|
$diskInfo = Get-PSDrive -Name $installDrive
|
||||||
if ($diskInfo.Free / 1MB -le 100) {
|
if ($diskInfo.Free / 1MB -le 100) {
|
||||||
throw "There is not enough disk space on drive ${installDrive}:"
|
Say "There is not enough disk space on drive ${installDrive}:"
|
||||||
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
|
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
|
||||||
Say-Verbose "Zip path: $ZipPath"
|
Say-Verbose "Zip path: $ZipPath"
|
||||||
|
|
||||||
$DownloadFailed = $false
|
$DownloadFailed = $false
|
||||||
|
Say "Downloading link: $DownloadLink"
|
||||||
$PrimaryDownloadStatusCode = 0
|
|
||||||
$LegacyDownloadStatusCode = 0
|
|
||||||
|
|
||||||
$PrimaryDownloadFailedMsg = ""
|
|
||||||
$LegacyDownloadFailedMsg = ""
|
|
||||||
|
|
||||||
Say "Downloading primary link $DownloadLink"
|
|
||||||
try {
|
try {
|
||||||
DownloadFile -Source $DownloadLink -OutPath $ZipPath
|
DownloadFile -Source $DownloadLink -OutPath $ZipPath
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
if ($PSItem.Exception.Data.Contains("StatusCode")) {
|
Say "Cannot download: $DownloadLink"
|
||||||
$PrimaryDownloadStatusCode = $PSItem.Exception.Data["StatusCode"]
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($PSItem.Exception.Data.Contains("ErrorMessage")) {
|
|
||||||
$PrimaryDownloadFailedMsg = $PSItem.Exception.Data["ErrorMessage"]
|
|
||||||
} else {
|
|
||||||
$PrimaryDownloadFailedMsg = $PSItem.Exception.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($PrimaryDownloadStatusCode -eq 404) {
|
|
||||||
Say "The resource at $DownloadLink is not available."
|
|
||||||
} else {
|
|
||||||
Say $PSItem.Exception.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
SafeRemoveFile -Path $ZipPath
|
|
||||||
|
|
||||||
if ($LegacyDownloadLink) {
|
if ($LegacyDownloadLink) {
|
||||||
$DownloadLink = $LegacyDownloadLink
|
$DownloadLink = $LegacyDownloadLink
|
||||||
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
|
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
|
||||||
Say-Verbose "Legacy zip path: $ZipPath"
|
Say-Verbose "Legacy zip path: $ZipPath"
|
||||||
Say "Downloading legacy link $DownloadLink"
|
Say "Downloading legacy link: $DownloadLink"
|
||||||
try {
|
try {
|
||||||
DownloadFile -Source $DownloadLink -OutPath $ZipPath
|
DownloadFile -Source $DownloadLink -OutPath $ZipPath
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
if ($PSItem.Exception.Data.Contains("StatusCode")) {
|
Say "Cannot download: $DownloadLink"
|
||||||
$LegacyDownloadStatusCode = $PSItem.Exception.Data["StatusCode"]
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($PSItem.Exception.Data.Contains("ErrorMessage")) {
|
|
||||||
$LegacyDownloadFailedMsg = $PSItem.Exception.Data["ErrorMessage"]
|
|
||||||
} else {
|
|
||||||
$LegacyDownloadFailedMsg = $PSItem.Exception.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($LegacyDownloadStatusCode -eq 404) {
|
|
||||||
Say "The resource at $DownloadLink is not available."
|
|
||||||
} else {
|
|
||||||
Say $PSItem.Exception.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
SafeRemoveFile -Path $ZipPath
|
|
||||||
$DownloadFailed = $true
|
$DownloadFailed = $true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -837,19 +743,7 @@ catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($DownloadFailed) {
|
if ($DownloadFailed) {
|
||||||
if (($PrimaryDownloadStatusCode -eq 404) -and ((-not $LegacyDownloadLink) -or ($LegacyDownloadStatusCode -eq 404))) {
|
throw "Could not find/download: `"$assetName`" with version = $SpecificVersion`nRefer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support"
|
||||||
throw "Could not find `"$assetName`" with version = $SpecificVersion`nRefer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support"
|
|
||||||
} else {
|
|
||||||
# 404-NotFound is an expected response if it goes from only one of the links, do not show that error.
|
|
||||||
# If primary path is available (not 404-NotFound) then show the primary error else show the legacy error.
|
|
||||||
if ($PrimaryDownloadStatusCode -ne 404) {
|
|
||||||
throw "Could not download `"$assetName`" with version = $SpecificVersion`r`n$PrimaryDownloadFailedMsg"
|
|
||||||
}
|
|
||||||
if (($LegacyDownloadLink) -and ($LegacyDownloadStatusCode -ne 404)) {
|
|
||||||
throw "Could not download `"$assetName`" with version = $SpecificVersion`r`n$LegacyDownloadFailedMsg"
|
|
||||||
}
|
|
||||||
throw "Could not download `"$assetName`" with version = $SpecificVersion"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Say "Extracting zip from $DownloadLink"
|
Say "Extracting zip from $DownloadLink"
|
||||||
@@ -871,24 +765,21 @@ if (!$isAssetInstalled) {
|
|||||||
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion
|
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
# Version verification failed. More likely something is wrong either with the downloaded content or with the verification algorithm.
|
|
||||||
if (!$isAssetInstalled) {
|
if (!$isAssetInstalled) {
|
||||||
Say-Error "Failed to verify the version of installed `"$assetName`".`nInstallation source: $DownloadLink.`nInstallation location: $InstallRoot.`nReport the bug at https://github.com/dotnet/install-scripts/issues."
|
|
||||||
throw "`"$assetName`" with version = $SpecificVersion failed to install with an unknown error."
|
throw "`"$assetName`" with version = $SpecificVersion failed to install with an unknown error."
|
||||||
}
|
}
|
||||||
|
|
||||||
SafeRemoveFile -Path $ZipPath
|
Remove-Item $ZipPath
|
||||||
|
|
||||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
|
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
|
||||||
|
|
||||||
Say "Note that the script does not resolve dependencies during installation."
|
|
||||||
Say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install/windows#dependencies"
|
|
||||||
Say "Installation finished"
|
Say "Installation finished"
|
||||||
|
exit 0
|
||||||
# SIG # Begin signature block
|
# SIG # Begin signature block
|
||||||
# MIIjkgYJKoZIhvcNAQcCoIIjgzCCI38CAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
# MIIjkgYJKoZIhvcNAQcCoIIjgzCCI38CAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
||||||
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
||||||
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD2c707qnCLOLIC
|
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAdMJOqDPFy5F1i
|
||||||
# n6Mu5Gr4+Xp68foyZlGlTycnycc5l6CCDYEwggX/MIID56ADAgECAhMzAAABh3IX
|
# HBXPyOE4hGkUv5EGyQzmS901lRr+baCCDYEwggX/MIID56ADAgECAhMzAAABh3IX
|
||||||
# chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
# chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
||||||
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
||||||
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
||||||
@@ -965,50 +856,50 @@ Say "Installation finished"
|
|||||||
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
|
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
|
||||||
# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN
|
# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN
|
||||||
# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
|
# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
|
||||||
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgE/MRhWyu
|
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgGfshXxhl
|
||||||
# Zg+EA2WKcxYC31nHVCTE6guHppZppc70RtkwQgYKKwYBBAGCNwIBDDE0MDKgFIAS
|
# 7+O9cl90lOU62gZCBmJzcomUxEL8+XyoDYQwQgYKKwYBBAGCNwIBDDE0MDKgFIAS
|
||||||
# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN
|
# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN
|
||||||
# BgkqhkiG9w0BAQEFAASCAQBvcYCjRDXUYEIz9j2j0r4GFI2Y3g/CoNxDDBaeQ+gV
|
# BgkqhkiG9w0BAQEFAASCAQCPVhcZxxdIzkFdrv/FCW737QgR8fCO1/oRXwhigOyQ
|
||||||
# khO0fK0oLh18RbV271Mg6SF7X7+mXB5MnL68voVQDqHnsCYrIAuMF/AEpv9YuDDp
|
# P2MF39fIYsVXuzVnO8pYZZOeW04kMECcWf9420okd4lXP7Xc5m+5UrqPuN1UgNle
|
||||||
# ZRJuqN7Vwg3HM02l/FyATBIMgf/V79aYzJL3jjtt9bRIyxk6aPU4XcwMeA4usnUQ
|
# hhwLBiXuZaAfllBMWMeQi7DZmg7XW8Yay9TAbc2XSTGQ8foDxPllKFbdPvvQ2DRy
|
||||||
# rMhIiQz07DgfSrcQWe4AvGFAIvqTAKE4P944EZWWVnWI/10rvatEAefqJZX3XljW
|
# VRLyNNQQEo3IuHHa0nnVNaL2PUYJf0udMCdGkxIMbApAYcitJLSwMLqMzrMkrvS9
|
||||||
# sK/6NY/0MyAyiILOuXbvVS0YFbHaR2qd1jUXbrY79fS+H4Ts6qnbufOkHQvmcDxs
|
# ubm7CgigsKRJ3cZtCtFFMUkMsstoVuKLFtu69OvOfgLy1qmKotE6EnF7xudV+qAA
|
||||||
# 801wKLHumMdPTtMVzfVMCwPvrHP0wtzsFlmCcKjBbGpvoYIS8TCCEu0GCisGAQQB
|
# a+UxGVT715tK5kgb5eTr1K2NdWRj517oANQNOjR/m6OPoYIS8TCCEu0GCisGAQQB
|
||||||
# gjcDAwExghLdMIIS2QYJKoZIhvcNAQcCoIISyjCCEsYCAQMxDzANBglghkgBZQME
|
# gjcDAwExghLdMIIS2QYJKoZIhvcNAQcCoIISyjCCEsYCAQMxDzANBglghkgBZQME
|
||||||
# AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB
|
# AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB
|
||||||
# MDEwDQYJYIZIAWUDBAIBBQAEINdeoXtuzW+Dihw6n+VdG+91si0f6TvWhJXaPtvW
|
# MDEwDQYJYIZIAWUDBAIBBQAEIHYNJoLIl+IWj/Npb6r479Guw3UW/q0/jJhqKgHm
|
||||||
# oF4cAgZfu+i3IT8YEzIwMjAxMjE3MDYzMDM2LjU0M1owBIACAfSggdSkgdEwgc4x
|
# xq1NAgZfdIY1B90YEzIwMjAxMDE0MTcxOTIwLjg5NVowBIACAfSggdSkgdEwgc4x
|
||||||
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
|
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
|
||||||
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p
|
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p
|
||||||
# Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg
|
# Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg
|
||||||
# VFNTIEVTTjo4OTdBLUUzNTYtMTcwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
|
# VFNTIEVTTjo2MEJDLUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
|
||||||
# U3RhbXAgU2VydmljZaCCDkQwggT1MIID3aADAgECAhMzAAABLCKvRZd1+RvuAAAA
|
# U3RhbXAgU2VydmljZaCCDkQwggT1MIID3aADAgECAhMzAAABJt+6SyK5goIHAAAA
|
||||||
# AAEsMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
|
# AAEmMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
|
||||||
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
|
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
|
||||||
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
|
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
|
||||||
# MB4XDTE5MTIxOTAxMTUwM1oXDTIxMDMxNzAxMTUwM1owgc4xCzAJBgNVBAYTAlVT
|
# MB4XDTE5MTIxOTAxMTQ1OVoXDTIxMDMxNzAxMTQ1OVowgc4xCzAJBgNVBAYTAlVT
|
||||||
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
|
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
|
||||||
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy
|
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy
|
||||||
# YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4OTdB
|
# YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo2MEJD
|
||||||
# LUUzNTYtMTcwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj
|
# LUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj
|
||||||
# ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPK1zgSSq+MxAYo3qpCt
|
# ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ4wvoacTvMNlXQTtfF/
|
||||||
# QDxSMPPJy6mm/wfEJNjNUnYtLFBwl1BUS5trEk/t41ldxITKehs+ABxYqo4Qxsg3
|
# Cx5Ol3X0fcjUNMvjLgTmO5+WHYJFbp725P3+qvFKDRQHWEI1Sz0gB24urVDIjXjB
|
||||||
# Gy1ugKiwHAnYiiekfC+ZhptNFgtnDZIn45zC0AlVr/6UfLtsLcHCh1XElLUHfEC0
|
# h5NVNJVMQJI2tltv7M4/4IbhZJb3xzQW7LolEoZYUZanBTUuyly9osCg4o5joViT
|
||||||
# nBuQcM/SpYo9e3l1qY5NdMgDGxCsmCKdiZfYXIu+U0UYIBhdzmSHnB3fxZOBVcr5
|
# 2GtmyxK+Fv5kC20l2opeaeptd/E7ceDAFRM87hiNCsK/KHyC+8+swnlg4gTOey6z
|
||||||
# htFHEBBNt/rFJlm/A4yb8oBsp+Uf0p5QwmO/bCcdqB15JpylOhZmWs0sUfJKlK9E
|
# QqhzgNsG6HrjLBuDtDs9izAMwS2yWT0T52QA9h3Q+B1C9ps2fMKMe+DHpG+0c61D
|
||||||
# rAhBwGki2eIRFKsQBdkXS9PWpF1w2gIJRvSkDEaCf+lbGTPdSzHSbfREWOF9wY3i
|
# 94Yh6cV2XHib4SBCnwIFZAeZE2UJ4qPANSYozI8PH+E5rCT3SVqYvHou97HsXvP2
|
||||||
# Yj8CAwEAAaOCARswggEXMB0GA1UdDgQWBBRRahZSGfrCQhCyIyGH9DkiaW7L0zAf
|
# I3MCAwEAAaOCARswggEXMB0GA1UdDgQWBBRJq6wfF7B+mEKN0VimX8ajNA5hQTAf
|
||||||
# BgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBH
|
# BgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBH
|
||||||
# hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNU
|
# hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNU
|
||||||
# aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF
|
# aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF
|
||||||
# BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0
|
# BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0
|
||||||
# YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG
|
# YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG
|
||||||
# AQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQBPFxHIwi4vAH49w9Svmz6K3tM55RlW
|
# AQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQBAlvudaOlv9Cfzv56bnX41czF6tLtH
|
||||||
# 5pPeULXdut2Rqy6Ys0+VpZsbuaEoxs6Z1C3hMbkiqZFxxyltxJpuHTyGTg61zfNI
|
# LB46l6XUch+qNN45ZmOTFwLot3JjwSrn4oycQ9qTET1TFDYd1QND0LiXmKz9OqBX
|
||||||
# F5n6RsYF3s7IElDXNfZznF1/2iWc6uRPZK8rxxUJ/7emYXZCYwuUY0XjsCpP9pbR
|
# ai6S8XdyCQEZvfL82jIAs9pwsAQ6XvV9jNybPStRgF/sOAM/Deyfmej9Tg9FcRwX
|
||||||
# RKeJi6r5arSyI+NfKxvgoM21JNt1BcdlXuAecdd/k8UjxCscffanoK2n6LFw1PcZ
|
# ank2qgzdZZNb8GoEze7f1orcTF0Q89IUXWIlmwEwQFYF1wjn87N4ZxL9Z/xA2m/R
|
||||||
# lEO7NId7o+soM2C0QY5BYdghpn7uqopB6ixyFIIkDXFub+1E7GmAEwfU6VwEHL7y
|
# 1zizFylWP/mpamCnVfZZLkafFLNUNVmcvc+9gM7vceJs37d3ydabk4wR6ObR34sW
|
||||||
# 9rNE8bd+JrQs+yAtkkHy9FmXg/PsGq1daVzX1So7CJ6nyphpuHSN3VfTMIIGcTCC
|
# aLppmyPlsI1Qq5Lu6bJCWoXzYuWpkoK6oEep1gML6SRC3HKVS3UscZhtMIIGcTCC
|
||||||
# BFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC
|
# BFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC
|
||||||
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
|
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
|
||||||
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJv
|
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJv
|
||||||
@@ -1046,33 +937,33 @@ Say "Installation finished"
|
|||||||
# NR4Iuto229Nfj950iEkSoYIC0jCCAjsCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT
|
# NR4Iuto229Nfj950iEkSoYIC0jCCAjsCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT
|
||||||
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
|
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
|
||||||
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP
|
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP
|
||||||
# cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4
|
# cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo2
|
||||||
# OTdBLUUzNTYtMTcwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
|
# MEJDLUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
|
||||||
# dmljZaIjCgEBMAcGBSsOAwIaAxUADE5OKSMoNx/mYxYWap1RTOohbJ2ggYMwgYCk
|
# dmljZaIjCgEBMAcGBSsOAwIaAxUACmcyOWmZxErpq06B8dy6oMZ6//yggYMwgYCk
|
||||||
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
|
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
|
||||||
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
|
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
|
||||||
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF
|
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF
|
||||||
# AOOFYaowIhgPMjAyMDEyMTcwODQ4NDJaGA8yMDIwMTIxODA4NDg0MlowdzA9Bgor
|
# AOMxeOgwIhgPMjAyMDEwMTQxNzE3MjhaGA8yMDIwMTAxNTE3MTcyOFowdzA9Bgor
|
||||||
# BgEEAYRZCgQBMS8wLTAKAgUA44VhqgIBADAKAgEAAgIoWgIB/zAHAgEAAgISJTAK
|
# BgEEAYRZCgQBMS8wLTAKAgUA4zF46AIBADAKAgEAAgIQPAIB/zAHAgEAAgIRZDAK
|
||||||
# AgUA44azKgIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB
|
# AgUA4zLKaAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB
|
||||||
# AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAB53NDoDDF4vqFWY
|
# AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBALEDKhtH6no+VBWb
|
||||||
# fwUnSvAy3z0CtqSFeA9RzDKGklPRwVkya5DtmVBDTZUbVQ2ST9hvRAVxhktfyVBZ
|
# KHscN3Q0bphy1tgMhLZ0UBYpPSgcrPnF36tX3nswRAci3gLdgc77hjn2Zc6UyVJk
|
||||||
# ewapGJsvwMhg7nnEqBOumt6TvueIZpbs+p5z//3+iFYGkT3YFQI0Gd2JkvgBxfs5
|
# WhFguWv6KoyTunGPejS/fPIGKm1CXQnEV/JUvt1EAf7YRpHImfjZBhNXbVyV61gy
|
||||||
# +GptO6JKtiyA+zkKijxqXZvMqMxBMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMC
|
# fEGA6fNNgbI+57xQJCZqdKBYX3EFMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMC
|
||||||
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
|
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
|
||||||
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
|
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
|
||||||
# bWUtU3RhbXAgUENBIDIwMTACEzMAAAEsIq9Fl3X5G+4AAAAAASwwDQYJYIZIAWUD
|
# bWUtU3RhbXAgUENBIDIwMTACEzMAAAEm37pLIrmCggcAAAAAASYwDQYJYIZIAWUD
|
||||||
# BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B
|
# BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B
|
||||||
# CQQxIgQg3wEUtEvxwCp3aAFB2vGXOOqg/AXHyXZh9P9J+0uArDMwgfoGCyqGSIb3
|
# CQQxIgQgmfmj5y7wRFTyeI0TaXaljaCJoRQMvGBEAXsAQuY3ZOcwgfoGCyqGSIb3
|
||||||
# DQEJEAIvMYHqMIHnMIHkMIG9BCBbn/0uFFh42hTM5XOoKdXevBaiSxmYK9Ilcn9n
|
# DQEJEAIvMYHqMIHnMIHkMIG9BCA2/c/vnr1ecAzvapOWZ2xGfAkzrkfpGcrvMW07
|
||||||
# u5ZH4TCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
|
# CQl1DzCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
|
||||||
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
|
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
|
||||||
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB
|
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB
|
||||||
# LCKvRZd1+RvuAAAAAAEsMCIEINBRtGID6jvA2ptfwIuPyG7qPcLRYb9YrJ8aKfVg
|
# Jt+6SyK5goIHAAAAAAEmMCIEIJ7sOcZ9sNFABAvIMRs2kk0cZhB239DZbXCLYMT8
|
||||||
# TulFMA0GCSqGSIb3DQEBCwUABIIBACQQpFGWW6JmH5MTKwhaE/8+gyzI2bT8XJnA
|
# frPMMA0GCSqGSIb3DQEBCwUABIIBAEiXebYdQ9DIz74YpfQ9FBaLHiSfD3s+jO7x
|
||||||
# t8k7PHFvEGA7whgp9eNgW+wWJm1gnsmswjx2l7FW4DLg9lghM8FK77JRCg7CJfse
|
# 1noNe0HIdZaX/Asow0OqsEMzZanOpa3yO8BJskKoDJW9pU//xqCzV1W5FzoOT4Qs
|
||||||
# dSbnTv81/4VhSXOAO0jMP2dALP7DF59vQmlDh50u8/Wu61ActMOt6cArkoUhBRXO
|
# ZJpG0R5f/eHqMMeRBVUPn1FfT4pQVcHfRHOW/I3hWC0G4SeVwU/L9d8JLSQKzl39
|
||||||
# LnqOQCOEEku5Xy2ES9g9eUfLUvTvlWo6HiAq+cJnNV08QRBOnGWRxdwy8YJ5vwNW
|
# 8bMFbtLJWxUJMM4Vp8Tf+cR7ShZdsK9w88QokR9xbuQgn6jsqhOuyw+dUGrwEI7h
|
||||||
# Pwx0ZG3rTvMtGzOaW6Ve5O36H2ynoEdzCmpakeDaF2sZ86/LNERKyIXiykV/Uig1
|
# GCdUmsT614oSgdnuUBf/g1aew0e3ulmZYYQ2QLKqnDXuqUIFnPtWFB90h++mdlFg
|
||||||
# SZh2VLY/Yni9SCVHbYgvTOCh5ZZE5eOi6BwLf0T4xl5alHUx+AA=
|
# fvIEusNgYkb2kl5xQfxm3wynbxtP249vWF4GACZtqqSj3tcQ+xQ=
|
||||||
# SIG # End signature block
|
# SIG # End signature block
|
||||||
|
|||||||
276
src/Misc/dotnet-install.sh
vendored
276
src/Misc/dotnet-install.sh
vendored
@@ -40,7 +40,7 @@ if [ -t 1 ] && command -v tput > /dev/null; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
say_warning() {
|
say_warning() {
|
||||||
printf "%b\n" "${yellow:-}dotnet_install: Warning: $1${normal:-}" >&3
|
printf "%b\n" "${yellow:-}dotnet_install: Warning: $1${normal:-}"
|
||||||
}
|
}
|
||||||
|
|
||||||
say_err() {
|
say_err() {
|
||||||
@@ -183,9 +183,6 @@ get_current_os_name() {
|
|||||||
elif is_musl_based_distro; then
|
elif is_musl_based_distro; then
|
||||||
echo "linux-musl"
|
echo "linux-musl"
|
||||||
return 0
|
return 0
|
||||||
elif [ "$linux_platform_name" = "linux-musl" ]; then
|
|
||||||
echo "linux-musl"
|
|
||||||
return 0
|
|
||||||
else
|
else
|
||||||
echo "linux"
|
echo "linux"
|
||||||
return 0
|
return 0
|
||||||
@@ -244,6 +241,42 @@ check_min_reqs() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_pre_reqs() {
|
||||||
|
eval $invocation
|
||||||
|
|
||||||
|
if [ "${DOTNET_INSTALL_SKIP_PREREQS:-}" = "1" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(uname)" = "Linux" ]; then
|
||||||
|
if is_musl_based_distro; then
|
||||||
|
if ! command -v scanelf > /dev/null; then
|
||||||
|
say_warning "scanelf not found, please install pax-utils package."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
LDCONFIG_COMMAND="scanelf --ldpath -BF '%f'"
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep libintl)" ] && say_warning "Unable to locate libintl. Probable prerequisite missing; install libintl (or gettext)."
|
||||||
|
else
|
||||||
|
if [ ! -x "$(command -v ldconfig)" ]; then
|
||||||
|
say_verbose "ldconfig is not in PATH, trying /sbin/ldconfig."
|
||||||
|
LDCONFIG_COMMAND="/sbin/ldconfig"
|
||||||
|
else
|
||||||
|
LDCONFIG_COMMAND="ldconfig"
|
||||||
|
fi
|
||||||
|
local librarypath=${LD_LIBRARY_PATH:-}
|
||||||
|
LDCONFIG_COMMAND="$LDCONFIG_COMMAND -NXv ${librarypath//:/ }"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep zlib)" ] && say_warning "Unable to locate zlib. Probable prerequisite missing; install zlib."
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep ssl)" ] && say_warning "Unable to locate libssl. Probable prerequisite missing; install libssl."
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep libicu)" ] && say_warning "Unable to locate libicu. Probable prerequisite missing; install libicu."
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep lttng)" ] && say_warning "Unable to locate liblttng. Probable prerequisite missing; install liblttng."
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep libcurl)" ] && say_warning "Unable to locate libcurl. Probable prerequisite missing; install libcurl."
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# args:
|
# args:
|
||||||
# input - $1
|
# input - $1
|
||||||
to_lowercase() {
|
to_lowercase() {
|
||||||
@@ -299,7 +332,7 @@ get_machine_architecture() {
|
|||||||
if command -v uname > /dev/null; then
|
if command -v uname > /dev/null; then
|
||||||
CPUName=$(uname -m)
|
CPUName=$(uname -m)
|
||||||
case $CPUName in
|
case $CPUName in
|
||||||
armv*l)
|
armv7l)
|
||||||
echo "arm"
|
echo "arm"
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -344,30 +377,6 @@ get_normalized_architecture_from_architecture() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# args:
|
|
||||||
# user_defined_os - $1
|
|
||||||
get_normalized_os() {
|
|
||||||
eval $invocation
|
|
||||||
|
|
||||||
local osname="$(to_lowercase "$1")"
|
|
||||||
if [ ! -z "$osname" ]; then
|
|
||||||
case "$osname" in
|
|
||||||
osx | freebsd | rhel.6 | linux-musl | linux)
|
|
||||||
echo "$osname"
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
say_err "'$user_defined_os' is not a supported value for --os option, supported values are: osx, linux, linux-musl, freebsd, rhel.6. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues."
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
osname="$(get_current_os_name)" || return 1
|
|
||||||
fi
|
|
||||||
echo "$osname"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# The version text returned from the feeds is a 1-line or 2-line string:
|
# The version text returned from the feeds is a 1-line or 2-line string:
|
||||||
# For the SDK and the dotnet runtime (2 lines):
|
# For the SDK and the dotnet runtime (2 lines):
|
||||||
# Line 1: # commit_hash
|
# Line 1: # commit_hash
|
||||||
@@ -409,12 +418,14 @@ is_dotnet_package_installed() {
|
|||||||
# azure_feed - $1
|
# azure_feed - $1
|
||||||
# channel - $2
|
# channel - $2
|
||||||
# normalized_architecture - $3
|
# normalized_architecture - $3
|
||||||
|
# coherent - $4
|
||||||
get_latest_version_info() {
|
get_latest_version_info() {
|
||||||
eval $invocation
|
eval $invocation
|
||||||
|
|
||||||
local azure_feed="$1"
|
local azure_feed="$1"
|
||||||
local channel="$2"
|
local channel="$2"
|
||||||
local normalized_architecture="$3"
|
local normalized_architecture="$3"
|
||||||
|
local coherent="$4"
|
||||||
|
|
||||||
local version_file_url=null
|
local version_file_url=null
|
||||||
if [[ "$runtime" == "dotnet" ]]; then
|
if [[ "$runtime" == "dotnet" ]]; then
|
||||||
@@ -422,7 +433,11 @@ get_latest_version_info() {
|
|||||||
elif [[ "$runtime" == "aspnetcore" ]]; then
|
elif [[ "$runtime" == "aspnetcore" ]]; then
|
||||||
version_file_url="$uncached_feed/aspnetcore/Runtime/$channel/latest.version"
|
version_file_url="$uncached_feed/aspnetcore/Runtime/$channel/latest.version"
|
||||||
elif [ -z "$runtime" ]; then
|
elif [ -z "$runtime" ]; then
|
||||||
version_file_url="$uncached_feed/Sdk/$channel/latest.version"
|
if [ "$coherent" = true ]; then
|
||||||
|
version_file_url="$uncached_feed/Sdk/$channel/latest.coherent.version"
|
||||||
|
else
|
||||||
|
version_file_url="$uncached_feed/Sdk/$channel/latest.version"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
say_err "Invalid value for \$runtime"
|
say_err "Invalid value for \$runtime"
|
||||||
return 1
|
return 1
|
||||||
@@ -453,6 +468,7 @@ parse_jsonfile_for_version() {
|
|||||||
sdk_list=$(echo $sdk_section | awk -F"[{}]" '{print $2}')
|
sdk_list=$(echo $sdk_section | awk -F"[{}]" '{print $2}')
|
||||||
sdk_list=${sdk_list//[\" ]/}
|
sdk_list=${sdk_list//[\" ]/}
|
||||||
sdk_list=${sdk_list//,/$'\n'}
|
sdk_list=${sdk_list//,/$'\n'}
|
||||||
|
sdk_list="$(echo -e "${sdk_list}" | tr -d '[[:space:]]')"
|
||||||
|
|
||||||
local version_info=""
|
local version_info=""
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
@@ -489,16 +505,26 @@ get_specific_version_from_version() {
|
|||||||
local json_file="$5"
|
local json_file="$5"
|
||||||
|
|
||||||
if [ -z "$json_file" ]; then
|
if [ -z "$json_file" ]; then
|
||||||
if [[ "$version" == "latest" ]]; then
|
case "$version" in
|
||||||
local version_info
|
latest)
|
||||||
version_info="$(get_latest_version_info "$azure_feed" "$channel" "$normalized_architecture" false)" || return 1
|
local version_info
|
||||||
say_verbose "get_specific_version_from_version: version_info=$version_info"
|
version_info="$(get_latest_version_info "$azure_feed" "$channel" "$normalized_architecture" false)" || return 1
|
||||||
echo "$version_info" | get_version_from_version_info
|
say_verbose "get_specific_version_from_version: version_info=$version_info"
|
||||||
return 0
|
echo "$version_info" | get_version_from_version_info
|
||||||
else
|
return 0
|
||||||
echo "$version"
|
;;
|
||||||
return 0
|
coherent)
|
||||||
fi
|
local version_info
|
||||||
|
version_info="$(get_latest_version_info "$azure_feed" "$channel" "$normalized_architecture" true)" || return 1
|
||||||
|
say_verbose "get_specific_version_from_version: version_info=$version_info"
|
||||||
|
echo "$version_info" | get_version_from_version_info
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "$version"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
else
|
else
|
||||||
local version_info
|
local version_info
|
||||||
version_info="$(parse_jsonfile_for_version "$json_file")" || return 1
|
version_info="$(parse_jsonfile_for_version "$json_file")" || return 1
|
||||||
@@ -512,7 +538,6 @@ get_specific_version_from_version() {
|
|||||||
# channel - $2
|
# channel - $2
|
||||||
# normalized_architecture - $3
|
# normalized_architecture - $3
|
||||||
# specific_version - $4
|
# specific_version - $4
|
||||||
# normalized_os - $5
|
|
||||||
construct_download_link() {
|
construct_download_link() {
|
||||||
eval $invocation
|
eval $invocation
|
||||||
|
|
||||||
@@ -521,8 +546,10 @@ construct_download_link() {
|
|||||||
local normalized_architecture="$3"
|
local normalized_architecture="$3"
|
||||||
local specific_version="${4//[$'\t\r\n']}"
|
local specific_version="${4//[$'\t\r\n']}"
|
||||||
local specific_product_version="$(get_specific_product_version "$1" "$4")"
|
local specific_product_version="$(get_specific_product_version "$1" "$4")"
|
||||||
local osname="$5"
|
|
||||||
|
local osname
|
||||||
|
osname="$(get_current_os_name)" || return 1
|
||||||
|
|
||||||
local download_link=null
|
local download_link=null
|
||||||
if [[ "$runtime" == "dotnet" ]]; then
|
if [[ "$runtime" == "dotnet" ]]; then
|
||||||
download_link="$azure_feed/Runtime/$specific_version/dotnet-runtime-$specific_product_version-$osname-$normalized_architecture.tar.gz"
|
download_link="$azure_feed/Runtime/$specific_version/dotnet-runtime-$specific_product_version-$osname-$normalized_architecture.tar.gz"
|
||||||
@@ -561,20 +588,14 @@ get_specific_product_version() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if machine_has "curl"
|
specific_product_version=$(curl -s --fail "$download_link")
|
||||||
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
specific_product_version=$(curl -s --fail "$download_link")
|
specific_product_version=$(wget -qO- "$download_link")
|
||||||
if [ $? -ne 0 ]
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
specific_product_version=$specific_version
|
specific_product_version=$specific_version
|
||||||
fi
|
fi
|
||||||
elif machine_has "wget"
|
|
||||||
then
|
|
||||||
specific_product_version=$(wget -qO- "$download_link")
|
|
||||||
if [ $? -ne 0 ]
|
|
||||||
then
|
|
||||||
specific_product_version=$specific_version
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
specific_product_version="${specific_product_version//[$'\t\r\n']}"
|
specific_product_version="${specific_product_version//[$'\t\r\n']}"
|
||||||
|
|
||||||
@@ -702,31 +723,11 @@ extract_dotnet_package() {
|
|||||||
find "$temp_out_path" -type f | grep -Ev "$folders_with_version_regex" | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" "$override_non_versioned_files"
|
find "$temp_out_path" -type f | grep -Ev "$folders_with_version_regex" | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" "$override_non_versioned_files"
|
||||||
|
|
||||||
rm -rf "$temp_out_path"
|
rm -rf "$temp_out_path"
|
||||||
rm -f "$zip_path" && say_verbose "Temporary zip file $zip_path was removed"
|
|
||||||
|
|
||||||
if [ "$failed" = true ]; then
|
if [ "$failed" = true ]; then
|
||||||
say_err "Extraction failed"
|
say_err "Extraction failed"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
get_http_header_curl() {
|
|
||||||
eval $invocation
|
|
||||||
local remote_path="$1"
|
|
||||||
remote_path_with_credential="${remote_path}${feed_credential}"
|
|
||||||
curl_options="-I -sSL --retry 5 --retry-delay 2 --connect-timeout 15 "
|
|
||||||
curl $curl_options "$remote_path_with_credential" || return 1
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
get_http_header_wget() {
|
|
||||||
eval $invocation
|
|
||||||
local remote_path="$1"
|
|
||||||
remote_path_with_credential="${remote_path}${feed_credential}"
|
|
||||||
wget_options="-q -S --spider --tries 5 --waitretry 2 --connect-timeout 15 "
|
|
||||||
wget $wget_options "$remote_path_with_credential" 2>&1 || return 1
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# args:
|
# args:
|
||||||
@@ -758,56 +759,44 @@ download() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# Updates global variables $http_code and $download_error_msg
|
|
||||||
downloadcurl() {
|
downloadcurl() {
|
||||||
eval $invocation
|
eval $invocation
|
||||||
local remote_path="$1"
|
local remote_path="$1"
|
||||||
local out_path="${2:-}"
|
local out_path="${2:-}"
|
||||||
|
|
||||||
# Append feed_credential as late as possible before calling curl to avoid logging feed_credential
|
# Append feed_credential as late as possible before calling curl to avoid logging feed_credential
|
||||||
local remote_path_with_credential="${remote_path}${feed_credential}"
|
remote_path="${remote_path}${feed_credential}"
|
||||||
|
|
||||||
local curl_options="--retry 20 --retry-delay 2 --connect-timeout 15 -sSL -f --create-dirs "
|
local curl_options="--retry 20 --retry-delay 2 --connect-timeout 15 -sSL -f --create-dirs "
|
||||||
local failed=false
|
local failed=false
|
||||||
if [ -z "$out_path" ]; then
|
if [ -z "$out_path" ]; then
|
||||||
curl $curl_options "$remote_path_with_credential" || failed=true
|
curl $curl_options "$remote_path" || failed=true
|
||||||
else
|
else
|
||||||
curl $curl_options -o "$out_path" "$remote_path_with_credential" || failed=true
|
curl $curl_options -o "$out_path" "$remote_path" || failed=true
|
||||||
fi
|
fi
|
||||||
if [ "$failed" = true ]; then
|
if [ "$failed" = true ]; then
|
||||||
local response=$(get_http_header_curl $remote_path_with_credential)
|
say_verbose "Curl download failed"
|
||||||
http_code=$( echo "$response" | awk '/^HTTP/{print $2}' | tail -1 )
|
|
||||||
download_error_msg="Unable to download $remote_path."
|
|
||||||
if [[ $http_code != 2* ]]; then
|
|
||||||
download_error_msg+=" Returned HTTP status code: $http_code."
|
|
||||||
fi
|
|
||||||
say_verbose "$download_error_msg"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Updates global variables $http_code and $download_error_msg
|
|
||||||
downloadwget() {
|
downloadwget() {
|
||||||
eval $invocation
|
eval $invocation
|
||||||
local remote_path="$1"
|
local remote_path="$1"
|
||||||
local out_path="${2:-}"
|
local out_path="${2:-}"
|
||||||
|
|
||||||
# Append feed_credential as late as possible before calling wget to avoid logging feed_credential
|
# Append feed_credential as late as possible before calling wget to avoid logging feed_credential
|
||||||
local remote_path_with_credential="${remote_path}${feed_credential}"
|
remote_path="${remote_path}${feed_credential}"
|
||||||
local wget_options="--tries 20 --waitretry 2 --connect-timeout 15 "
|
local wget_options="--tries 20 --waitretry 2 --connect-timeout 15 "
|
||||||
local failed=false
|
local failed=false
|
||||||
if [ -z "$out_path" ]; then
|
if [ -z "$out_path" ]; then
|
||||||
wget -q $wget_options -O - "$remote_path_with_credential" || failed=true
|
wget -q $wget_options -O - "$remote_path" || failed=true
|
||||||
else
|
else
|
||||||
wget $wget_options -O "$out_path" "$remote_path_with_credential" || failed=true
|
wget $wget_options -O "$out_path" "$remote_path" || failed=true
|
||||||
fi
|
fi
|
||||||
if [ "$failed" = true ]; then
|
if [ "$failed" = true ]; then
|
||||||
local response=$(get_http_header_wget $remote_path_with_credential)
|
say_verbose "Wget download failed"
|
||||||
http_code=$( echo "$response" | awk '/^ HTTP/{print $2}' | tail -1 )
|
|
||||||
download_error_msg="Unable to download $remote_path."
|
|
||||||
if [[ $http_code != 2* ]]; then
|
|
||||||
download_error_msg+=" Returned HTTP status code: $http_code."
|
|
||||||
fi
|
|
||||||
say_verbose "$download_error_msg"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
@@ -820,9 +809,6 @@ calculate_vars() {
|
|||||||
normalized_architecture="$(get_normalized_architecture_from_architecture "$architecture")"
|
normalized_architecture="$(get_normalized_architecture_from_architecture "$architecture")"
|
||||||
say_verbose "normalized_architecture=$normalized_architecture"
|
say_verbose "normalized_architecture=$normalized_architecture"
|
||||||
|
|
||||||
normalized_os="$(get_normalized_os "$user_defined_os")"
|
|
||||||
say_verbose "normalized_os=$normalized_os"
|
|
||||||
|
|
||||||
specific_version="$(get_specific_version_from_version "$azure_feed" "$channel" "$normalized_architecture" "$version" "$json_file")"
|
specific_version="$(get_specific_version_from_version "$azure_feed" "$channel" "$normalized_architecture" "$version" "$json_file")"
|
||||||
specific_product_version="$(get_specific_product_version "$azure_feed" "$specific_version")"
|
specific_product_version="$(get_specific_product_version "$azure_feed" "$specific_version")"
|
||||||
say_verbose "specific_version=$specific_version"
|
say_verbose "specific_version=$specific_version"
|
||||||
@@ -831,7 +817,7 @@ calculate_vars() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
download_link="$(construct_download_link "$azure_feed" "$channel" "$normalized_architecture" "$specific_version" "$normalized_os")"
|
download_link="$(construct_download_link "$azure_feed" "$channel" "$normalized_architecture" "$specific_version")"
|
||||||
say_verbose "Constructed primary named payload URL: $download_link"
|
say_verbose "Constructed primary named payload URL: $download_link"
|
||||||
|
|
||||||
legacy_download_link="$(construct_legacy_download_link "$azure_feed" "$channel" "$normalized_architecture" "$specific_version")" || valid_legacy_download_link=false
|
legacy_download_link="$(construct_legacy_download_link "$azure_feed" "$channel" "$normalized_architecture" "$specific_version")" || valid_legacy_download_link=false
|
||||||
@@ -876,76 +862,38 @@ install_dotnet() {
|
|||||||
zip_path="$(mktemp "$temporary_file_template")"
|
zip_path="$(mktemp "$temporary_file_template")"
|
||||||
say_verbose "Zip path: $zip_path"
|
say_verbose "Zip path: $zip_path"
|
||||||
|
|
||||||
|
say "Downloading link: $download_link"
|
||||||
|
|
||||||
# Failures are normal in the non-legacy case for ultimately legacy downloads.
|
# Failures are normal in the non-legacy case for ultimately legacy downloads.
|
||||||
# Do not output to stderr, since output to stderr is considered an error.
|
# Do not output to stderr, since output to stderr is considered an error.
|
||||||
say "Downloading primary link $download_link"
|
|
||||||
|
|
||||||
# The download function will set variables $http_code and $download_error_msg in case of failure.
|
|
||||||
http_code=""; download_error_msg=""
|
|
||||||
download "$download_link" "$zip_path" 2>&1 || download_failed=true
|
download "$download_link" "$zip_path" 2>&1 || download_failed=true
|
||||||
primary_path_http_code="$http_code"; primary_path_download_error_msg="$download_error_msg"
|
|
||||||
|
|
||||||
# if the download fails, download the legacy_download_link
|
# if the download fails, download the legacy_download_link
|
||||||
if [ "$download_failed" = true ]; then
|
if [ "$download_failed" = true ]; then
|
||||||
case $primary_path_http_code in
|
say "Cannot download: $download_link"
|
||||||
404)
|
|
||||||
say "The resource at $download_link is not available."
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
say "$primary_path_download_error_msg"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
rm -f "$zip_path" 2>&1 && say_verbose "Temporary zip file $zip_path was removed"
|
|
||||||
if [ "$valid_legacy_download_link" = true ]; then
|
if [ "$valid_legacy_download_link" = true ]; then
|
||||||
download_failed=false
|
download_failed=false
|
||||||
download_link="$legacy_download_link"
|
download_link="$legacy_download_link"
|
||||||
zip_path="$(mktemp "$temporary_file_template")"
|
zip_path="$(mktemp "$temporary_file_template")"
|
||||||
say_verbose "Legacy zip path: $zip_path"
|
say_verbose "Legacy zip path: $zip_path"
|
||||||
|
say "Downloading legacy link: $download_link"
|
||||||
say "Downloading legacy link $download_link"
|
|
||||||
|
|
||||||
# The download function will set variables $http_code and $download_error_msg in case of failure.
|
|
||||||
http_code=""; download_error_msg=""
|
|
||||||
download "$download_link" "$zip_path" 2>&1 || download_failed=true
|
download "$download_link" "$zip_path" 2>&1 || download_failed=true
|
||||||
legacy_path_http_code="$http_code"; legacy_path_download_error_msg="$download_error_msg"
|
|
||||||
|
|
||||||
if [ "$download_failed" = true ]; then
|
if [ "$download_failed" = true ]; then
|
||||||
case $legacy_path_http_code in
|
say "Cannot download: $download_link"
|
||||||
404)
|
|
||||||
say "The resource at $download_link is not available."
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
say "$legacy_path_download_error_msg"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
rm -f "$zip_path" 2>&1 && say_verbose "Temporary zip file $zip_path was removed"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$download_failed" = true ]; then
|
if [ "$download_failed" = true ]; then
|
||||||
if [[ "$primary_path_http_code" = "404" && ( "$valid_legacy_download_link" = false || "$legacy_path_http_code" = "404") ]]; then
|
say_err "Could not find/download: \`$asset_name\` with version = $specific_version"
|
||||||
say_err "Could not find \`$asset_name\` with version = $specific_version"
|
say_err "Refer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support"
|
||||||
say_err "Refer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support"
|
|
||||||
else
|
|
||||||
say_err "Could not download: \`$asset_name\` with version = $specific_version"
|
|
||||||
# 404-NotFound is an expected response if it goes from only one of the links, do not show that error.
|
|
||||||
# If primary path is available (not 404-NotFound) then show the primary error else show the legacy error.
|
|
||||||
if [ "$primary_path_http_code" != "404" ]; then
|
|
||||||
say_err "$primary_path_download_error_msg"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if [[ "$valid_legacy_download_link" = true && "$legacy_path_http_code" != "404" ]]; then
|
|
||||||
say_err "$legacy_path_download_error_msg"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say "Extracting zip from $download_link"
|
say "Extracting zip from $download_link"
|
||||||
extract_dotnet_package "$zip_path" "$install_root" || return 1
|
extract_dotnet_package "$zip_path" "$install_root"
|
||||||
|
|
||||||
# Check if the SDK version is installed; if not, fail the installation.
|
# Check if the SDK version is installed; if not, fail the installation.
|
||||||
# if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed.
|
# if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed.
|
||||||
@@ -966,8 +914,6 @@ install_dotnet() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Version verification failed. More likely something is wrong either with the downloaded content or with the verification algorithm.
|
|
||||||
say_err "Failed to verify the version of installed \`$asset_name\`.\nInstallation source: $download_link.\nInstallation location: $install_root.\nReport the bug at https://github.com/dotnet/install-scripts/issues."
|
|
||||||
say_err "\`$asset_name\` with version = $specific_product_version failed to install with an unknown error."
|
say_err "\`$asset_name\` with version = $specific_product_version failed to install with an unknown error."
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -994,7 +940,6 @@ runtime=""
|
|||||||
runtime_id=""
|
runtime_id=""
|
||||||
override_non_versioned_files=true
|
override_non_versioned_files=true
|
||||||
non_dynamic_parameters=""
|
non_dynamic_parameters=""
|
||||||
user_defined_os=""
|
|
||||||
|
|
||||||
while [ $# -ne 0 ]
|
while [ $# -ne 0 ]
|
||||||
do
|
do
|
||||||
@@ -1016,10 +961,6 @@ do
|
|||||||
shift
|
shift
|
||||||
architecture="$1"
|
architecture="$1"
|
||||||
;;
|
;;
|
||||||
--os|-[Oo][SS])
|
|
||||||
shift
|
|
||||||
user_defined_os="$1"
|
|
||||||
;;
|
|
||||||
--shared-runtime|-[Ss]hared[Rr]untime)
|
--shared-runtime|-[Ss]hared[Rr]untime)
|
||||||
say_warning "The --shared-runtime flag is obsolete and may be removed in a future version of this script. The recommended usage is to specify '--runtime dotnet'."
|
say_warning "The --shared-runtime flag is obsolete and may be removed in a future version of this script. The recommended usage is to specify '--runtime dotnet'."
|
||||||
if [ -z "$runtime" ]; then
|
if [ -z "$runtime" ]; then
|
||||||
@@ -1071,7 +1012,6 @@ do
|
|||||||
shift
|
shift
|
||||||
runtime_id="$1"
|
runtime_id="$1"
|
||||||
non_dynamic_parameters+=" $name "\""$1"\"""
|
non_dynamic_parameters+=" $name "\""$1"\"""
|
||||||
say_warning "Use of --runtime-id is obsolete and should be limited to the versions below 2.1. To override architecture, use --architecture option instead. To override OS, use --os option instead."
|
|
||||||
;;
|
;;
|
||||||
--jsonfile|-[Jj][Ss]on[Ff]ile)
|
--jsonfile|-[Jj][Ss]on[Ff]ile)
|
||||||
shift
|
shift
|
||||||
@@ -1104,6 +1044,8 @@ do
|
|||||||
echo " -Version"
|
echo " -Version"
|
||||||
echo " Possible values:"
|
echo " Possible values:"
|
||||||
echo " - latest - most latest build on specific channel"
|
echo " - latest - most latest build on specific channel"
|
||||||
|
echo " - coherent - most latest coherent build on specific channel"
|
||||||
|
echo " coherent applies only to SDK downloads"
|
||||||
echo " - 3-part version in a format A.B.C - represents specific version of build"
|
echo " - 3-part version in a format A.B.C - represents specific version of build"
|
||||||
echo " examples: 2.0.0-preview2-006120; 1.1.0"
|
echo " examples: 2.0.0-preview2-006120; 1.1.0"
|
||||||
echo " -i,--install-dir <DIR> Install under specified location (see Install Location below)"
|
echo " -i,--install-dir <DIR> Install under specified location (see Install Location below)"
|
||||||
@@ -1111,11 +1053,6 @@ do
|
|||||||
echo " --architecture <ARCHITECTURE> Architecture of dotnet binaries to be installed, Defaults to \`$architecture\`."
|
echo " --architecture <ARCHITECTURE> Architecture of dotnet binaries to be installed, Defaults to \`$architecture\`."
|
||||||
echo " --arch,-Architecture,-Arch"
|
echo " --arch,-Architecture,-Arch"
|
||||||
echo " Possible values: x64, arm, and arm64"
|
echo " Possible values: x64, arm, and arm64"
|
||||||
echo " --os <system> Specifies operating system to be used when selecting the installer."
|
|
||||||
echo " Overrides the OS determination approach used by the script. Supported values: osx, linux, linux-musl, freebsd, rhel.6."
|
|
||||||
echo " In case any other value is provided, the platform will be determined by the script based on machine configuration."
|
|
||||||
echo " Not supported for legacy links. Use --runtime-id to specify platform for legacy links."
|
|
||||||
echo " Refer to: https://aka.ms/dotnet-os-lifecycle for more information."
|
|
||||||
echo " --runtime <RUNTIME> Installs a shared runtime only, without the SDK."
|
echo " --runtime <RUNTIME> Installs a shared runtime only, without the SDK."
|
||||||
echo " -Runtime"
|
echo " -Runtime"
|
||||||
echo " Possible values:"
|
echo " Possible values:"
|
||||||
@@ -1132,15 +1069,14 @@ do
|
|||||||
echo " --no-cdn,-NoCdn Disable downloading from the Azure CDN, and use the uncached feed directly."
|
echo " --no-cdn,-NoCdn Disable downloading from the Azure CDN, and use the uncached feed directly."
|
||||||
echo " --jsonfile <JSONFILE> Determines the SDK version from a user specified global.json file."
|
echo " --jsonfile <JSONFILE> Determines the SDK version from a user specified global.json file."
|
||||||
echo " Note: global.json must have a value for 'SDK:Version'"
|
echo " Note: global.json must have a value for 'SDK:Version'"
|
||||||
|
echo " --runtime-id Installs the .NET Tools for the given platform (use linux-x64 for portable linux)."
|
||||||
|
echo " -RuntimeId"
|
||||||
echo " -?,--?,-h,--help,-Help Shows this help message"
|
echo " -?,--?,-h,--help,-Help Shows this help message"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Obsolete parameters:"
|
echo "Obsolete parameters:"
|
||||||
echo " --shared-runtime The recommended alternative is '--runtime dotnet'."
|
echo " --shared-runtime The recommended alternative is '--runtime dotnet'."
|
||||||
echo " This parameter is obsolete and may be removed in a future version of this script."
|
echo " This parameter is obsolete and may be removed in a future version of this script."
|
||||||
echo " Installs just the shared runtime bits, not the entire SDK."
|
echo " Installs just the shared runtime bits, not the entire SDK."
|
||||||
echo " --runtime-id Installs the .NET Tools for the given platform (use linux-x64 for portable linux)."
|
|
||||||
echo " -RuntimeId" The parameter is obsolete and may be removed in a future version of this script. Should be used only for versions below 2.1.
|
|
||||||
echo " For primary links to override OS or/and architecture, use --os and --architecture option instead."
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Install Location:"
|
echo "Install Location:"
|
||||||
echo " Location is chosen in following order:"
|
echo " Location is chosen in following order:"
|
||||||
@@ -1162,11 +1098,6 @@ if [ "$no_cdn" = true ]; then
|
|||||||
azure_feed="$uncached_feed"
|
azure_feed="$uncached_feed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
|
|
||||||
say "- The SDK needs to be installed without user interaction and without admin rights."
|
|
||||||
say "- The SDK installation doesn't need to persist across multiple CI runs."
|
|
||||||
say "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.\n"
|
|
||||||
|
|
||||||
check_min_reqs
|
check_min_reqs
|
||||||
calculate_vars
|
calculate_vars
|
||||||
script_name=$(basename "$0")
|
script_name=$(basename "$0")
|
||||||
@@ -1177,7 +1108,7 @@ if [ "$dry_run" = true ]; then
|
|||||||
if [ "$valid_legacy_download_link" = true ]; then
|
if [ "$valid_legacy_download_link" = true ]; then
|
||||||
say "Legacy named payload URL: $legacy_download_link"
|
say "Legacy named payload URL: $legacy_download_link"
|
||||||
fi
|
fi
|
||||||
repeatable_command="./$script_name --version "\""$specific_version"\"" --install-dir "\""$install_root"\"" --architecture "\""$normalized_architecture"\"" --os "\""$normalized_os"\"""
|
repeatable_command="./$script_name --version "\""$specific_version"\"" --install-dir "\""$install_root"\"" --architecture "\""$normalized_architecture"\"""
|
||||||
if [[ "$runtime" == "dotnet" ]]; then
|
if [[ "$runtime" == "dotnet" ]]; then
|
||||||
repeatable_command+=" --runtime "\""dotnet"\"""
|
repeatable_command+=" --runtime "\""dotnet"\"""
|
||||||
elif [[ "$runtime" == "aspnetcore" ]]; then
|
elif [[ "$runtime" == "aspnetcore" ]]; then
|
||||||
@@ -1188,6 +1119,7 @@ if [ "$dry_run" = true ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
check_pre_reqs
|
||||||
install_dotnet
|
install_dotnet
|
||||||
|
|
||||||
bin_path="$(get_absolute_path "$(combine_paths "$install_root" "$bin_folder_relative_path")")"
|
bin_path="$(get_absolute_path "$(combine_paths "$install_root" "$bin_folder_relative_path")")"
|
||||||
@@ -1198,6 +1130,4 @@ else
|
|||||||
say "Binaries of dotnet can be found in $bin_path"
|
say "Binaries of dotnet can be found in $bin_path"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say "Note that the script does not resolve dependencies during installation."
|
|
||||||
say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install, select your operating system and check the \"Dependencies\" section."
|
|
||||||
say "Installation finished successfully."
|
say "Installation finished successfully."
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": {
|
"@actions/core": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.0.tgz",
|
||||||
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
"integrity": "sha512-ZKdyhlSlyz38S6YFfPnyNgCDZuAF2T0Qv5eHflNWytPS8Qjvz39bZFMry9Bb/dpSnqWcNeav5yM2CTYpJeY+Dw=="
|
||||||
},
|
},
|
||||||
"@actions/glob": {
|
"@actions/glob": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ if (supported.indexOf(process.platform) == -1) {
|
|||||||
var stopping = false;
|
var stopping = false;
|
||||||
var listener = null;
|
var listener = null;
|
||||||
|
|
||||||
var runService = function () {
|
var runService = function() {
|
||||||
var listenerExePath = path.join(__dirname, '../bin/Runner.Listener');
|
var listenerExePath = path.join(__dirname, '../bin/Runner.Listener');
|
||||||
var interactive = process.argv[2] === "interactive";
|
var interactive = process.argv[2] === "interactive";
|
||||||
|
|
||||||
if (!stopping) {
|
if(!stopping) {
|
||||||
try {
|
try {
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
console.log('Starting Runner listener interactively');
|
console.log('Starting Runner listener interactively');
|
||||||
@@ -30,8 +30,8 @@ var runService = function () {
|
|||||||
listener = childProcess.spawn(listenerExePath, ['run', '--startuptype', 'service'], { env: process.env });
|
listener = childProcess.spawn(listenerExePath, ['run', '--startuptype', 'service'], { env: process.env });
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Started listener process, pid: ${listener.pid}`);
|
console.log('Started listener process');
|
||||||
|
|
||||||
listener.stdout.on('data', (data) => {
|
listener.stdout.on('data', (data) => {
|
||||||
process.stdout.write(data.toString('utf8'));
|
process.stdout.write(data.toString('utf8'));
|
||||||
});
|
});
|
||||||
@@ -40,10 +40,6 @@ var runService = function () {
|
|||||||
process.stdout.write(data.toString('utf8'));
|
process.stdout.write(data.toString('utf8'));
|
||||||
});
|
});
|
||||||
|
|
||||||
listener.on("error", (err) => {
|
|
||||||
console.log(`Runner listener fail to start with error ${err.message}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
listener.on('close', (code) => {
|
listener.on('close', (code) => {
|
||||||
console.log(`Runner listener exited with error code ${code}`);
|
console.log(`Runner listener exited with error code ${code}`);
|
||||||
|
|
||||||
@@ -60,13 +56,13 @@ var runService = function () {
|
|||||||
} else {
|
} else {
|
||||||
console.log('Runner listener exit with undefined return code, re-launch runner in 5 seconds.');
|
console.log('Runner listener exit with undefined return code, re-launch runner in 5 seconds.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stopping) {
|
if(!stopping) {
|
||||||
setTimeout(runService, 5000);
|
setTimeout(runService, 5000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (ex) {
|
} catch(ex) {
|
||||||
console.log(ex);
|
console.log(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +71,7 @@ var runService = function () {
|
|||||||
runService();
|
runService();
|
||||||
console.log('Started running service');
|
console.log('Started running service');
|
||||||
|
|
||||||
var gracefulShutdown = function (code) {
|
var gracefulShutdown = function(code) {
|
||||||
console.log('Shutting down runner listener');
|
console.log('Shutting down runner listener');
|
||||||
stopping = true;
|
stopping = true;
|
||||||
if (listener) {
|
if (listener) {
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
const https = require('https')
|
|
||||||
const fs = require('fs')
|
|
||||||
const http = require('http')
|
|
||||||
const hostname = process.env['HOSTNAME'] || ''
|
|
||||||
const port = process.env['PORT'] || ''
|
|
||||||
const path = process.env['PATH'] || ''
|
|
||||||
const pat = process.env['PAT'] || ''
|
|
||||||
const proxyHost = process.env['PROXYHOST'] || ''
|
|
||||||
const proxyPort = process.env['PROXYPORT'] || ''
|
|
||||||
const proxyUsername = process.env['PROXYUSERNAME'] || ''
|
|
||||||
const proxyPassword = process.env['PROXYPASSWORD'] || ''
|
|
||||||
|
|
||||||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
|
|
||||||
|
|
||||||
if (proxyHost === '') {
|
|
||||||
const options = {
|
|
||||||
hostname: hostname,
|
|
||||||
port: port,
|
|
||||||
path: path,
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'User-Agent': 'GitHubActionsRunnerCheck/1.0',
|
|
||||||
'Authorization': `token ${pat}`
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const req = https.request(options, res => {
|
|
||||||
console.log(`statusCode: ${res.statusCode}`)
|
|
||||||
console.log(`headers: ${JSON.stringify(res.headers)}`)
|
|
||||||
let cert = socket.getPeerCertificate(true)
|
|
||||||
let certPEM = ''
|
|
||||||
let fingerprints = {}
|
|
||||||
while (cert != null && fingerprints[cert.fingerprint] != '1') {
|
|
||||||
fingerprints[cert.fingerprint] = '1'
|
|
||||||
certPEM = certPEM + '-----BEGIN CERTIFICATE-----\n'
|
|
||||||
let certEncoded = cert.raw.toString('base64')
|
|
||||||
for (let i = 0; i < certEncoded.length; i++) {
|
|
||||||
certPEM = certPEM + certEncoded[i]
|
|
||||||
if (i != certEncoded.length - 1 && (i + 1) % 64 == 0) {
|
|
||||||
certPEM = certPEM + '\n'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
certPEM = certPEM + '\n-----END CERTIFICATE-----\n'
|
|
||||||
cert = cert.issuerCertificate
|
|
||||||
}
|
|
||||||
console.log(certPEM)
|
|
||||||
fs.writeFileSync('./download_ca_cert.pem', certPEM)
|
|
||||||
res.on('data', d => {
|
|
||||||
process.stdout.write(d)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
req.on('error', error => {
|
|
||||||
console.error(error)
|
|
||||||
})
|
|
||||||
req.end()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const auth = 'Basic ' + Buffer.from(proxyUsername + ':' + proxyPassword).toString('base64')
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
host: proxyHost,
|
|
||||||
port: proxyPort,
|
|
||||||
method: 'CONNECT',
|
|
||||||
path: `${hostname}:${port}`,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proxyUsername != '' || proxyPassword != '') {
|
|
||||||
options.headers = {
|
|
||||||
'Proxy-Authorization': auth,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
http.request(options).on('connect', (res, socket) => {
|
|
||||||
if (res.statusCode != 200) {
|
|
||||||
throw new Error(`Proxy returns code: ${res.statusCode}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
https.get({
|
|
||||||
host: hostname,
|
|
||||||
port: port,
|
|
||||||
socket: socket,
|
|
||||||
agent: false,
|
|
||||||
path: '/',
|
|
||||||
headers: {
|
|
||||||
'User-Agent': 'GitHubActionsRunnerCheck/1.0',
|
|
||||||
'Authorization': `token ${pat}`
|
|
||||||
}
|
|
||||||
}, (res) => {
|
|
||||||
let cert = res.socket.getPeerCertificate(true)
|
|
||||||
let certPEM = ''
|
|
||||||
let fingerprints = {}
|
|
||||||
while (cert != null && fingerprints[cert.fingerprint] != '1') {
|
|
||||||
fingerprints[cert.fingerprint] = '1'
|
|
||||||
certPEM = certPEM + '-----BEGIN CERTIFICATE-----\n'
|
|
||||||
let certEncoded = cert.raw.toString('base64')
|
|
||||||
for (let i = 0; i < certEncoded.length; i++) {
|
|
||||||
certPEM = certPEM + certEncoded[i]
|
|
||||||
if (i != certEncoded.length - 1 && (i + 1) % 64 == 0) {
|
|
||||||
certPEM = certPEM + '\n'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
certPEM = certPEM + '\n-----END CERTIFICATE-----\n'
|
|
||||||
cert = cert.issuerCertificate
|
|
||||||
}
|
|
||||||
console.log(certPEM)
|
|
||||||
fs.writeFileSync('./download_ca_cert.pem', certPEM)
|
|
||||||
console.log(`statusCode: ${res.statusCode}`)
|
|
||||||
console.log(`headers: ${JSON.stringify(res.headers)}`)
|
|
||||||
res.on('data', d => {
|
|
||||||
process.stdout.write(d)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}).on('error', (err) => {
|
|
||||||
console.error('error', err)
|
|
||||||
}).end()
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
const https = require('https')
|
|
||||||
const http = require('http')
|
|
||||||
const hostname = process.env['HOSTNAME'] || ''
|
|
||||||
const port = process.env['PORT'] || ''
|
|
||||||
const path = process.env['PATH'] || ''
|
|
||||||
const pat = process.env['PAT'] || ''
|
|
||||||
const proxyHost = process.env['PROXYHOST'] || ''
|
|
||||||
const proxyPort = process.env['PROXYPORT'] || ''
|
|
||||||
const proxyUsername = process.env['PROXYUSERNAME'] || ''
|
|
||||||
const proxyPassword = process.env['PROXYPASSWORD'] || ''
|
|
||||||
|
|
||||||
if (proxyHost === '') {
|
|
||||||
const options = {
|
|
||||||
hostname: hostname,
|
|
||||||
port: port,
|
|
||||||
path: path,
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'User-Agent': 'GitHubActionsRunnerCheck/1.0',
|
|
||||||
'Authorization': `token ${pat}`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const req = https.request(options, res => {
|
|
||||||
console.log(`statusCode: ${res.statusCode}`)
|
|
||||||
console.log(`headers: ${JSON.stringify(res.headers)}`)
|
|
||||||
|
|
||||||
res.on('data', d => {
|
|
||||||
process.stdout.write(d)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
req.on('error', error => {
|
|
||||||
console.error(error)
|
|
||||||
})
|
|
||||||
req.end()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const proxyAuth = 'Basic ' + Buffer.from(proxyUsername + ':' + proxyPassword).toString('base64')
|
|
||||||
const options = {
|
|
||||||
hostname: proxyHost,
|
|
||||||
port: proxyPort,
|
|
||||||
method: 'CONNECT',
|
|
||||||
path: `${hostname}:${port}`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proxyUsername != '' || proxyPassword != '') {
|
|
||||||
options.headers = {
|
|
||||||
'Proxy-Authorization': proxyAuth,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
http.request(options).on('connect', (res, socket) => {
|
|
||||||
if (res.statusCode != 200) {
|
|
||||||
throw new Error(`Proxy returns code: ${res.statusCode}`)
|
|
||||||
}
|
|
||||||
https.get({
|
|
||||||
host: hostname,
|
|
||||||
port: port,
|
|
||||||
socket: socket,
|
|
||||||
agent: false,
|
|
||||||
path: path,
|
|
||||||
headers: {
|
|
||||||
'User-Agent': 'GitHubActionsRunnerCheck/1.0',
|
|
||||||
'Authorization': `token ${pat}`,
|
|
||||||
}
|
|
||||||
}, (res) => {
|
|
||||||
console.log(`statusCode: ${res.statusCode}`)
|
|
||||||
console.log(`headers: ${JSON.stringify(res.headers)}`)
|
|
||||||
|
|
||||||
res.on('data', d => {
|
|
||||||
process.stdout.write(d)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}).on('error', (err) => {
|
|
||||||
console.error('error', err)
|
|
||||||
}).end()
|
|
||||||
}
|
|
||||||
@@ -49,67 +49,69 @@ then
|
|||||||
cat /etc/debian_version
|
cat /etc/debian_version
|
||||||
echo "------------------------------"
|
echo "------------------------------"
|
||||||
|
|
||||||
# prefer apt-get over apt
|
# prefer apt over apt-get
|
||||||
command -v apt-get
|
command -v apt
|
||||||
if [ $? -eq 0 ]
|
if [ $? -eq 0 ]
|
||||||
then
|
then
|
||||||
apt_get=apt-get
|
apt update && apt install -y liblttng-ust0 libkrb5-3 zlib1g
|
||||||
else
|
if [ $? -ne 0 ]
|
||||||
command -v apt
|
|
||||||
if [ $? -eq 0 ]
|
|
||||||
then
|
then
|
||||||
apt_get=apt
|
echo "'apt' failed with exit code '$?'"
|
||||||
else
|
|
||||||
echo "Found neither 'apt-get' nor 'apt'"
|
|
||||||
print_errormessage
|
print_errormessage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
$apt_get update && $apt_get install -y liblttng-ust0 libkrb5-3 zlib1g
|
# libissl version prefer: libssl1.1 -> libssl1.0.2 -> libssl1.0.0
|
||||||
if [ $? -ne 0 ]
|
apt install -y libssl1.1$ || apt install -y libssl1.0.2$ || apt install -y libssl1.0.0$
|
||||||
then
|
if [ $? -ne 0 ]
|
||||||
echo "'$apt_get' failed with exit code '$?'"
|
|
||||||
print_errormessage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
apt_get_with_fallbacks() {
|
|
||||||
$apt_get install -y $1
|
|
||||||
fail=$?
|
|
||||||
if [ $fail -eq 0 ]
|
|
||||||
then
|
then
|
||||||
if [ "${1#"${1%?}"}" = '$' ]; then
|
echo "'apt' failed with exit code '$?'"
|
||||||
dpkg -l "${1%?}" > /dev/null 2> /dev/null
|
print_errormessage
|
||||||
fail=$?
|
exit 1
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
if [ $fail -ne 0 ]
|
|
||||||
|
# libicu version prefer: libicu66 -> libicu63 -> libicu60 -> libicu57 -> libicu55 -> libicu52
|
||||||
|
apt install -y libicu66 || apt install -y libicu63 || apt install -y libicu60 || apt install -y libicu57 || apt install -y libicu55 || apt install -y libicu52
|
||||||
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
shift
|
echo "'apt' failed with exit code '$?'"
|
||||||
if [ -n "$1" ]
|
print_errormessage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
command -v apt-get
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
apt-get update && apt-get install -y liblttng-ust0 libkrb5-3 zlib1g
|
||||||
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
apt_get_with_fallbacks "$@"
|
echo "'apt-get' failed with exit code '$?'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# libissl version prefer: libssl1.1 -> libssl1.0.2 -> libssl1.0.0
|
||||||
|
apt-get install -y libssl1.1$ || apt-get install -y libssl1.0.2$ || apt install -y libssl1.0.0$
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "'apt-get' failed with exit code '$?'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# libicu version prefer: libicu66 -> libicu63 -> libicu60 -> libicu57 -> libicu55 -> libicu52
|
||||||
|
apt-get install -y libicu66 || apt-get install -y libicu63 || apt-get install -y libicu60 || apt install -y libicu57 || apt install -y libicu55 || apt install -y libicu52
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "'apt-get' failed with exit code '$?'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Can not find 'apt' or 'apt-get'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
# libssl version prefer: libssl1.1 -> libssl1.0.2 -> libssl1.0.0
|
|
||||||
apt_get_with_fallbacks libssl1.1$ libssl1.0.2$ libssl1.0.0$
|
|
||||||
if [ $? -ne 0 ]
|
|
||||||
then
|
|
||||||
echo "'$apt_get' failed with exit code '$?'"
|
|
||||||
print_errormessage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# libicu version prefer: libicu66 -> libicu63 -> libicu60 -> libicu57 -> libicu55 -> libicu52
|
|
||||||
apt_get_with_fallbacks libicu66 libicu63 libicu60 libicu57 libicu55 libicu52
|
|
||||||
if [ $? -ne 0 ]
|
|
||||||
then
|
|
||||||
echo "'$apt_get' failed with exit code '$?'"
|
|
||||||
print_errormessage
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
elif [ -e /etc/redhat-release ]
|
elif [ -e /etc/redhat-release ]
|
||||||
then
|
then
|
||||||
|
|||||||
4
src/Misc/layoutbin/update.sh.template
Executable file → Normal file
4
src/Misc/layoutbin/update.sh.template
Executable file → Normal file
@@ -28,13 +28,13 @@ date "+[%F %T-%4N] Waiting for $runnerprocessname ($runnerpid) to complete" >> "
|
|||||||
while [ -e /proc/$runnerpid ]
|
while [ -e /proc/$runnerpid ]
|
||||||
do
|
do
|
||||||
date "+[%F %T-%4N] Process $runnerpid still running" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Process $runnerpid still running" >> "$logfile" 2>&1
|
||||||
sleep 2
|
ping -c 2 127.0.0.1 >nul
|
||||||
done
|
done
|
||||||
date "+[%F %T-%4N] Process $runnerpid finished running" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Process $runnerpid finished running" >> "$logfile" 2>&1
|
||||||
|
|
||||||
# start re-organize folders
|
# start re-organize folders
|
||||||
date "+[%F %T-%4N] Sleep 1 more second to make sure process exited" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Sleep 1 more second to make sure process exited" >> "$logfile" 2>&1
|
||||||
sleep 1
|
ping -c 2 127.0.0.1 >nul
|
||||||
|
|
||||||
# the folder structure under runner root will be
|
# the folder structure under runner root will be
|
||||||
# ./bin -> bin.2.100.0 (junction folder)
|
# ./bin -> bin.2.100.0 (junction folder)
|
||||||
|
|||||||
@@ -18,26 +18,24 @@ then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
message="Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
|
||||||
|
|
||||||
ldd ./bin/libcoreclr.so | grep 'not found'
|
ldd ./bin/libcoreclr.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 3.0"
|
||||||
echo $message
|
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ldd ./bin/System.Security.Cryptography.Native.OpenSsl.so | grep 'not found'
|
ldd ./bin/System.Security.Cryptography.Native.OpenSsl.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 3.0"
|
||||||
echo $message
|
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ldd ./bin/System.IO.Compression.Native.so | grep 'not found'
|
ldd ./bin/System.IO.Compression.Native.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 3.0"
|
||||||
echo $message
|
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -52,10 +50,10 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
libpath=${LD_LIBRARY_PATH:-}
|
libpath=${LD_LIBRARY_PATH:-}
|
||||||
$LDCONFIG_COMMAND -NXv ${libpath//:/ } 2>&1 | grep libicu >/dev/null 2>&1
|
$LDCONFIG_COMMAND -NXv ${libpath//:/} 2>&1 | grep libicu >/dev/null 2>&1
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Libicu's dependencies is missing for Dotnet Core 3.0"
|
echo "Libicu's dependencies is missing for Dotnet Core 3.0"
|
||||||
echo $message
|
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ varCheckList=(
|
|||||||
'ANT_HOME'
|
'ANT_HOME'
|
||||||
'M2_HOME'
|
'M2_HOME'
|
||||||
'ANDROID_HOME'
|
'ANDROID_HOME'
|
||||||
'ANDROID_SDK_ROOT'
|
|
||||||
'GRADLE_HOME'
|
'GRADLE_HOME'
|
||||||
'NVM_BIN'
|
'NVM_BIN'
|
||||||
'NVM_PATH'
|
'NVM_PATH'
|
||||||
|
|||||||
@@ -26,23 +26,25 @@ if [[ "$1" == "localRun" ]]; then
|
|||||||
else
|
else
|
||||||
"$DIR"/bin/Runner.Listener run $*
|
"$DIR"/bin/Runner.Listener run $*
|
||||||
|
|
||||||
# Return code 3 means the run once runner received an update message.
|
# Return code 4 means the run once runner received an update message.
|
||||||
# Sleep 5 seconds to wait for the update process finish
|
# Sleep 5 seconds to wait for the update process finish and run the runner again.
|
||||||
returnCode=$?
|
returnCode=$?
|
||||||
if [[ $returnCode == 3 ]]; then
|
if [[ $returnCode == 4 ]]; then
|
||||||
if [ ! -x "$(command -v sleep)" ]; then
|
if [ ! -x "$(command -v sleep)" ]; then
|
||||||
if [ ! -x "$(command -v ping)" ]; then
|
if [ ! -x "$(command -v ping)" ]; then
|
||||||
COUNT="0"
|
COUNT="0"
|
||||||
while [[ $COUNT != 5000 ]]; do
|
while [[ $COUNT != 5000 ]]; do
|
||||||
echo "SLEEP" > /dev/null
|
echo "SLEEP" >nul
|
||||||
COUNT=$[$COUNT+1]
|
COUNT=$[$COUNT+1]
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
ping -c 5 127.0.0.1 > /dev/null
|
ping -n 5 127.0.0.1 >nul
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
sleep 5
|
sleep 5 >nul
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
"$DIR"/bin/Runner.Listener run $*
|
||||||
else
|
else
|
||||||
exit $returnCode
|
exit $returnCode
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -99,11 +99,9 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
// Secret args. Must be added to the "Secrets" getter as well.
|
// Secret args. Must be added to the "Secrets" getter as well.
|
||||||
public static readonly string Token = "token";
|
public static readonly string Token = "token";
|
||||||
public static readonly string PAT = "pat";
|
|
||||||
public static readonly string WindowsLogonPassword = "windowslogonpassword";
|
public static readonly string WindowsLogonPassword = "windowslogonpassword";
|
||||||
public static string[] Secrets => new[]
|
public static string[] Secrets => new[]
|
||||||
{
|
{
|
||||||
PAT,
|
|
||||||
Token,
|
Token,
|
||||||
WindowsLogonPassword,
|
WindowsLogonPassword,
|
||||||
};
|
};
|
||||||
@@ -121,7 +119,6 @@ namespace GitHub.Runner.Common
|
|||||||
//validFlags array as well present in the CommandSettings.cs
|
//validFlags array as well present in the CommandSettings.cs
|
||||||
public static class Flags
|
public static class Flags
|
||||||
{
|
{
|
||||||
public static readonly string Check = "check";
|
|
||||||
public static readonly string Commit = "commit";
|
public static readonly string Commit = "commit";
|
||||||
public static readonly string Help = "help";
|
public static readonly string Help = "help";
|
||||||
public static readonly string Replace = "replace";
|
public static readonly string Replace = "replace";
|
||||||
@@ -141,15 +138,10 @@ namespace GitHub.Runner.Common
|
|||||||
public const int RunOnceRunnerUpdating = 4;
|
public const int RunOnceRunnerUpdating = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Features
|
|
||||||
{
|
|
||||||
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
||||||
public static readonly string WorkerCrash = "WORKER_CRASH";
|
public static readonly string WorkerCrash = "WORKER_CRASH";
|
||||||
public static readonly string LowDiskSpace = "LOW_DISK_SPACE";
|
|
||||||
public static readonly string UnsupportedCommand = "UNSUPPORTED_COMMAND";
|
public static readonly string UnsupportedCommand = "UNSUPPORTED_COMMAND";
|
||||||
|
public static readonly string UnsupportedCommandMessage = "The `{0}` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
||||||
public static readonly string UnsupportedCommandMessageDisabled = "The `{0}` command is disabled. Please upgrade to using Environment Files or opt into unsecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_COMMANDS` environment variable to `true`. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
public static readonly string UnsupportedCommandMessageDisabled = "The `{0}` command is disabled. Please upgrade to using Environment Files or opt into unsecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_COMMANDS` environment variable to `true`. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,12 +60,6 @@ namespace GitHub.Runner.Common
|
|||||||
Add<T>(extensions, "GitHub.Runner.Worker.AddPathFileCommand, Runner.Worker");
|
Add<T>(extensions, "GitHub.Runner.Worker.AddPathFileCommand, Runner.Worker");
|
||||||
Add<T>(extensions, "GitHub.Runner.Worker.SetEnvFileCommand, Runner.Worker");
|
Add<T>(extensions, "GitHub.Runner.Worker.SetEnvFileCommand, Runner.Worker");
|
||||||
break;
|
break;
|
||||||
case "GitHub.Runner.Listener.Check.ICheckExtension":
|
|
||||||
Add<T>(extensions, "GitHub.Runner.Listener.Check.InternetCheck, Runner.Listener");
|
|
||||||
Add<T>(extensions, "GitHub.Runner.Listener.Check.ActionsCheck, Runner.Listener");
|
|
||||||
Add<T>(extensions, "GitHub.Runner.Listener.Check.GitCheck, Runner.Listener");
|
|
||||||
Add<T>(extensions, "GitHub.Runner.Listener.Check.NodeJsCheck, Runner.Listener");
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
// This should never happen.
|
// This should never happen.
|
||||||
throw new NotSupportedException($"Unexpected extension type: '{typeof(T).FullName}'");
|
throw new NotSupportedException($"Unexpected extension type: '{typeof(T).FullName}'");
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ namespace GitHub.Runner.Common
|
|||||||
Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken);
|
Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken);
|
||||||
|
|
||||||
// agent package
|
// agent package
|
||||||
Task<List<PackageMetadata>> GetPackagesAsync(string packageType, string platform, int top, bool includeToken, CancellationToken cancellationToken);
|
Task<List<PackageMetadata>> GetPackagesAsync(string packageType, string platform, int top, CancellationToken cancellationToken);
|
||||||
Task<PackageMetadata> GetPackageAsync(string packageType, string platform, string version, bool includeToken, CancellationToken cancellationToken);
|
Task<PackageMetadata> GetPackageAsync(string packageType, string platform, string version, CancellationToken cancellationToken);
|
||||||
|
|
||||||
// agent update
|
// agent update
|
||||||
Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState);
|
Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState);
|
||||||
@@ -317,16 +317,16 @@ namespace GitHub.Runner.Common
|
|||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
// Agent Package
|
// Agent Package
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
public Task<List<PackageMetadata>> GetPackagesAsync(string packageType, string platform, int top, bool includeToken, CancellationToken cancellationToken)
|
public Task<List<PackageMetadata>> GetPackagesAsync(string packageType, string platform, int top, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection(RunnerConnectionType.Generic);
|
CheckConnection(RunnerConnectionType.Generic);
|
||||||
return _genericTaskAgentClient.GetPackagesAsync(packageType, platform, top, includeToken, cancellationToken: cancellationToken);
|
return _genericTaskAgentClient.GetPackagesAsync(packageType, platform, top, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<PackageMetadata> GetPackageAsync(string packageType, string platform, string version, bool includeToken, CancellationToken cancellationToken)
|
public Task<PackageMetadata> GetPackageAsync(string packageType, string platform, string version, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection(RunnerConnectionType.Generic);
|
CheckConnection(RunnerConnectionType.Generic);
|
||||||
return _genericTaskAgentClient.GetPackageAsync(packageType, platform, version, includeToken, cancellationToken: cancellationToken);
|
return _genericTaskAgentClient.GetPackageAsync(packageType, platform, version, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState)
|
public Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState)
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Check
|
|
||||||
{
|
|
||||||
public sealed class ActionsCheck : RunnerService, ICheckExtension
|
|
||||||
{
|
|
||||||
private string _logFile = null;
|
|
||||||
|
|
||||||
public int Order => 2;
|
|
||||||
|
|
||||||
public string CheckName => "GitHub Actions Connection";
|
|
||||||
|
|
||||||
public string CheckDescription => "Check if the Actions runner has access to the GitHub Actions service.";
|
|
||||||
|
|
||||||
public string CheckLog => _logFile;
|
|
||||||
|
|
||||||
public string HelpLink => "https://github.com/actions/runner/blob/main/docs/checks/actions.md";
|
|
||||||
|
|
||||||
public Type ExtensionType => typeof(ICheckExtension);
|
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
|
||||||
{
|
|
||||||
base.Initialize(hostContext);
|
|
||||||
_logFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Diag), StringUtil.Format("{0}_{1:yyyyMMdd-HHmmss}-utc.log", nameof(ActionsCheck), DateTime.UtcNow));
|
|
||||||
}
|
|
||||||
|
|
||||||
// runner access to actions service
|
|
||||||
public async Task<bool> RunCheck(string url, string pat)
|
|
||||||
{
|
|
||||||
await File.AppendAllLinesAsync(_logFile, HostContext.WarnLog());
|
|
||||||
await File.AppendAllLinesAsync(_logFile, HostContext.CheckProxy());
|
|
||||||
|
|
||||||
var checkTasks = new List<Task<CheckResult>>();
|
|
||||||
string githubApiUrl = null;
|
|
||||||
string actionsTokenServiceUrl = null;
|
|
||||||
string actionsPipelinesServiceUrl = null;
|
|
||||||
var urlBuilder = new UriBuilder(url);
|
|
||||||
if (UrlUtil.IsHostedServer(urlBuilder))
|
|
||||||
{
|
|
||||||
urlBuilder.Host = $"api.{urlBuilder.Host}";
|
|
||||||
urlBuilder.Path = "";
|
|
||||||
githubApiUrl = urlBuilder.Uri.AbsoluteUri;
|
|
||||||
actionsTokenServiceUrl = "https://vstoken.actions.githubusercontent.com/_apis/health";
|
|
||||||
actionsPipelinesServiceUrl = "https://pipelines.actions.githubusercontent.com/_apis/health";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
urlBuilder.Path = "api/v3";
|
|
||||||
githubApiUrl = urlBuilder.Uri.AbsoluteUri;
|
|
||||||
urlBuilder.Path = "_services/vstoken/_apis/health";
|
|
||||||
actionsTokenServiceUrl = urlBuilder.Uri.AbsoluteUri;
|
|
||||||
urlBuilder.Path = "_services/pipelines/_apis/health";
|
|
||||||
actionsPipelinesServiceUrl = urlBuilder.Uri.AbsoluteUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check github api
|
|
||||||
checkTasks.Add(CheckUtil.CheckDns(githubApiUrl));
|
|
||||||
checkTasks.Add(CheckUtil.CheckPing(githubApiUrl));
|
|
||||||
checkTasks.Add(HostContext.CheckHttpsGetRequests(githubApiUrl, pat, expectedHeader: "X-GitHub-Request-Id"));
|
|
||||||
|
|
||||||
// check actions token service
|
|
||||||
checkTasks.Add(CheckUtil.CheckDns(actionsTokenServiceUrl));
|
|
||||||
checkTasks.Add(CheckUtil.CheckPing(actionsTokenServiceUrl));
|
|
||||||
checkTasks.Add(HostContext.CheckHttpsGetRequests(actionsTokenServiceUrl, pat, expectedHeader: "x-vss-e2eid"));
|
|
||||||
|
|
||||||
// check actions pipelines service
|
|
||||||
checkTasks.Add(CheckUtil.CheckDns(actionsPipelinesServiceUrl));
|
|
||||||
checkTasks.Add(CheckUtil.CheckPing(actionsPipelinesServiceUrl));
|
|
||||||
checkTasks.Add(HostContext.CheckHttpsGetRequests(actionsPipelinesServiceUrl, pat, expectedHeader: "x-vss-e2eid"));
|
|
||||||
|
|
||||||
// check HTTP POST to actions pipelines service
|
|
||||||
checkTasks.Add(HostContext.CheckHttpsPostRequests(actionsPipelinesServiceUrl, pat, expectedHeader: "x-vss-e2eid"));
|
|
||||||
|
|
||||||
var result = true;
|
|
||||||
while (checkTasks.Count > 0)
|
|
||||||
{
|
|
||||||
var finishedCheckTask = await Task.WhenAny<CheckResult>(checkTasks);
|
|
||||||
var finishedCheck = await finishedCheckTask;
|
|
||||||
result = result && finishedCheck.Pass;
|
|
||||||
await File.AppendAllLinesAsync(_logFile, finishedCheck.Logs);
|
|
||||||
checkTasks.Remove(finishedCheckTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.WhenAll(checkTasks);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,417 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.Tracing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using GitHub.Services.Common;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Check
|
|
||||||
{
|
|
||||||
public static class CheckUtil
|
|
||||||
{
|
|
||||||
public static List<string> WarnLog(this IHostContext hostContext)
|
|
||||||
{
|
|
||||||
var logs = new List<string>();
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} **** !!! WARNING !!! ");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} **** DO NOT share the log in public place! The log may contains secrets in plain text. ");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} **** !!! WARNING !!! ");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
return logs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<string> CheckProxy(this IHostContext hostContext)
|
|
||||||
{
|
|
||||||
var logs = new List<string>();
|
|
||||||
if (!string.IsNullOrEmpty(hostContext.WebProxy.HttpProxyAddress) ||
|
|
||||||
!string.IsNullOrEmpty(hostContext.WebProxy.HttpsProxyAddress))
|
|
||||||
{
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} **** Runner is behind web proxy {hostContext.WebProxy.HttpsProxyAddress ?? hostContext.WebProxy.HttpProxyAddress} ");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
}
|
|
||||||
|
|
||||||
return logs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<CheckResult> CheckDns(string targetUrl)
|
|
||||||
{
|
|
||||||
var result = new CheckResult();
|
|
||||||
var url = new Uri(targetUrl);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Try DNS lookup for {url.Host} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
IPHostEntry host = await Dns.GetHostEntryAsync(url.Host);
|
|
||||||
foreach (var address in host.AddressList)
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Resolved DNS for {url.Host} to '{address}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Pass = true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Resolved DNS for {url.Host} failed with error: {ex}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<CheckResult> CheckPing(string targetUrl)
|
|
||||||
{
|
|
||||||
var result = new CheckResult();
|
|
||||||
var url = new Uri(targetUrl);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Try ping {url.Host} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
using (var ping = new Ping())
|
|
||||||
{
|
|
||||||
var reply = await ping.SendPingAsync(url.Host);
|
|
||||||
if (reply.Status == IPStatus.Success)
|
|
||||||
{
|
|
||||||
result.Pass = true;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Ping {url.Host} ({reply.Address}) succeed within to '{reply.RoundtripTime} ms'");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Ping {url.Host} ({reply.Address}) failed with '{reply.Status}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Ping api.github.com failed with error: {ex}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<CheckResult> CheckHttpsGetRequests(this IHostContext hostContext, string url, string pat, string expectedHeader)
|
|
||||||
{
|
|
||||||
var result = new CheckResult();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Send HTTPS Request (GET) to {url} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
using (var _ = new HttpEventSourceListener(result.Logs))
|
|
||||||
using (var httpClientHandler = hostContext.CreateHttpClientHandler())
|
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
|
||||||
{
|
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(hostContext.UserAgents);
|
|
||||||
if (!string.IsNullOrEmpty(pat))
|
|
||||||
{
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", pat);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = await httpClient.GetAsync(url);
|
|
||||||
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http status code: {response.StatusCode}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http response headers: {response.Headers}");
|
|
||||||
|
|
||||||
var responseContent = await response.Content.ReadAsStringAsync();
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http response body: {responseContent}");
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
if (response.Headers.Contains(expectedHeader))
|
|
||||||
{
|
|
||||||
result.Pass = true;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http request 'GET' to {url} succeed");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http request 'GET' to {url} succeed but doesn't have expected HTTP response Header '{expectedHeader}'.");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http request 'GET' to {url} failed with {response.StatusCode}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Https request 'GET' to {url} failed with error: {ex}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<CheckResult> CheckHttpsPostRequests(this IHostContext hostContext, string url, string pat, string expectedHeader)
|
|
||||||
{
|
|
||||||
var result = new CheckResult();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Send HTTPS Request (POST) to {url} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
using (var _ = new HttpEventSourceListener(result.Logs))
|
|
||||||
using (var httpClientHandler = hostContext.CreateHttpClientHandler())
|
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
|
||||||
{
|
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(hostContext.UserAgents);
|
|
||||||
if (!string.IsNullOrEmpty(pat))
|
|
||||||
{
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", pat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send empty JSON '{}' to service
|
|
||||||
var response = await httpClient.PostAsJsonAsync<Dictionary<string, string>>(url, new Dictionary<string, string>());
|
|
||||||
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http status code: {response.StatusCode}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http response headers: {response.Headers}");
|
|
||||||
|
|
||||||
var responseContent = await response.Content.ReadAsStringAsync();
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http response body: {responseContent}");
|
|
||||||
if (response.Headers.Contains(expectedHeader))
|
|
||||||
{
|
|
||||||
result.Pass = true;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http request 'POST' to {url} has expected HTTP response header");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Http request 'POST' to {url} doesn't have expected HTTP response Header '{expectedHeader}'.");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Https request 'POST' to {url} failed with error: {ex}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<CheckResult> DownloadExtraCA(this IHostContext hostContext, string url, string pat)
|
|
||||||
{
|
|
||||||
var result = new CheckResult();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Download SSL Certificate from {url} ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
|
|
||||||
var uri = new Uri(url);
|
|
||||||
var env = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "HOSTNAME", uri.Host },
|
|
||||||
{ "PORT", uri.IsDefaultPort ? (uri.Scheme.ToLowerInvariant() == "https" ? "443" : "80") : uri.Port.ToString() },
|
|
||||||
{ "PATH", uri.AbsolutePath },
|
|
||||||
{ "PAT", pat }
|
|
||||||
};
|
|
||||||
|
|
||||||
var proxy = hostContext.WebProxy.GetProxy(uri);
|
|
||||||
if (proxy != null)
|
|
||||||
{
|
|
||||||
env["PROXYHOST"] = proxy.Host;
|
|
||||||
env["PROXYPORT"] = proxy.IsDefaultPort ? (proxy.Scheme.ToLowerInvariant() == "https" ? "443" : "80") : proxy.Port.ToString();
|
|
||||||
if (hostContext.WebProxy.HttpProxyUsername != null ||
|
|
||||||
hostContext.WebProxy.HttpsProxyUsername != null)
|
|
||||||
{
|
|
||||||
env["PROXYUSERNAME"] = hostContext.WebProxy.HttpProxyUsername ?? hostContext.WebProxy.HttpsProxyUsername;
|
|
||||||
env["PROXYPASSWORD"] = hostContext.WebProxy.HttpProxyPassword ?? hostContext.WebProxy.HttpsProxyPassword;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
env["PROXYUSERNAME"] = "";
|
|
||||||
env["PROXYPASSWORD"] = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
env["PROXYHOST"] = "";
|
|
||||||
env["PROXYPORT"] = "";
|
|
||||||
env["PROXYUSERNAME"] = "";
|
|
||||||
env["PROXYPASSWORD"] = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var processInvoker = hostContext.CreateService<IProcessInvoker>())
|
|
||||||
{
|
|
||||||
processInvoker.OutputDataReceived += new EventHandler<ProcessDataReceivedEventArgs>((sender, args) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(args.Data))
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} [STDOUT] {args.Data}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
processInvoker.ErrorDataReceived += new EventHandler<ProcessDataReceivedEventArgs>((sender, args) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(args.Data))
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} [STDERR] {args.Data}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var downloadCertScript = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Bin), "checkScripts", "downloadCert");
|
|
||||||
var node12 = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Run '{node12} \"{downloadCertScript}\"' ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} {StringUtil.ConvertToJson(env)}");
|
|
||||||
await processInvoker.ExecuteAsync(
|
|
||||||
hostContext.GetDirectory(WellKnownDirectory.Root),
|
|
||||||
node12,
|
|
||||||
$"\"{downloadCertScript}\"",
|
|
||||||
env,
|
|
||||||
true,
|
|
||||||
CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Pass = true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Download SSL Certificate from '{url}' failed with error: {ex}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EventSource listener for dotnet debug trace for HTTP and SSL
|
|
||||||
public sealed class HttpEventSourceListener : EventListener
|
|
||||||
{
|
|
||||||
private readonly List<string> _logs;
|
|
||||||
private readonly object _lock = new object();
|
|
||||||
private readonly Dictionary<string, HashSet<string>> _ignoredEvent = new Dictionary<string, HashSet<string>>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"Microsoft-System-Net-Http",
|
|
||||||
new HashSet<string>
|
|
||||||
{
|
|
||||||
"Info",
|
|
||||||
"Associate",
|
|
||||||
"Enter",
|
|
||||||
"Exit"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Microsoft-System-Net-Security",
|
|
||||||
new HashSet<string>
|
|
||||||
{
|
|
||||||
"Enter",
|
|
||||||
"Exit",
|
|
||||||
"Info",
|
|
||||||
"DumpBuffer",
|
|
||||||
"SslStreamCtor",
|
|
||||||
"SecureChannelCtor",
|
|
||||||
"NoDelegateNoClientCert",
|
|
||||||
"CertsAfterFiltering",
|
|
||||||
"UsingCachedCredential",
|
|
||||||
"SspiSelectedCipherSuite"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public HttpEventSourceListener(List<string> logs)
|
|
||||||
{
|
|
||||||
_logs = logs;
|
|
||||||
if (Environment.GetEnvironmentVariable("ACTIONS_RUNNER_TRACE_ALL_HTTP_EVENT") == "1")
|
|
||||||
{
|
|
||||||
_ignoredEvent.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnEventSourceCreated(EventSource eventSource)
|
|
||||||
{
|
|
||||||
base.OnEventSourceCreated(eventSource);
|
|
||||||
|
|
||||||
if (eventSource.Name == "Microsoft-System-Net-Http" ||
|
|
||||||
eventSource.Name == "Microsoft-System-Net-Security")
|
|
||||||
{
|
|
||||||
EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.All);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnEventWritten(EventWrittenEventArgs eventData)
|
|
||||||
{
|
|
||||||
base.OnEventWritten(eventData);
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (_ignoredEvent.TryGetValue(eventData.EventSource.Name, out var ignored) &&
|
|
||||||
ignored.Contains(eventData.EventName))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logs.Add($"{DateTime.UtcNow.ToString("O")} [START {eventData.EventSource.Name} - {eventData.EventName}]");
|
|
||||||
_logs.AddRange(eventData.Payload.Select(x => string.Join(Environment.NewLine, x.ToString().Split(Environment.NewLine).Select(y => $"{DateTime.UtcNow.ToString("O")} {y}"))));
|
|
||||||
_logs.Add($"{DateTime.UtcNow.ToString("O")} [END {eventData.EventSource.Name} - {eventData.EventName}]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Check
|
|
||||||
{
|
|
||||||
public sealed class GitCheck : RunnerService, ICheckExtension
|
|
||||||
{
|
|
||||||
private string _logFile = null;
|
|
||||||
private string _gitPath = null;
|
|
||||||
|
|
||||||
public int Order => 3;
|
|
||||||
|
|
||||||
public string CheckName => "Git Certificate/Proxy Validation";
|
|
||||||
|
|
||||||
public string CheckDescription => "Check if the Git CLI can access GitHub.com or GitHub Enterprise Server.";
|
|
||||||
|
|
||||||
public string CheckLog => _logFile;
|
|
||||||
|
|
||||||
public string HelpLink => "https://github.com/actions/runner/blob/main/docs/checks/git.md";
|
|
||||||
|
|
||||||
public Type ExtensionType => typeof(ICheckExtension);
|
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
|
||||||
{
|
|
||||||
base.Initialize(hostContext);
|
|
||||||
_logFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Diag), StringUtil.Format("{0}_{1:yyyyMMdd-HHmmss}-utc.log", nameof(GitCheck), DateTime.UtcNow));
|
|
||||||
_gitPath = WhichUtil.Which("git");
|
|
||||||
}
|
|
||||||
|
|
||||||
// git access to ghes/gh
|
|
||||||
public async Task<bool> RunCheck(string url, string pat)
|
|
||||||
{
|
|
||||||
await File.AppendAllLinesAsync(_logFile, HostContext.WarnLog());
|
|
||||||
await File.AppendAllLinesAsync(_logFile, HostContext.CheckProxy());
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_gitPath))
|
|
||||||
{
|
|
||||||
await File.AppendAllLinesAsync(_logFile, new[] { $"{DateTime.UtcNow.ToString("O")} Can't verify git with GitHub.com or GitHub Enterprise Server since git is not installed." });
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var checkGit = await CheckGit(url, pat);
|
|
||||||
var result = checkGit.Pass;
|
|
||||||
await File.AppendAllLinesAsync(_logFile, checkGit.Logs);
|
|
||||||
|
|
||||||
// try fix SSL error by providing extra CA certificate.
|
|
||||||
if (checkGit.SslError)
|
|
||||||
{
|
|
||||||
await File.AppendAllLinesAsync(_logFile, new[] { $"{DateTime.UtcNow.ToString("O")} Try fix SSL error by providing extra CA certificate." });
|
|
||||||
var downloadCert = await HostContext.DownloadExtraCA(url, pat);
|
|
||||||
await File.AppendAllLinesAsync(_logFile, downloadCert.Logs);
|
|
||||||
|
|
||||||
if (downloadCert.Pass)
|
|
||||||
{
|
|
||||||
var recheckGit = await CheckGit(url, pat, extraCA: true);
|
|
||||||
await File.AppendAllLinesAsync(_logFile, recheckGit.Logs);
|
|
||||||
if (recheckGit.Pass)
|
|
||||||
{
|
|
||||||
await File.AppendAllLinesAsync(_logFile, new[] { $"{DateTime.UtcNow.ToString("O")} Fixed SSL error by providing extra CA certs." });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<CheckResult> CheckGit(string url, string pat, bool extraCA = false)
|
|
||||||
{
|
|
||||||
var result = new CheckResult();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Validate server cert and proxy configuration with Git ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
var repoUrlBuilder = new UriBuilder(url);
|
|
||||||
repoUrlBuilder.Path = "actions/checkout";
|
|
||||||
repoUrlBuilder.UserName = "gh";
|
|
||||||
repoUrlBuilder.Password = pat;
|
|
||||||
|
|
||||||
var gitProxy = "";
|
|
||||||
var proxy = HostContext.WebProxy.GetProxy(repoUrlBuilder.Uri);
|
|
||||||
if (proxy != null)
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Runner is behind http proxy '{proxy.AbsoluteUri}'");
|
|
||||||
if (HostContext.WebProxy.HttpProxyUsername != null ||
|
|
||||||
HostContext.WebProxy.HttpsProxyUsername != null)
|
|
||||||
{
|
|
||||||
var proxyUrlWithCred = UrlUtil.GetCredentialEmbeddedUrl(
|
|
||||||
proxy,
|
|
||||||
HostContext.WebProxy.HttpProxyUsername ?? HostContext.WebProxy.HttpsProxyUsername,
|
|
||||||
HostContext.WebProxy.HttpProxyPassword ?? HostContext.WebProxy.HttpsProxyPassword);
|
|
||||||
gitProxy = $"-c http.proxy={proxyUrlWithCred}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gitProxy = $"-c http.proxy={proxy.AbsoluteUri}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
|
||||||
{
|
|
||||||
processInvoker.OutputDataReceived += new EventHandler<ProcessDataReceivedEventArgs>((sender, args) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(args.Data))
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} {args.Data}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
processInvoker.ErrorDataReceived += new EventHandler<ProcessDataReceivedEventArgs>((sender, args) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(args.Data))
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} {args.Data}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var gitArgs = $"{gitProxy} ls-remote --exit-code {repoUrlBuilder.Uri.AbsoluteUri} HEAD";
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Run 'git {gitArgs}' ");
|
|
||||||
|
|
||||||
var env = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "GIT_TRACE", "1" },
|
|
||||||
{ "GIT_CURL_VERBOSE", "1" }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (extraCA)
|
|
||||||
{
|
|
||||||
env["GIT_SSL_CAINFO"] = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), "download_ca_cert.pem");
|
|
||||||
}
|
|
||||||
|
|
||||||
await processInvoker.ExecuteAsync(
|
|
||||||
HostContext.GetDirectory(WellKnownDirectory.Root),
|
|
||||||
_gitPath,
|
|
||||||
gitArgs,
|
|
||||||
env,
|
|
||||||
true,
|
|
||||||
CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Pass = true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** git ls-remote failed with error: {ex}");
|
|
||||||
if (result.Logs.Any(x => x.Contains("SSL Certificate problem", StringComparison.OrdinalIgnoreCase)))
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** git ls-remote failed due to SSL cert issue.");
|
|
||||||
result.SslError = true;
|
|
||||||
}
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Check
|
|
||||||
{
|
|
||||||
public interface ICheckExtension : IExtension
|
|
||||||
{
|
|
||||||
int Order { get; }
|
|
||||||
string CheckName { get; }
|
|
||||||
string CheckDescription { get; }
|
|
||||||
string CheckLog { get; }
|
|
||||||
string HelpLink { get; }
|
|
||||||
Task<bool> RunCheck(string url, string pat);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CheckResult
|
|
||||||
{
|
|
||||||
public CheckResult()
|
|
||||||
{
|
|
||||||
Logs = new List<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Pass { get; set; }
|
|
||||||
|
|
||||||
public bool SslError { get; set; }
|
|
||||||
|
|
||||||
public List<string> Logs { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Check
|
|
||||||
{
|
|
||||||
public sealed class InternetCheck : RunnerService, ICheckExtension
|
|
||||||
{
|
|
||||||
private string _logFile = null;
|
|
||||||
|
|
||||||
public int Order => 1;
|
|
||||||
|
|
||||||
public string CheckName => "Internet Connection";
|
|
||||||
|
|
||||||
public string CheckDescription => "Check if the Actions runner has internet access.";
|
|
||||||
|
|
||||||
public string CheckLog => _logFile;
|
|
||||||
|
|
||||||
public string HelpLink => "https://github.com/actions/runner/blob/main/docs/checks/internet.md";
|
|
||||||
|
|
||||||
public Type ExtensionType => typeof(ICheckExtension);
|
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
|
||||||
{
|
|
||||||
base.Initialize(hostContext);
|
|
||||||
_logFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Diag), StringUtil.Format("{0}_{1:yyyyMMdd-HHmmss}-utc.log", nameof(InternetCheck), DateTime.UtcNow));
|
|
||||||
}
|
|
||||||
|
|
||||||
// check runner access to api.github.com
|
|
||||||
public async Task<bool> RunCheck(string url, string pat)
|
|
||||||
{
|
|
||||||
await File.AppendAllLinesAsync(_logFile, HostContext.WarnLog());
|
|
||||||
await File.AppendAllLinesAsync(_logFile, HostContext.CheckProxy());
|
|
||||||
|
|
||||||
var checkTasks = new List<Task<CheckResult>>();
|
|
||||||
checkTasks.Add(CheckUtil.CheckDns("https://api.github.com"));
|
|
||||||
checkTasks.Add(CheckUtil.CheckPing("https://api.github.com"));
|
|
||||||
|
|
||||||
// We don't need to pass a PAT since it might be a token for GHES.
|
|
||||||
checkTasks.Add(HostContext.CheckHttpsGetRequests("https://api.github.com", pat: null, expectedHeader: "X-GitHub-Request-Id"));
|
|
||||||
|
|
||||||
var result = true;
|
|
||||||
while (checkTasks.Count > 0)
|
|
||||||
{
|
|
||||||
var finishedCheckTask = await Task.WhenAny<CheckResult>(checkTasks);
|
|
||||||
var finishedCheck = await finishedCheckTask;
|
|
||||||
result = result && finishedCheck.Pass;
|
|
||||||
await File.AppendAllLinesAsync(_logFile, finishedCheck.Logs);
|
|
||||||
checkTasks.Remove(finishedCheckTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.WhenAll(checkTasks);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Check
|
|
||||||
{
|
|
||||||
public sealed class NodeJsCheck : RunnerService, ICheckExtension
|
|
||||||
{
|
|
||||||
private string _logFile = null;
|
|
||||||
|
|
||||||
public int Order => 4;
|
|
||||||
|
|
||||||
public string CheckName => "Node.js Certificate/Proxy Validation";
|
|
||||||
|
|
||||||
public string CheckDescription => "Check if Node.js has access to GitHub.com or GitHub Enterprise Server.";
|
|
||||||
|
|
||||||
public string CheckLog => _logFile;
|
|
||||||
|
|
||||||
public string HelpLink => "https://github.com/actions/runner/blob/main/docs/checks/nodejs.md";
|
|
||||||
|
|
||||||
public Type ExtensionType => typeof(ICheckExtension);
|
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
|
||||||
{
|
|
||||||
base.Initialize(hostContext);
|
|
||||||
_logFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Diag), StringUtil.Format("{0}_{1:yyyyMMdd-HHmmss}-utc.log", nameof(NodeJsCheck), DateTime.UtcNow));
|
|
||||||
}
|
|
||||||
|
|
||||||
// node access to ghes/gh
|
|
||||||
public async Task<bool> RunCheck(string url, string pat)
|
|
||||||
{
|
|
||||||
await File.AppendAllLinesAsync(_logFile, HostContext.WarnLog());
|
|
||||||
await File.AppendAllLinesAsync(_logFile, HostContext.CheckProxy());
|
|
||||||
|
|
||||||
// Request to github.com or ghes server
|
|
||||||
var urlBuilder = new UriBuilder(url);
|
|
||||||
if (UrlUtil.IsHostedServer(urlBuilder))
|
|
||||||
{
|
|
||||||
urlBuilder.Host = $"api.{urlBuilder.Host}";
|
|
||||||
urlBuilder.Path = "";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
urlBuilder.Path = "api/v3";
|
|
||||||
}
|
|
||||||
|
|
||||||
var checkNode = await CheckNodeJs(urlBuilder.Uri.AbsoluteUri, pat);
|
|
||||||
var result = checkNode.Pass;
|
|
||||||
await File.AppendAllLinesAsync(_logFile, checkNode.Logs);
|
|
||||||
|
|
||||||
// try fix SSL error by providing extra CA certificate.
|
|
||||||
if (checkNode.SslError)
|
|
||||||
{
|
|
||||||
var downloadCert = await HostContext.DownloadExtraCA(urlBuilder.Uri.AbsoluteUri, pat);
|
|
||||||
await File.AppendAllLinesAsync(_logFile, downloadCert.Logs);
|
|
||||||
|
|
||||||
if (downloadCert.Pass)
|
|
||||||
{
|
|
||||||
var recheckNode = await CheckNodeJs(urlBuilder.Uri.AbsoluteUri, pat, extraCA: true);
|
|
||||||
await File.AppendAllLinesAsync(_logFile, recheckNode.Logs);
|
|
||||||
if (recheckNode.Pass)
|
|
||||||
{
|
|
||||||
await File.AppendAllLinesAsync(_logFile, new[] { $"{DateTime.UtcNow.ToString("O")} Fixed SSL error by providing extra CA certs." });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<CheckResult> CheckNodeJs(string url, string pat, bool extraCA = false)
|
|
||||||
{
|
|
||||||
var result = new CheckResult();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Make Http request to {url} using node.js ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
|
|
||||||
// Request to github.com or ghes server
|
|
||||||
Uri requestUrl = new Uri(url);
|
|
||||||
var env = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "HOSTNAME", requestUrl.Host },
|
|
||||||
{ "PORT", requestUrl.IsDefaultPort ? (requestUrl.Scheme.ToLowerInvariant() == "https" ? "443" : "80") : requestUrl.Port.ToString() },
|
|
||||||
{ "PATH", requestUrl.AbsolutePath },
|
|
||||||
{ "PAT", pat }
|
|
||||||
};
|
|
||||||
|
|
||||||
var proxy = HostContext.WebProxy.GetProxy(requestUrl);
|
|
||||||
if (proxy != null)
|
|
||||||
{
|
|
||||||
env["PROXYHOST"] = proxy.Host;
|
|
||||||
env["PROXYPORT"] = proxy.IsDefaultPort ? (proxy.Scheme.ToLowerInvariant() == "https" ? "443" : "80") : proxy.Port.ToString();
|
|
||||||
if (HostContext.WebProxy.HttpProxyUsername != null ||
|
|
||||||
HostContext.WebProxy.HttpsProxyUsername != null)
|
|
||||||
{
|
|
||||||
env["PROXYUSERNAME"] = HostContext.WebProxy.HttpProxyUsername ?? HostContext.WebProxy.HttpsProxyUsername;
|
|
||||||
env["PROXYPASSWORD"] = HostContext.WebProxy.HttpProxyPassword ?? HostContext.WebProxy.HttpsProxyPassword;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
env["PROXYUSERNAME"] = "";
|
|
||||||
env["PROXYPASSWORD"] = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
env["PROXYHOST"] = "";
|
|
||||||
env["PROXYPORT"] = "";
|
|
||||||
env["PROXYUSERNAME"] = "";
|
|
||||||
env["PROXYPASSWORD"] = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extraCA)
|
|
||||||
{
|
|
||||||
env["NODE_EXTRA_CA_CERTS"] = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), "download_ca_cert.pem");
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
|
||||||
{
|
|
||||||
processInvoker.OutputDataReceived += new EventHandler<ProcessDataReceivedEventArgs>((sender, args) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(args.Data))
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} [STDOUT] {args.Data}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
processInvoker.ErrorDataReceived += new EventHandler<ProcessDataReceivedEventArgs>((sender, args) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(args.Data))
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} [STDERR] {args.Data}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var makeWebRequestScript = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "checkScripts", "makeWebRequest.js");
|
|
||||||
var node12 = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Run '{node12} \"{makeWebRequestScript}\"' ");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} {StringUtil.ConvertToJson(env)}");
|
|
||||||
await processInvoker.ExecuteAsync(
|
|
||||||
HostContext.GetDirectory(WellKnownDirectory.Root),
|
|
||||||
node12,
|
|
||||||
$"\"{makeWebRequestScript}\"",
|
|
||||||
env,
|
|
||||||
true,
|
|
||||||
CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Pass = true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.Pass = false;
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Make https request to {url} using node.js failed with error: {ex}");
|
|
||||||
if (result.Logs.Any(x => x.Contains("UNABLE_TO_VERIFY_LEAF_SIGNATURE") ||
|
|
||||||
x.Contains("UNABLE_TO_GET_ISSUER_CERT_LOCALLY") ||
|
|
||||||
x.Contains("SELF_SIGNED_CERT_IN_CHAIN")))
|
|
||||||
{
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** Https request failed due to SSL cert issue.");
|
|
||||||
result.SslError = true;
|
|
||||||
}
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} **** ****");
|
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} ***************************************************************************************************************");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,6 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
private readonly string[] validFlags =
|
private readonly string[] validFlags =
|
||||||
{
|
{
|
||||||
Constants.Runner.CommandLine.Flags.Check,
|
|
||||||
Constants.Runner.CommandLine.Flags.Commit,
|
Constants.Runner.CommandLine.Flags.Commit,
|
||||||
Constants.Runner.CommandLine.Flags.Help,
|
Constants.Runner.CommandLine.Flags.Help,
|
||||||
Constants.Runner.CommandLine.Flags.Replace,
|
Constants.Runner.CommandLine.Flags.Replace,
|
||||||
@@ -43,7 +42,6 @@ namespace GitHub.Runner.Listener
|
|||||||
Constants.Runner.CommandLine.Args.Labels,
|
Constants.Runner.CommandLine.Args.Labels,
|
||||||
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
||||||
Constants.Runner.CommandLine.Args.Name,
|
Constants.Runner.CommandLine.Args.Name,
|
||||||
Constants.Runner.CommandLine.Args.PAT,
|
|
||||||
Constants.Runner.CommandLine.Args.RunnerGroup,
|
Constants.Runner.CommandLine.Args.RunnerGroup,
|
||||||
Constants.Runner.CommandLine.Args.StartupType,
|
Constants.Runner.CommandLine.Args.StartupType,
|
||||||
Constants.Runner.CommandLine.Args.Token,
|
Constants.Runner.CommandLine.Args.Token,
|
||||||
@@ -61,7 +59,6 @@ namespace GitHub.Runner.Listener
|
|||||||
public bool Warmup => TestCommand(Constants.Runner.CommandLine.Commands.Warmup);
|
public bool Warmup => TestCommand(Constants.Runner.CommandLine.Commands.Warmup);
|
||||||
|
|
||||||
// Flags.
|
// Flags.
|
||||||
public bool Check => TestFlag(Constants.Runner.CommandLine.Flags.Check);
|
|
||||||
public bool Commit => TestFlag(Constants.Runner.CommandLine.Flags.Commit);
|
public bool Commit => TestFlag(Constants.Runner.CommandLine.Flags.Commit);
|
||||||
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
|
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
|
||||||
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
||||||
@@ -190,22 +187,6 @@ namespace GitHub.Runner.Listener
|
|||||||
validator: Validators.NonEmptyValidator);
|
validator: Validators.NonEmptyValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetGitHubPersonalAccessToken(bool required = false)
|
|
||||||
{
|
|
||||||
if (required)
|
|
||||||
{
|
|
||||||
return GetArgOrPrompt(
|
|
||||||
name: Constants.Runner.CommandLine.Args.PAT,
|
|
||||||
description: "What is your GitHub personal access token?",
|
|
||||||
defaultValue: string.Empty,
|
|
||||||
validator: Validators.NonEmptyValidator);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return GetArg(name: Constants.Runner.CommandLine.Args.PAT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetRunnerRegisterToken()
|
public string GetRunnerRegisterToken()
|
||||||
{
|
{
|
||||||
return GetArgOrPrompt(
|
return GetArgOrPrompt(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using GitHub.Runner.Common.Util;
|
|||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.OAuth;
|
using GitHub.Services.OAuth;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -11,7 +12,6 @@ using System.Net.Http;
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Configuration
|
namespace GitHub.Runner.Listener.Configuration
|
||||||
@@ -107,8 +107,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
runnerSettings.GitHubUrl = inputUrl;
|
runnerSettings.GitHubUrl = inputUrl;
|
||||||
var registerToken = await GetRunnerTokenAsync(command, inputUrl, "registration");
|
var githubToken = command.GetRunnerRegisterToken();
|
||||||
GitHubAuthResult authResult = await GetTenantCredential(inputUrl, registerToken, Constants.RunnerEvent.Register);
|
GitHubAuthResult authResult = await GetTenantCredential(inputUrl, githubToken, Constants.RunnerEvent.Register);
|
||||||
runnerSettings.ServerUrl = authResult.TenantUrl;
|
runnerSettings.ServerUrl = authResult.TenantUrl;
|
||||||
creds = authResult.ToVssCredentials();
|
creds = authResult.ToVssCredentials();
|
||||||
Trace.Info("cred retrieved via GitHub auth");
|
Trace.Info("cred retrieved via GitHub auth");
|
||||||
@@ -117,7 +117,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
||||||
runnerSettings.IsHostedServer = runnerSettings.GitHubUrl == null || UrlUtil.IsHostedServer(new UriBuilder(runnerSettings.GitHubUrl));
|
runnerSettings.IsHostedServer = runnerSettings.GitHubUrl == null || IsHostedServer(new UriBuilder(runnerSettings.GitHubUrl));
|
||||||
|
|
||||||
// Warn if the Actions server url and GHES server url has different Host
|
// Warn if the Actions server url and GHES server url has different Host
|
||||||
if (!runnerSettings.IsHostedServer)
|
if (!runnerSettings.IsHostedServer)
|
||||||
@@ -263,7 +263,6 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
{ "clientId", agent.Authorization.ClientId.ToString("D") },
|
{ "clientId", agent.Authorization.ClientId.ToString("D") },
|
||||||
{ "authorizationUrl", agent.Authorization.AuthorizationUrl.AbsoluteUri },
|
{ "authorizationUrl", agent.Authorization.AuthorizationUrl.AbsoluteUri },
|
||||||
{ "requireFipsCryptography", agent.Properties.GetValue("RequireFipsCryptography", false).ToString() }
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -374,8 +373,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var deletionToken = await GetRunnerTokenAsync(command, settings.GitHubUrl, "remove");
|
var githubToken = command.GetRunnerDeletionToken();
|
||||||
GitHubAuthResult authResult = await GetTenantCredential(settings.GitHubUrl, deletionToken, Constants.RunnerEvent.Remove);
|
GitHubAuthResult authResult = await GetTenantCredential(settings.GitHubUrl, githubToken, Constants.RunnerEvent.Remove);
|
||||||
creds = authResult.ToVssCredentials();
|
creds = authResult.ToVssCredentials();
|
||||||
Trace.Info("cred retrieved via GitHub auth");
|
Trace.Info("cred retrieved via GitHub auth");
|
||||||
}
|
}
|
||||||
@@ -509,107 +508,18 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> GetRunnerTokenAsync(CommandSettings command, string githubUrl, string tokenType)
|
private bool IsHostedServer(UriBuilder gitHubUrl)
|
||||||
{
|
{
|
||||||
var githubPAT = command.GetGitHubPersonalAccessToken();
|
return string.Equals(gitHubUrl.Host, "github.com", StringComparison.OrdinalIgnoreCase) ||
|
||||||
var runnerToken = string.Empty;
|
string.Equals(gitHubUrl.Host, "www.github.com", StringComparison.OrdinalIgnoreCase) ||
|
||||||
if (!string.IsNullOrEmpty(githubPAT))
|
string.Equals(gitHubUrl.Host, "github.localhost", StringComparison.OrdinalIgnoreCase);
|
||||||
{
|
|
||||||
Trace.Info($"Retriving runner {tokenType} token using GitHub PAT.");
|
|
||||||
var jitToken = await GetJITRunnerTokenAsync(githubUrl, githubPAT, tokenType);
|
|
||||||
Trace.Info($"Retrived runner {tokenType} token is good to {jitToken.ExpiresAt}.");
|
|
||||||
HostContext.SecretMasker.AddValue(jitToken.Token);
|
|
||||||
runnerToken = jitToken.Token;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(runnerToken))
|
|
||||||
{
|
|
||||||
if (string.Equals("registration", tokenType, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
runnerToken = command.GetRunnerRegisterToken();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
runnerToken = command.GetRunnerDeletionToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return runnerToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<GitHubRunnerRegisterToken> GetJITRunnerTokenAsync(string githubUrl, string githubToken, string tokenType)
|
|
||||||
{
|
|
||||||
var githubApiUrl = "";
|
|
||||||
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
|
||||||
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
if (path.Length == 1)
|
|
||||||
{
|
|
||||||
// org runner
|
|
||||||
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
|
||||||
{
|
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/orgs/{path[0]}/actions/runners/{tokenType}-token";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runners/{tokenType}-token";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (path.Length == 2)
|
|
||||||
{
|
|
||||||
// repo or enterprise runner.
|
|
||||||
var repoScope = "repos/";
|
|
||||||
if (string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
repoScope = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
|
||||||
{
|
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{repoScope}{path[0]}/{path[1]}/actions/runners/{tokenType}-token";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{repoScope}{path[0]}/{path[1]}/actions/runners/{tokenType}-token";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"'{githubUrl}' should point to an org or repository.");
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
|
||||||
{
|
|
||||||
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"github:{githubToken}"));
|
|
||||||
HostContext.SecretMasker.AddValue(base64EncodingToken);
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", base64EncodingToken);
|
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
|
||||||
httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
|
|
||||||
|
|
||||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
|
||||||
return StringUtil.ConvertFromJson<GitHubRunnerRegisterToken>(jsonResponse);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
|
||||||
var errorResponse = await response.Content.ReadAsStringAsync();
|
|
||||||
_term.WriteError(errorResponse);
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<GitHubAuthResult> GetTenantCredential(string githubUrl, string githubToken, string runnerEvent)
|
private async Task<GitHubAuthResult> GetTenantCredential(string githubUrl, string githubToken, string runnerEvent)
|
||||||
{
|
{
|
||||||
var githubApiUrl = "";
|
var githubApiUrl = "";
|
||||||
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
||||||
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
if (IsHostedServer(gitHubUrlBuilder))
|
||||||
{
|
{
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/actions/runner-registration";
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/actions/runner-registration";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,16 +71,6 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public sealed class GitHubRunnerRegisterToken
|
|
||||||
{
|
|
||||||
[DataMember(Name = "token")]
|
|
||||||
public string Token { get; set; }
|
|
||||||
|
|
||||||
[DataMember(Name = "expires_at")]
|
|
||||||
public string ExpiresAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
[DataContract]
|
||||||
public sealed class GitHubAuthResult
|
public sealed class GitHubAuthResult
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
/// key is returned to the caller.
|
/// key is returned to the caller.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>An <c>RSACryptoServiceProvider</c> instance representing the key for the runner</returns>
|
/// <returns>An <c>RSACryptoServiceProvider</c> instance representing the key for the runner</returns>
|
||||||
RSA CreateKey();
|
RSACryptoServiceProvider CreateKey();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes the RSA key managed by the key manager.
|
/// Deletes the RSA key managed by the key manager.
|
||||||
@@ -32,7 +32,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>An <c>RSACryptoServiceProvider</c> instance representing the key for the runner</returns>
|
/// <returns>An <c>RSACryptoServiceProvider</c> instance representing the key for the runner</returns>
|
||||||
/// <exception cref="CryptographicException">No key exists in the store</exception>
|
/// <exception cref="CryptographicException">No key exists in the store</exception>
|
||||||
RSA GetKey();
|
RSACryptoServiceProvider GetKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Newtonsoft 10 is not working properly with dotnet RSAParameters class
|
// Newtonsoft 10 is not working properly with dotnet RSAParameters class
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// We expect the key to be in the machine store at this point. Configuration should have set all of
|
// We expect the key to be in the machine store at this point. Configuration should have set all of
|
||||||
// this up correctly so we can use the key to generate access tokens.
|
// this up correctly so we can use the key to generate access tokens.
|
||||||
var keyManager = context.GetService<IRSAKeyManager>();
|
var keyManager = context.GetService<IRSAKeyManager>();
|
||||||
var signingCredentials = VssSigningCredentials.Create(() => keyManager.GetKey(), StringUtil.ConvertToBoolean(CredentialData.Data.GetValueOrDefault("requireFipsCryptography"), false));
|
var signingCredentials = VssSigningCredentials.Create(() => keyManager.GetKey());
|
||||||
var clientCredential = new VssOAuthJwtBearerClientCredential(clientId, authorizationUrl, signingCredentials);
|
var clientCredential = new VssOAuthJwtBearerClientCredential(clientId, authorizationUrl, signingCredentials);
|
||||||
var agentCredential = new VssOAuthCredential(new Uri(oauthEndpointUrl, UriKind.Absolute), VssOAuthGrant.ClientCredentials, clientCredential);
|
var agentCredential = new VssOAuthCredential(new Uri(oauthEndpointUrl, UriKind.Absolute), VssOAuthGrant.ClientCredentials, clientCredential);
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
private string _keyFile;
|
private string _keyFile;
|
||||||
private IHostContext _context;
|
private IHostContext _context;
|
||||||
|
|
||||||
public RSA CreateKey()
|
public RSACryptoServiceProvider CreateKey()
|
||||||
{
|
{
|
||||||
RSA rsa = null;
|
RSACryptoServiceProvider rsa = null;
|
||||||
if (!File.Exists(_keyFile))
|
if (!File.Exists(_keyFile))
|
||||||
{
|
{
|
||||||
Trace.Info("Creating new RSA key using 2048-bit key length");
|
Trace.Info("Creating new RSA key using 2048-bit key length");
|
||||||
|
|
||||||
rsa = RSA.Create(2048);
|
rsa = new RSACryptoServiceProvider(2048);
|
||||||
|
|
||||||
// Now write the parameters to disk
|
// Now write the parameters to disk
|
||||||
SaveParameters(rsa.ExportParameters(true));
|
SaveParameters(rsa.ExportParameters(true));
|
||||||
@@ -30,7 +30,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
Trace.Info("Found existing RSA key parameters file {0}", _keyFile);
|
Trace.Info("Found existing RSA key parameters file {0}", _keyFile);
|
||||||
|
|
||||||
rsa = RSA.Create();
|
rsa = new RSACryptoServiceProvider();
|
||||||
rsa.ImportParameters(LoadParameters());
|
rsa.ImportParameters(LoadParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RSA GetKey()
|
public RSACryptoServiceProvider GetKey()
|
||||||
{
|
{
|
||||||
if (!File.Exists(_keyFile))
|
if (!File.Exists(_keyFile))
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
Trace.Info("Loading RSA key parameters from file {0}", _keyFile);
|
Trace.Info("Loading RSA key parameters from file {0}", _keyFile);
|
||||||
|
|
||||||
var rsa = RSA.Create();
|
var rsa = new RSACryptoServiceProvider();
|
||||||
rsa.ImportParameters(LoadParameters());
|
rsa.ImportParameters(LoadParameters());
|
||||||
return rsa;
|
return rsa;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
private string _keyFile;
|
private string _keyFile;
|
||||||
private IHostContext _context;
|
private IHostContext _context;
|
||||||
|
|
||||||
public RSA CreateKey()
|
public RSACryptoServiceProvider CreateKey()
|
||||||
{
|
{
|
||||||
RSA rsa = null;
|
RSACryptoServiceProvider rsa = null;
|
||||||
if (!File.Exists(_keyFile))
|
if (!File.Exists(_keyFile))
|
||||||
{
|
{
|
||||||
Trace.Info("Creating new RSA key using 2048-bit key length");
|
Trace.Info("Creating new RSA key using 2048-bit key length");
|
||||||
|
|
||||||
rsa = RSA.Create(2048);
|
rsa = new RSACryptoServiceProvider(2048);
|
||||||
|
|
||||||
// Now write the parameters to disk
|
// Now write the parameters to disk
|
||||||
IOUtil.SaveObject(new RSAParametersSerializable(rsa.ExportParameters(true)), _keyFile);
|
IOUtil.SaveObject(new RSAParametersSerializable(rsa.ExportParameters(true)), _keyFile);
|
||||||
@@ -54,7 +54,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
Trace.Info("Found existing RSA key parameters file {0}", _keyFile);
|
Trace.Info("Found existing RSA key parameters file {0}", _keyFile);
|
||||||
|
|
||||||
rsa = RSA.Create();
|
rsa = new RSACryptoServiceProvider();
|
||||||
rsa.ImportParameters(IOUtil.LoadObject<RSAParametersSerializable>(_keyFile).RSAParameters);
|
rsa.ImportParameters(IOUtil.LoadObject<RSAParametersSerializable>(_keyFile).RSAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RSA GetKey()
|
public RSACryptoServiceProvider GetKey()
|
||||||
{
|
{
|
||||||
if (!File.Exists(_keyFile))
|
if (!File.Exists(_keyFile))
|
||||||
{
|
{
|
||||||
@@ -80,7 +80,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
Trace.Info("Loading RSA key parameters from file {0}", _keyFile);
|
Trace.Info("Loading RSA key parameters from file {0}", _keyFile);
|
||||||
|
|
||||||
var parameters = IOUtil.LoadObject<RSAParametersSerializable>(_keyFile).RSAParameters;
|
var parameters = IOUtil.LoadObject<RSAParametersSerializable>(_keyFile).RSAParameters;
|
||||||
var rsa = RSA.Create();
|
var rsa = new RSACryptoServiceProvider();
|
||||||
rsa.ImportParameters(parameters);
|
rsa.ImportParameters(parameters);
|
||||||
return rsa;
|
return rsa;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,8 +319,7 @@ namespace GitHub.Runner.Listener
|
|||||||
var keyManager = HostContext.GetService<IRSAKeyManager>();
|
var keyManager = HostContext.GetService<IRSAKeyManager>();
|
||||||
using (var rsa = keyManager.GetKey())
|
using (var rsa = keyManager.GetKey())
|
||||||
{
|
{
|
||||||
var padding = _session.UseFipsEncryption ? RSAEncryptionPadding.OaepSHA256 : RSAEncryptionPadding.OaepSHA1;
|
return aes.CreateDecryptor(rsa.Decrypt(_session.EncryptionKey.Value, RSAEncryptionPadding.OaepSHA1), message.IV);
|
||||||
return aes.CreateDecryptor(rsa.Decrypt(_session.EncryptionKey.Value, padding), message.IV);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Listener.Configuration;
|
using GitHub.Runner.Listener.Configuration;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -10,8 +11,6 @@ using System.Reflection;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System.Linq;
|
|
||||||
using GitHub.Runner.Listener.Check;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -73,46 +72,6 @@ namespace GitHub.Runner.Listener
|
|||||||
return Constants.Runner.ReturnCode.Success;
|
return Constants.Runner.ReturnCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.Check)
|
|
||||||
{
|
|
||||||
var url = command.GetUrl();
|
|
||||||
var pat = command.GetGitHubPersonalAccessToken(required: true);
|
|
||||||
var checkExtensions = HostContext.GetService<IExtensionManager>().GetExtensions<ICheckExtension>();
|
|
||||||
var sortedChecks = checkExtensions.OrderBy(x => x.Order);
|
|
||||||
foreach (var check in sortedChecks)
|
|
||||||
{
|
|
||||||
_term.WriteLine($"**********************************************************************************************************************");
|
|
||||||
_term.WriteLine($"** Check: {check.CheckName}");
|
|
||||||
_term.WriteLine($"** Description: {check.CheckDescription}");
|
|
||||||
_term.WriteLine($"**********************************************************************************************************************");
|
|
||||||
var result = await check.RunCheck(url, pat);
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
_term.WriteLine($"** **");
|
|
||||||
_term.WriteLine($"** F A I L **");
|
|
||||||
_term.WriteLine($"** **");
|
|
||||||
_term.WriteLine($"**********************************************************************************************************************");
|
|
||||||
_term.WriteLine($"** Log: {check.CheckLog}");
|
|
||||||
_term.WriteLine($"** Help Doc: {check.HelpLink}");
|
|
||||||
_term.WriteLine($"**********************************************************************************************************************");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_term.WriteLine($"** **");
|
|
||||||
_term.WriteLine($"** P A S S **");
|
|
||||||
_term.WriteLine($"** **");
|
|
||||||
_term.WriteLine($"**********************************************************************************************************************");
|
|
||||||
_term.WriteLine($"** Log: {check.CheckLog}");
|
|
||||||
_term.WriteLine($"**********************************************************************************************************************");
|
|
||||||
}
|
|
||||||
|
|
||||||
_term.WriteLine();
|
|
||||||
_term.WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Constants.Runner.ReturnCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure runner prompt for args if not supplied
|
// Configure runner prompt for args if not supplied
|
||||||
// Unattended configure mode will not prompt for args if not supplied and error on any missing or invalid value.
|
// Unattended configure mode will not prompt for args if not supplied and error on any missing or invalid value.
|
||||||
if (command.Configure)
|
if (command.Configure)
|
||||||
@@ -501,7 +460,6 @@ Options:
|
|||||||
--help Prints the help for each command
|
--help Prints the help for each command
|
||||||
--version Prints the runner version
|
--version Prints the runner version
|
||||||
--commit Prints the runner commit
|
--commit Prints the runner commit
|
||||||
--check Check the runner's network connectivity with GitHub server
|
|
||||||
|
|
||||||
Config Options:
|
Config Options:
|
||||||
--unattended Disable interactive prompts for missing arguments. Defaults will be used for missing options
|
--unattended Disable interactive prompts for missing arguments. Defaults will be used for missing options
|
||||||
@@ -511,8 +469,7 @@ Config Options:
|
|||||||
--runnergroup string Name of the runner group to add this runner to (defaults to the default runner group)
|
--runnergroup string Name of the runner group to add this runner to (defaults to the default runner group)
|
||||||
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
|
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
|
||||||
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
||||||
--replace Replace any existing runner with the same name (default false)
|
--replace Replace any existing runner with the same name (default false)");
|
||||||
--pat GitHub personal access token used for checking network connectivity when executing `.{separator}run.{ext} --check`");
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
_term.WriteLine($@" --runasservice Run the runner as a service");
|
_term.WriteLine($@" --runasservice Run the runner as a service");
|
||||||
_term.WriteLine($@" --windowslogonaccount string Account to run the service as. Requires runasservice");
|
_term.WriteLine($@" --windowslogonaccount string Account to run the service as. Requires runasservice");
|
||||||
@@ -520,8 +477,6 @@ Config Options:
|
|||||||
#endif
|
#endif
|
||||||
_term.WriteLine($@"
|
_term.WriteLine($@"
|
||||||
Examples:
|
Examples:
|
||||||
Check GitHub server network connectivity:
|
|
||||||
.{separator}run.{ext} --check --url <url> --pat <pat>
|
|
||||||
Configure a runner non-interactively:
|
Configure a runner non-interactively:
|
||||||
.{separator}config.{ext} --unattended --url <url> --token <token>
|
.{separator}config.{ext} --unattended --url <url> --token <token>
|
||||||
Configure a runner non-interactively, replacing any existing runner with the same name:
|
Configure a runner non-interactively, replacing any existing runner with the same name:
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using GitHub.Services.Common;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
|
||||||
@@ -112,7 +110,7 @@ namespace GitHub.Runner.Listener
|
|||||||
// old server won't send target version as part of update message.
|
// old server won't send target version as part of update message.
|
||||||
if (string.IsNullOrEmpty(targetVersion))
|
if (string.IsNullOrEmpty(targetVersion))
|
||||||
{
|
{
|
||||||
var packages = await _runnerServer.GetPackagesAsync(_packageType, _platform, 1, true, token);
|
var packages = await _runnerServer.GetPackagesAsync(_packageType, _platform, 1, token);
|
||||||
if (packages == null || packages.Count == 0)
|
if (packages == null || packages.Count == 0)
|
||||||
{
|
{
|
||||||
Trace.Info($"There is no package for {_packageType} and {_platform}.");
|
Trace.Info($"There is no package for {_packageType} and {_platform}.");
|
||||||
@@ -123,7 +121,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_targetPackage = await _runnerServer.GetPackageAsync(_packageType, _platform, targetVersion, true, token);
|
_targetPackage = await _runnerServer.GetPackageAsync(_packageType, _platform, targetVersion, token);
|
||||||
if (_targetPackage == null)
|
if (_targetPackage == null)
|
||||||
{
|
{
|
||||||
Trace.Info($"There is no package for {_packageType} and {_platform} with version {targetVersion}.");
|
Trace.Info($"There is no package for {_packageType} and {_platform} with version {targetVersion}.");
|
||||||
@@ -213,22 +211,12 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
//open zip stream in async mode
|
//open zip stream in async mode
|
||||||
using (HttpClient httpClient = new HttpClient(HostContext.CreateHttpClientHandler()))
|
using (HttpClient httpClient = new HttpClient(HostContext.CreateHttpClientHandler()))
|
||||||
|
using (FileStream fs = new FileStream(archiveFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
|
||||||
|
using (Stream result = await httpClient.GetStreamAsync(_targetPackage.DownloadUrl))
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_targetPackage.Token))
|
//81920 is the default used by System.IO.Stream.CopyTo and is under the large object heap threshold (85k).
|
||||||
{
|
await result.CopyToAsync(fs, 81920, downloadCts.Token);
|
||||||
Trace.Info($"Adding authorization token ({_targetPackage.Token.Length} chars)");
|
await fs.FlushAsync(downloadCts.Token);
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _targetPackage.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
Trace.Info($"Downloading {_targetPackage.DownloadUrl}");
|
|
||||||
|
|
||||||
using (FileStream fs = new FileStream(archiveFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
|
|
||||||
using (Stream result = await httpClient.GetStreamAsync(_targetPackage.DownloadUrl))
|
|
||||||
{
|
|
||||||
//81920 is the default used by System.IO.Stream.CopyTo and is under the large object heap threshold (85k).
|
|
||||||
await result.CopyToAsync(fs, 81920, downloadCts.Token);
|
|
||||||
await fs.FlushAsync(downloadCts.Token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Trace.Info($"Download runner: finished download");
|
Trace.Info($"Download runner: finished download");
|
||||||
@@ -258,24 +246,6 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we got this far, we know that we've successfully downloaded the runner package
|
// If we got this far, we know that we've successfully downloaded the runner package
|
||||||
// Validate Hash Matches if it is provided
|
|
||||||
using (FileStream stream = File.OpenRead(archiveFile))
|
|
||||||
{
|
|
||||||
if (!String.IsNullOrEmpty(_targetPackage.HashValue))
|
|
||||||
{
|
|
||||||
using (SHA256 sha256 = SHA256.Create())
|
|
||||||
{
|
|
||||||
byte[] srcHashBytes = await sha256.ComputeHashAsync(stream);
|
|
||||||
var hash = PrimitiveExtensions.ConvertToHexString(srcHashBytes);
|
|
||||||
if (hash != _targetPackage.HashValue)
|
|
||||||
{
|
|
||||||
// Hash did not match, we can't recover from this, just throw
|
|
||||||
throw new Exception($"Computed runner hash {hash} did not match expected Runner Hash {_targetPackage.HashValue} for {_targetPackage.Filename}");
|
|
||||||
}
|
|
||||||
Trace.Info($"Validated Runner Hash matches {_targetPackage.Filename} : {_targetPackage.HashValue}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (archiveFile.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
|
if (archiveFile.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
ZipFile.ExtractToDirectory(archiveFile, latestRunnerDirectory);
|
ZipFile.ExtractToDirectory(archiveFile, latestRunnerDirectory);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -71,7 +71,7 @@ namespace GitHub.Runner.Sdk
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(httpProxyAddress) && Uri.TryCreate(httpProxyAddress, UriKind.Absolute, out var proxyHttpUri))
|
if (!string.IsNullOrEmpty(httpProxyAddress) && Uri.TryCreate(httpProxyAddress, UriKind.Absolute, out var proxyHttpUri))
|
||||||
{
|
{
|
||||||
_httpProxyAddress = proxyHttpUri.OriginalString;
|
_httpProxyAddress = proxyHttpUri.AbsoluteUri;
|
||||||
|
|
||||||
// Set both environment variables since there are tools support both casing (curl, wget) and tools support only one casing (docker)
|
// Set both environment variables since there are tools support both casing (curl, wget) and tools support only one casing (docker)
|
||||||
Environment.SetEnvironmentVariable("HTTP_PROXY", _httpProxyAddress);
|
Environment.SetEnvironmentVariable("HTTP_PROXY", _httpProxyAddress);
|
||||||
@@ -101,7 +101,7 @@ namespace GitHub.Runner.Sdk
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(httpsProxyAddress) && Uri.TryCreate(httpsProxyAddress, UriKind.Absolute, out var proxyHttpsUri))
|
if (!string.IsNullOrEmpty(httpsProxyAddress) && Uri.TryCreate(httpsProxyAddress, UriKind.Absolute, out var proxyHttpsUri))
|
||||||
{
|
{
|
||||||
_httpsProxyAddress = proxyHttpsUri.OriginalString;
|
_httpsProxyAddress = proxyHttpsUri.AbsoluteUri;
|
||||||
|
|
||||||
// Set both environment variables since there are tools support both casing (curl, wget) and tools support only one casing (docker)
|
// Set both environment variables since there are tools support both casing (curl, wget) and tools support only one casing (docker)
|
||||||
Environment.SetEnvironmentVariable("HTTPS_PROXY", _httpsProxyAddress);
|
Environment.SetEnvironmentVariable("HTTPS_PROXY", _httpsProxyAddress);
|
||||||
|
|||||||
@@ -4,13 +4,6 @@ namespace GitHub.Runner.Sdk
|
|||||||
{
|
{
|
||||||
public static class UrlUtil
|
public static class UrlUtil
|
||||||
{
|
{
|
||||||
public static bool IsHostedServer(UriBuilder gitHubUrl)
|
|
||||||
{
|
|
||||||
return string.Equals(gitHubUrl.Host, "github.com", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(gitHubUrl.Host, "www.github.com", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(gitHubUrl.Host, "github.localhost", StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri GetCredentialEmbeddedUrl(Uri baseUrl, string username, string password)
|
public static Uri GetCredentialEmbeddedUrl(Uri baseUrl, string username, string password)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(baseUrl, nameof(baseUrl));
|
ArgUtil.NotNull(baseUrl, nameof(baseUrl));
|
||||||
|
|||||||
@@ -184,6 +184,9 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
||||||
{
|
{
|
||||||
|
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
||||||
|
var isHostedServer = configurationStore.GetSettings().IsHostedServer;
|
||||||
|
|
||||||
var allowUnsecureCommands = false;
|
var allowUnsecureCommands = false;
|
||||||
bool.TryParse(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedCommands), out allowUnsecureCommands);
|
bool.TryParse(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedCommands), out allowUnsecureCommands);
|
||||||
|
|
||||||
@@ -198,10 +201,22 @@ namespace GitHub.Runner.Worker
|
|||||||
bool.TryParse(envContext[Constants.Variables.Actions.AllowUnsupportedCommands].ToString(), out allowUnsecureCommands);
|
bool.TryParse(envContext[Constants.Variables.Actions.AllowUnsupportedCommands].ToString(), out allowUnsecureCommands);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!allowUnsecureCommands)
|
// TODO: Eventually remove isHostedServer and apply this to dotcom customers as well
|
||||||
|
if (!isHostedServer && !allowUnsecureCommands)
|
||||||
{
|
{
|
||||||
throw new Exception(String.Format(Constants.Runner.UnsupportedCommandMessageDisabled, this.Command));
|
throw new Exception(String.Format(Constants.Runner.UnsupportedCommandMessageDisabled, this.Command));
|
||||||
}
|
}
|
||||||
|
else if (!allowUnsecureCommands)
|
||||||
|
{
|
||||||
|
// Log Telemetry and let user know they shouldn't do this
|
||||||
|
var issue = new Issue()
|
||||||
|
{
|
||||||
|
Type = IssueType.Error,
|
||||||
|
Message = String.Format(Constants.Runner.UnsupportedCommandMessage, this.Command)
|
||||||
|
};
|
||||||
|
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.UnsupportedCommand;
|
||||||
|
context.AddIssue(issue);
|
||||||
|
}
|
||||||
|
|
||||||
if (!command.Properties.TryGetValue(SetEnvCommandProperties.Name, out string envName) || string.IsNullOrEmpty(envName))
|
if (!command.Properties.TryGetValue(SetEnvCommandProperties.Name, out string envName) || string.IsNullOrEmpty(envName))
|
||||||
{
|
{
|
||||||
@@ -324,7 +339,10 @@ namespace GitHub.Runner.Worker
|
|||||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
||||||
{
|
{
|
||||||
|
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
||||||
|
var isHostedServer = configurationStore.GetSettings().IsHostedServer;
|
||||||
|
|
||||||
var allowUnsecureCommands = false;
|
var allowUnsecureCommands = false;
|
||||||
bool.TryParse(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedCommands), out allowUnsecureCommands);
|
bool.TryParse(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedCommands), out allowUnsecureCommands);
|
||||||
|
|
||||||
@@ -339,10 +357,22 @@ namespace GitHub.Runner.Worker
|
|||||||
bool.TryParse(envContext[Constants.Variables.Actions.AllowUnsupportedCommands].ToString(), out allowUnsecureCommands);
|
bool.TryParse(envContext[Constants.Variables.Actions.AllowUnsupportedCommands].ToString(), out allowUnsecureCommands);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!allowUnsecureCommands)
|
// TODO: Eventually remove isHostedServer and apply this to dotcom customers as well
|
||||||
|
if (!isHostedServer && !allowUnsecureCommands)
|
||||||
{
|
{
|
||||||
throw new Exception(String.Format(Constants.Runner.UnsupportedCommandMessageDisabled, this.Command));
|
throw new Exception(String.Format(Constants.Runner.UnsupportedCommandMessageDisabled, this.Command));
|
||||||
}
|
}
|
||||||
|
else if (!allowUnsecureCommands)
|
||||||
|
{
|
||||||
|
// Log Telemetry and let user know they shouldn't do this
|
||||||
|
var issue = new Issue()
|
||||||
|
{
|
||||||
|
Type = IssueType.Error,
|
||||||
|
Message = String.Format(Constants.Runner.UnsupportedCommandMessage, this.Command)
|
||||||
|
};
|
||||||
|
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.UnsupportedCommand;
|
||||||
|
context.AddIssue(issue);
|
||||||
|
}
|
||||||
|
|
||||||
ArgUtil.NotNullOrEmpty(command.Data, "path");
|
ArgUtil.NotNullOrEmpty(command.Data, "path");
|
||||||
context.Global.PrependPath.RemoveAll(x => string.Equals(x, command.Data, StringComparison.CurrentCulture));
|
context.Global.PrependPath.RemoveAll(x => string.Equals(x, command.Data, StringComparison.CurrentCulture));
|
||||||
|
|||||||
@@ -594,33 +594,15 @@ namespace GitHub.Runner.Worker
|
|||||||
actionDownloadInfos = await jobServer.ResolveActionDownloadInfoAsync(executionContext.Global.Plan.ScopeIdentifier, executionContext.Global.Plan.PlanType, executionContext.Global.Plan.PlanId, new WebApi.ActionReferenceList { Actions = actionReferences }, executionContext.CancellationToken);
|
actionDownloadInfos = await jobServer.ResolveActionDownloadInfoAsync(executionContext.Global.Plan.ScopeIdentifier, executionContext.Global.Plan.PlanType, executionContext.Global.Plan.PlanId, new WebApi.ActionReferenceList { Actions = actionReferences }, executionContext.CancellationToken);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!executionContext.CancellationToken.IsCancellationRequested) // Do not retry if the run is canceled.
|
catch (Exception ex) when (attempt < 3)
|
||||||
{
|
{
|
||||||
if (attempt < 3)
|
executionContext.Output($"Failed to resolve action download info. Error: {ex.Message}");
|
||||||
|
executionContext.Debug(ex.ToString());
|
||||||
|
if (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("_GITHUB_ACTION_DOWNLOAD_NO_BACKOFF")))
|
||||||
{
|
{
|
||||||
executionContext.Output($"Failed to resolve action download info. Error: {ex.Message}");
|
var backoff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(30));
|
||||||
executionContext.Debug(ex.ToString());
|
executionContext.Output($"Retrying in {backoff.TotalSeconds} seconds");
|
||||||
if (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("_GITHUB_ACTION_DOWNLOAD_NO_BACKOFF")))
|
await Task.Delay(backoff);
|
||||||
{
|
|
||||||
var backoff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(30));
|
|
||||||
executionContext.Output($"Retrying in {backoff.TotalSeconds} seconds");
|
|
||||||
await Task.Delay(backoff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Some possible cases are:
|
|
||||||
// * Repo is rate limited
|
|
||||||
// * Repo or tag doesn't exist, or isn't public
|
|
||||||
if (ex is WebApi.UnresolvableActionDownloadInfoException)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This exception will be traced as an infrastructure failure
|
|
||||||
throw new WebApi.FailedToResolveActionDownloadInfoException("Failed to resolve action download info.", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,19 +135,6 @@ namespace GitHub.Runner.Worker
|
|||||||
ExecutionContext.SetGitHubContext("event_path", workflowFile);
|
ExecutionContext.SetGitHubContext("event_path", workflowFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set GITHUB_ACTION_REPOSITORY if this Action is from a repository
|
|
||||||
if (Action.Reference is Pipelines.RepositoryPathReference repoPathReferenceAction &&
|
|
||||||
!string.Equals(repoPathReferenceAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
ExecutionContext.SetGitHubContext("action_repository", repoPathReferenceAction.Name);
|
|
||||||
ExecutionContext.SetGitHubContext("action_ref", repoPathReferenceAction.Ref);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExecutionContext.SetGitHubContext("action_repository", null);
|
|
||||||
ExecutionContext.SetGitHubContext("action_ref", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup container stephost for running inside the container.
|
// Setup container stephost for running inside the container.
|
||||||
if (ExecutionContext.Global.Container != null)
|
if (ExecutionContext.Global.Container != null)
|
||||||
{
|
{
|
||||||
@@ -255,11 +242,11 @@ namespace GitHub.Runner.Worker
|
|||||||
handler.PrintActionDetails(Stage);
|
handler.PrintActionDetails(Stage);
|
||||||
|
|
||||||
// Run the task.
|
// Run the task.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await handler.RunAsync(Stage);
|
await handler.RunAsync(Stage);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
fileCommandManager.ProcessFiles(ExecutionContext, ExecutionContext.Global.Container);
|
fileCommandManager.ProcessFiles(ExecutionContext, ExecutionContext.Global.Container);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContainerInfo(IHostContext hostContext)
|
|
||||||
{
|
|
||||||
UpdateWebProxyEnv(hostContext.WebProxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContainerInfo(IHostContext hostContext, Pipelines.JobContainer container, bool isJobContainer = true, string networkAlias = null)
|
public ContainerInfo(IHostContext hostContext, Pipelines.JobContainer container, bool isJobContainer = true, string networkAlias = null)
|
||||||
{
|
{
|
||||||
this.ContainerName = container.Alias;
|
this.ContainerName = container.Alias;
|
||||||
|
|||||||
@@ -197,8 +197,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
|
|
||||||
dockerOptions.Add($"--workdir {container.ContainerWorkDirectory}");
|
dockerOptions.Add($"--workdir {container.ContainerWorkDirectory}");
|
||||||
dockerOptions.Add($"--rm");
|
dockerOptions.Add($"--rm");
|
||||||
dockerOptions.Add($"-t");
|
|
||||||
|
|
||||||
foreach (var env in container.ContainerEnvironmentVariables)
|
foreach (var env in container.ContainerEnvironmentVariables)
|
||||||
{
|
{
|
||||||
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
Dictionary<string, string> IntraActionState { get; }
|
Dictionary<string, string> IntraActionState { get; }
|
||||||
Dictionary<string, VariableValue> JobOutputs { get; }
|
Dictionary<string, VariableValue> JobOutputs { get; }
|
||||||
ActionsEnvironmentReference ActionsEnvironment { get; }
|
|
||||||
DictionaryContextData ExpressionValues { get; }
|
DictionaryContextData ExpressionValues { get; }
|
||||||
IList<IFunctionInfo> ExpressionFunctions { get; }
|
IList<IFunctionInfo> ExpressionFunctions { get; }
|
||||||
JobContext JobContext { get; }
|
JobContext JobContext { get; }
|
||||||
@@ -138,8 +137,6 @@ namespace GitHub.Runner.Worker
|
|||||||
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
||||||
public Dictionary<string, string> IntraActionState { get; private set; }
|
public Dictionary<string, string> IntraActionState { get; private set; }
|
||||||
public Dictionary<string, VariableValue> JobOutputs { get; private set; }
|
public Dictionary<string, VariableValue> JobOutputs { get; private set; }
|
||||||
|
|
||||||
public ActionsEnvironmentReference ActionsEnvironment { get; private set; }
|
|
||||||
public DictionaryContextData ExpressionValues { get; } = new DictionaryContextData();
|
public DictionaryContextData ExpressionValues { get; } = new DictionaryContextData();
|
||||||
public IList<IFunctionInfo> ExpressionFunctions { get; } = new List<IFunctionInfo>();
|
public IList<IFunctionInfo> ExpressionFunctions { get; } = new List<IFunctionInfo>();
|
||||||
|
|
||||||
@@ -255,7 +252,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper function used in CompositeActionHandler::RunAsync to
|
/// Helper function used in CompositeActionHandler::RunAsync to
|
||||||
/// add a child node, aka a step, to the current job to the Root.JobSteps based on the location.
|
/// add a child node, aka a step, to the current job to the Root.JobSteps based on the location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IStep CreateCompositeStep(
|
public IStep CreateCompositeStep(
|
||||||
string scopeName,
|
string scopeName,
|
||||||
@@ -381,7 +378,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (Root != this)
|
if (Root != this)
|
||||||
{
|
{
|
||||||
// only dispose TokenSource for step level ExecutionContext
|
// only dispose TokenSource for step level ExecutionContext
|
||||||
_cancellationTokenSource?.Dispose();
|
_cancellationTokenSource?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,9 +611,6 @@ namespace GitHub.Runner.Worker
|
|||||||
// Job Outputs
|
// Job Outputs
|
||||||
JobOutputs = new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
|
JobOutputs = new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
// Actions environment
|
|
||||||
ActionsEnvironment = message.ActionsEnvironment;
|
|
||||||
|
|
||||||
// Service container info
|
// Service container info
|
||||||
Global.ServiceContainers = new List<ContainerInfo>();
|
Global.ServiceContainers = new List<ContainerInfo>();
|
||||||
|
|
||||||
@@ -724,6 +718,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
_jobServerQueue.QueueWebConsoleLine(_record.Id, msg, totalLines);
|
_jobServerQueue.QueueWebConsoleLine(_record.Id, msg, totalLines);
|
||||||
|
|
||||||
return totalLines;
|
return totalLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,10 +853,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
_record.ParentId = parentTimelineRecordId;
|
_record.ParentId = parentTimelineRecordId;
|
||||||
}
|
}
|
||||||
else if (parentTimelineRecordId == null)
|
|
||||||
{
|
|
||||||
_record.AgentPlatform = VarUtil.OS;
|
|
||||||
}
|
|
||||||
|
|
||||||
var configuration = HostContext.GetService<IConfigurationStore>();
|
var configuration = HostContext.GetService<IConfigurationStore>();
|
||||||
_record.WorkerName = configuration.GetSettings().AgentName;
|
_record.WorkerName = configuration.GetSettings().AgentName;
|
||||||
@@ -922,12 +913,6 @@ namespace GitHub.Runner.Worker
|
|||||||
context.AddIssue(new Issue() { Type = IssueType.Error, Message = message });
|
context.AddIssue(new Issue() { Type = IssueType.Error, Message = message });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
|
||||||
public static void InfrastructureError(this IExecutionContext context, string message)
|
|
||||||
{
|
|
||||||
context.AddIssue(new Issue() { Type = IssueType.Error, Message = message, IsInfrastructureIssue = true});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
||||||
public static void Warning(this IExecutionContext context, string message)
|
public static void Warning(this IExecutionContext context, string message)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
"action",
|
"action",
|
||||||
"action_path",
|
"action_path",
|
||||||
"action_ref",
|
|
||||||
"action_repository",
|
|
||||||
"actor",
|
"actor",
|
||||||
"api_url",
|
"api_url",
|
||||||
"base_ref",
|
"base_ref",
|
||||||
@@ -57,4 +55,4 @@ namespace GitHub.Runner.Worker
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run container
|
// run container
|
||||||
var container = new ContainerInfo(HostContext)
|
var container = new ContainerInfo()
|
||||||
{
|
{
|
||||||
ContainerImage = Data.Image,
|
ContainerImage = Data.Image,
|
||||||
ContainerName = ExecutionContext.Id.ToString("N"),
|
ContainerName = ExecutionContext.Id.ToString("N"),
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
dockerCommandArgs.Add($"exec");
|
dockerCommandArgs.Add($"exec");
|
||||||
|
|
||||||
// [OPTIONS]
|
// [OPTIONS]
|
||||||
dockerCommandArgs.Add($"-it");
|
dockerCommandArgs.Add($"-i");
|
||||||
dockerCommandArgs.Add($"--workdir {workingDirectory}");
|
dockerCommandArgs.Add($"--workdir {workingDirectory}");
|
||||||
foreach (var env in environment)
|
foreach (var env in environment)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
@@ -42,8 +41,6 @@ namespace GitHub.Runner.Worker
|
|||||||
private readonly HashSet<string> _existingProcesses = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
private readonly HashSet<string> _existingProcesses = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
private bool _processCleanup;
|
private bool _processCleanup;
|
||||||
private string _processLookupId = $"github_{Guid.NewGuid()}";
|
private string _processLookupId = $"github_{Guid.NewGuid()}";
|
||||||
private CancellationTokenSource _diskSpaceCheckToken = new CancellationTokenSource();
|
|
||||||
private Task _diskSpaceCheckTask = null;
|
|
||||||
|
|
||||||
// Download all required actions.
|
// Download all required actions.
|
||||||
// Make sure all condition inputs are valid.
|
// Make sure all condition inputs are valid.
|
||||||
@@ -77,10 +74,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
// print out HostName for self-hosted runner
|
// print out HostName for self-hosted runner
|
||||||
context.Output($"Runner name: '{setting.AgentName}'");
|
context.Output($"Runner name: '{setting.AgentName}'");
|
||||||
if (message.Variables.TryGetValue("system.runnerGroupName", out VariableValue runnerGroupName))
|
|
||||||
{
|
|
||||||
context.Output($"Runner group name: '{runnerGroupName.Value}'");
|
|
||||||
}
|
|
||||||
context.Output($"Machine name: '{Environment.MachineName}'");
|
context.Output($"Machine name: '{Environment.MachineName}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,26 +115,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var tokenPermissions = jobContext.Global.Variables.Get("system.github.token.permissions") ?? "";
|
|
||||||
if (!string.IsNullOrEmpty(tokenPermissions))
|
|
||||||
{
|
|
||||||
context.Output($"##[group]GITHUB_TOKEN Permissions");
|
|
||||||
var permissions = StringUtil.ConvertFromJson<Dictionary<string, string>>(tokenPermissions);
|
|
||||||
foreach(KeyValuePair<string, string> entry in permissions)
|
|
||||||
{
|
|
||||||
context.Output($"{entry.Key}: {entry.Value}");
|
|
||||||
}
|
|
||||||
context.Output("##[endgroup]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
context.Output($"Fail to parse and display GITHUB_TOKEN permissions list: {ex.Message}");
|
|
||||||
Trace.Error(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
var repoFullName = context.GetGitHubContext("repository");
|
var repoFullName = context.GetGitHubContext("repository");
|
||||||
ArgUtil.NotNull(repoFullName, nameof(repoFullName));
|
ArgUtil.NotNull(repoFullName, nameof(repoFullName));
|
||||||
context.Debug($"Primary repository: {repoFullName}");
|
context.Debug($"Primary repository: {repoFullName}");
|
||||||
@@ -348,12 +321,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jobContext.Global.EnvironmentVariables.TryGetValue(Constants.Runner.Features.DiskSpaceWarning, out var enableWarning);
|
|
||||||
if (StringUtil.ConvertToBoolean(enableWarning, defaultValue: true))
|
|
||||||
{
|
|
||||||
_diskSpaceCheckTask = CheckDiskSpaceAsync(context, _diskSpaceCheckToken.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return steps;
|
return steps;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException ex) when (jobContext.CancellationToken.IsCancellationRequested)
|
catch (OperationCanceledException ex) when (jobContext.CancellationToken.IsCancellationRequested)
|
||||||
@@ -364,14 +331,6 @@ namespace GitHub.Runner.Worker
|
|||||||
context.Result = TaskResult.Canceled;
|
context.Result = TaskResult.Canceled;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (FailedToResolveActionDownloadInfoException ex)
|
|
||||||
{
|
|
||||||
// Log the error and fail the JobExtension Initialization.
|
|
||||||
Trace.Error($"Caught exception from JobExtenion Initialization: {ex}");
|
|
||||||
context.InfrastructureError(ex.Message);
|
|
||||||
context.Result = TaskResult.Failed;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Log the error and fail the JobExtension Initialization.
|
// Log the error and fail the JobExtension Initialization.
|
||||||
@@ -402,24 +361,6 @@ namespace GitHub.Runner.Worker
|
|||||||
context.Start();
|
context.Start();
|
||||||
context.Debug("Starting: Complete job");
|
context.Debug("Starting: Complete job");
|
||||||
|
|
||||||
Trace.Info("Initialize Env context");
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
var envContext = new DictionaryContextData();
|
|
||||||
#else
|
|
||||||
var envContext = new CaseSensitiveDictionaryContextData();
|
|
||||||
#endif
|
|
||||||
context.ExpressionValues["env"] = envContext;
|
|
||||||
foreach (var pair in context.Global.EnvironmentVariables)
|
|
||||||
{
|
|
||||||
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate env context for each step
|
|
||||||
Trace.Info("Initialize steps context");
|
|
||||||
context.ExpressionValues["steps"] = context.Global.StepsContext.GetScope(context.ScopeName);
|
|
||||||
|
|
||||||
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
|
||||||
// Evaluate job outputs
|
// Evaluate job outputs
|
||||||
if (message.JobOutputs != null && message.JobOutputs.Type != TokenType.Null)
|
if (message.JobOutputs != null && message.JobOutputs.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
@@ -429,7 +370,21 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// Populate env context for each step
|
// Populate env context for each step
|
||||||
Trace.Info("Initialize Env context for evaluating job outputs");
|
Trace.Info("Initialize Env context for evaluating job outputs");
|
||||||
|
#if OS_WINDOWS
|
||||||
|
var envContext = new DictionaryContextData();
|
||||||
|
#else
|
||||||
|
var envContext = new CaseSensitiveDictionaryContextData();
|
||||||
|
#endif
|
||||||
|
context.ExpressionValues["env"] = envContext;
|
||||||
|
foreach (var pair in context.Global.EnvironmentVariables)
|
||||||
|
{
|
||||||
|
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.Info("Initialize steps context for evaluating job outputs");
|
||||||
|
context.ExpressionValues["steps"] = context.Global.StepsContext.GetScope(context.ScopeName);
|
||||||
|
|
||||||
|
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
||||||
var outputs = templateEvaluator.EvaluateJobOutput(message.JobOutputs, context.ExpressionValues, context.ExpressionFunctions);
|
var outputs = templateEvaluator.EvaluateJobOutput(message.JobOutputs, context.ExpressionValues, context.ExpressionFunctions);
|
||||||
foreach (var output in outputs)
|
foreach (var output in outputs)
|
||||||
{
|
{
|
||||||
@@ -458,34 +413,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate environment data
|
|
||||||
if (jobContext.ActionsEnvironment?.Url != null && jobContext.ActionsEnvironment?.Url.Type != TokenType.Null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
context.Output($"Evaluate and set environment url");
|
|
||||||
|
|
||||||
var environmentUrlToken = templateEvaluator.EvaluateEnvironmentUrl(jobContext.ActionsEnvironment.Url, context.ExpressionValues, context.ExpressionFunctions);
|
|
||||||
var environmentUrl = environmentUrlToken.AssertString("environment.url");
|
|
||||||
if (!string.Equals(environmentUrl.Value, HostContext.SecretMasker.MaskSecrets(environmentUrl.Value)))
|
|
||||||
{
|
|
||||||
context.Warning($"Skip setting environment url as environment '{jobContext.ActionsEnvironment.Name}' may contain secret.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
context.Output($"Evaluated environment url: {environmentUrl}");
|
|
||||||
jobContext.ActionsEnvironment.Url = environmentUrlToken;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
context.Result = TaskResult.Failed;
|
|
||||||
context.Error($"Failed to evaluate environment url");
|
|
||||||
context.Error(ex);
|
|
||||||
jobContext.Result = TaskResultUtil.MergeTaskResults(jobContext.Result, TaskResult.Failed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Global.Variables.GetBoolean(Constants.Variables.Actions.RunnerDebug) ?? false)
|
if (context.Global.Variables.GetBoolean(Constants.Variables.Actions.RunnerDebug) ?? false)
|
||||||
{
|
{
|
||||||
Trace.Info("Support log upload starting.");
|
Trace.Info("Support log upload starting.");
|
||||||
@@ -558,11 +485,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_diskSpaceCheckTask != null)
|
|
||||||
{
|
|
||||||
_diskSpaceCheckToken.Cancel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -578,39 +500,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CheckDiskSpaceAsync(IExecutionContext context, CancellationToken token)
|
|
||||||
{
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
// Add warning when disk is lower than system.runner.lowdiskspacethreshold from service (default to 100 MB on service side)
|
|
||||||
var lowDiskSpaceThreshold = context.Global.Variables.GetInt(WellKnownDistributedTaskVariables.RunnerLowDiskspaceThreshold);
|
|
||||||
if (lowDiskSpaceThreshold == null)
|
|
||||||
{
|
|
||||||
Trace.Info($"Low diskspace warning is not enabled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var workDirRoot = Directory.GetDirectoryRoot(HostContext.GetDirectory(WellKnownDirectory.Work));
|
|
||||||
var driveInfo = new DriveInfo(workDirRoot);
|
|
||||||
var freeSpaceInMB = driveInfo.AvailableFreeSpace / 1024 / 1024;
|
|
||||||
if (freeSpaceInMB < lowDiskSpaceThreshold)
|
|
||||||
{
|
|
||||||
var issue = new Issue() { Type = IssueType.Warning, Message = $"You are running out of disk space. The runner will stop working when the machine runs out of disk space. Free space left: {freeSpaceInMB} MB" };
|
|
||||||
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.LowDiskSpace;
|
|
||||||
context.AddIssue(issue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Task.Delay(10 * 1000, token);
|
|
||||||
}
|
|
||||||
catch (TaskCanceledException)
|
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<int, Process> SnapshotProcesses()
|
private Dictionary<int, Process> SnapshotProcesses()
|
||||||
{
|
{
|
||||||
Dictionary<int, Process> snapshot = new Dictionary<int, Process>();
|
Dictionary<int, Process> snapshot = new Dictionary<int, Process>();
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
Trace.Info("Raising job completed event.");
|
Trace.Info("Raising job completed event.");
|
||||||
var jobCompletedEvent = new JobCompletedEvent(message.RequestId, message.JobId, result, jobContext.JobOutputs, jobContext.ActionsEnvironment);
|
var jobCompletedEvent = new JobCompletedEvent(message.RequestId, message.JobId, result, jobContext.JobOutputs);
|
||||||
|
|
||||||
var completeJobRetryLimit = 5;
|
var completeJobRetryLimit = 5;
|
||||||
var exceptions = new List<Exception>();
|
var exceptions = new List<Exception>();
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace GitHub.Services.Common
|
|
||||||
{
|
|
||||||
public static class HashAlgorithmExtensions
|
|
||||||
{
|
|
||||||
public static async Task<byte[]> ComputeHashAsync(this HashAlgorithm hashAlg, Stream inputStream)
|
|
||||||
{
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int read = await inputStream.ReadAsync(buffer, 0, buffer.Length);
|
|
||||||
if (read == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
hashAlg.TransformBlock(buffer, 0, read, null, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
hashAlg.TransformFinalBlock(buffer, 0, 0);
|
|
||||||
return hashAlg.Hash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -85,19 +85,5 @@ namespace GitHub.Services.Common
|
|||||||
var bytes = FromBase64StringNoPadding(base64String);
|
var bytes = FromBase64StringNoPadding(base64String);
|
||||||
return BitConverter.ToString(bytes).Replace("-", String.Empty);
|
return BitConverter.ToString(bytes).Replace("-", String.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts byte array into a hex string
|
|
||||||
/// </summary>
|
|
||||||
public static String ConvertToHexString(byte[] bytes)
|
|
||||||
{
|
|
||||||
// Convert byte array to string
|
|
||||||
var sBuilder = new StringBuilder();
|
|
||||||
for (int i = 0; i < bytes.Length; i++)
|
|
||||||
{
|
|
||||||
sBuilder.Append(bytes[i].ToString("x2"));
|
|
||||||
}
|
|
||||||
return sBuilder.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -587,7 +587,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
/// <param name="packageType"></param>
|
/// <param name="packageType"></param>
|
||||||
/// <param name="platform"></param>
|
/// <param name="platform"></param>
|
||||||
/// <param name="version"></param>
|
/// <param name="version"></param>
|
||||||
/// <param name="includeToken"></param>
|
|
||||||
/// <param name="userState"></param>
|
/// <param name="userState"></param>
|
||||||
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
@@ -595,7 +594,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
string packageType,
|
string packageType,
|
||||||
string platform,
|
string platform,
|
||||||
string version,
|
string version,
|
||||||
bool? includeToken = null,
|
|
||||||
object userState = null,
|
object userState = null,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
@@ -603,18 +601,11 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
Guid locationId = new Guid("8ffcd551-079c-493a-9c02-54346299d144");
|
Guid locationId = new Guid("8ffcd551-079c-493a-9c02-54346299d144");
|
||||||
object routeValues = new { packageType = packageType, platform = platform, version = version };
|
object routeValues = new { packageType = packageType, platform = platform, version = version };
|
||||||
|
|
||||||
List<KeyValuePair<string, string>> queryParams = new List<KeyValuePair<string, string>>();
|
|
||||||
if (includeToken != null)
|
|
||||||
{
|
|
||||||
queryParams.Add("includeToken", includeToken.Value.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return SendAsync<PackageMetadata>(
|
return SendAsync<PackageMetadata>(
|
||||||
httpMethod,
|
httpMethod,
|
||||||
locationId,
|
locationId,
|
||||||
routeValues: routeValues,
|
routeValues: routeValues,
|
||||||
version: new ApiResourceVersion(5.1, 2),
|
version: new ApiResourceVersion(5.1, 2),
|
||||||
queryParameters: queryParams,
|
|
||||||
userState: userState,
|
userState: userState,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
@@ -625,7 +616,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
/// <param name="packageType"></param>
|
/// <param name="packageType"></param>
|
||||||
/// <param name="platform"></param>
|
/// <param name="platform"></param>
|
||||||
/// <param name="top"></param>
|
/// <param name="top"></param>
|
||||||
/// <param name="includeToken"></param>
|
|
||||||
/// <param name="userState"></param>
|
/// <param name="userState"></param>
|
||||||
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
@@ -633,7 +623,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
string packageType,
|
string packageType,
|
||||||
string platform = null,
|
string platform = null,
|
||||||
int? top = null,
|
int? top = null,
|
||||||
bool? includeToken = null,
|
|
||||||
object userState = null,
|
object userState = null,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
@@ -646,10 +635,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
{
|
{
|
||||||
queryParams.Add("$top", top.Value.ToString(CultureInfo.InvariantCulture));
|
queryParams.Add("$top", top.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
if (includeToken != null)
|
|
||||||
{
|
|
||||||
queryParams.Add("includeToken", includeToken.Value.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return SendAsync<List<PackageMetadata>>(
|
return SendAsync<List<PackageMetadata>>(
|
||||||
httpMethod,
|
httpMethod,
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
internal const String String = "string";
|
internal const String String = "string";
|
||||||
internal const String StringDefinition = "string-definition";
|
internal const String StringDefinition = "string-definition";
|
||||||
internal const String StringDefinitionProperties = "string-definition-properties";
|
internal const String StringDefinitionProperties = "string-definition-properties";
|
||||||
internal const String StringRunnerContextNoSecrets = "string-runner-context-no-secrets";
|
|
||||||
internal const String Structure = "structure";
|
internal const String Structure = "structure";
|
||||||
internal const String TemplateSchema = "template-schema";
|
internal const String TemplateSchema = "template-schema";
|
||||||
internal const String True = "true";
|
internal const String True = "true";
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
IEnumerable<JobStep> steps,
|
IEnumerable<JobStep> steps,
|
||||||
IList<String> fileTable,
|
IList<String> fileTable,
|
||||||
TemplateToken jobOutputs,
|
TemplateToken jobOutputs,
|
||||||
IList<TemplateToken> defaults,
|
IList<TemplateToken> defaults)
|
||||||
ActionsEnvironmentReference actionsEnvironment)
|
|
||||||
{
|
{
|
||||||
this.MessageType = JobRequestMessageTypes.PipelineAgentJobRequest;
|
this.MessageType = JobRequestMessageTypes.PipelineAgentJobRequest;
|
||||||
this.Plan = plan;
|
this.Plan = plan;
|
||||||
@@ -55,7 +54,7 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
this.Resources = jobResources;
|
this.Resources = jobResources;
|
||||||
this.Workspace = workspaceOptions;
|
this.Workspace = workspaceOptions;
|
||||||
this.JobOutputs = jobOutputs;
|
this.JobOutputs = jobOutputs;
|
||||||
this.ActionsEnvironment = actionsEnvironment;
|
|
||||||
m_variables = new Dictionary<String, VariableValue>(variables, StringComparer.OrdinalIgnoreCase);
|
m_variables = new Dictionary<String, VariableValue>(variables, StringComparer.OrdinalIgnoreCase);
|
||||||
m_maskHints = new List<MaskHint>(maskHints);
|
m_maskHints = new List<MaskHint>(maskHints);
|
||||||
m_steps = new List<JobStep>(steps);
|
m_steps = new List<JobStep>(steps);
|
||||||
@@ -229,13 +228,6 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public ActionsEnvironmentReference ActionsEnvironment
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of variables associated with the current context.
|
/// Gets the collection of variables associated with the current context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public const String Credentials = "credentials";
|
public const String Credentials = "credentials";
|
||||||
public const String Defaults = "defaults";
|
public const String Defaults = "defaults";
|
||||||
public const String Env = "env";
|
public const String Env = "env";
|
||||||
public const String Environment = "environment";
|
|
||||||
public const String Event = "event";
|
public const String Event = "event";
|
||||||
public const String EventPattern = "github.event";
|
public const String EventPattern = "github.event";
|
||||||
public const String Exclude = "exclude";
|
public const String Exclude = "exclude";
|
||||||
|
|||||||
@@ -279,33 +279,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TemplateToken EvaluateEnvironmentUrl(
|
|
||||||
TemplateToken token,
|
|
||||||
DictionaryContextData contextData,
|
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
|
||||||
var result = default(TemplateToken);
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
|
||||||
{
|
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
token = TemplateEvaluator.Evaluate(context, TemplateConstants.StringRunnerContextNoSecrets, token, 0, null, omitHeader: true);
|
|
||||||
context.Errors.Check();
|
|
||||||
result = token.AssertString("environment.url");
|
|
||||||
}
|
|
||||||
catch (Exception ex) when (!(ex is TemplateValidationException))
|
|
||||||
{
|
|
||||||
context.Errors.Add(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Errors.Check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Dictionary<String, String> EvaluateJobDefaultsRun(
|
public Dictionary<String, String> EvaluateJobDefaultsRun(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData,
|
||||||
|
|||||||
@@ -515,20 +515,6 @@
|
|||||||
"string": {}
|
"string": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
"string-runner-context-no-secrets": {
|
|
||||||
"context": [
|
|
||||||
"github",
|
|
||||||
"needs",
|
|
||||||
"strategy",
|
|
||||||
"matrix",
|
|
||||||
"steps",
|
|
||||||
"job",
|
|
||||||
"runner",
|
|
||||||
"env"
|
|
||||||
],
|
|
||||||
"string": {}
|
|
||||||
},
|
|
||||||
|
|
||||||
"string-steps-context": {
|
"string-steps-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
@@ -545,4 +531,4 @@
|
|||||||
"string": {}
|
"string": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using System.Runtime.Serialization;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.WebApi
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Information about an environment parsed from YML with evaluated name, URL will be evaluated on runner
|
|
||||||
/// </summary>
|
|
||||||
[DataContract]
|
|
||||||
public class ActionsEnvironmentReference
|
|
||||||
{
|
|
||||||
public ActionsEnvironmentReference(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public TemplateToken Url { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2458,42 +2458,4 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class UnresolvableActionDownloadInfoException : DistributedTaskException
|
|
||||||
{
|
|
||||||
public UnresolvableActionDownloadInfoException(String message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnresolvableActionDownloadInfoException(String message, Exception innerException)
|
|
||||||
: base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UnresolvableActionDownloadInfoException(SerializationInfo info, StreamingContext context)
|
|
||||||
: base(info, context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public sealed class FailedToResolveActionDownloadInfoException : DistributedTaskException
|
|
||||||
{
|
|
||||||
public FailedToResolveActionDownloadInfoException(String message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public FailedToResolveActionDownloadInfoException(String message, Exception innerException)
|
|
||||||
: base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private FailedToResolveActionDownloadInfoException(SerializationInfo info, StreamingContext context)
|
|
||||||
: base(info, context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
this.Type = issueToBeCloned.Type;
|
this.Type = issueToBeCloned.Type;
|
||||||
this.Category = issueToBeCloned.Category;
|
this.Category = issueToBeCloned.Category;
|
||||||
this.Message = issueToBeCloned.Message;
|
this.Message = issueToBeCloned.Message;
|
||||||
this.IsInfrastructureIssue = issueToBeCloned.IsInfrastructureIssue;
|
|
||||||
|
|
||||||
if (issueToBeCloned.m_data != null)
|
if (issueToBeCloned.m_data != null)
|
||||||
{
|
{
|
||||||
@@ -49,13 +48,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(Order = 4)]
|
|
||||||
public bool? IsInfrastructureIssue
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary<String, String> Data
|
public IDictionary<String, String> Data
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -131,17 +131,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
this.Outputs = outputs;
|
this.Outputs = outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobCompletedEvent(
|
|
||||||
Int64 requestId,
|
|
||||||
Guid jobId,
|
|
||||||
TaskResult result,
|
|
||||||
Dictionary<String, VariableValue> outputs,
|
|
||||||
ActionsEnvironmentReference actionsEnvironment)
|
|
||||||
: this(requestId, jobId, result, outputs)
|
|
||||||
{
|
|
||||||
this.ActionsEnvironment = actionsEnvironment;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public Int64 RequestId
|
public Int64 RequestId
|
||||||
{
|
{
|
||||||
@@ -162,13 +151,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public ActionsEnvironmentReference ActionsEnvironment
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataContract]
|
[DataContract]
|
||||||
|
|||||||
@@ -59,16 +59,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Auth token to download the package
|
|
||||||
/// </summary>
|
|
||||||
[DataMember]
|
|
||||||
public String Token
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MD5 hash as a base64 string
|
/// MD5 hash as a base64 string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -65,15 +65,5 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets whether to use FIPS compliant encryption scheme for job message key
|
|
||||||
/// </summary>
|
|
||||||
[DataMember]
|
|
||||||
public bool UseFipsEncryption
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
this.RefName = recordToBeCloned.RefName;
|
this.RefName = recordToBeCloned.RefName;
|
||||||
this.ErrorCount = recordToBeCloned.ErrorCount;
|
this.ErrorCount = recordToBeCloned.ErrorCount;
|
||||||
this.WarningCount = recordToBeCloned.WarningCount;
|
this.WarningCount = recordToBeCloned.WarningCount;
|
||||||
this.AgentPlatform = recordToBeCloned.AgentPlatform;
|
|
||||||
|
|
||||||
if (recordToBeCloned.Log != null)
|
if (recordToBeCloned.Log != null)
|
||||||
{
|
{
|
||||||
@@ -255,13 +254,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(Order = 132, EmitDefaultValue = false)]
|
|
||||||
public string AgentPlatform
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<TimelineAttempt> PreviousAttempts
|
public IList<TimelineAttempt> PreviousAttempts
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -13,8 +13,5 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
|
|
||||||
[EnumMember]
|
[EnumMember]
|
||||||
Completed,
|
Completed,
|
||||||
|
|
||||||
[EnumMember]
|
|
||||||
Delayed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,5 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
public static class WellKnownDistributedTaskVariables
|
public static class WellKnownDistributedTaskVariables
|
||||||
{
|
{
|
||||||
public static readonly String JobId = "system.jobId";
|
public static readonly String JobId = "system.jobId";
|
||||||
public static readonly String RunnerLowDiskspaceThreshold = "system.runner.lowdiskspacethreshold";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,55 @@ namespace GitHub.Services.WebApi.Jwt
|
|||||||
return credentials.SignatureAlgorithm;
|
return credentials.SignatureAlgorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ClaimsPrincipal ValidateToken(this JsonWebToken token, JsonWebTokenValidationParameters parameters)
|
||||||
|
{
|
||||||
|
ArgumentUtility.CheckForNull(token, nameof(token));
|
||||||
|
ArgumentUtility.CheckForNull(parameters, nameof(parameters));
|
||||||
|
|
||||||
|
ClaimsIdentity actorIdentity = ValidateActor(token, parameters);
|
||||||
|
ValidateLifetime(token, parameters);
|
||||||
|
ValidateAudience(token, parameters);
|
||||||
|
ValidateSignature(token, parameters);
|
||||||
|
ValidateIssuer(token, parameters);
|
||||||
|
|
||||||
|
ClaimsIdentity identity = new ClaimsIdentity("Federation", parameters.IdentityNameClaimType, ClaimTypes.Role);
|
||||||
|
|
||||||
|
if (actorIdentity != null)
|
||||||
|
{
|
||||||
|
identity.Actor = actorIdentity;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<Claim> claims = token.ExtractClaims();
|
||||||
|
|
||||||
|
foreach (Claim claim in claims)
|
||||||
|
{
|
||||||
|
identity.AddClaim(new Claim(claim.Type, claim.Value, claim.ValueType, token.Issuer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ClaimsPrincipal(identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClaimsIdentity ValidateActor(JsonWebToken token, JsonWebTokenValidationParameters parameters)
|
||||||
|
{
|
||||||
|
ArgumentUtility.CheckForNull(token, nameof(token));
|
||||||
|
ArgumentUtility.CheckForNull(parameters, nameof(parameters));
|
||||||
|
|
||||||
|
if (!parameters.ValidateActor)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this recursive call with check the parameters
|
||||||
|
ClaimsPrincipal principal = token.Actor.ValidateToken(parameters.ActorValidationParameters);
|
||||||
|
|
||||||
|
if (!(principal?.Identity is ClaimsIdentity))
|
||||||
|
{
|
||||||
|
throw new ActorValidationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ClaimsIdentity)principal.Identity;
|
||||||
|
}
|
||||||
|
|
||||||
private static void ValidateLifetime(JsonWebToken token, JsonWebTokenValidationParameters parameters)
|
private static void ValidateLifetime(JsonWebToken token, JsonWebTokenValidationParameters parameters)
|
||||||
{
|
{
|
||||||
ArgumentUtility.CheckForNull(token, nameof(token));
|
ArgumentUtility.CheckForNull(token, nameof(token));
|
||||||
@@ -192,6 +241,59 @@ namespace GitHub.Services.WebApi.Jwt
|
|||||||
throw new InvalidAudienceException(); //validation exception;
|
throw new InvalidAudienceException(); //validation exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ValidateSignature(JsonWebToken token, JsonWebTokenValidationParameters parameters)
|
||||||
|
{
|
||||||
|
ArgumentUtility.CheckForNull(token, nameof(token));
|
||||||
|
ArgumentUtility.CheckForNull(parameters, nameof(parameters));
|
||||||
|
|
||||||
|
if (!parameters.ValidateSignature)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string encodedData = token.EncodedToken;
|
||||||
|
|
||||||
|
string[] parts = encodedData.Split('.');
|
||||||
|
|
||||||
|
if (parts.Length != 3)
|
||||||
|
{
|
||||||
|
throw new InvalidTokenException(JwtResources.EncodedTokenDataMalformed()); //validation exception
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(parts[2]))
|
||||||
|
{
|
||||||
|
throw new InvalidTokenException(JwtResources.SignatureNotFound()); //validation exception
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.Algorithm == JWTAlgorithm.None)
|
||||||
|
{
|
||||||
|
throw new InvalidTokenException(JwtResources.InvalidSignatureAlgorithm()); //validation exception
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgumentUtility.CheckForNull(parameters.SigningCredentials, nameof(parameters.SigningCredentials));
|
||||||
|
|
||||||
|
//ArgumentUtility.CheckEnumerableForNullOrEmpty(parameters.SigningToken.SecurityKeys, nameof(parameters.SigningToken.SecurityKeys));
|
||||||
|
|
||||||
|
byte[] sourceInput = Encoding.UTF8.GetBytes(string.Format("{0}.{1}", parts[0], parts[1]));
|
||||||
|
|
||||||
|
byte[] sourceSignature = parts[2].FromBase64StringNoPadding();
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (parameters.SigningCredentials.VerifySignature(sourceInput, sourceSignature))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
//swallow exceptions here, we'll throw if nothing works...
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new SignatureValidationException(); //valiation exception
|
||||||
|
}
|
||||||
|
|
||||||
private static void ValidateIssuer(JsonWebToken token, JsonWebTokenValidationParameters parameters)
|
private static void ValidateIssuer(JsonWebToken token, JsonWebTokenValidationParameters parameters)
|
||||||
{
|
{
|
||||||
ArgumentUtility.CheckForNull(token, nameof(token));
|
ArgumentUtility.CheckForNull(token, nameof(token));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.WebApi.Jwt;
|
using GitHub.Services.WebApi.Jwt;
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ namespace GitHub.Services.WebApi
|
|||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetSignature(input);
|
return GetSignature(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,13 +86,48 @@ namespace GitHub.Services.WebApi
|
|||||||
/// <returns>A blob of data representing the signature of the input data</returns>
|
/// <returns>A blob of data representing the signature of the input data</returns>
|
||||||
protected abstract Byte[] GetSignature(Byte[] input);
|
protected abstract Byte[] GetSignature(Byte[] input);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies the signature of the input data, returning true if the signature is valid.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The data which should be signed</param>
|
||||||
|
/// <param name="signature">The signature which should be verified</param>
|
||||||
|
/// <returns>True if the provided signature matches the current signing token; otherwise, false</returns>
|
||||||
|
public abstract Boolean VerifySignature(Byte[] input, Byte[] signature);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <c>VssSigningCredentials</c> instance using the specified <paramref name="certificate"/> instance
|
||||||
|
/// as the signing key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="certificate">The certificate which contains the key used for signing and verification</param>
|
||||||
|
/// <returns>A new <c>VssSigningCredentials</c> instance which uses the specified certificate for signing</returns>
|
||||||
|
public static VssSigningCredentials Create(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
ArgumentUtility.CheckForNull(certificate, nameof(certificate));
|
||||||
|
|
||||||
|
if (certificate.HasPrivateKey)
|
||||||
|
{
|
||||||
|
var rsa = certificate.GetRSAPrivateKey();
|
||||||
|
if (rsa == null)
|
||||||
|
{
|
||||||
|
throw new SignatureAlgorithmUnsupportedException(certificate.SignatureAlgorithm.FriendlyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsa.KeySize < c_minKeySize)
|
||||||
|
{
|
||||||
|
throw new InvalidCredentialsException(JwtResources.SigningTokenKeyTooSmall());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new X509Certificate2SigningToken(certificate);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <c>VssSigningCredentials</c> instance using the specified <paramref name="factory"/>
|
/// Creates a new <c>VssSigningCredentials</c> instance using the specified <paramref name="factory"/>
|
||||||
/// callback function to retrieve the signing key.
|
/// callback function to retrieve the signing key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="factory">The factory which creates <c>RSA</c> keys used for signing and verification</param>
|
/// <param name="factory">The factory which creates <c>RSA</c> keys used for signing and verification</param>
|
||||||
/// <returns>A new <c>VssSigningCredentials</c> instance which uses the specified provider for signing</returns>
|
/// <returns>A new <c>VssSigningCredentials</c> instance which uses the specified provider for signing</returns>
|
||||||
public static VssSigningCredentials Create(Func<RSA> factory, bool requireFipsCryptography)
|
public static VssSigningCredentials Create(Func<RSA> factory)
|
||||||
{
|
{
|
||||||
ArgumentUtility.CheckForNull(factory, nameof(factory));
|
ArgumentUtility.CheckForNull(factory, nameof(factory));
|
||||||
|
|
||||||
@@ -106,19 +143,80 @@ namespace GitHub.Services.WebApi
|
|||||||
throw new InvalidCredentialsException(JwtResources.SigningTokenKeyTooSmall());
|
throw new InvalidCredentialsException(JwtResources.SigningTokenKeyTooSmall());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requireFipsCryptography)
|
return new RSASigningToken(factory, rsa.KeySize);
|
||||||
{
|
|
||||||
return new RSASigningToken(factory, rsa.KeySize, RSASignaturePadding.Pss);
|
|
||||||
}
|
|
||||||
return new RSASigningToken(factory, rsa.KeySize, RSASignaturePadding.Pkcs1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <c>VssSigningCredentials</c> instance using the specified <paramref name="key"/> as the signing
|
||||||
|
/// key. The returned signing token performs symmetric key signing and verification.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rsa">The key used for signing and verification</param>
|
||||||
|
/// <returns>A new <c>VssSigningCredentials</c> instance which uses the specified key for signing</returns>
|
||||||
|
public static VssSigningCredentials Create(Byte[] key)
|
||||||
|
{
|
||||||
|
ArgumentUtility.CheckForNull(key, nameof(key));
|
||||||
|
|
||||||
|
// Probably should have validation here, but there was none previously
|
||||||
|
return new SymmetricKeySigningToken(key);
|
||||||
|
}
|
||||||
|
|
||||||
private const Int32 c_minKeySize = 2048;
|
private const Int32 c_minKeySize = 2048;
|
||||||
private readonly DateTime m_effectiveDate;
|
private readonly DateTime m_effectiveDate;
|
||||||
|
|
||||||
#region Concrete Implementations
|
#region Concrete Implementations
|
||||||
|
|
||||||
|
private class SymmetricKeySigningToken : VssSigningCredentials
|
||||||
|
{
|
||||||
|
public SymmetricKeySigningToken(Byte[] key)
|
||||||
|
{
|
||||||
|
m_key = new Byte[key.Length];
|
||||||
|
Buffer.BlockCopy(key, 0, m_key, 0, m_key.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Boolean CanSignData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Int32 KeySize
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_key.Length * 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override JWTAlgorithm SignatureAlgorithm
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return JWTAlgorithm.HS256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Byte[] GetSignature(Byte[] input)
|
||||||
|
{
|
||||||
|
using (var hash = new HMACSHA256(m_key))
|
||||||
|
{
|
||||||
|
return hash.ComputeHash(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Boolean VerifySignature(
|
||||||
|
Byte[] input,
|
||||||
|
Byte[] signature)
|
||||||
|
{
|
||||||
|
var computedSignature = SignData(input);
|
||||||
|
return SecureCompare.TimeInvariantEquals(computedSignature, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Byte[] m_key;
|
||||||
|
}
|
||||||
|
|
||||||
private abstract class AsymmetricKeySigningToken : VssSigningCredentials
|
private abstract class AsymmetricKeySigningToken : VssSigningCredentials
|
||||||
{
|
{
|
||||||
protected abstract Boolean HasPrivateKey();
|
protected abstract Boolean HasPrivateKey();
|
||||||
@@ -146,14 +244,70 @@ namespace GitHub.Services.WebApi
|
|||||||
private Boolean? m_hasPrivateKey;
|
private Boolean? m_hasPrivateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class X509Certificate2SigningToken : AsymmetricKeySigningToken, IJsonWebTokenHeaderProvider
|
||||||
|
{
|
||||||
|
public X509Certificate2SigningToken(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
m_certificate = certificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Int32 KeySize
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_certificate.GetRSAPublicKey().KeySize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DateTime ValidFrom
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_certificate.NotBefore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DateTime ValidTo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_certificate.NotAfter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Boolean VerifySignature(
|
||||||
|
Byte[] input,
|
||||||
|
Byte[] signature)
|
||||||
|
{
|
||||||
|
var rsa = m_certificate.GetRSAPublicKey();
|
||||||
|
return rsa.VerifyData(input, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Byte[] GetSignature(Byte[] input)
|
||||||
|
{
|
||||||
|
var rsa = m_certificate.GetRSAPrivateKey();
|
||||||
|
return rsa.SignData(input, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Boolean HasPrivateKey()
|
||||||
|
{
|
||||||
|
return m_certificate.HasPrivateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IJsonWebTokenHeaderProvider.SetHeaders(IDictionary<String, Object> headers)
|
||||||
|
{
|
||||||
|
headers[JsonWebTokenHeaderParameters.X509CertificateThumbprint] = m_certificate.GetCertHash().ToBase64StringNoPadding();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly X509Certificate2 m_certificate;
|
||||||
|
}
|
||||||
|
|
||||||
private class RSASigningToken : AsymmetricKeySigningToken
|
private class RSASigningToken : AsymmetricKeySigningToken
|
||||||
{
|
{
|
||||||
public RSASigningToken(
|
public RSASigningToken(
|
||||||
Func<RSA> factory,
|
Func<RSA> factory,
|
||||||
Int32 keySize,
|
Int32 keySize)
|
||||||
RSASignaturePadding signaturePadding)
|
|
||||||
{
|
{
|
||||||
m_signaturePadding = signaturePadding;
|
|
||||||
m_keySize = keySize;
|
m_keySize = keySize;
|
||||||
m_factory = factory;
|
m_factory = factory;
|
||||||
}
|
}
|
||||||
@@ -170,7 +324,7 @@ namespace GitHub.Services.WebApi
|
|||||||
{
|
{
|
||||||
using (var rsa = m_factory())
|
using (var rsa = m_factory())
|
||||||
{
|
{
|
||||||
return rsa.SignData(input, HashAlgorithmName.SHA256, m_signaturePadding);
|
return rsa.SignData(input, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +335,7 @@ namespace GitHub.Services.WebApi
|
|||||||
// As unfortunate as this is, there is no way to tell from an RSA implementation, based on querying
|
// As unfortunate as this is, there is no way to tell from an RSA implementation, based on querying
|
||||||
// properties alone, if it supports signature operations or has a private key. This is a one-time
|
// properties alone, if it supports signature operations or has a private key. This is a one-time
|
||||||
// hit for the signing credentials implementation, so it shouldn't be a huge deal.
|
// hit for the signing credentials implementation, so it shouldn't be a huge deal.
|
||||||
GetSignature(new Byte[1] { 1 });
|
GetSignature(new Byte[1] { 1 });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (CryptographicException)
|
catch (CryptographicException)
|
||||||
@@ -190,9 +344,18 @@ namespace GitHub.Services.WebApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Boolean VerifySignature(
|
||||||
|
Byte[] input,
|
||||||
|
Byte[] signature)
|
||||||
|
{
|
||||||
|
using (var rsa = m_factory())
|
||||||
|
{
|
||||||
|
return rsa.VerifyData(input, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly Int32 m_keySize;
|
private readonly Int32 m_keySize;
|
||||||
private readonly Func<RSA> m_factory;
|
private readonly Func<RSA> m_factory;
|
||||||
private readonly RSASignaturePadding m_signaturePadding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests
|
namespace GitHub.Runner.Common.Tests
|
||||||
{
|
{
|
||||||
@@ -13,12 +12,6 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
[Trait("Category", "Runner")]
|
[Trait("Category", "Runner")]
|
||||||
public async Task EnsureDotnetsdkBashDownloadScriptUpToDate()
|
public async Task EnsureDotnetsdkBashDownloadScriptUpToDate()
|
||||||
{
|
{
|
||||||
if ((DateTime.UtcNow.Month - 1) % 3 != 0)
|
|
||||||
{
|
|
||||||
// Only check these script once a quater.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string shDownloadUrl = "https://dot.net/v1/dotnet-install.sh";
|
string shDownloadUrl = "https://dot.net/v1/dotnet-install.sh";
|
||||||
|
|
||||||
using (HttpClient downloadClient = new HttpClient())
|
using (HttpClient downloadClient = new HttpClient())
|
||||||
@@ -43,12 +36,6 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
[Trait("Category", "Runner")]
|
[Trait("Category", "Runner")]
|
||||||
public async Task EnsureDotnetsdkPowershellDownloadScriptUpToDate()
|
public async Task EnsureDotnetsdkPowershellDownloadScriptUpToDate()
|
||||||
{
|
{
|
||||||
if ((DateTime.UtcNow.Month - 1) % 3 != 0)
|
|
||||||
{
|
|
||||||
// Only check these script once a quater.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string ps1DownloadUrl = "https://dot.net/v1/dotnet-install.ps1";
|
string ps1DownloadUrl = "https://dot.net/v1/dotnet-install.ps1";
|
||||||
|
|
||||||
using (HttpClient downloadClient = new HttpClient())
|
using (HttpClient downloadClient = new HttpClient())
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||||
TimelineReference timeline = null;
|
TimelineReference timeline = null;
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||||
TimelineReference timeline = null;
|
TimelineReference timeline = null;
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JobCancelMessage CreateJobCancelMessage()
|
private JobCancelMessage CreateJobCancelMessage()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -127,11 +127,11 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
||||||
var proxy = new RunnerWebProxy();
|
var proxy = new RunnerWebProxy();
|
||||||
|
|
||||||
Assert.Equal("http://127.0.0.1:8888", proxy.HttpProxyAddress);
|
Assert.Equal("http://127.0.0.1:8888/", proxy.HttpProxyAddress);
|
||||||
Assert.Null(proxy.HttpProxyUsername);
|
Assert.Null(proxy.HttpProxyUsername);
|
||||||
Assert.Null(proxy.HttpProxyPassword);
|
Assert.Null(proxy.HttpProxyPassword);
|
||||||
|
|
||||||
Assert.Equal("http://user:pass@127.0.0.1:9999", proxy.HttpsProxyAddress);
|
Assert.Equal("http://user:pass@127.0.0.1:9999/", proxy.HttpsProxyAddress);
|
||||||
Assert.Equal("user", proxy.HttpsProxyUsername);
|
Assert.Equal("user", proxy.HttpsProxyUsername);
|
||||||
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
||||||
|
|
||||||
@@ -161,11 +161,11 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Environment.SetEnvironmentVariable("NO_PROXY", "github.com, google.com,");
|
Environment.SetEnvironmentVariable("NO_PROXY", "github.com, google.com,");
|
||||||
var proxy = new RunnerWebProxy();
|
var proxy = new RunnerWebProxy();
|
||||||
|
|
||||||
Assert.Equal("http://127.0.0.1:7777", proxy.HttpProxyAddress);
|
Assert.Equal("http://127.0.0.1:7777/", proxy.HttpProxyAddress);
|
||||||
Assert.Null(proxy.HttpProxyUsername);
|
Assert.Null(proxy.HttpProxyUsername);
|
||||||
Assert.Null(proxy.HttpProxyPassword);
|
Assert.Null(proxy.HttpProxyPassword);
|
||||||
|
|
||||||
Assert.Equal("http://user:pass@127.0.0.1:8888", proxy.HttpsProxyAddress);
|
Assert.Equal("http://user:pass@127.0.0.1:8888/", proxy.HttpsProxyAddress);
|
||||||
Assert.Equal("user", proxy.HttpsProxyUsername);
|
Assert.Equal("user", proxy.HttpsProxyUsername);
|
||||||
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
||||||
|
|
||||||
@@ -218,19 +218,19 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
||||||
var proxy = new RunnerWebProxy();
|
var proxy = new RunnerWebProxy();
|
||||||
|
|
||||||
Assert.Equal("http://user1@127.0.0.1:8888", proxy.HttpProxyAddress);
|
Assert.Equal("http://user1@127.0.0.1:8888/", proxy.HttpProxyAddress);
|
||||||
Assert.Equal("user1", proxy.HttpProxyUsername);
|
Assert.Equal("user1", proxy.HttpProxyUsername);
|
||||||
Assert.Null(proxy.HttpProxyPassword);
|
Assert.Null(proxy.HttpProxyPassword);
|
||||||
|
|
||||||
var cred = proxy.Credentials.GetCredential(new Uri("http://user1@127.0.0.1:8888"), "Basic");
|
var cred = proxy.Credentials.GetCredential(new Uri("http://user1@127.0.0.1:8888/"), "Basic");
|
||||||
Assert.Equal("user1", cred.UserName);
|
Assert.Equal("user1", cred.UserName);
|
||||||
Assert.Equal(string.Empty, cred.Password);
|
Assert.Equal(string.Empty, cred.Password);
|
||||||
|
|
||||||
Assert.Equal("http://user2:pass@127.0.0.1:9999", proxy.HttpsProxyAddress);
|
Assert.Equal("http://user2:pass@127.0.0.1:9999/", proxy.HttpsProxyAddress);
|
||||||
Assert.Equal("user2", proxy.HttpsProxyUsername);
|
Assert.Equal("user2", proxy.HttpsProxyUsername);
|
||||||
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
||||||
|
|
||||||
cred = proxy.Credentials.GetCredential(new Uri("http://user2:pass@127.0.0.1:9999"), "Basic");
|
cred = proxy.Credentials.GetCredential(new Uri("http://user2:pass@127.0.0.1:9999/"), "Basic");
|
||||||
Assert.Equal("user2", cred.UserName);
|
Assert.Equal("user2", cred.UserName);
|
||||||
Assert.Equal("pass", cred.Password);
|
Assert.Equal("pass", cred.Password);
|
||||||
|
|
||||||
@@ -256,19 +256,19 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
||||||
var proxy = new RunnerWebProxy();
|
var proxy = new RunnerWebProxy();
|
||||||
|
|
||||||
Assert.Equal("http://user1:pass1%40@127.0.0.1:8888", proxy.HttpProxyAddress);
|
Assert.Equal("http://user1:pass1%40@127.0.0.1:8888/", proxy.HttpProxyAddress);
|
||||||
Assert.Equal("user1", proxy.HttpProxyUsername);
|
Assert.Equal("user1", proxy.HttpProxyUsername);
|
||||||
Assert.Equal("pass1@", proxy.HttpProxyPassword);
|
Assert.Equal("pass1@", proxy.HttpProxyPassword);
|
||||||
|
|
||||||
var cred = proxy.Credentials.GetCredential(new Uri("http://user1:pass1%40@127.0.0.1:8888"), "Basic");
|
var cred = proxy.Credentials.GetCredential(new Uri("http://user1:pass1%40@127.0.0.1:8888/"), "Basic");
|
||||||
Assert.Equal("user1", cred.UserName);
|
Assert.Equal("user1", cred.UserName);
|
||||||
Assert.Equal("pass1@", cred.Password);
|
Assert.Equal("pass1@", cred.Password);
|
||||||
|
|
||||||
Assert.Equal("http://user2:pass2%40@127.0.0.1:9999", proxy.HttpsProxyAddress);
|
Assert.Equal("http://user2:pass2%40@127.0.0.1:9999/", proxy.HttpsProxyAddress);
|
||||||
Assert.Equal("user2", proxy.HttpsProxyUsername);
|
Assert.Equal("user2", proxy.HttpsProxyUsername);
|
||||||
Assert.Equal("pass2@", proxy.HttpsProxyPassword);
|
Assert.Equal("pass2@", proxy.HttpsProxyPassword);
|
||||||
|
|
||||||
cred = proxy.Credentials.GetCredential(new Uri("http://user2:pass2%40@127.0.0.1:9999"), "Basic");
|
cred = proxy.Credentials.GetCredential(new Uri("http://user2:pass2%40@127.0.0.1:9999/"), "Basic");
|
||||||
Assert.Equal("user2", cred.UserName);
|
Assert.Equal("user2", cred.UserName);
|
||||||
Assert.Equal("pass2@", cred.Password);
|
Assert.Equal("pass2@", cred.Password);
|
||||||
|
|
||||||
@@ -405,36 +405,6 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Common")]
|
|
||||||
public void WebProxyFromEnvironmentVariablesWithPort80()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Environment.SetEnvironmentVariable("http_proxy", "http://127.0.0.1:80");
|
|
||||||
Environment.SetEnvironmentVariable("https_proxy", "http://user:pass@127.0.0.1:80");
|
|
||||||
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
|
||||||
var proxy = new RunnerWebProxy();
|
|
||||||
|
|
||||||
Assert.Equal("http://127.0.0.1:80", Environment.GetEnvironmentVariable("http_proxy"));
|
|
||||||
Assert.Null(proxy.HttpProxyUsername);
|
|
||||||
Assert.Null(proxy.HttpProxyPassword);
|
|
||||||
|
|
||||||
Assert.Equal("http://user:pass@127.0.0.1:80", Environment.GetEnvironmentVariable("https_proxy"));
|
|
||||||
Assert.Equal("user", proxy.HttpsProxyUsername);
|
|
||||||
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
|
||||||
|
|
||||||
Assert.Equal(2, proxy.NoProxyList.Count);
|
|
||||||
Assert.Equal("github.com", proxy.NoProxyList[0].Host);
|
|
||||||
Assert.Equal("google.com", proxy.NoProxyList[1].Host);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
CleanProxyEnv();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CleanProxyEnv()
|
private void CleanProxyEnv()
|
||||||
{
|
{
|
||||||
Environment.SetEnvironmentVariable("http_proxy", null);
|
Environment.SetEnvironmentVariable("http_proxy", null);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using GitHub.Runner.Listener;
|
using GitHub.Runner.Listener;
|
||||||
using GitHub.Runner.Listener.Check;
|
|
||||||
using GitHub.Runner.Listener.Configuration;
|
using GitHub.Runner.Listener.Configuration;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
@@ -22,8 +21,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
// Otherwise, the interface needs to whitelisted.
|
// Otherwise, the interface needs to whitelisted.
|
||||||
var whitelist = new[]
|
var whitelist = new[]
|
||||||
{
|
{
|
||||||
typeof(ICredentialProvider),
|
typeof(ICredentialProvider)
|
||||||
typeof(ICheckExtension),
|
|
||||||
};
|
};
|
||||||
Validate(
|
Validate(
|
||||||
assembly: typeof(IMessageListener).GetTypeInfo().Assembly,
|
assembly: typeof(IMessageListener).GetTypeInfo().Assembly,
|
||||||
@@ -87,8 +85,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interfaceTypeInfo.FullName.Contains("IConverter"))
|
if (interfaceTypeInfo.FullName.Contains("IConverter")){
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
|
|||||||
@@ -333,66 +333,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_ec.Verify(x => x.AddIssue(It.Is<Issue>(s => s.Message.Contains("Unexpected input(s) 'invalid1', 'invalid2'")), It.IsAny<string>()), Times.Once);
|
_ec.Verify(x => x.AddIssue(It.Is<Issue>(s => s.Message.Contains("Unexpected input(s) 'invalid1', 'invalid2'")), It.IsAny<string>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public async void SetGitHubContextActionRepoRef()
|
|
||||||
{
|
|
||||||
//Arrange
|
|
||||||
Setup();
|
|
||||||
var actionId = Guid.NewGuid();
|
|
||||||
var actionInputs = new MappingToken(null, null, null);
|
|
||||||
actionInputs.Add(new StringToken(null, null, null, "input1"), new StringToken(null, null, null, "test1"));
|
|
||||||
actionInputs.Add(new StringToken(null, null, null, "input2"), new StringToken(null, null, null, "test2"));
|
|
||||||
var action = new Pipelines.ActionStep()
|
|
||||||
{
|
|
||||||
Name = "action",
|
|
||||||
Id = actionId,
|
|
||||||
Reference = new Pipelines.RepositoryPathReference()
|
|
||||||
{
|
|
||||||
Name = "actions/test",
|
|
||||||
Ref = "master"
|
|
||||||
},
|
|
||||||
Inputs = actionInputs
|
|
||||||
};
|
|
||||||
|
|
||||||
_actionRunner.Action = action;
|
|
||||||
|
|
||||||
Dictionary<string, string> finialInputs = new Dictionary<string, string>();
|
|
||||||
_handlerFactory.Setup(x => x.Create(It.IsAny<IExecutionContext>(), It.IsAny<ActionStepDefinitionReference>(), It.IsAny<IStepHost>(), It.IsAny<ActionExecutionData>(), It.IsAny<Dictionary<string, string>>(), It.IsAny<Dictionary<string, string>>(), It.IsAny<Variables>(), It.IsAny<string>()))
|
|
||||||
.Callback((IExecutionContext executionContext, Pipelines.ActionStepDefinitionReference actionReference, IStepHost stepHost, ActionExecutionData data, Dictionary<string, string> inputs, Dictionary<string, string> environment, Variables runtimeVariables, string taskDirectory) =>
|
|
||||||
{
|
|
||||||
finialInputs = inputs;
|
|
||||||
})
|
|
||||||
.Returns(new Mock<IHandler>().Object);
|
|
||||||
|
|
||||||
//Act
|
|
||||||
await _actionRunner.RunAsync();
|
|
||||||
|
|
||||||
//Assert
|
|
||||||
_ec.Verify(x => x.SetGitHubContext("action_repository", "actions/test"), Times.Once);
|
|
||||||
_ec.Verify(x => x.SetGitHubContext("action_ref", "master"), Times.Once);
|
|
||||||
|
|
||||||
action = new Pipelines.ActionStep()
|
|
||||||
{
|
|
||||||
Name = "action",
|
|
||||||
Id = actionId,
|
|
||||||
Reference = new Pipelines.ScriptReference(),
|
|
||||||
Inputs = actionInputs
|
|
||||||
};
|
|
||||||
_actionRunner.Action = action;
|
|
||||||
|
|
||||||
_hc.EnqueueInstance<IDefaultStepHost>(_defaultStepHost.Object);
|
|
||||||
_hc.EnqueueInstance(_fileCommandManager.Object);
|
|
||||||
|
|
||||||
//Act
|
|
||||||
await _actionRunner.RunAsync();
|
|
||||||
|
|
||||||
//Assert
|
|
||||||
_ec.Verify(x => x.SetGitHubContext("action_repository", null), Times.Once);
|
|
||||||
_ec.Verify(x => x.SetGitHubContext("action_ref", null), Times.Once);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Setup([CallerMemberName] string name = "")
|
private void Setup([CallerMemberName] string name = "")
|
||||||
{
|
{
|
||||||
_ecTokenSource?.Dispose();
|
_ecTokenSource?.Dispose();
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
@@ -102,7 +102,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
@@ -153,7 +153,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
@@ -251,7 +251,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
@@ -335,7 +335,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests.Worker
|
namespace GitHub.Runner.Common.Tests.Worker
|
||||||
@@ -99,7 +98,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
};
|
};
|
||||||
|
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null, null);
|
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null);
|
||||||
GitHubContext github = new GitHubContext();
|
GitHubContext github = new GitHubContext();
|
||||||
github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner");
|
github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner");
|
||||||
_message.ContextData.Add("github", github);
|
_message.ContextData.Add("github", github);
|
||||||
@@ -282,70 +281,5 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Times.Never);
|
Times.Never);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void EnsureFinalizeJobRunsIfMessageHasNoEnvironmentUrl()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
var jobExtension = new JobExtension();
|
|
||||||
jobExtension.Initialize(hc);
|
|
||||||
|
|
||||||
_message.ActionsEnvironment = new ActionsEnvironmentReference("production");
|
|
||||||
|
|
||||||
_jobEc = new Runner.Worker.ExecutionContext {Result = TaskResult.Succeeded};
|
|
||||||
_jobEc.Initialize(hc);
|
|
||||||
_jobEc.InitializeJob(_message, _tokenSource.Token);
|
|
||||||
|
|
||||||
jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow);
|
|
||||||
|
|
||||||
Assert.Equal(TaskResult.Succeeded, _jobEc.Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact] [Trait("Level", "L0")] [Trait("Category", "Worker")]
|
|
||||||
public void EnsureFinalizeJobHandlesNullEnvironmentUrl()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
var jobExtension = new JobExtension();
|
|
||||||
jobExtension.Initialize(hc);
|
|
||||||
|
|
||||||
_message.ActionsEnvironment = new ActionsEnvironmentReference("production")
|
|
||||||
{
|
|
||||||
Url = null
|
|
||||||
};
|
|
||||||
|
|
||||||
_jobEc = new Runner.Worker.ExecutionContext {Result = TaskResult.Succeeded};
|
|
||||||
_jobEc.Initialize(hc);
|
|
||||||
_jobEc.InitializeJob(_message, _tokenSource.Token);
|
|
||||||
|
|
||||||
jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow);
|
|
||||||
|
|
||||||
Assert.Equal(TaskResult.Succeeded, _jobEc.Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact] [Trait("Level", "L0")] [Trait("Category", "Worker")]
|
|
||||||
public void EnsureFinalizeJobHandlesNullEnvironment()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
var jobExtension = new JobExtension();
|
|
||||||
jobExtension.Initialize(hc);
|
|
||||||
|
|
||||||
_message.ActionsEnvironment = null;
|
|
||||||
|
|
||||||
_jobEc = new Runner.Worker.ExecutionContext {Result = TaskResult.Succeeded};
|
|
||||||
_jobEc.Initialize(hc);
|
|
||||||
_jobEc.InitializeJob(_message, _tokenSource.Token);
|
|
||||||
|
|
||||||
jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow);
|
|
||||||
|
|
||||||
Assert.Equal(TaskResult.Succeeded, _jobEc.Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||||
TimelineReference timeline = new Timeline(Guid.NewGuid());
|
TimelineReference timeline = new Timeline(Guid.NewGuid());
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, testName, testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, testName, testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
_message.Variables[Constants.Variables.System.Culture] = "en-US";
|
_message.Variables[Constants.Variables.System.Culture] = "en-US";
|
||||||
_message.Resources.Endpoints.Add(new ServiceEndpoint()
|
_message.Resources.Endpoints.Add(new ServiceEndpoint()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
new Pipelines.ContextData.DictionaryContextData()
|
new Pipelines.ContextData.DictionaryContextData()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, new StringToken(null, null, null, "ubuntu"), sidecarContainers, null, variables, new List<MaskHint>(), resources, context, null, actions, null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, new StringToken(null, null, null, "ubuntu"), sidecarContainers, null, variables, new List<MaskHint>(), resources, context, null, actions, null, null, null);
|
||||||
return jobRequest;
|
return jobRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
|||||||
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
||||||
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
||||||
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
||||||
DOTNETSDK_VERSION="3.1.302"
|
DOTNETSDK_VERSION="3.1.100"
|
||||||
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
||||||
RUNNER_VERSION=$(cat runnerversion)
|
RUNNER_VERSION=$(cat runnerversion)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "3.1.302"
|
"version": "3.1.100"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
2.277.0
|
2.273.6
|
||||||
|
|||||||
Reference in New Issue
Block a user