Compare commits

..

1 Commits

Author SHA1 Message Date
Brandon Foley 9d200da279 Add dependabot 2024-09-05 17:08:19 -04:00
37 changed files with 2065 additions and 21068 deletions
+4 -4
View File
@@ -16,7 +16,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
with: with:
# We must fetch at least the immediate parents so that if this is # We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head. # a pull request then we can checkout the head.
@@ -24,7 +24,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd #v3.27.0 uses: github/codeql-action/init@05963f47d870e2cb19a537396c1f668a348c7d8f #v3.24.8
# Override language selection by uncommenting this and choosing your languages # Override language selection by uncommenting this and choosing your languages
# with: # with:
# languages: go, javascript, csharp, python, cpp, java # languages: go, javascript, csharp, python, cpp, java
@@ -32,7 +32,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@662472033e021d55d94146f66f6058822b0b39fd #v3.27.0 uses: github/codeql-action/autobuild@05963f47d870e2cb19a537396c1f668a348c7d8f #v3.24.8
# ️ Command-line programs to run using the OS shell. # ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
@@ -46,4 +46,4 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd #v3.27.0 uses: github/codeql-action/analyze@05963f47d870e2cb19a537396c1f668a348c7d8f #v3.24.8
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
# Steps represent a sequence of tasks that will be executed as part of the job # Steps represent a sequence of tasks that will be executed as part of the job
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v3
name: Setting issue as idle name: Setting issue as idle
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
@@ -24,7 +24,7 @@ jobs:
operations-per-run: 100 operations-per-run: 100
exempt-issue-labels: 'backlog' exempt-issue-labels: 'backlog'
- uses: actions/stale@v9 - uses: actions/stale@v3
name: Setting PR as idle name: Setting PR as idle
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
+4 -4
View File
@@ -10,9 +10,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v2
- name: install deps
run: npm install
- name: Enforce Prettier - name: Enforce Prettier
run: npm run format-check uses: actionsx/prettier@v2
with:
args: --check .
@@ -18,7 +18,7 @@ jobs:
KUBECONFIG: /home/runner/.kube/config KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }} NAMESPACE: test-${{ github.run_id }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -31,7 +31,7 @@ jobs:
- name: Build - name: Build
run: ncc build src/run.ts -o lib run: ncc build src/run.ts -o lib
- uses: Azure/setup-kubectl@v4 - uses: Azure/setup-kubectl@v3
name: Install Kubectl name: Install Kubectl
- id: setup-minikube - id: setup-minikube
@@ -46,7 +46,7 @@ jobs:
- name: Create namespace to run tests - name: Create namespace to run tests
run: kubectl create ns ${{ env.NAMESPACE }} run: kubectl create ns ${{ env.NAMESPACE }}
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
name: Install Python name: Install Python
with: with:
python-version: '3.x' python-version: '3.x'
@@ -18,7 +18,7 @@ jobs:
KUBECONFIG: /home/runner/.kube/config KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }} NAMESPACE: test-${{ github.run_id }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -31,7 +31,7 @@ jobs:
- name: Build - name: Build
run: ncc build src/run.ts -o lib run: ncc build src/run.ts -o lib
- uses: Azure/setup-kubectl@v4 - uses: Azure/setup-kubectl@v3
name: Install Kubectl name: Install Kubectl
- id: setup-minikube - id: setup-minikube
@@ -46,7 +46,7 @@ jobs:
- name: Create namespace to run tests - name: Create namespace to run tests
run: kubectl create ns ${{ env.NAMESPACE }} run: kubectl create ns ${{ env.NAMESPACE }}
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
name: Install Python name: Install Python
with: with:
python-version: '3.x' python-version: '3.x'
@@ -18,7 +18,7 @@ jobs:
KUBECONFIG: /home/runner/.kube/config KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }} NAMESPACE: test-${{ github.run_id }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -31,7 +31,7 @@ jobs:
- name: Build - name: Build
run: ncc build src/run.ts -o lib run: ncc build src/run.ts -o lib
- uses: Azure/setup-kubectl@v4 - uses: Azure/setup-kubectl@v3
name: Install Kubectl name: Install Kubectl
- id: setup-minikube - id: setup-minikube
@@ -46,7 +46,7 @@ jobs:
- name: Create namespace to run tests - name: Create namespace to run tests
run: kubectl create ns ${{ env.NAMESPACE }} run: kubectl create ns ${{ env.NAMESPACE }}
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
name: Install Python name: Install Python
with: with:
python-version: '3.x' python-version: '3.x'
@@ -18,7 +18,7 @@ jobs:
KUBECONFIG: /home/runner/.kube/config KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }} NAMESPACE: test-${{ github.run_id }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -31,7 +31,7 @@ jobs:
- name: Build - name: Build
run: ncc build src/run.ts -o lib run: ncc build src/run.ts -o lib
- uses: Azure/setup-kubectl@v4 - uses: Azure/setup-kubectl@v3
name: Install Kubectl name: Install Kubectl
- id: setup-minikube - id: setup-minikube
@@ -56,7 +56,7 @@ jobs:
- name: Create namespace to run tests - name: Create namespace to run tests
run: kubectl create ns ${{ env.NAMESPACE }} run: kubectl create ns ${{ env.NAMESPACE }}
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
name: Install Python name: Install Python
with: with:
python-version: '3.x' python-version: '3.x'
@@ -18,7 +18,7 @@ jobs:
KUBECONFIG: /home/runner/.kube/config KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }} NAMESPACE: test-${{ github.run_id }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -31,7 +31,7 @@ jobs:
- name: Build - name: Build
run: ncc build src/run.ts -o lib run: ncc build src/run.ts -o lib
- uses: Azure/setup-kubectl@v4 - uses: Azure/setup-kubectl@v3
name: Install Kubectl name: Install Kubectl
- id: setup-minikube - id: setup-minikube
@@ -46,7 +46,7 @@ jobs:
- name: Create namespace to run tests - name: Create namespace to run tests
run: kubectl create ns ${{ env.NAMESPACE }} run: kubectl create ns ${{ env.NAMESPACE }}
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
name: Install Python name: Install Python
with: with:
python-version: '3.x' python-version: '3.x'
@@ -18,7 +18,7 @@ jobs:
KUBECONFIG: /home/runner/.kube/config KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }} NAMESPACE: test-${{ github.run_id }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -31,7 +31,7 @@ jobs:
- name: Build - name: Build
run: ncc build src/run.ts -o lib run: ncc build src/run.ts -o lib
- uses: Azure/setup-kubectl@v4 - uses: Azure/setup-kubectl@v3
name: Install Kubectl name: Install Kubectl
- id: setup-minikube - id: setup-minikube
@@ -56,7 +56,7 @@ jobs:
- name: Create namespace to run tests - name: Create namespace to run tests
run: kubectl create ns ${{ env.NAMESPACE }} run: kubectl create ns ${{ env.NAMESPACE }}
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
name: Install Python name: Install Python
with: with:
python-version: '3.x' python-version: '3.x'
@@ -19,7 +19,7 @@ jobs:
contents: read contents: read
id-token: write id-token: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -30,13 +30,13 @@ jobs:
- name: Build - name: Build
run: ncc build src/run.ts -o lib run: ncc build src/run.ts -o lib
- name: Azure login - name: Azure login
uses: azure/login@v2.2.0 uses: azure/login@v1.4.3
with: with:
client-id: ${{ secrets.AZURE_CLIENT_ID }} client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- uses: Azure/setup-kubectl@v4 - uses: Azure/setup-kubectl@v3
name: Install Kubectl name: Install Kubectl
- name: Create private AKS cluster and set context - name: Create private AKS cluster and set context
@@ -51,7 +51,7 @@ jobs:
run: | run: |
az aks command invoke --resource-group ${{ env.NAMESPACE }} --name ${{ env.NAMESPACE }} --command "kubectl create ns ${{ env.NAMESPACE }}" az aks command invoke --resource-group ${{ env.NAMESPACE }} --name ${{ env.NAMESPACE }} --command "kubectl create ns ${{ env.NAMESPACE }}"
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
name: Install Python name: Install Python
with: with:
python-version: '3.x' python-version: '3.x'
@@ -18,7 +18,7 @@ jobs:
KUBECONFIG: /home/runner/.kube/config KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }} NAMESPACE: test-${{ github.run_id }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -31,7 +31,7 @@ jobs:
- name: Build - name: Build
run: ncc build src/run.ts -o lib run: ncc build src/run.ts -o lib
- uses: Azure/setup-kubectl@v4 - uses: Azure/setup-kubectl@v3
name: Install Kubectl name: Install Kubectl
- id: setup-minikube - id: setup-minikube
@@ -46,7 +46,7 @@ jobs:
- name: Create namespace to run tests - name: Create namespace to run tests
run: kubectl create ns ${{ env.NAMESPACE }} run: kubectl create ns ${{ env.NAMESPACE }}
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
name: Install Python name: Install Python
with: with:
python-version: '3.x' python-version: '3.x'
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
name: Run Unit Tests name: Run Unit Tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- run: | - run: |
npm install npm install
npm test npm test
+1
View File
@@ -2,5 +2,6 @@ node_modules
.DS_Store .DS_Store
.idea .idea
lib/
coverage/ coverage/
-6
View File
@@ -1,11 +1,5 @@
# Changelog # Changelog
## [5.0.1] - 2024-03-12
### Added
- #356 Add fleet support
## [5.0.0] - 2024-03-12 ## [5.0.0] - 2024-03-12
### Changed ### Changed
-4
View File
@@ -125,10 +125,6 @@ Following are the key capabilities of this action:
<td>skip-tls-verify</br></br>(Optional)</td> <td>skip-tls-verify</br></br>(Optional)</td>
<td>Acceptable values: true/false</br>Default value: false</br>True if the insecure-skip-tls-verify option should be used</td> <td>Acceptable values: true/false</br>Default value: false</br>True if the insecure-skip-tls-verify option should be used</td>
</tr> </tr>
<tr>
<td>resource-type (Optional)</td>
<td>Acceptable values: `Microsoft.ContainerService/managedClusters` (default), 'Microsoft.ContainerService/fleets'</td>
</tr>
</table> </table>
## Usage Examples ## Usage Examples
-6
View File
@@ -1,6 +0,0 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript'
]
}
+2 -11
View File
@@ -1,20 +1,11 @@
module.exports = { module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'], moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node', testEnvironment: 'node',
testMatch: ['**/*.test.ts'], testMatch: ['**/*.test.ts'],
transform: { transform: {
'\\.[jt]sx?$': 'babel-jest' '^.+\\.ts$': 'ts-jest'
}, },
transformIgnorePatterns: [
'node_modules/(?!' +
[
'@octokit',
'universal-user-agent',
'before-after-hook',
'minimist'
].join('|') +
')'
],
verbose: true, verbose: true,
testTimeout: 9000 testTimeout: 9000
} }
-17642
View File
File diff suppressed because it is too large Load Diff
+1753 -2905
View File
File diff suppressed because it is too large Load Diff
+14 -17
View File
@@ -12,27 +12,24 @@
"format-check": "prettier --check ." "format-check": "prettier --check ."
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.10.0",
"@actions/exec": "^1.0.0", "@actions/exec": "^1.0.0",
"@actions/io": "^1.1.3", "@actions/io": "^1.0.0",
"@actions/tool-cache": "2.0.1", "@actions/tool-cache": "1.1.2",
"@babel/preset-env": "^7.26.0", "@octokit/core": "^3.5.1",
"@babel/preset-typescript": "^7.26.0", "@octokit/plugin-retry": "^3.0.9",
"@octokit/core": "^6.1.2", "@types/minipass": "^3.1.2",
"@octokit/plugin-retry": "^7.1.2", "js-yaml": "3.13.1",
"@types/minipass": "^3.3.5",
"js-yaml": "4.1.0",
"minimist": "^1.2.8" "minimist": "^1.2.8"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.14", "@types/jest": "^26.0.0",
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^3.12.7",
"@types/minimist": "^1.2.5", "@types/node": "^12.20.41",
"@types/node": "^22.8.7", "@vercel/ncc": "^0.36.1",
"@vercel/ncc": "^0.38.3",
"jest": "^29.7.0", "jest": "^29.7.0",
"prettier": "^3.3.3", "prettier": "^2.8.8",
"ts-jest": "^29.2.5", "ts-jest": "^29.2.3",
"typescript": "5.6.3" "typescript": "5.5.4"
} }
} }
+1 -19
View File
@@ -13,12 +13,6 @@ import {
} from '../strategyHelpers/deploymentHelper' } from '../strategyHelpers/deploymentHelper'
import {DeploymentStrategy} from '../types/deploymentStrategy' import {DeploymentStrategy} from '../types/deploymentStrategy'
import {parseTrafficSplitMethod} from '../types/trafficSplitMethod' import {parseTrafficSplitMethod} from '../types/trafficSplitMethod'
export const ResourceTypeManagedCluster =
'Microsoft.ContainerService/managedClusters'
export const ResourceTypeFleet = 'Microsoft.ContainerService/fleets'
export type ClusterType =
| typeof ResourceTypeManagedCluster
| typeof ResourceTypeFleet
export async function deploy( export async function deploy(
kubectl: Kubectl, kubectl: Kubectl,
@@ -45,25 +39,13 @@ export async function deploy(
// check manifest stability // check manifest stability
core.startGroup('Checking manifest stability') core.startGroup('Checking manifest stability')
const resourceTypeInput =
core.getInput('resource-type') || ResourceTypeManagedCluster
const resourceTypes: Resource[] = getResources( const resourceTypes: Resource[] = getResources(
deployedManifestFiles, deployedManifestFiles,
models.DEPLOYMENT_TYPES.concat([ models.DEPLOYMENT_TYPES.concat([
KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE
]) ])
) )
await checkManifestStability(kubectl, resourceTypes)
if (
resourceTypeInput !== ResourceTypeManagedCluster &&
resourceTypeInput !== ResourceTypeFleet
) {
let errMsg = `Invalid resource type: ${resourceTypeInput}. Supported resource types are: ${ResourceTypeManagedCluster} (default), ${ResourceTypeFleet}`
core.setFailed(errMsg)
throw new Error(errMsg)
}
await checkManifestStability(kubectl, resourceTypes, resourceTypeInput)
core.endGroup() core.endGroup()
// print ingresses // print ingresses
+1 -16
View File
@@ -38,7 +38,6 @@ import {
TrafficSplitMethod TrafficSplitMethod
} from '../types/trafficSplitMethod' } from '../types/trafficSplitMethod'
import {parseRouteStrategy, RouteStrategy} from '../types/routeStrategy' import {parseRouteStrategy, RouteStrategy} from '../types/routeStrategy'
import {ResourceTypeFleet, ResourceTypeManagedCluster} from './deploy'
export async function promote( export async function promote(
kubectl: Kubectl, kubectl: Kubectl,
@@ -167,8 +166,6 @@ async function promoteBlueGreen(kubectl: Kubectl, manifests: string[]) {
// checking stability of newly created deployments // checking stability of newly created deployments
core.startGroup('Checking manifest stability') core.startGroup('Checking manifest stability')
const resourceType =
core.getInput('resource-type') || ResourceTypeManagedCluster
const deployedManifestFiles = deployResult.manifestFiles const deployedManifestFiles = deployResult.manifestFiles
const resources: Resource[] = getResources( const resources: Resource[] = getResources(
deployedManifestFiles, deployedManifestFiles,
@@ -176,19 +173,7 @@ async function promoteBlueGreen(kubectl: Kubectl, manifests: string[]) {
models.DiscoveryAndLoadBalancerResource.SERVICE models.DiscoveryAndLoadBalancerResource.SERVICE
]) ])
) )
if ( await KubernetesManifestUtility.checkManifestStability(kubectl, resources)
resourceType !== ResourceTypeManagedCluster &&
resourceType !== ResourceTypeFleet
) {
const errMsg = `Invalid resource type: ${resourceType}. Supported resource types are: ${ResourceTypeManagedCluster} (default), fleet`
core.setFailed(errMsg)
throw new Error(errMsg)
}
await KubernetesManifestUtility.checkManifestStability(
kubectl,
resources,
resourceType
)
core.endGroup() core.endGroup()
core.startGroup( core.startGroup(
+3 -2
View File
@@ -26,8 +26,9 @@ export async function run() {
.map((manifest) => manifest.trim()) // remove surrounding whitespace .map((manifest) => manifest.trim()) // remove surrounding whitespace
.filter((manifest) => manifest.length > 0) // remove any blanks .filter((manifest) => manifest.length > 0) // remove any blanks
const fullManifestFilePaths = const fullManifestFilePaths = await getFilesFromDirectoriesAndURLs(
await getFilesFromDirectoriesAndURLs(manifestFilePaths) manifestFilePaths
)
const kubectlPath = await getKubectlPath() const kubectlPath = await getKubectlPath()
const namespace = core.getInput('namespace') || 'default' const namespace = core.getInput('namespace') || 'default'
const isPrivateCluster = const isPrivateCluster =
@@ -77,11 +77,11 @@ export function getManifestObjects(filePaths: string[]): BlueGreenManifests {
// Manifest objects per type. All resources should be parsed and // Manifest objects per type. All resources should be parsed and
// organized before we can check if services are “routed” or not. // organized before we can check if services are “routed” or not.
filePaths.forEach((filePath: string) => { filePaths.forEach((filePath: string) => {
try {
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
yaml.loadAll(fileContents, (inputObject: any) => { yaml.safeLoadAll(fileContents, (inputObject) => {
if (!!inputObject) { if (!!inputObject) {
const kind = inputObject.kind const kind = inputObject.kind
if (isDeploymentEntity(kind)) { if (isDeploymentEntity(kind)) {
deploymentEntityList.push(inputObject) deploymentEntityList.push(inputObject)
} else if (isServiceEntity(kind)) { } else if (isServiceEntity(kind)) {
@@ -93,10 +93,6 @@ export function getManifestObjects(filePaths: string[]): BlueGreenManifests {
} }
} }
}) })
} catch (error) {
core.error(`Error processing file ${filePath}: ${error.message}`)
throw error
}
}) })
serviceEntityList.forEach((inputObject: any) => { serviceEntityList.forEach((inputObject: any) => {
@@ -77,8 +77,9 @@ export async function createTrafficSplitObject(
): Promise<TrafficSplitObject> { ): Promise<TrafficSplitObject> {
// cache traffic split api version // cache traffic split api version
if (!trafficSplitAPIVersion) if (!trafficSplitAPIVersion)
trafficSplitAPIVersion = trafficSplitAPIVersion = await kubectlUtils.getTrafficSplitAPIVersion(
await kubectlUtils.getTrafficSplitAPIVersion(kubectl) kubectl
)
// retrieve annotations for TS object // retrieve annotations for TS object
const annotations = inputAnnotations const annotations = inputAnnotations
+2 -8
View File
@@ -211,15 +211,13 @@ async function cleanUpCanary(
const deletedFiles: string[] = [] const deletedFiles: string[] = []
for (const filePath of files) { for (const filePath of files) {
try {
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
const parsedYaml: any[] = yaml.loadAll(fileContents) const parsedYaml = yaml.safeLoadAll(fileContents)
for (const inputObject of parsedYaml) { for (const inputObject of parsedYaml) {
const name = inputObject.metadata.name const name = inputObject.metadata.name
const kind = inputObject.kind const kind = inputObject.kind
const namespace: string | undefined = const namespace: string | undefined = inputObject?.metadata?.namespace
inputObject?.metadata?.namespace
if ( if (
isDeploymentEntity(kind) || isDeploymentEntity(kind) ||
@@ -233,10 +231,6 @@ async function cleanUpCanary(
await deleteObject(kind, baselineObjectName, namespace) await deleteObject(kind, baselineObjectName, namespace)
} }
} }
} catch (error) {
core.error(`Failed to process file ${filePath}: ${error.message}`)
throw error
}
} }
return deletedFiles return deletedFiles
+10 -34
View File
@@ -8,7 +8,6 @@ import * as canaryDeploymentHelper from './canaryHelper'
import {isDeploymentEntity} from '../../types/kubernetesTypes' import {isDeploymentEntity} from '../../types/kubernetesTypes'
import {getReplicaCount} from '../../utilities/manifestUpdateUtils' import {getReplicaCount} from '../../utilities/manifestUpdateUtils'
import {DeployResult} from '../../types/deployResult' import {DeployResult} from '../../types/deployResult'
import {K8sObject} from '../../types/k8sObject'
export async function deployPodCanary( export async function deployPodCanary(
filePaths: string[], filePaths: string[],
@@ -22,43 +21,28 @@ export async function deployPodCanary(
throw Error('Percentage must be between 0 and 100') throw Error('Percentage must be between 0 and 100')
for (const filePath of filePaths) { for (const filePath of filePaths) {
try { const fileContents = fs.readFileSync(filePath).toString()
const fileContents = fs.readFileSync(filePath, 'utf8') const parsedYaml = yaml.safeLoadAll(fileContents)
const parsedYaml = yaml.loadAll(fileContents)
for (const inputObject of parsedYaml) { for (const inputObject of parsedYaml) {
if ( const name = inputObject.metadata.name
inputObject && const kind = inputObject.kind
typeof inputObject === 'object' &&
'metadata' in inputObject &&
'kind' in inputObject &&
'spec' in inputObject &&
typeof inputObject.metadata === 'object' &&
'name' in inputObject.metadata &&
typeof inputObject.metadata.name === 'string' &&
typeof inputObject.kind === 'string'
) {
const obj = inputObject as K8sObject
const name = obj.metadata.name
const kind = obj.kind
if (!onlyDeployStable && isDeploymentEntity(kind)) { if (!onlyDeployStable && isDeploymentEntity(kind)) {
core.debug('Calculating replica count for canary') core.debug('Calculating replica count for canary')
const canaryReplicaCount = calculateReplicaCountForCanary( const canaryReplicaCount = calculateReplicaCountForCanary(
obj, inputObject,
percentage percentage
) )
core.debug('Replica count is ' + canaryReplicaCount) core.debug('Replica count is ' + canaryReplicaCount)
const newCanaryObject = const newCanaryObject = canaryDeploymentHelper.getNewCanaryResource(
canaryDeploymentHelper.getNewCanaryResource( inputObject,
obj,
canaryReplicaCount canaryReplicaCount
) )
newObjectsList.push(newCanaryObject) newObjectsList.push(newCanaryObject)
// if there's already a stable object, deploy baseline as well // if there's already a stable object, deploy baseline as well
const stableObject = const stableObject = await canaryDeploymentHelper.fetchResource(
await canaryDeploymentHelper.fetchResource(
kubectl, kubectl,
kind, kind,
name name
@@ -73,24 +57,16 @@ export async function deployPodCanary(
canaryReplicaCount canaryReplicaCount
) )
core.debug( core.debug(
'New baseline object: ' + 'New baseline object: ' + JSON.stringify(newBaselineObject)
JSON.stringify(newBaselineObject)
) )
newObjectsList.push(newBaselineObject) newObjectsList.push(newBaselineObject)
} }
} else { } else {
// deploy non deployment entity or regular deployments for promote as they are // deploy non deployment entity or regular deployments for promote as they are
newObjectsList.push(obj) newObjectsList.push(inputObject)
} }
} }
} }
} catch (error) {
core.error(
`Failed to parse YAML file at ${filePath}: ${error.message}`
)
throw error
}
}
core.debug('New objects list: ' + JSON.stringify(newObjectsList)) core.debug('New objects list: ' + JSON.stringify(newObjectsList))
const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList) const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList)
+8 -33
View File
@@ -11,7 +11,6 @@ import {isDeploymentEntity, isServiceEntity} from '../../types/kubernetesTypes'
import {checkForErrors} from '../../utilities/kubectlUtils' import {checkForErrors} from '../../utilities/kubectlUtils'
import {inputAnnotations} from '../../inputUtils' import {inputAnnotations} from '../../inputUtils'
import {DeployResult} from '../../types/deployResult' import {DeployResult} from '../../types/deployResult'
import {K8sObject} from '../../types/k8sObject'
const TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX = '-workflow-rollout' const TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX = '-workflow-rollout'
const TRAFFIC_SPLIT_OBJECT = 'TrafficSplit' const TRAFFIC_SPLIT_OBJECT = 'TrafficSplit'
@@ -37,11 +36,8 @@ export async function deploySMICanary(
const newObjectsList = [] const newObjectsList = []
for await (const filePath of filePaths) { for await (const filePath of filePaths) {
try {
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
const inputObjects: K8sObject[] = yaml.loadAll( const inputObjects = yaml.safeLoadAll(fileContents)
fileContents
) as K8sObject[]
for (const inputObject of inputObjects) { for (const inputObject of inputObjects) {
const name = inputObject.metadata.name const name = inputObject.metadata.name
const kind = inputObject.kind const kind = inputObject.kind
@@ -61,8 +57,7 @@ export async function deploySMICanary(
} }
core.debug('Creating canary object') core.debug('Creating canary object')
const newCanaryObject = const newCanaryObject = canaryDeploymentHelper.getNewCanaryResource(
canaryDeploymentHelper.getNewCanaryResource(
inputObject, inputObject,
canaryReplicaCount canaryReplicaCount
) )
@@ -96,10 +91,6 @@ export async function deploySMICanary(
newObjectsList.push(inputObject) newObjectsList.push(inputObject)
} }
} }
} catch (error) {
core.error(`Failed to process file at ${filePath}: ${error.message}`)
throw error
}
} }
core.debug( core.debug(
`deploying canary objects with SMI: \n ${JSON.stringify(newObjectsList)}` `deploying canary objects with SMI: \n ${JSON.stringify(newObjectsList)}`
@@ -120,12 +111,8 @@ async function createCanaryService(
const trafficObjectsList: string[] = [] const trafficObjectsList: string[] = []
for (const filePath of filePaths) { for (const filePath of filePaths) {
try {
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
const parsedYaml: K8sObject[] = yaml.loadAll( const parsedYaml = yaml.safeLoadAll(fileContents)
fileContents
) as K8sObject[]
for (const inputObject of parsedYaml) { for (const inputObject of parsedYaml) {
const name = inputObject.metadata.name const name = inputObject.metadata.name
const kind = inputObject.kind const kind = inputObject.kind
@@ -162,8 +149,7 @@ async function createCanaryService(
trafficObjectsList.push(trafficObject) trafficObjectsList.push(trafficObject)
} else { } else {
let updateTrafficObject = true let updateTrafficObject = true
const trafficObject = const trafficObject = await canaryDeploymentHelper.fetchResource(
await canaryDeploymentHelper.fetchResource(
kubectl, kubectl,
TRAFFIC_SPLIT_OBJECT, TRAFFIC_SPLIT_OBJECT,
getTrafficSplitResourceName(name) getTrafficSplitResourceName(name)
@@ -201,10 +187,6 @@ async function createCanaryService(
} }
} }
} }
} catch (error) {
core.error(`Failed to process file at ${filePath}: ${error.message}`)
throw error
}
} }
const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList) const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList)
@@ -242,12 +224,8 @@ async function adjustTraffic(
const trafficSplitManifests = [] const trafficSplitManifests = []
for (const filePath of manifestFilePaths) { for (const filePath of manifestFilePaths) {
try {
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
const parsedYaml: K8sObject[] = yaml.loadAll( const parsedYaml = yaml.safeLoadAll(fileContents)
fileContents
) as K8sObject[]
for (const inputObject of parsedYaml) { for (const inputObject of parsedYaml) {
const name = inputObject.metadata.name const name = inputObject.metadata.name
const kind = inputObject.kind const kind = inputObject.kind
@@ -264,10 +242,6 @@ async function adjustTraffic(
) )
} }
} }
} catch (error) {
core.error(`Failed to process file at ${filePath}: ${error.message}`)
throw error
}
} }
if (trafficSplitManifests.length <= 0) { if (trafficSplitManifests.length <= 0) {
@@ -347,8 +321,9 @@ async function getTrafficSplitObject(
): Promise<string> { ): Promise<string> {
// cached version // cached version
if (!trafficSplitAPIVersion) { if (!trafficSplitAPIVersion) {
trafficSplitAPIVersion = trafficSplitAPIVersion = await kubectlUtils.getTrafficSplitAPIVersion(
await kubectlUtils.getTrafficSplitAPIVersion(kubectl) kubectl
)
} }
return JSON.stringify({ return JSON.stringify({
+5 -21
View File
@@ -35,7 +35,6 @@ import {
} from '../utilities/githubUtils' } from '../utilities/githubUtils'
import {getDeploymentConfig} from '../utilities/dockerUtils' import {getDeploymentConfig} from '../utilities/dockerUtils'
import {DeployResult} from '../types/deployResult' import {DeployResult} from '../types/deployResult'
import {ClusterType} from '../actions/deploy'
export async function deployManifests( export async function deployManifests(
files: string[], files: string[],
@@ -111,11 +110,10 @@ function appendStableVersionLabelToResource(files: string[]): string[] {
const newObjectsList = [] const newObjectsList = []
files.forEach((filePath: string) => { files.forEach((filePath: string) => {
try {
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
yaml.loadAll(fileContents, function (inputObject) { yaml.safeLoadAll(fileContents, function (inputObject) {
const kind = (inputObject as {kind: string}).kind const {kind} = inputObject
if (isDeploymentEntity(kind)) { if (isDeploymentEntity(kind)) {
const updatedObject = const updatedObject =
@@ -125,10 +123,6 @@ function appendStableVersionLabelToResource(files: string[]): string[] {
manifestFiles.push(filePath) manifestFiles.push(filePath)
} }
}) })
} catch (error) {
core.error(`Failed to parse file at ${filePath}: ${error.message}`)
throw error
}
}) })
const updatedManifestFiles = fileHelper.writeObjectsToFile(newObjectsList) const updatedManifestFiles = fileHelper.writeObjectsToFile(newObjectsList)
@@ -139,14 +133,9 @@ function appendStableVersionLabelToResource(files: string[]): string[] {
export async function checkManifestStability( export async function checkManifestStability(
kubectl: Kubectl, kubectl: Kubectl,
resources: Resource[], resources: Resource[]
resourceType: ClusterType
): Promise<void> { ): Promise<void> {
await KubernetesManifestUtility.checkManifestStability( await KubernetesManifestUtility.checkManifestStability(kubectl, resources)
kubectl,
resources,
resourceType
)
} }
export async function annotateAndLabelResources( export async function annotateAndLabelResources(
@@ -204,20 +193,15 @@ async function annotateResources(
) )
if (core.isDebug()) { if (core.isDebug()) {
try {
core.debug(`files getting annotated are ${JSON.stringify(files)}`) core.debug(`files getting annotated are ${JSON.stringify(files)}`)
for (const filePath of files) { for (const filePath of files) {
core.debug('printing objects getting annotated...') core.debug('printing objects getting annotated...')
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
const inputObjects = yaml.loadAll(fileContents) const inputObjects = yaml.safeLoadAll(fileContents)
for (const inputObject of inputObjects) { for (const inputObject of inputObjects) {
core.debug(`object: ${JSON.stringify(inputObject)}`) core.debug(`object: ${JSON.stringify(inputObject)}`)
} }
} }
} catch (error) {
core.error(`Failed to load and parse files: ${error.message}`)
throw error
}
} }
const annotationKeyValStr = `${annotationKey}=${getWorkflowAnnotations( const annotationKeyValStr = `${annotationKey}=${getWorkflowAnnotations(
+1 -1
View File
@@ -1,5 +1,5 @@
import * as fileUtils from '../utilities/fileUtils' import * as fileUtils from '../utilities/fileUtils'
import fs from 'node:fs' import * as fs from 'fs'
import { import {
PrivateKubectl, PrivateKubectl,
extractFileNames, extractFileNames,
+3 -2
View File
@@ -1,8 +1,9 @@
import {Kubectl} from './kubectl' import {Kubectl} from './kubectl'
import minimist from 'minimist' import * as minimist from 'minimist'
import {ExecOptions, ExecOutput, getExecOutput} from '@actions/exec' import {ExecOptions, ExecOutput, getExecOutput} from '@actions/exec'
import * as core from '@actions/core' import * as core from '@actions/core'
import fs from 'node:fs' import * as os from 'os'
import * as fs from 'fs'
import * as path from 'path' import * as path from 'path'
import {getTempDirectory} from '../utilities/fileUtils' import {getTempDirectory} from '../utilities/fileUtils'
+2 -5
View File
@@ -1,9 +1,8 @@
import * as fileUtils from './fileUtils' import * as fileUtils from './fileUtils'
import * as yaml from 'js-yaml' import * as yaml from 'js-yaml'
import fs from 'node:fs' import * as fs from 'fs'
import * as path from 'path' import * as path from 'path'
import {K8sObject} from '../types/k8sObject'
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'
@@ -11,9 +10,7 @@ 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 fileUtils.writeYamlFromURLToFile(sampleYamlUrl, 0)
const fileContents = fs.readFileSync(tempFile).toString() const fileContents = fs.readFileSync(tempFile).toString()
const inputObjects: K8sObject[] = yaml.loadAll( const inputObjects = yaml.safeLoadAll(fileContents)
fileContents
) as K8sObject[]
expect(inputObjects).toHaveLength(1) expect(inputObjects).toHaveLength(1)
for (const obj of inputObjects) { for (const obj of inputObjects) {
+2 -2
View File
@@ -1,4 +1,4 @@
import fs from 'node:fs' import * as fs from 'fs'
import * as https from 'https' import * as https from 'https'
import * as path from 'path' import * as path from 'path'
import * as core from '@actions/core' import * as core from '@actions/core'
@@ -183,7 +183,7 @@ function verifyYaml(filepath: string, url: string): Errorable<K8sObject[]> {
const fileContents = fs.readFileSync(filepath).toString() const fileContents = fs.readFileSync(filepath).toString()
let inputObjects let inputObjects
try { try {
inputObjects = yaml.loadAll(fileContents) inputObjects = yaml.safeLoadAll(fileContents)
} catch (e) { } catch (e) {
return { return {
succeeded: false, succeeded: false,
@@ -1,52 +0,0 @@
import * as manifestStabilityUtils from './manifestStabilityUtils'
import {Kubectl} from '../types/kubectl'
import {ResourceTypeFleet, ResourceTypeManagedCluster} from '../actions/deploy'
import {ExecOutput} from '@actions/exec'
import {exitCode, stdout} from 'process'
describe('manifestStabilityUtils', () => {
const kc = new Kubectl('')
const resources = [
{
type: 'deployment',
name: 'test',
namespace: 'default'
}
]
it('should return immediately if the resource type is fleet', async () => {
const spy = jest.spyOn(manifestStabilityUtils, 'checkManifestStability')
const checkRolloutStatusSpy = jest.spyOn(kc, 'checkRolloutStatus')
await manifestStabilityUtils.checkManifestStability(
kc,
resources,
ResourceTypeFleet
)
expect(checkRolloutStatusSpy).not.toHaveBeenCalled()
expect(spy).toHaveReturned()
})
it('should run fully if the resource type is managedCluster', async () => {
const spy = jest.spyOn(manifestStabilityUtils, 'checkManifestStability')
const checkRolloutStatusSpy = jest
.spyOn(kc, 'checkRolloutStatus')
.mockImplementation(() => {
return new Promise<ExecOutput>((resolve, reject) => {
resolve({
exitCode: 0,
stderr: '',
stdout: ''
})
})
})
await manifestStabilityUtils.checkManifestStability(
kc,
resources,
ResourceTypeManagedCluster
)
expect(checkRolloutStatusSpy).toHaveBeenCalled()
expect(spy).toHaveReturned()
})
})
+1 -8
View File
@@ -3,21 +3,14 @@ import * as KubernetesConstants from '../types/kubernetesTypes'
import {Kubectl, Resource} from '../types/kubectl' import {Kubectl, Resource} from '../types/kubectl'
import {checkForErrors} from './kubectlUtils' import {checkForErrors} from './kubectlUtils'
import {sleep} from './timeUtils' import {sleep} from './timeUtils'
import {ClusterType, ResourceTypeFleet} from '../actions/deploy'
const IS_SILENT = false const IS_SILENT = false
const POD = 'pod' const POD = 'pod'
export async function checkManifestStability( export async function checkManifestStability(
kubectl: Kubectl, kubectl: Kubectl,
resources: Resource[], resources: Resource[]
clusterTyper: ClusterType
): Promise<void> { ): Promise<void> {
// Skip if resource type is microsoft.containerservice/fleets
if (clusterTyper === ResourceTypeFleet) {
core.info(`Skipping checkManifestStability for ${ResourceTypeFleet}`)
return
}
let rolloutStatusHasErrors = false let rolloutStatusHasErrors = false
for (let i = 0; i < resources.length; i++) { for (let i = 0; i < resources.length; i++) {
const resource = resources[i] const resource = resources[i]
+2 -16
View File
@@ -20,7 +20,6 @@ import {
setImagePullSecrets setImagePullSecrets
} from './manifestPullSecretUtils' } from './manifestPullSecretUtils'
import {Resource} from '../types/kubectl' import {Resource} from '../types/kubectl'
import {K8sObject} from '../types/k8sObject'
export function updateManifestFiles(manifestFilePaths: string[]) { export function updateManifestFiles(manifestFilePaths: string[]) {
if (manifestFilePaths?.length === 0) { if (manifestFilePaths?.length === 0) {
@@ -275,12 +274,8 @@ export function getResources(
const resources: Resource[] = [] const resources: Resource[] = []
filePaths.forEach((filePath: string) => { filePaths.forEach((filePath: string) => {
try {
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
const inputObjects: K8sObject[] = yaml.loadAll( yaml.safeLoadAll(fileContents, (inputObject) => {
fileContents
) as K8sObject[]
inputObjects.forEach((inputObject) => {
const inputObjectKind = inputObject?.kind || '' const inputObjectKind = inputObject?.kind || ''
if ( if (
filterResourceTypes.filter( filterResourceTypes.filter(
@@ -294,10 +289,6 @@ export function getResources(
}) })
} }
}) })
} catch (error) {
core.error(`Failed to process file at ${filePath}: ${error.message}`)
throw error
}
}) })
return resources return resources
@@ -311,9 +302,8 @@ function updateImagePullSecretsInManifestFiles(
const newObjectsList = [] const newObjectsList = []
filePaths.forEach((filePath: string) => { filePaths.forEach((filePath: string) => {
try {
const fileContents = fs.readFileSync(filePath).toString() const fileContents = fs.readFileSync(filePath).toString()
yaml.loadAll(fileContents, (inputObject: any) => { yaml.safeLoadAll(fileContents, (inputObject: any) => {
if (inputObject?.kind) { if (inputObject?.kind) {
const {kind} = inputObject const {kind} = inputObject
if (isWorkloadEntity(kind)) { if (isWorkloadEntity(kind)) {
@@ -322,10 +312,6 @@ function updateImagePullSecretsInManifestFiles(
newObjectsList.push(inputObject) newObjectsList.push(inputObject)
} }
}) })
} catch (error) {
core.error(`Failed to process file at ${filePath}: ${error.message}`)
throw error
}
}) })
return fileHelper.writeObjectsToFile(newObjectsList) return fileHelper.writeObjectsToFile(newObjectsList)
+1 -2
View File
@@ -1,8 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES6", "target": "ES6",
"module": "commonjs", "module": "commonjs"
"esModuleInterop": true
}, },
"exclude": ["node_modules", "test", "src/**/*.test.ts"] "exclude": ["node_modules", "test", "src/**/*.test.ts"]
} }