mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-04-21 15:07:34 +08:00
* Bump the actions group across 1 directory with 14 updates Bumps the actions group with 14 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) | `1.10.0` | `1.10.1` | | [@actions/io](https://github.com/actions/toolkit/tree/HEAD/packages/io) | `1.1.2` | `1.1.3` | | [@actions/tool-cache](https://github.com/actions/toolkit/tree/HEAD/packages/tool-cache) | `1.1.2` | `2.0.1` | | [@octokit/core](https://github.com/octokit/core.js) | `3.6.0` | `6.1.2` | | [@octokit/plugin-retry](https://github.com/octokit/plugin-retry.js) | `3.0.9` | `7.1.2` | | [@types/minipass](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/minipass) | `3.1.2` | `3.3.5` | | [js-yaml](https://github.com/nodeca/js-yaml) | `3.13.1` | `4.1.0` | | [@types/js-yaml](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/js-yaml) | `3.12.7` | `4.0.9` | | [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) | `26.0.24` | `29.5.13` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `12.20.55` | `22.7.4` | | [@vercel/ncc](https://github.com/vercel/ncc) | `0.36.1` | `0.38.2` | | [prettier](https://github.com/prettier/prettier) | `2.8.8` | `3.3.3` | | [ts-jest](https://github.com/kulshekhar/ts-jest) | `29.2.3` | `29.2.5` | | [typescript](https://github.com/microsoft/TypeScript) | `5.5.4` | `5.6.2` | Updates `@actions/core` from 1.10.0 to 1.10.1 - [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md) - [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core) Updates `@actions/io` from 1.1.2 to 1.1.3 - [Changelog](https://github.com/actions/toolkit/blob/main/packages/io/RELEASES.md) - [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/io) Updates `@actions/tool-cache` from 1.1.2 to 2.0.1 - [Changelog](https://github.com/actions/toolkit/blob/main/packages/tool-cache/RELEASES.md) - [Commits](https://github.com/actions/toolkit/commits/@actions/artifact@2.0.1/packages/tool-cache) Updates `@octokit/core` from 3.6.0 to 6.1.2 - [Release notes](https://github.com/octokit/core.js/releases) - [Commits](https://github.com/octokit/core.js/compare/v3.6.0...v6.1.2) Updates `@octokit/plugin-retry` from 3.0.9 to 7.1.2 - [Release notes](https://github.com/octokit/plugin-retry.js/releases) - [Commits](https://github.com/octokit/plugin-retry.js/compare/v3.0.9...v7.1.2) Updates `@types/minipass` from 3.1.2 to 3.3.5 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/minipass) Updates `js-yaml` from 3.13.1 to 4.1.0 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/3.13.1...4.1.0) Updates `@types/js-yaml` from 3.12.7 to 4.0.9 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/js-yaml) Updates `@types/jest` from 26.0.24 to 29.5.13 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest) Updates `@types/js-yaml` from 3.12.7 to 4.0.9 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/js-yaml) Updates `@types/node` from 12.20.55 to 22.7.4 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@vercel/ncc` from 0.36.1 to 0.38.2 - [Release notes](https://github.com/vercel/ncc/releases) - [Commits](https://github.com/vercel/ncc/compare/0.36.1...0.38.2) Updates `prettier` from 2.8.8 to 3.3.3 - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/2.8.8...3.3.3) Updates `ts-jest` from 29.2.3 to 29.2.5 - [Release notes](https://github.com/kulshekhar/ts-jest/releases) - [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md) - [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.2.3...v29.2.5) Updates `typescript` from 5.5.4 to 5.6.2 - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml) - [Commits](https://github.com/microsoft/TypeScript/compare/v5.5.4...v5.6.2) --- updated-dependencies: - dependency-name: "@actions/core" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: "@actions/io" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: "@actions/tool-cache" dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: "@octokit/core" dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: "@octokit/plugin-retry" dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: "@types/minipass" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: js-yaml dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: "@types/js-yaml" dependency-type: direct:development update-type: version-update:semver-major dependency-group: actions - dependency-name: "@types/jest" dependency-type: direct:development update-type: version-update:semver-major dependency-group: actions - dependency-name: "@types/js-yaml" dependency-type: direct:development update-type: version-update:semver-major dependency-group: actions - dependency-name: "@types/node" dependency-type: direct:development update-type: version-update:semver-major dependency-group: actions - dependency-name: "@vercel/ncc" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: actions - dependency-name: prettier dependency-type: direct:development update-type: version-update:semver-major dependency-group: actions - dependency-name: ts-jest dependency-type: direct:development update-type: version-update:semver-patch dependency-group: actions - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-minor dependency-group: actions ... Signed-off-by: dependabot[bot] <support@github.com> * code changes to use yaml.loadAll and upgrade of octokit version * few code changes to handle errors * apply prettier formatting * downgrade prettier version since actionsx/prettier@v3 doesn't support the latest version * adding try catch to handle yaml loading * addressing comments * updating assertions for name * apply prettier code --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Vidya Reddy <59590642+Vidya2606@users.noreply.github.com>
277 lines
8.2 KiB
TypeScript
277 lines
8.2 KiB
TypeScript
import * as core from '@actions/core'
|
|
import * as fs from 'fs'
|
|
import * as yaml from 'js-yaml'
|
|
|
|
import {DeployResult} from '../../types/deployResult'
|
|
import {K8sObject, K8sDeleteObject} from '../../types/k8sObject'
|
|
import {Kubectl} from '../../types/kubectl'
|
|
import {
|
|
isDeploymentEntity,
|
|
isIngressEntity,
|
|
isServiceEntity,
|
|
KubernetesWorkload
|
|
} from '../../types/kubernetesTypes'
|
|
import {
|
|
BlueGreenDeployment,
|
|
BlueGreenManifests
|
|
} from '../../types/blueGreenTypes'
|
|
import * as fileHelper from '../../utilities/fileUtils'
|
|
import {updateSpecLabels} from '../../utilities/manifestSpecLabelUtils'
|
|
import {checkForErrors} from '../../utilities/kubectlUtils'
|
|
import {
|
|
UnsetClusterSpecificDetails,
|
|
updateObjectLabels,
|
|
updateSelectorLabels
|
|
} from '../../utilities/manifestUpdateUtils'
|
|
|
|
export const GREEN_LABEL_VALUE = 'green'
|
|
export const NONE_LABEL_VALUE = 'None'
|
|
export const BLUE_GREEN_VERSION_LABEL = 'k8s.deploy.color'
|
|
export const GREEN_SUFFIX = '-green'
|
|
export const STABLE_SUFFIX = '-stable'
|
|
|
|
export async function deleteGreenObjects(
|
|
kubectl: Kubectl,
|
|
toDelete: K8sObject[]
|
|
): Promise<K8sDeleteObject[]> {
|
|
// const resourcesToDelete: K8sDeleteObject[] = []
|
|
const resourcesToDelete: K8sDeleteObject[] = toDelete.map((obj) => {
|
|
return {
|
|
name: getBlueGreenResourceName(obj.metadata.name, GREEN_SUFFIX),
|
|
kind: obj.kind,
|
|
namespace: obj.metadata.namespace
|
|
}
|
|
})
|
|
|
|
core.debug(`deleting green objects: ${JSON.stringify(resourcesToDelete)}`)
|
|
|
|
await deleteObjects(kubectl, resourcesToDelete)
|
|
return resourcesToDelete
|
|
}
|
|
|
|
export async function deleteObjects(
|
|
kubectl: Kubectl,
|
|
deleteList: K8sDeleteObject[]
|
|
) {
|
|
// delete services and deployments
|
|
for (const delObject of deleteList) {
|
|
try {
|
|
const result = await kubectl.delete([delObject.kind, delObject.name])
|
|
checkForErrors([result])
|
|
} catch (ex) {
|
|
core.debug(`failed to delete object ${delObject.name}: ${ex}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
// other common functions
|
|
export function getManifestObjects(filePaths: string[]): BlueGreenManifests {
|
|
const deploymentEntityList: K8sObject[] = []
|
|
const serviceEntityList: K8sObject[] = []
|
|
const routedServiceEntityList: K8sObject[] = []
|
|
const unroutedServiceEntityList: K8sObject[] = []
|
|
const ingressEntityList: K8sObject[] = []
|
|
const otherEntitiesList: K8sObject[] = []
|
|
const serviceNameMap = new Map<string, string>()
|
|
|
|
// Manifest objects per type. All resources should be parsed and
|
|
// organized before we can check if services are “routed” or not.
|
|
filePaths.forEach((filePath: string) => {
|
|
try {
|
|
const fileContents = fs.readFileSync(filePath).toString()
|
|
yaml.loadAll(fileContents, (inputObject: any) => {
|
|
if (!!inputObject) {
|
|
const kind = inputObject.kind
|
|
if (isDeploymentEntity(kind)) {
|
|
deploymentEntityList.push(inputObject)
|
|
} else if (isServiceEntity(kind)) {
|
|
serviceEntityList.push(inputObject)
|
|
} else if (isIngressEntity(kind)) {
|
|
ingressEntityList.push(inputObject)
|
|
} else {
|
|
otherEntitiesList.push(inputObject)
|
|
}
|
|
}
|
|
})
|
|
} catch (error) {
|
|
core.error(`Error processing file ${filePath}: ${error.message}`)
|
|
throw error
|
|
}
|
|
})
|
|
|
|
serviceEntityList.forEach((inputObject: any) => {
|
|
if (isServiceRouted(inputObject, deploymentEntityList)) {
|
|
const name = inputObject.metadata.name
|
|
routedServiceEntityList.push(inputObject)
|
|
serviceNameMap.set(name, getBlueGreenResourceName(name, GREEN_SUFFIX))
|
|
} else {
|
|
unroutedServiceEntityList.push(inputObject)
|
|
}
|
|
})
|
|
|
|
return {
|
|
serviceEntityList: routedServiceEntityList,
|
|
serviceNameMap: serviceNameMap,
|
|
unroutedServiceEntityList: unroutedServiceEntityList,
|
|
deploymentEntityList: deploymentEntityList,
|
|
ingressEntityList: ingressEntityList,
|
|
otherObjects: otherEntitiesList
|
|
}
|
|
}
|
|
|
|
export function isServiceRouted(
|
|
serviceObject: any[],
|
|
deploymentEntityList: any[]
|
|
): boolean {
|
|
const serviceSelector: any = getServiceSelector(serviceObject)
|
|
|
|
return (
|
|
serviceSelector &&
|
|
deploymentEntityList.some((depObject) => {
|
|
// finding if there is a deployment in the given manifests the service targets
|
|
const matchLabels: any = getDeploymentMatchLabels(depObject)
|
|
return (
|
|
matchLabels &&
|
|
isServiceSelectorSubsetOfMatchLabel(serviceSelector, matchLabels)
|
|
)
|
|
})
|
|
)
|
|
}
|
|
|
|
export async function deployWithLabel(
|
|
kubectl: Kubectl,
|
|
deploymentObjectList: any[],
|
|
nextLabel: string
|
|
): Promise<BlueGreenDeployment> {
|
|
const newObjectsList = deploymentObjectList.map((inputObject) =>
|
|
getNewBlueGreenObject(inputObject, nextLabel)
|
|
)
|
|
|
|
core.debug(
|
|
`objects deployed with label are ${JSON.stringify(newObjectsList)}`
|
|
)
|
|
const deployResult = await deployObjects(kubectl, newObjectsList)
|
|
return {deployResult, objects: newObjectsList}
|
|
}
|
|
|
|
export function getNewBlueGreenObject(
|
|
inputObject: any,
|
|
labelValue: string
|
|
): K8sObject {
|
|
const newObject = JSON.parse(JSON.stringify(inputObject))
|
|
|
|
// Updating name only if label is green label is given
|
|
if (labelValue === GREEN_LABEL_VALUE) {
|
|
newObject.metadata.name = getBlueGreenResourceName(
|
|
inputObject.metadata.name,
|
|
GREEN_SUFFIX
|
|
)
|
|
}
|
|
|
|
// Adding labels and annotations
|
|
addBlueGreenLabelsAndAnnotations(newObject, labelValue)
|
|
return newObject
|
|
}
|
|
|
|
export function addBlueGreenLabelsAndAnnotations(
|
|
inputObject: any,
|
|
labelValue: string
|
|
) {
|
|
//creating the k8s.deploy.color label
|
|
const newLabels = new Map<string, string>()
|
|
newLabels[BLUE_GREEN_VERSION_LABEL] = labelValue
|
|
|
|
// updating object labels and selector labels
|
|
updateObjectLabels(inputObject, newLabels, false)
|
|
updateSelectorLabels(inputObject, newLabels, false)
|
|
|
|
// updating spec labels if it is not a service
|
|
if (!isServiceEntity(inputObject.kind)) {
|
|
updateSpecLabels(inputObject, newLabels, false)
|
|
}
|
|
}
|
|
|
|
export function getBlueGreenResourceName(name: string, suffix: string) {
|
|
return `${name}${suffix}`
|
|
}
|
|
|
|
export function getDeploymentMatchLabels(deploymentObject: any): any {
|
|
if (
|
|
deploymentObject?.kind?.toUpperCase() ==
|
|
KubernetesWorkload.POD.toUpperCase() &&
|
|
deploymentObject?.metadata?.labels
|
|
) {
|
|
return deploymentObject.metadata.labels
|
|
} else if (deploymentObject?.spec?.selector?.matchLabels) {
|
|
return deploymentObject.spec.selector.matchLabels
|
|
}
|
|
}
|
|
|
|
export function getServiceSelector(serviceObject: any): any {
|
|
if (serviceObject?.spec?.selector) {
|
|
return serviceObject.spec.selector
|
|
}
|
|
}
|
|
|
|
export function isServiceSelectorSubsetOfMatchLabel(
|
|
serviceSelector: any,
|
|
matchLabels: any
|
|
): boolean {
|
|
const serviceSelectorMap = new Map()
|
|
const matchLabelsMap = new Map()
|
|
|
|
JSON.parse(JSON.stringify(serviceSelector), (key, value) => {
|
|
serviceSelectorMap.set(key, value)
|
|
})
|
|
|
|
JSON.parse(JSON.stringify(matchLabels), (key, value) => {
|
|
matchLabelsMap.set(key, value)
|
|
})
|
|
|
|
let isMatch = true
|
|
serviceSelectorMap.forEach((value, key) => {
|
|
if (
|
|
!!key &&
|
|
(!matchLabelsMap.has(key) || matchLabelsMap.get(key)) != value
|
|
)
|
|
isMatch = false
|
|
})
|
|
|
|
return isMatch
|
|
}
|
|
|
|
export async function fetchResource(
|
|
kubectl: Kubectl,
|
|
kind: string,
|
|
name: string,
|
|
namespace?: string
|
|
): Promise<K8sObject> {
|
|
const result = await kubectl.getResource(kind, name, false, namespace)
|
|
if (result == null || !!result.stderr) {
|
|
return null
|
|
}
|
|
|
|
if (!!result.stdout) {
|
|
const resource = JSON.parse(result.stdout) as K8sObject
|
|
|
|
try {
|
|
UnsetClusterSpecificDetails(resource)
|
|
return resource
|
|
} catch (ex) {
|
|
core.debug(
|
|
`Exception occurred while Parsing ${resource} in Json object: ${ex}`
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function deployObjects(
|
|
kubectl: Kubectl,
|
|
objectsList: any[]
|
|
): Promise<DeployResult> {
|
|
const manifestFiles = fileHelper.writeObjectsToFile(objectsList)
|
|
const execResult = await kubectl.apply(manifestFiles)
|
|
|
|
return {execResult, manifestFiles}
|
|
}
|