Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91f29e07f4 | ||
|
|
efb34d6cb2 | ||
|
|
767276df48 | ||
|
|
2b874f780f | ||
|
|
716cfe229d | ||
|
|
e93dd2d865 | ||
|
|
9c4bb5002a | ||
|
|
560e7ff9e2 | ||
|
|
9685b6d613 | ||
|
|
c83ced7ece | ||
|
|
6e8a90cd56 | ||
|
|
5aa0d1bacd | ||
|
|
93d421ead9 | ||
|
|
e49d06518c | ||
|
|
69c8dc994c | ||
|
|
e70828b58c | ||
|
|
d7c0fa7a71 | ||
|
|
9d3c93f137 | ||
|
|
ce29488755 | ||
|
|
f08750dda0 | ||
|
|
a3a1ddb586 | ||
|
|
b413e7e15e | ||
|
|
43525325f3 | ||
|
|
8c4badf72a | ||
|
|
ff8bf47b42 |
6
.github/workflows/deploy.yaml
vendored
6
.github/workflows/deploy.yaml
vendored
@@ -15,9 +15,8 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Build latest dist/ folder
|
- name: Build latest dist/ folder
|
||||||
run: |
|
run: |
|
||||||
npm install -g pnpm
|
npm ci
|
||||||
pnpm install --frozen-lockfile
|
npm run build
|
||||||
pnpm run build
|
|
||||||
- name: Upload dist/ folder
|
- name: Upload dist/ folder
|
||||||
run: |
|
run: |
|
||||||
git config --global user.email "<41898282+github-actions[bot]@users.noreply.github.com>"
|
git config --global user.email "<41898282+github-actions[bot]@users.noreply.github.com>"
|
||||||
@@ -26,4 +25,5 @@ jobs:
|
|||||||
git add -f dist README.md LICENSE action.yaml
|
git add -f dist README.md LICENSE action.yaml
|
||||||
git commit -m "chore: create ci release ($GITHUB_SHA)"
|
git commit -m "chore: create ci release ($GITHUB_SHA)"
|
||||||
git tag --force v1
|
git tag --force v1
|
||||||
|
git tag --force $GITHUB_REF_NAME
|
||||||
git push -f --tags origin deploy
|
git push -f --tags origin deploy
|
||||||
|
|||||||
5
.github/workflows/test.yaml
vendored
5
.github/workflows/test.yaml
vendored
@@ -13,9 +13,8 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Build latest dist/ folder
|
- name: Build latest dist/ folder
|
||||||
run: |
|
run: |
|
||||||
npm install -g pnpm
|
npm ci
|
||||||
pnpm install --frozen-lockfile
|
npm run build
|
||||||
pnpm run build
|
|
||||||
- name: Upload dist/ folder
|
- name: Upload dist/ folder
|
||||||
run: |
|
run: |
|
||||||
git config --global user.email "<41898282+github-actions[bot]@users.noreply.github.com>"
|
git config --global user.email "<41898282+github-actions[bot]@users.noreply.github.com>"
|
||||||
|
|||||||
32
README.md
32
README.md
@@ -12,7 +12,7 @@ To use this action, add the following step to your GitHub Action workflow:
|
|||||||
base64-kube-config: ${{ secrets.KUBE_CONFIG }}
|
base64-kube-config: ${{ secrets.KUBE_CONFIG }}
|
||||||
```
|
```
|
||||||
|
|
||||||
Keep in mind that the action expects a base64 encoded string of your Kubernetes configuration. The simplest way to do that is to run `cat $HOME/.kube/config | base64` and save that output as an action secret.
|
Keep in mind that the action expects a base64 encoded string of your Kubernetes configuration. The simplest way to do that is to run `cat $HOME/.kube/config | base64` and save that output as an action secret. It's additionally possible to generate a config file using the `aws` CLI for EKS or any other tools with other cloud providers.
|
||||||
|
|
||||||
It's also possible to specify the version of the [kubectl](https://kubernetes.io/docs/reference/kubectl/) CLI to use. The current default release used by this action is the latest version.
|
It's also possible to specify the version of the [kubectl](https://kubernetes.io/docs/reference/kubectl/) CLI to use. The current default release used by this action is the latest version.
|
||||||
|
|
||||||
@@ -40,3 +40,33 @@ jobs:
|
|||||||
base64-kube-config: ${{ secrets.KUBE_CONFIG }}
|
base64-kube-config: ${{ secrets.KUBE_CONFIG }}
|
||||||
- run: kubectl get pods
|
- run: kubectl get pods
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Here's an example using AWS EKS:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Kubectl Action
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v4
|
||||||
|
with:
|
||||||
|
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
|
||||||
|
aws-region: us-east-2
|
||||||
|
- name: Generate kubeconfig
|
||||||
|
run: |
|
||||||
|
{
|
||||||
|
echo 'EKS_CREDS<<EOF'
|
||||||
|
aws eks update-kubeconfig --region us-east-2 --name my-cluster --dry-run | base64
|
||||||
|
echo EOF
|
||||||
|
} >> $GITHUB_ENV
|
||||||
|
- uses: tale/kubectl-action@v1
|
||||||
|
with:
|
||||||
|
base64-kube-config: ${{ env.EKS_CREDS }}
|
||||||
|
- run: kubectl get pods
|
||||||
|
```
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ inputs:
|
|||||||
description: A base64 encoded reference to your authorization file (~/.kube/config)
|
description: A base64 encoded reference to your authorization file (~/.kube/config)
|
||||||
required: true
|
required: true
|
||||||
runs:
|
runs:
|
||||||
using: node16
|
using: node20
|
||||||
main: dist/index.js
|
main: dist/index.js
|
||||||
post: dist/index.js
|
post: dist/index.js
|
||||||
|
|||||||
8564
package-lock.json
generated
Normal file
8564
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -1,21 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "kubectl-action",
|
"name": "kubectl-action",
|
||||||
"version": "1.1.1",
|
"version": "1.4.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "ncc -smw --license licenses.txt build src/main.ts",
|
"dev": "ncc -smw --license licenses.txt build src/main.ts",
|
||||||
"build": "ncc -sm --license licenses.txt build src/main.ts",
|
"build": "ncc -sm --license licenses.txt build src/main.ts",
|
||||||
"push": "np --no-cleanup --no-publish --no-tests --message 'chore: v%s'"
|
"push": "np --no-cleanup --no-publish --no-tests --message 'chore: v%s'"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.1",
|
||||||
"undici": "^5.16.0"
|
"@actions/tool-cache": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^20.11.30",
|
||||||
"@vercel/ncc": "^0.36.0",
|
"@vercel/ncc": "^0.38.1",
|
||||||
"eslint": "^8.32.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-tale": "^1.0.15",
|
"eslint-config-tale": "^1.0.16",
|
||||||
"np": "^7.6.3",
|
"np": "^9.2.0",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^5.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3630
pnpm-lock.yaml
generated
3630
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
18
src/main.ts
18
src/main.ts
@@ -1,10 +1,24 @@
|
|||||||
|
import { env, exit, platform } from 'node:process'
|
||||||
|
|
||||||
import { debug, getState, setFailed } from '@actions/core'
|
import { debug, getState, setFailed } from '@actions/core'
|
||||||
import { setupKubeconfig } from 'login'
|
import { setupKubeconfig } from 'login'
|
||||||
import { installKubectl } from 'setup'
|
import { installKubectl } from 'setup'
|
||||||
|
import { teardown } from 'teardown'
|
||||||
|
|
||||||
const post = Boolean(getState('isPost'))
|
if (env.RUNNER_OS === 'Windows' || platform === 'win32') {
|
||||||
|
setFailed('kubectl-action does not support Windows')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
if (!post) {
|
if (getState('kubectl-path')) {
|
||||||
|
debug('Running post kubectl-action setup')
|
||||||
|
teardown()
|
||||||
|
// eslint-disable-next-line unicorn/prefer-top-level-await
|
||||||
|
.catch(error => {
|
||||||
|
setFailed('Failed to teardown kubectl (this is a bug in kubectl-action): ')
|
||||||
|
debug(JSON.stringify(error))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
debug('Running kubectl-action setup')
|
debug('Running kubectl-action setup')
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
// eslint-disable-next-line no-async-promise-executor
|
||||||
new Promise(async () => {
|
new Promise(async () => {
|
||||||
|
|||||||
115
src/setup.ts
115
src/setup.ts
@@ -1,11 +1,9 @@
|
|||||||
import { createHash, randomUUID } from 'node:crypto'
|
import { chmod } from 'node:fs/promises'
|
||||||
import { mkdir, writeFile } from 'node:fs/promises'
|
import { dirname, join } from 'node:path'
|
||||||
import { join } from 'node:path'
|
import { env } from 'node:process'
|
||||||
import { env, stdout } from 'node:process'
|
|
||||||
import { clearLine, cursorTo } from 'node:readline'
|
|
||||||
|
|
||||||
import { addPath, debug, getInput, saveState, setFailed, warning } from '@actions/core'
|
import { addPath, debug, getInput, setFailed } from '@actions/core'
|
||||||
import { fetch } from 'undici'
|
import { cacheFile, downloadTool, find } from '@actions/tool-cache'
|
||||||
|
|
||||||
export async function installKubectl() {
|
export async function installKubectl() {
|
||||||
debug('Running kubectl-action installKubectl()')
|
debug('Running kubectl-action installKubectl()')
|
||||||
@@ -29,19 +27,16 @@ export async function installKubectl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Installing kubectl version ${version}`)
|
console.log(`Installing kubectl version ${version}`)
|
||||||
const kubectl = await downloadKubectl(version)
|
|
||||||
|
|
||||||
if (!kubectl) {
|
try {
|
||||||
return
|
const path = await fetchKubectl(version)
|
||||||
|
await chmod(path, '775')
|
||||||
|
addPath(dirname(path))
|
||||||
|
debug(`kubectl ${version} installed and cached at ${path}`)
|
||||||
|
} catch {
|
||||||
|
debug('Failed to download kubectl from dl.k8s.io')
|
||||||
|
setFailed('Failed to download kubectl from dl.k8s.io\nPlease check the version you specified is valid')
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = join(env.RUNNER_TEMP, randomUUID())
|
|
||||||
await mkdir(path, { recursive: true })
|
|
||||||
saveState('kubectl-path', path)
|
|
||||||
|
|
||||||
console.log(`Installing kubectl to ${path}`)
|
|
||||||
await writeFile(join(path, 'kubectl'), kubectl)
|
|
||||||
addPath(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetches the latest kubectl version from the Kubernetes release server
|
// Fetches the latest kubectl version from the Kubernetes release server
|
||||||
@@ -57,62 +52,34 @@ async function fetchLatestVersion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Downloads the kubectl binary from the Kubernetes release server
|
// Downloads the kubectl binary from the Kubernetes release server
|
||||||
// Also runs a checksum verification on the downloaded binary
|
// If already downloaded, returns the path to the cached binary
|
||||||
async function downloadKubectl(version: string) {
|
async function fetchKubectl(version: string) {
|
||||||
const url = `https://dl.k8s.io/release/${version}/bin/linux/amd64/kubectl`
|
const cachedPath = find('kubectl', version)
|
||||||
const hashUrl = `${url}.sha256`
|
|
||||||
|
// Cached path is a directory containing the kubectl binary
|
||||||
|
if (cachedPath) {
|
||||||
|
debug(`kubectl ${version} already installed`)
|
||||||
|
return join(cachedPath, 'kubectl')
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `https://dl.k8s.io/release/${version}/bin/${retrieveRunnerMetadata()}/kubectl`
|
||||||
|
|
||||||
console.log(`Downloading kubectl (${url})`)
|
console.log(`Downloading kubectl (${url})`)
|
||||||
debug(`Downloading kubectl checksum (${hashUrl})`)
|
const downloadPath = await downloadTool(url)
|
||||||
|
const toolPath = await cacheFile(downloadPath, 'kubectl', 'kubectl', version)
|
||||||
const hashResponse = await fetch(hashUrl)
|
return join(toolPath, 'kubectl')
|
||||||
if (!hashResponse.ok) {
|
}
|
||||||
debug(`Failed to download kubectl checksum with status ${hashResponse.status}`)
|
|
||||||
warning(`Skipping checksum verification for kubectl ${version}`)
|
// Gets the proper architecture and OS for the current platform
|
||||||
}
|
// This doesn't use node functions, but instead CI variables provided by GitHub
|
||||||
|
function retrieveRunnerMetadata() {
|
||||||
const hash = hashResponse.ok ? await hashResponse.text() : ''
|
// Currently we don't support win32 platforms anyways
|
||||||
|
const runnerSystem = env.RUNNER_OS === 'Linux' ? 'linux' : 'darwin'
|
||||||
const response = await fetch(url)
|
const runnerArch = env.RUNNER_ARCH?.toLowerCase()
|
||||||
if (!response.ok || !response.body) {
|
|
||||||
debug(`Failed to download kubectl with status ${response.status}`)
|
if (runnerArch?.includes('arm')) {
|
||||||
setFailed(`Failed to download kubectl with status ${response.status}`)
|
return `${runnerSystem}/arm64`
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
return `${runnerSystem}/amd64`
|
||||||
const hashStream = createHash('sha256')
|
|
||||||
const { body, headers } = response
|
|
||||||
const size = Number(headers.get('content-length'))
|
|
||||||
debug(`Downloaded kubectl (${size} bytes)`)
|
|
||||||
|
|
||||||
let downloaded = 0
|
|
||||||
let progressed = 0
|
|
||||||
const buffer = Buffer.alloc(size)
|
|
||||||
|
|
||||||
for await (const chunk of body as AsyncIterable<Buffer>) {
|
|
||||||
buffer.write(chunk.toString('binary'), downloaded, 'binary')
|
|
||||||
hashStream.update(chunk)
|
|
||||||
downloaded += chunk.length
|
|
||||||
|
|
||||||
if (Math.floor((downloaded / size) * 80) > progressed) {
|
|
||||||
clearLine(stdout, 0)
|
|
||||||
cursorTo(stdout, 0)
|
|
||||||
|
|
||||||
progressed++
|
|
||||||
stdout.write(`[${'='.repeat(progressed)}>${' '.repeat(80 - progressed)}]`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearLine(stdout, 0)
|
|
||||||
cursorTo(stdout, 0)
|
|
||||||
console.log(`[${'='.repeat(80)}]`)
|
|
||||||
|
|
||||||
const hashSum = hashStream.digest('hex')
|
|
||||||
if (hashResponse.ok && hashSum !== hash) {
|
|
||||||
debug(`Checksum verification failed for kubectl ${version}`)
|
|
||||||
setFailed(`Checksum verification failed for kubectl ${version}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,7 @@ import { debug, getState } from '@actions/core'
|
|||||||
|
|
||||||
export async function teardown() {
|
export async function teardown() {
|
||||||
debug('Running kubectl-action teardown()')
|
debug('Running kubectl-action teardown()')
|
||||||
console.log('Removing kubectl and kubeconfig')
|
console.log('Removing kubeconfig')
|
||||||
|
|
||||||
const path = getState('kubectl-path')
|
|
||||||
await rm(path, { recursive: true, force: true })
|
|
||||||
|
|
||||||
const configPath = getState('kubeconfig-path')
|
const configPath = getState('kubeconfig-path')
|
||||||
await rm(configPath, { recursive: true, force: true })
|
await rm(configPath, { recursive: true, force: true })
|
||||||
|
|||||||
Reference in New Issue
Block a user