mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-06-23 21:19:28 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da331a158c | |||
| e08fe4d10f | |||
| 159ed4c2e2 | |||
| e394a363ea | |||
| 9a3f9b33d4 | |||
| 2deb54c5d3 | |||
| f0b74d1da1 | |||
| 0767161214 | |||
| ee4689b033 | |||
| 103b5ccfa2 | |||
| 209431e7c0 | |||
| 18f9d6f27c | |||
| f9cf4e2ef6 | |||
| db9a5aa2d4 | |||
| f7415623aa | |||
| 43974c78e2 |
@@ -1,18 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: npm
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
groups:
|
|
||||||
actions:
|
|
||||||
patterns:
|
|
||||||
- '*'
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
directory: .github/workflows
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
groups:
|
|
||||||
actions:
|
|
||||||
patterns:
|
|
||||||
- '*'
|
|
||||||
@@ -64,13 +64,9 @@ jobs:
|
|||||||
images: nginx:1.14.2
|
images: nginx:1.14.2
|
||||||
manifests: |
|
manifests: |
|
||||||
test/integration/manifests/test.yml
|
test/integration/manifests/test.yml
|
||||||
test/integration/manifests/manifest_test_dir/test.yml
|
|
||||||
action: deploy
|
action: deploy
|
||||||
|
|
||||||
- name: Checking if deployments and services were created
|
- name: Checking if deployments and services were created
|
||||||
run: |
|
run: |
|
||||||
python test/integration/k8s-deploy-test.py namespace=${{ env.NAMESPACE }} kind=Deployment name=nginx-deployment containerName=nginx:1.14.2 labels=app:nginx,workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Minikube_Integration_Tests_-_basic selectorLabels=app:nginx
|
python test/integration/k8s-deploy-test.py namespace=${{ env.NAMESPACE }} kind=Deployment name=nginx-deployment containerName=nginx:1.14.2 labels=app:nginx,workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Minikube_Integration_Tests_-_basic selectorLabels=app:nginx
|
||||||
python test/integration/k8s-deploy-test.py namespace=${{ env.NAMESPACE }} kind=Service name=nginx-service labels=workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Minikube_Integration_Tests_-_basic selectorLabels=app:nginx
|
python test/integration/k8s-deploy-test.py namespace=${{ env.NAMESPACE }} kind=Service name=nginx-service labels=workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Minikube_Integration_Tests_-_basic selectorLabels=app:nginx
|
||||||
|
|
||||||
python test/integration/k8s-deploy-test.py namespace=${{ env.NAMESPACE }} kind=Deployment name=nginx-deployment3 containerName=nginx:1.14.2 labels=app:nginx3,workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Minikube_Integration_Tests_-_basic selectorLabels=app:nginx3
|
|
||||||
python test/integration/k8s-deploy-test.py namespace=${{ env.NAMESPACE }} kind=Service name=nginx-service3 labels=workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Minikube_Integration_Tests_-_basic selectorLabels=app:nginx3
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set +x
|
set +x
|
||||||
# create cluster
|
# create cluster
|
||||||
az group create --location eastus2 --name ${{ env.NAMESPACE }}
|
az group create --location eastus --name ${{ env.NAMESPACE }}
|
||||||
az aks create --name ${{ env.NAMESPACE }} --resource-group ${{ env.NAMESPACE }} --enable-private-cluster --generate-ssh-keys
|
az aks create --name ${{ env.NAMESPACE }} --resource-group ${{ env.NAMESPACE }} --enable-private-cluster --generate-ssh-keys
|
||||||
az aks get-credentials --resource-group ${{ env.NAMESPACE }} --name ${{ env.NAMESPACE }}
|
az aks get-credentials --resource-group ${{ env.NAMESPACE }} --name ${{ env.NAMESPACE }}
|
||||||
|
|
||||||
@@ -63,7 +63,6 @@ jobs:
|
|||||||
images: nginx:1.14.2
|
images: nginx:1.14.2
|
||||||
manifests: |
|
manifests: |
|
||||||
test/integration/manifests/test.yml
|
test/integration/manifests/test.yml
|
||||||
test/integration/manifests/test2.yml
|
|
||||||
action: deploy
|
action: deploy
|
||||||
private-cluster: true
|
private-cluster: true
|
||||||
resource-group: ${{ env.NAMESPACE }}
|
resource-group: ${{ env.NAMESPACE }}
|
||||||
@@ -74,9 +73,6 @@ jobs:
|
|||||||
python test/integration/k8s-deploy-test.py private=${{ env.NAMESPACE }} namespace=${{ env.NAMESPACE }} kind=Deployment name=nginx-deployment containerName=nginx:1.14.2 labels=app:nginx,workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Cluster_Integration_Tests_-_private_cluster selectorLabels=app:nginx
|
python test/integration/k8s-deploy-test.py private=${{ env.NAMESPACE }} namespace=${{ env.NAMESPACE }} kind=Deployment name=nginx-deployment containerName=nginx:1.14.2 labels=app:nginx,workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Cluster_Integration_Tests_-_private_cluster selectorLabels=app:nginx
|
||||||
python test/integration/k8s-deploy-test.py private=${{ env.NAMESPACE }} namespace=${{ env.NAMESPACE }} kind=Service name=nginx-service labels=workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Cluster_Integration_Tests_-_private_cluster selectorLabels=app:nginx
|
python test/integration/k8s-deploy-test.py private=${{ env.NAMESPACE }} namespace=${{ env.NAMESPACE }} kind=Service name=nginx-service labels=workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Cluster_Integration_Tests_-_private_cluster selectorLabels=app:nginx
|
||||||
|
|
||||||
python test/integration/k8s-deploy-test.py private=${{ env.NAMESPACE }} namespace=${{ env.NAMESPACE }} kind=Deployment name=nginx-deployment2 containerName=nginx:1.14.2 labels=app:nginx2,workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Cluster_Integration_Tests_-_private_cluster selectorLabels=app:nginx2
|
|
||||||
python test/integration/k8s-deploy-test.py private=${{ env.NAMESPACE }} namespace=${{ env.NAMESPACE }} kind=Service name=nginx-service2 labels=workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Cluster_Integration_Tests_-_private_cluster selectorLabels=app:nginx2
|
|
||||||
|
|
||||||
- name: Clean up AKS cluster
|
- name: Clean up AKS cluster
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
Generated
+6772
-2957
File diff suppressed because it is too large
Load Diff
+6
-7
@@ -4,7 +4,7 @@
|
|||||||
"author": "Deepak Sattiraju",
|
"author": "Deepak Sattiraju",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "npm i @vercel/ncc",
|
"prebuild": "npm i @ncc/vercel",
|
||||||
"build": "ncc build src/run.ts -o lib",
|
"build": "ncc build src/run.ts -o lib",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"coverage": "jest --coverage=true",
|
"coverage": "jest --coverage=true",
|
||||||
@@ -19,17 +19,16 @@
|
|||||||
"@octokit/core": "^3.5.1",
|
"@octokit/core": "^3.5.1",
|
||||||
"@octokit/plugin-retry": "^3.0.9",
|
"@octokit/plugin-retry": "^3.0.9",
|
||||||
"@types/minipass": "^3.1.2",
|
"@types/minipass": "^3.1.2",
|
||||||
"js-yaml": "3.13.1",
|
"js-yaml": "3.13.1"
|
||||||
"minimist": "^1.2.8"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^26.0.0",
|
"@types/jest": "^26.0.0",
|
||||||
"@types/js-yaml": "^3.12.7",
|
"@types/js-yaml": "^3.12.7",
|
||||||
"@types/node": "^12.20.41",
|
"@types/node": "^12.20.41",
|
||||||
"@vercel/ncc": "^0.36.1",
|
"@vercel/ncc": "^0.36.1",
|
||||||
"jest": "^29.7.0",
|
"jest": "^26.0.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.7.1",
|
||||||
"ts-jest": "^29.2.3",
|
"ts-jest": "^26.0.0",
|
||||||
"typescript": "5.5.4"
|
"typescript": "3.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,12 @@ import {Kubectl, Resource} from '../types/kubectl'
|
|||||||
import {deployPodCanary} from './canary/podCanaryHelper'
|
import {deployPodCanary} from './canary/podCanaryHelper'
|
||||||
import {deploySMICanary} from './canary/smiCanaryHelper'
|
import {deploySMICanary} from './canary/smiCanaryHelper'
|
||||||
import {DeploymentConfig} from '../types/deploymentConfig'
|
import {DeploymentConfig} from '../types/deploymentConfig'
|
||||||
import {deployBlueGreen} from './blueGreen/deploy'
|
import {
|
||||||
|
deployBlueGreen,
|
||||||
|
deployBlueGreenIngress,
|
||||||
|
deployBlueGreenService
|
||||||
|
} from './blueGreen/deploy'
|
||||||
|
import {deployBlueGreenSMI} from './blueGreen/deploy'
|
||||||
import {DeploymentStrategy} from '../types/deploymentStrategy'
|
import {DeploymentStrategy} from '../types/deploymentStrategy'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {
|
import {
|
||||||
@@ -34,6 +39,7 @@ import {
|
|||||||
normalizeWorkflowStrLabel
|
normalizeWorkflowStrLabel
|
||||||
} from '../utilities/githubUtils'
|
} from '../utilities/githubUtils'
|
||||||
import {getDeploymentConfig} from '../utilities/dockerUtils'
|
import {getDeploymentConfig} from '../utilities/dockerUtils'
|
||||||
|
import {deploy} from '../actions/deploy'
|
||||||
import {DeployResult} from '../types/deployResult'
|
import {DeployResult} from '../types/deployResult'
|
||||||
|
|
||||||
export async function deployManifests(
|
export async function deployManifests(
|
||||||
|
|||||||
@@ -39,6 +39,17 @@ const testNamespace = 'testNamespace'
|
|||||||
const defaultNamespace = 'default'
|
const defaultNamespace = 'default'
|
||||||
const otherNamespace = 'otherns'
|
const otherNamespace = 'otherns'
|
||||||
describe('Kubectl class', () => {
|
describe('Kubectl class', () => {
|
||||||
|
describe('default namespace behavior', () => {
|
||||||
|
const kubectl = new Kubectl(kubectlPath, defaultNamespace)
|
||||||
|
const execReturn = {exitCode: 0, stdout: 'Output', stderr: ''}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.spyOn(exec, 'getExecOutput').mockImplementation(async () => {
|
||||||
|
return execReturn
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('with a success exec return in testNamespace', () => {
|
describe('with a success exec return in testNamespace', () => {
|
||||||
const kubectl = new Kubectl(kubectlPath, testNamespace)
|
const kubectl = new Kubectl(kubectlPath, testNamespace)
|
||||||
const execReturn = {exitCode: 0, stdout: 'Output', stderr: ''}
|
const execReturn = {exitCode: 0, stdout: 'Output', stderr: ''}
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
import * as fileUtils from '../utilities/fileUtils'
|
import {PrivateKubectl} from './privatekubectl'
|
||||||
import * as fs from 'fs'
|
|
||||||
import {
|
|
||||||
PrivateKubectl,
|
|
||||||
extractFileNames,
|
|
||||||
replaceFileNamesWithShallowNamesRelativeToTemp
|
|
||||||
} from './privatekubectl'
|
|
||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
|
|
||||||
describe('Private kubectl', () => {
|
describe('Private kubectl', () => {
|
||||||
const testString = `kubectl annotate -f /tmp/testdir/test.yml,/tmp/test2.yml,/tmp/testdir/subdir/test3.yml -f /tmp/test4.yml --filename /tmp/test5.yml actions.github.com/k8s-deploy={"run":"3498366832","repository":"jaiveerk/k8s-deploy","workflow":"Minikube Integration Tests - private cluster","workflowFileName":"run-integration-tests-private.yml","jobName":"run-integration-test","createdBy":"jaiveerk","runUri":"https://github.com/jaiveerk/k8s-deploy/actions/runs/3498366832","commit":"c63b323186ea1320a31290de6dcc094c06385e75","lastSuccessRunCommit":"NA","branch":"refs/heads/main","deployTimestamp":1668787848577,"dockerfilePaths":{"nginx:1.14.2":""},"manifestsPaths":["https://github.com/jaiveerk/k8s-deploy/blob/c63b323186ea1320a31290de6dcc094c06385e75/test/integration/test.yml"],"helmChartPaths":[],"provider":"GitHub"} --overwrite --namespace test-3498366832`
|
const testString = `kubectl annotate -f test.yml,test2.yml,test3.yml -f test4.yml --filename test5.yml actions.github.com/k8s-deploy={"run":"3498366832","repository":"jaiveerk/k8s-deploy","workflow":"Minikube Integration Tests - private cluster","workflowFileName":"run-integration-tests-private.yml","jobName":"run-integration-test","createdBy":"jaiveerk","runUri":"https://github.com/jaiveerk/k8s-deploy/actions/runs/3498366832","commit":"c63b323186ea1320a31290de6dcc094c06385e75","lastSuccessRunCommit":"NA","branch":"refs/heads/main","deployTimestamp":1668787848577,"dockerfilePaths":{"nginx:1.14.2":""},"manifestsPaths":["https://github.com/jaiveerk/k8s-deploy/blob/c63b323186ea1320a31290de6dcc094c06385e75/test/integration/manifests/test.yml"],"helmChartPaths":[],"provider":"GitHub"} --overwrite --namespace test-3498366832`
|
||||||
const mockKube = new PrivateKubectl(
|
const mockKube = new PrivateKubectl(
|
||||||
'kubectlPath',
|
'kubectlPath',
|
||||||
'namespace',
|
'namespace',
|
||||||
@@ -17,32 +11,9 @@ describe('Private kubectl', () => {
|
|||||||
'resourceName'
|
'resourceName'
|
||||||
)
|
)
|
||||||
|
|
||||||
const spy = jest
|
|
||||||
.spyOn(fileUtils, 'getTempDirectory')
|
|
||||||
.mockImplementation(() => {
|
|
||||||
return '/tmp'
|
|
||||||
})
|
|
||||||
|
|
||||||
jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {})
|
|
||||||
jest.spyOn(fs, 'readFileSync').mockImplementation((filename) => {
|
|
||||||
return 'test contents'
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should extract filenames correctly', () => {
|
it('should extract filenames correctly', () => {
|
||||||
expect(extractFileNames(testString)).toEqual([
|
expect(mockKube.extractFilesnames(testString)).toEqual(
|
||||||
'/tmp/testdir/test.yml',
|
'test.yml test2.yml test3.yml test4.yml test5.yml'
|
||||||
'/tmp/test2.yml',
|
|
||||||
'/tmp/testdir/subdir/test3.yml',
|
|
||||||
'/tmp/test4.yml',
|
|
||||||
'/tmp/test5.yml'
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should replace filenames with shallow names for relative locations in tmp correctly', () => {
|
|
||||||
expect(
|
|
||||||
replaceFileNamesWithShallowNamesRelativeToTemp(testString)
|
|
||||||
).toEqual(
|
|
||||||
`kubectl annotate -f testdir-test.yml,test2.yml,testdir-subdir-test3.yml -f test4.yml --filename test5.yml actions.github.com/k8s-deploy={"run":"3498366832","repository":"jaiveerk/k8s-deploy","workflow":"Minikube Integration Tests - private cluster","workflowFileName":"run-integration-tests-private.yml","jobName":"run-integration-test","createdBy":"jaiveerk","runUri":"https://github.com/jaiveerk/k8s-deploy/actions/runs/3498366832","commit":"c63b323186ea1320a31290de6dcc094c06385e75","lastSuccessRunCommit":"NA","branch":"refs/heads/main","deployTimestamp":1668787848577,"dockerfilePaths":{"nginx:1.14.2":""},"manifestsPaths":["https://github.com/jaiveerk/k8s-deploy/blob/c63b323186ea1320a31290de6dcc094c06385e75/test/integration/test.yml"],"helmChartPaths":[],"provider":"GitHub"} --overwrite --namespace test-3498366832`
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+95
-82
@@ -5,7 +5,6 @@ import * as core from '@actions/core'
|
|||||||
import * as os from 'os'
|
import * as os from 'os'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import {getTempDirectory} from '../utilities/fileUtils'
|
|
||||||
|
|
||||||
export class PrivateKubectl extends Kubectl {
|
export class PrivateKubectl extends Kubectl {
|
||||||
protected async execute(args: string[], silent: boolean = false) {
|
protected async execute(args: string[], silent: boolean = false) {
|
||||||
@@ -19,7 +18,8 @@ export class PrivateKubectl extends Kubectl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.containsFilenames(kubectlCmd)) {
|
if (this.containsFilenames(kubectlCmd)) {
|
||||||
kubectlCmd = replaceFileNamesWithShallowNamesRelativeToTemp(kubectlCmd)
|
// For private clusters, files will referenced solely by their basename
|
||||||
|
kubectlCmd = this.replaceFilnamesWithBasenames(kubectlCmd)
|
||||||
addFileFlag = true
|
addFileFlag = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,9 +43,22 @@ export class PrivateKubectl extends Kubectl {
|
|||||||
]
|
]
|
||||||
|
|
||||||
if (addFileFlag) {
|
if (addFileFlag) {
|
||||||
const tempDirectory = getTempDirectory()
|
const filenames = this.extractFilesnames(kubectlCmd).split(' ')
|
||||||
eo.cwd = path.join(tempDirectory, 'manifests')
|
|
||||||
|
const tempDirectory =
|
||||||
|
process.env['runner.tempDirectory'] || os.tmpdir() + '/manifests'
|
||||||
|
eo.cwd = tempDirectory
|
||||||
privateClusterArgs.push(...['--file', '.'])
|
privateClusterArgs.push(...['--file', '.'])
|
||||||
|
|
||||||
|
let filenamesArr = filenames[0].split(',')
|
||||||
|
for (let index = 0; index < filenamesArr.length; index++) {
|
||||||
|
const file = filenamesArr[index]
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
this.moveFileToTempManifestDir(file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core.debug(
|
core.debug(
|
||||||
@@ -82,89 +95,89 @@ export class PrivateKubectl extends Kubectl {
|
|||||||
} as ExecOutput
|
} as ExecOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private replaceFilnamesWithBasenames(kubectlCmd: string) {
|
||||||
|
let exFilenames = this.extractFilesnames(kubectlCmd)
|
||||||
|
let filenames = exFilenames.split(' ')
|
||||||
|
let filenamesArr = filenames[0].split(',')
|
||||||
|
|
||||||
|
for (let index = 0; index < filenamesArr.length; index++) {
|
||||||
|
filenamesArr[index] = path.basename(filenamesArr[index])
|
||||||
|
}
|
||||||
|
|
||||||
|
let baseFilenames = filenamesArr.join()
|
||||||
|
|
||||||
|
let result = kubectlCmd.replace(exFilenames, baseFilenames)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
public extractFilesnames(strToParse: string) {
|
||||||
|
const fileNames: string[] = []
|
||||||
|
const argv = minimist(strToParse.split(' '))
|
||||||
|
const fArg = 'f'
|
||||||
|
const filenameArg = 'filename'
|
||||||
|
|
||||||
|
fileNames.push(...this.extractFilesFromMinimist(argv, fArg))
|
||||||
|
fileNames.push(...this.extractFilesFromMinimist(argv, filenameArg))
|
||||||
|
|
||||||
|
return fileNames.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
private extractFilesFromMinimist(argv, arg: string): string[] {
|
||||||
|
if (!argv[arg]) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const toReturn: string[] = []
|
||||||
|
if (typeof argv[arg] === 'string') {
|
||||||
|
toReturn.push(...argv[arg].split(','))
|
||||||
|
} else {
|
||||||
|
for (const value of argv[arg] as string[]) {
|
||||||
|
toReturn.push(...value.split(','))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn
|
||||||
|
}
|
||||||
|
|
||||||
private containsFilenames(str: string) {
|
private containsFilenames(str: string) {
|
||||||
return str.includes('-f ') || str.includes('filename ')
|
return str.includes('-f ') || str.includes('filename ')
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function createTempManifestsDirectory(): string {
|
private createTempManifestsDirectory() {
|
||||||
const manifestsDirPath = path.join(getTempDirectory(), 'manifests')
|
const manifestsDir = '/tmp/manifests'
|
||||||
if (!fs.existsSync(manifestsDirPath)) {
|
if (!fs.existsSync('/tmp/manifests')) {
|
||||||
fs.mkdirSync(manifestsDirPath, {recursive: true})
|
fs.mkdirSync('/tmp/manifests', {recursive: true})
|
||||||
}
|
|
||||||
|
|
||||||
return manifestsDirPath
|
|
||||||
}
|
|
||||||
|
|
||||||
export function replaceFileNamesWithShallowNamesRelativeToTemp(
|
|
||||||
kubectlCmd: string
|
|
||||||
) {
|
|
||||||
let filenames = extractFileNames(kubectlCmd)
|
|
||||||
core.debug(`filenames originally provided in kubectl command: ${filenames}`)
|
|
||||||
let relativeShallowNames = filenames.map((filename) => {
|
|
||||||
const relativeName = path.relative(getTempDirectory(), filename)
|
|
||||||
|
|
||||||
const relativePathElements = relativeName.split(path.sep)
|
|
||||||
|
|
||||||
const shallowName = relativePathElements.join('-')
|
|
||||||
|
|
||||||
// make manifests dir in temp if it doesn't already exist
|
|
||||||
const manifestsTempDir = createTempManifestsDirectory()
|
|
||||||
|
|
||||||
const shallowPath = path.join(manifestsTempDir, shallowName)
|
|
||||||
core.debug(
|
|
||||||
`moving contents from ${filename} to shallow location at ${shallowPath}`
|
|
||||||
)
|
|
||||||
|
|
||||||
core.debug(`reading contents from ${filename}`)
|
|
||||||
const contents = fs.readFileSync(filename).toString()
|
|
||||||
|
|
||||||
core.debug(`writing contents to new path ${shallowPath}`)
|
|
||||||
fs.writeFileSync(shallowPath, contents)
|
|
||||||
|
|
||||||
return shallowName
|
|
||||||
})
|
|
||||||
|
|
||||||
let result = kubectlCmd
|
|
||||||
if (filenames.length != relativeShallowNames.length) {
|
|
||||||
throw Error(
|
|
||||||
'replacing filenames with relative path from temp dir, ' +
|
|
||||||
filenames.length +
|
|
||||||
' filenames != ' +
|
|
||||||
relativeShallowNames.length +
|
|
||||||
'basenames'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
for (let index = 0; index < filenames.length; index++) {
|
|
||||||
result = result.replace(filenames[index], relativeShallowNames[index])
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractFileNames(strToParse: string) {
|
|
||||||
const fileNames: string[] = []
|
|
||||||
const argv = minimist(strToParse.split(' '))
|
|
||||||
const fArg = 'f'
|
|
||||||
const filenameArg = 'filename'
|
|
||||||
|
|
||||||
fileNames.push(...extractFilesFromMinimist(argv, fArg))
|
|
||||||
fileNames.push(...extractFilesFromMinimist(argv, filenameArg))
|
|
||||||
|
|
||||||
return fileNames
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractFilesFromMinimist(argv, arg: string): string[] {
|
|
||||||
if (!argv[arg]) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
const toReturn: string[] = []
|
|
||||||
if (typeof argv[arg] === 'string') {
|
|
||||||
toReturn.push(...argv[arg].split(','))
|
|
||||||
} else {
|
|
||||||
for (const value of argv[arg] as string[]) {
|
|
||||||
toReturn.push(...value.split(','))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return toReturn
|
private moveFileToTempManifestDir(file: string) {
|
||||||
|
this.createTempManifestsDirectory()
|
||||||
|
if (!fs.existsSync('/tmp/' + file)) {
|
||||||
|
core.debug(
|
||||||
|
'/tmp/' +
|
||||||
|
file +
|
||||||
|
' does not exist, and therefore cannot be moved to the manifest directory'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.copyFile('/tmp/' + file, '/tmp/manifests/' + file, function (err) {
|
||||||
|
if (err) {
|
||||||
|
core.debug(
|
||||||
|
'Could not rename ' +
|
||||||
|
'/tmp/' +
|
||||||
|
file +
|
||||||
|
' to ' +
|
||||||
|
'/tmp/manifests/' +
|
||||||
|
file +
|
||||||
|
' ERROR: ' +
|
||||||
|
err
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
core.debug(
|
||||||
|
"Successfully moved file '" +
|
||||||
|
file +
|
||||||
|
"' from /tmp to /tmp/manifest directory"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import * as fileUtils from './fileUtils'
|
import {
|
||||||
|
getFilesFromDirectoriesAndURLs,
|
||||||
|
getTempDirectory,
|
||||||
|
urlFileKind,
|
||||||
|
writeYamlFromURLToFile
|
||||||
|
} from './fileUtils'
|
||||||
|
|
||||||
import * as yaml from 'js-yaml'
|
import * as yaml from 'js-yaml'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
import {succeeded} from '../types/errorable'
|
||||||
|
|
||||||
const sampleYamlUrl =
|
const sampleYamlUrl =
|
||||||
'https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/controllers/nginx-deployment.yaml'
|
'https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/controllers/nginx-deployment.yaml'
|
||||||
describe('File utils', () => {
|
describe('File utils', () => {
|
||||||
test('correctly parses a yaml file from a URL', async () => {
|
test('correctly parses a yaml file from a URL', async () => {
|
||||||
const tempFile = await fileUtils.writeYamlFromURLToFile(sampleYamlUrl, 0)
|
const tempFile = await writeYamlFromURLToFile(sampleYamlUrl, 0)
|
||||||
const fileContents = fs.readFileSync(tempFile).toString()
|
const fileContents = fs.readFileSync(tempFile).toString()
|
||||||
const inputObjects = yaml.safeLoadAll(fileContents)
|
const inputObjects = yaml.safeLoadAll(fileContents)
|
||||||
expect(inputObjects).toHaveLength(1)
|
expect(inputObjects).toHaveLength(1)
|
||||||
@@ -24,34 +30,34 @@ describe('File utils', () => {
|
|||||||
|
|
||||||
const testPath = path.join('test', 'unit', 'manifests')
|
const testPath = path.join('test', 'unit', 'manifests')
|
||||||
await expect(
|
await expect(
|
||||||
fileUtils.getFilesFromDirectoriesAndURLs([testPath, badUrl])
|
getFilesFromDirectoriesAndURLs([testPath, badUrl])
|
||||||
).rejects.toThrow()
|
).rejects.toThrow()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('detects files in nested directories with the same name and ignores non-manifest files and empty dirs', async () => {
|
it('detects files in nested directories and ignores non-manifest files and empty dirs', async () => {
|
||||||
const testPath = path.join('test', 'unit', 'manifests')
|
const testPath = path.join('test', 'unit', 'manifests')
|
||||||
const testSearch: string[] =
|
const testSearch: string[] = await getFilesFromDirectoriesAndURLs([
|
||||||
await fileUtils.getFilesFromDirectoriesAndURLs([
|
testPath,
|
||||||
testPath,
|
sampleYamlUrl
|
||||||
sampleYamlUrl
|
])
|
||||||
])
|
|
||||||
|
|
||||||
const expectedManifests = [
|
const expectedManifests = [
|
||||||
'test/unit/manifests/manifest_test_dir/another_layer/test-ingress.yaml',
|
'test/unit/manifests/manifest_test_dir/another_layer/deep-ingress.yaml',
|
||||||
'test/unit/manifests/manifest_test_dir/another_layer/nested-test-service.yaml',
|
'test/unit/manifests/manifest_test_dir/another_layer/deep-service.yaml',
|
||||||
'test/unit/manifests/manifest_test_dir/nested-test-service.yaml',
|
'test/unit/manifests/manifest_test_dir/nested-test-service.yaml',
|
||||||
'test/unit/manifests/test-ingress.yml',
|
'test/unit/manifests/test-ingress.yml',
|
||||||
'test/unit/manifests/test-ingress-new.yml',
|
'test/unit/manifests/test-ingress-new.yml',
|
||||||
'test/unit/manifests/test-service.yml'
|
'test/unit/manifests/test-service.yml'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// is there a more efficient way to test equality w random order?
|
||||||
expect(testSearch).toHaveLength(8)
|
expect(testSearch).toHaveLength(8)
|
||||||
expectedManifests.forEach((fileName) => {
|
expectedManifests.forEach((fileName) => {
|
||||||
if (fileName.startsWith('test/unit')) {
|
if (fileName.startsWith('test/unit')) {
|
||||||
expect(testSearch).toContain(fileName)
|
expect(testSearch).toContain(fileName)
|
||||||
} else {
|
} else {
|
||||||
expect(fileName.includes(fileUtils.urlFileKind)).toBe(true)
|
expect(fileName.includes(urlFileKind)).toBe(true)
|
||||||
expect(fileName.startsWith(fileUtils.getTempDirectory()))
|
expect(fileName.startsWith(getTempDirectory()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -66,7 +72,7 @@ describe('File utils', () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
fileUtils.getFilesFromDirectoriesAndURLs([badPath, goodPath])
|
getFilesFromDirectoriesAndURLs([badPath, goodPath])
|
||||||
).rejects.toThrowError()
|
).rejects.toThrowError()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -86,7 +92,7 @@ describe('File utils', () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await fileUtils.getFilesFromDirectoriesAndURLs([
|
await getFilesFromDirectoriesAndURLs([
|
||||||
outerPath,
|
outerPath,
|
||||||
fileAtOuter,
|
fileAtOuter,
|
||||||
innerPath
|
innerPath
|
||||||
@@ -96,24 +102,6 @@ describe('File utils', () => {
|
|||||||
|
|
||||||
it('throws an error for an invalid URL', async () => {
|
it('throws an error for an invalid URL', async () => {
|
||||||
const badUrl = 'https://www.github.com'
|
const badUrl = 'https://www.github.com'
|
||||||
await expect(
|
await expect(writeYamlFromURLToFile(badUrl, 0)).rejects.toBeTruthy()
|
||||||
fileUtils.writeYamlFromURLToFile(badUrl, 0)
|
|
||||||
).rejects.toBeTruthy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('moving files to temp', () => {
|
|
||||||
it('correctly moves the contents of a file to the temporary directory', () => {
|
|
||||||
jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {})
|
|
||||||
jest.spyOn(fs, 'readFileSync').mockImplementation((filename) => {
|
|
||||||
return 'test contents'
|
|
||||||
})
|
|
||||||
const originalFilePath = path.join('path', 'in', 'repo')
|
|
||||||
|
|
||||||
const output = fileUtils.moveFileToTmpDir(originalFilePath)
|
|
||||||
|
|
||||||
expect(output).toEqual(
|
|
||||||
path.join(fileUtils.getTempDirectory(), '/path/in/repo')
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export function writeObjectsToFile(inputObjects: any[]): string[] {
|
|||||||
const inputObjectString = JSON.stringify(inputObject)
|
const inputObjectString = JSON.stringify(inputObject)
|
||||||
|
|
||||||
if (inputObject?.metadata?.name) {
|
if (inputObject?.metadata?.name) {
|
||||||
const fileName = getNewTempManifestFileName(
|
const fileName = getManifestFileName(
|
||||||
inputObject.kind,
|
inputObject.kind,
|
||||||
inputObject.metadata.name
|
inputObject.metadata.name
|
||||||
)
|
)
|
||||||
@@ -52,7 +52,7 @@ export function writeManifestToFile(
|
|||||||
): string {
|
): string {
|
||||||
if (inputObjectString) {
|
if (inputObjectString) {
|
||||||
try {
|
try {
|
||||||
const fileName = getNewTempManifestFileName(kind, name)
|
const fileName = getManifestFileName(kind, name)
|
||||||
fs.writeFileSync(path.join(fileName), inputObjectString)
|
fs.writeFileSync(path.join(fileName), inputObjectString)
|
||||||
return fileName
|
return fileName
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
@@ -63,27 +63,7 @@ export function writeManifestToFile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function moveFileToTmpDir(originalFilepath: string) {
|
function getManifestFileName(kind: string, name: string) {
|
||||||
const tempDirectory = getTempDirectory()
|
|
||||||
const newPath = path.join(tempDirectory, originalFilepath)
|
|
||||||
|
|
||||||
core.debug(`reading original contents from path: ${originalFilepath}`)
|
|
||||||
const contents = fs.readFileSync(originalFilepath).toString()
|
|
||||||
|
|
||||||
const dirName = path.dirname(newPath)
|
|
||||||
if (!fs.existsSync(dirName)) {
|
|
||||||
core.debug(`path ${dirName} doesn't exist yet, making new dir...`)
|
|
||||||
fs.mkdirSync(dirName, {recursive: true})
|
|
||||||
}
|
|
||||||
core.debug(`writing contents to new path ${newPath}`)
|
|
||||||
fs.writeFileSync(path.join(newPath), contents)
|
|
||||||
|
|
||||||
core.debug(`moved contents from ${originalFilepath} to ${newPath}`)
|
|
||||||
|
|
||||||
return newPath
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNewTempManifestFileName(kind: string, name: string) {
|
|
||||||
const filePath = `${kind}_${name}_${getCurrentTime().toString()}`
|
const filePath = `${kind}_${name}_${getCurrentTime().toString()}`
|
||||||
const tempDirectory = getTempDirectory()
|
const tempDirectory = getTempDirectory()
|
||||||
return path.join(tempDirectory, path.basename(filePath))
|
return path.join(tempDirectory, path.basename(filePath))
|
||||||
@@ -150,7 +130,7 @@ export async function writeYamlFromURLToFile(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetPath = getNewTempManifestFileName(
|
const targetPath = getManifestFileName(
|
||||||
urlFileKind,
|
urlFileKind,
|
||||||
fileNumber.toString()
|
fileNumber.toString()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
import * as fileUtils from './fileUtils'
|
|
||||||
import * as manifestUpdateUtils from './manifestUpdateUtils'
|
|
||||||
import * as path from 'path'
|
|
||||||
import * as fs from 'fs'
|
|
||||||
|
|
||||||
describe('manifestUpdateUtils', () => {
|
|
||||||
jest.spyOn(fileUtils, 'moveFileToTmpDir').mockImplementation((filename) => {
|
|
||||||
return path.join('/tmp', filename)
|
|
||||||
})
|
|
||||||
jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {})
|
|
||||||
jest.spyOn(fs, 'readFileSync').mockImplementation((filename) => {
|
|
||||||
return 'test contents'
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should place all files within the temp dir with the same path that they have in the repo', () => {
|
|
||||||
const originalFilePaths: string[] = [
|
|
||||||
'path/in/repo/test.txt',
|
|
||||||
'path/deeper/in/repo/test.txt'
|
|
||||||
]
|
|
||||||
const expected: string[] = [
|
|
||||||
'/tmp/path/in/repo/test.txt',
|
|
||||||
'/tmp/path/deeper/in/repo/test.txt'
|
|
||||||
]
|
|
||||||
const newFilePaths =
|
|
||||||
manifestUpdateUtils.moveFilesToTmpDir(originalFilePaths)
|
|
||||||
expect(newFilePaths).toEqual(expected)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -3,7 +3,7 @@ import * as fs from 'fs'
|
|||||||
import * as yaml from 'js-yaml'
|
import * as yaml from 'js-yaml'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as fileHelper from './fileUtils'
|
import * as fileHelper from './fileUtils'
|
||||||
import {moveFileToTmpDir} from './fileUtils'
|
import {getTempDirectory} from './fileUtils'
|
||||||
import {
|
import {
|
||||||
InputObjectKindNotDefinedError,
|
InputObjectKindNotDefinedError,
|
||||||
InputObjectMetadataNotDefinedError,
|
InputObjectMetadataNotDefinedError,
|
||||||
@@ -26,14 +26,10 @@ export function updateManifestFiles(manifestFilePaths: string[]) {
|
|||||||
throw new Error('Manifest files not provided')
|
throw new Error('Manifest files not provided')
|
||||||
}
|
}
|
||||||
|
|
||||||
// move original set of input files to tmp dir
|
|
||||||
const manifestFilesInTempDir = moveFilesToTmpDir(manifestFilePaths)
|
|
||||||
|
|
||||||
// update container images
|
// update container images
|
||||||
const containers: string[] = core.getInput('images').split('\n')
|
const containers: string[] = core.getInput('images').split('\n')
|
||||||
|
|
||||||
const manifestFiles = updateContainerImagesInManifestFiles(
|
const manifestFiles = updateContainerImagesInManifestFiles(
|
||||||
manifestFilesInTempDir,
|
manifestFilePaths,
|
||||||
containers
|
containers
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,12 +41,6 @@ export function updateManifestFiles(manifestFilePaths: string[]) {
|
|||||||
return updateImagePullSecretsInManifestFiles(manifestFiles, imagePullSecrets)
|
return updateImagePullSecretsInManifestFiles(manifestFiles, imagePullSecrets)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function moveFilesToTmpDir(filepaths: string[]): string[] {
|
|
||||||
return filepaths.map((filename) => {
|
|
||||||
return moveFileToTmpDir(filename)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function UnsetClusterSpecificDetails(resource: any) {
|
export function UnsetClusterSpecificDetails(resource: any) {
|
||||||
if (!resource) {
|
if (!resource) {
|
||||||
return
|
return
|
||||||
@@ -80,9 +70,12 @@ function updateContainerImagesInManifestFiles(
|
|||||||
): string[] {
|
): string[] {
|
||||||
if (filePaths?.length <= 0) return filePaths
|
if (filePaths?.length <= 0) return filePaths
|
||||||
|
|
||||||
|
const newFilePaths = []
|
||||||
|
|
||||||
// update container images
|
// update container images
|
||||||
filePaths.forEach((filePath: string) => {
|
filePaths.forEach((filePath: string) => {
|
||||||
let contents = fs.readFileSync(filePath).toString()
|
let contents = fs.readFileSync(filePath).toString()
|
||||||
|
|
||||||
containers.forEach((container: string) => {
|
containers.forEach((container: string) => {
|
||||||
let [imageName] = container.split(':')
|
let [imageName] = container.split(':')
|
||||||
if (imageName.indexOf('@') > 0) {
|
if (imageName.indexOf('@') > 0) {
|
||||||
@@ -98,10 +91,13 @@ function updateContainerImagesInManifestFiles(
|
|||||||
})
|
})
|
||||||
|
|
||||||
// write updated files
|
// write updated files
|
||||||
fs.writeFileSync(path.join(filePath), contents)
|
const tempDirectory = getTempDirectory()
|
||||||
|
const fileName = path.join(tempDirectory, path.basename(filePath))
|
||||||
|
fs.writeFileSync(path.join(fileName), contents)
|
||||||
|
newFilePaths.push(fileName)
|
||||||
})
|
})
|
||||||
|
|
||||||
return filePaths
|
return newFilePaths
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -232,7 +232,8 @@ def main():
|
|||||||
getAllObjectsCmd = azPrefix + 'kubectl get '+kind+' -n '+namespace
|
getAllObjectsCmd = azPrefix + 'kubectl get '+kind+' -n '+namespace
|
||||||
if not azPrefix == "":
|
if not azPrefix == "":
|
||||||
getAllObjectsCmd = azPrefix + "'{getAllObjectsCmd}'" # add extra set of quotes
|
getAllObjectsCmd = azPrefix + "'{getAllObjectsCmd}'" # add extra set of quotes
|
||||||
foundObjects = os.popen(getAllObjectsCmd).read()
|
cmd = + "'" + cmd + "'"
|
||||||
|
foundObjects = os.popen().read()
|
||||||
suffix = f"resources of type {kind}: {foundObjects}"
|
suffix = f"resources of type {kind}: {foundObjects}"
|
||||||
sys.exit(msg + " " + suffix)
|
sys.exit(msg + " " + suffix)
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment3
|
|
||||||
labels:
|
|
||||||
app: nginx3
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: nginx3
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: nginx3
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: nginx-service3
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
app: nginx3
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 80
|
|
||||||
targetPort: 80
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment2
|
|
||||||
labels:
|
|
||||||
app: nginx2
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: nginx2
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: nginx2
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: nginx-service2
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
app: nginx2
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 80
|
|
||||||
targetPort: 80
|
|
||||||
Reference in New Issue
Block a user