mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-06-26 14:49:26 +08:00
v4 new release (#224)
* Add missing API switch for GHES (#200) * Vidya reddy/prettier code (#203) * switch none deployment strategy to basic (#204) * switch none deployment strategy to basic * update readme * update deployment strategy fallthrough logic * comment fixed * add disclaimer for basic strategy only supporting deploy action * Hari/beautify logs (#206) * Logging changes for deploy * Logging Changes with group * format check changes * Add ncc build to build script (#208) Co-authored-by: Vidya Reddy <vidyareddy@microsoft.com> * Logging Changes for Promote, Reject actions (#207) * add clean function (#211) * Added Traffic split annotations (#215) * Added Traffic split annotations * traffic split - blueGreen deployment * traffic split - canary deployment * Traffic split annotations - canary deployment * updated Readme and action.yml * Traffic split - canary deployment * clean code * Clean code * Clean code * Create annotation object * Updated Readme and action.yml * Spelling correction Co-authored-by: Vidya Reddy <vidyareddy@microsoft.com> * Swap annotation key to actions.github.com prefix (#216) * Private Cluster functionality (#214) * Fixed Blue/Green Strategy Ingress Route-Method Glitch (#217) * Added some tests, not sure what else to try but gonna think of more examples * forgot some files * reverted package-lock.json * Added empty dir test * Cleaned up some extra spaces * Add node modules and compiled JavaScript from main * forgot to actually include functionality * removed unnecessary files * Update .gitignore * Update .gitignore * Update .gitignore * thx david * renamed searchFilesRec * integrations test fix * added examples to README * added note about depth * added additional note * removed ticks * changed version string * removed conflict on readme * Added tests for bluegreen helper and resolved issue with ingress not being read correctly, still have to figure out why new services aren't showing up * resolved services name issue * looks functional, beginning refactor now * refactored deploy methods for type error * Removed refactor comments * prettier * implemented Oliver's feedback * prettier * added optional chaining operator * removed refactor comment Co-authored-by: Jaiveer Katariya <jaiveerkatariya@Jaiveers-MacBook-Pro.local> Co-authored-by: Oliver King <oking3@uncc.edu> Co-authored-by: Jaiveer Katariya <jaiveerkatariya@Jaiveers-MBP.lan> * Add node modules and compiled JavaScript from main Co-authored-by: nv35 <76777923+nv35@users.noreply.github.com> Co-authored-by: Vidya <59590642+Vidya2606@users.noreply.github.com> Co-authored-by: David Gamero <david340804@gmail.com> Co-authored-by: Hariharan Subramanian <105889062+hsubramanianaks@users.noreply.github.com> Co-authored-by: Vidya Reddy <vidyareddy@microsoft.com> Co-authored-by: Oliver King <oking3@uncc.edu> Co-authored-by: Marcus-Hines <marcus.chris.hines@gmail.com> Co-authored-by: Jaiveer Katariya <35347859+jaiveerk@users.noreply.github.com> Co-authored-by: Jaiveer Katariya <jaiveerkatariya@Jaiveers-MacBook-Pro.local> Co-authored-by: Jaiveer Katariya <jaiveerkatariya@Jaiveers-MBP.lan>
This commit is contained in:
committed by
GitHub
parent
497ce6351c
commit
4e60e959ea
@@ -0,0 +1,128 @@
|
||||
import {
|
||||
createWorkloadsWithLabel,
|
||||
deleteWorkloadsAndServicesWithLabel,
|
||||
getManifestObjects,
|
||||
getNewBlueGreenObject,
|
||||
GREEN_LABEL_VALUE,
|
||||
isServiceRouted,
|
||||
NONE_LABEL_VALUE
|
||||
} from './blueGreenHelper'
|
||||
import * as bgHelper from './blueGreenHelper'
|
||||
import {Kubectl} from '../../types/kubectl'
|
||||
import * as fileHelper from '../../utilities/fileUtils'
|
||||
|
||||
jest.mock('../../types/kubectl')
|
||||
|
||||
describe('bluegreenhelper functions', () => {
|
||||
let testObjects
|
||||
beforeEach(() => {
|
||||
//@ts-ignore
|
||||
Kubectl.mockClear()
|
||||
testObjects = getManifestObjects(['test/unit/manifests/test-ingress.yml'])
|
||||
|
||||
jest
|
||||
.spyOn(fileHelper, 'writeObjectsToFile')
|
||||
.mockImplementationOnce(() => [''])
|
||||
})
|
||||
|
||||
test('it should parse objects correctly from one file', () => {
|
||||
expect(testObjects.deploymentEntityList[0].kind).toBe('Deployment')
|
||||
expect(testObjects.serviceEntityList[0].kind).toBe('Service')
|
||||
expect(testObjects.ingressEntityList[0].kind).toBe('Ingress')
|
||||
|
||||
expect(
|
||||
testObjects.deploymentEntityList[0].spec.selector.matchLabels.app
|
||||
).toBe('nginx')
|
||||
})
|
||||
|
||||
test('correctly makes new blue green object', () => {
|
||||
const modifiedDeployment = getNewBlueGreenObject(
|
||||
testObjects.deploymentEntityList[0],
|
||||
GREEN_LABEL_VALUE
|
||||
)
|
||||
//@ts-ignore
|
||||
expect(modifiedDeployment.metadata.name).toBe('nginx-deployment-green')
|
||||
//@ts-ignore
|
||||
expect(modifiedDeployment.metadata.labels['k8s.deploy.color']).toBe(
|
||||
'green'
|
||||
)
|
||||
|
||||
const modifiedSvc = getNewBlueGreenObject(
|
||||
testObjects.serviceEntityList[0],
|
||||
GREEN_LABEL_VALUE
|
||||
)
|
||||
//@ts-ignore
|
||||
expect(modifiedSvc.metadata.name).toBe('nginx-service-green')
|
||||
//@ts-ignore
|
||||
expect(modifiedSvc.metadata.labels['k8s.deploy.color']).toBe('green')
|
||||
})
|
||||
|
||||
test('correctly makes labeled workloads', () => {
|
||||
const kubectl = new Kubectl('')
|
||||
expect(Kubectl).toBeCalledTimes(1)
|
||||
const cwlResult = createWorkloadsWithLabel(
|
||||
kubectl,
|
||||
testObjects.deploymentEntityList,
|
||||
GREEN_LABEL_VALUE
|
||||
)
|
||||
cwlResult.then((value) => {
|
||||
//@ts-ignore
|
||||
expect(value.newFilePaths[0]).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
test('correctly classifies routed services', () => {
|
||||
expect(
|
||||
isServiceRouted(
|
||||
testObjects.serviceEntityList[0],
|
||||
testObjects.deploymentEntityList
|
||||
)
|
||||
).toBe(true)
|
||||
testObjects.serviceEntityList[0].spec.selector.app = 'fakeapp'
|
||||
expect(
|
||||
isServiceRouted(
|
||||
testObjects.serviceEntityList[0],
|
||||
testObjects.deploymentEntityList
|
||||
)
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
test('correctly deletes services and workloads according to label', () => {
|
||||
const kubectl = new Kubectl('')
|
||||
jest.spyOn(bgHelper, 'deleteObjects').mockReturnValue({} as Promise<void>)
|
||||
|
||||
let objectsToDelete = deleteWorkloadsAndServicesWithLabel(
|
||||
kubectl,
|
||||
NONE_LABEL_VALUE,
|
||||
testObjects.deploymentEntityList,
|
||||
testObjects.serviceEntityList
|
||||
)
|
||||
objectsToDelete.then((value) => {
|
||||
expect(value).toHaveLength(2)
|
||||
expect(value).toContainEqual
|
||||
;({name: 'nginx-service', kind: 'Service'})
|
||||
expect(value).toContainEqual({
|
||||
name: 'nginx-deployment',
|
||||
kind: 'Deployment'
|
||||
})
|
||||
})
|
||||
|
||||
objectsToDelete = deleteWorkloadsAndServicesWithLabel(
|
||||
kubectl,
|
||||
GREEN_LABEL_VALUE,
|
||||
testObjects.deploymentEntityList,
|
||||
testObjects.serviceEntityList
|
||||
)
|
||||
objectsToDelete.then((value) => {
|
||||
expect(value).toHaveLength(2)
|
||||
expect(value).toContainEqual({
|
||||
name: 'nginx-service-green',
|
||||
kind: 'Service'
|
||||
})
|
||||
expect(value).toContainEqual({
|
||||
name: 'nginx-deployment-green',
|
||||
kind: 'Deployment'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -40,7 +40,8 @@ export interface BlueGreenManifests {
|
||||
export async function routeBlueGreen(
|
||||
kubectl: Kubectl,
|
||||
inputManifestFiles: string[],
|
||||
routeStrategy: RouteStrategy
|
||||
routeStrategy: RouteStrategy,
|
||||
annotations: {[key: string]: string} = {}
|
||||
) {
|
||||
// sleep for buffer time
|
||||
const bufferTime: number = parseInt(
|
||||
@@ -74,7 +75,8 @@ export async function routeBlueGreen(
|
||||
await routeBlueGreenSMI(
|
||||
kubectl,
|
||||
GREEN_LABEL_VALUE,
|
||||
manifestObjects.serviceEntityList
|
||||
manifestObjects.serviceEntityList,
|
||||
annotations
|
||||
)
|
||||
} else {
|
||||
await routeBlueGreenService(
|
||||
@@ -110,6 +112,7 @@ export async function deleteWorkloadsWithLabel(
|
||||
})
|
||||
|
||||
await deleteObjects(kubectl, resourcesToDelete)
|
||||
return resourcesToDelete
|
||||
}
|
||||
|
||||
export async function deleteWorkloadsAndServicesWithLabel(
|
||||
@@ -141,6 +144,7 @@ export async function deleteWorkloadsAndServicesWithLabel(
|
||||
})
|
||||
|
||||
await deleteObjects(kubectl, resourcesToDelete)
|
||||
return resourcesToDelete
|
||||
}
|
||||
|
||||
export async function deleteObjects(kubectl: Kubectl, deleteList: any[]) {
|
||||
@@ -235,9 +239,6 @@ export async function createWorkloadsWithLabel(
|
||||
deploymentObjectList.forEach((inputObject) => {
|
||||
// creating deployment with label
|
||||
const newBlueGreenObject = getNewBlueGreenObject(inputObject, nextLabel)
|
||||
core.debug(
|
||||
'New blue-green object is: ' + JSON.stringify(newBlueGreenObject)
|
||||
)
|
||||
newObjectsList.push(newBlueGreenObject)
|
||||
})
|
||||
|
||||
@@ -278,7 +279,7 @@ export function addBlueGreenLabelsAndAnnotations(
|
||||
updateObjectLabels(inputObject, newLabels, false)
|
||||
updateSelectorLabels(inputObject, newLabels, false)
|
||||
|
||||
// updating spec labels if it is a service
|
||||
// updating spec labels if it is not a service
|
||||
if (!isServiceEntity(inputObject.kind)) {
|
||||
updateSpecLabels(inputObject, newLabels, false)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import {getManifestObjects, GREEN_LABEL_VALUE} from './blueGreenHelper'
|
||||
import {
|
||||
deployBlueGreenIngress,
|
||||
getUpdatedBlueGreenIngress,
|
||||
isIngressRouted,
|
||||
routeBlueGreenIngress
|
||||
} from './ingressBlueGreenHelper'
|
||||
import {Kubectl} from '../../types/kubectl'
|
||||
import * as fileHelper from '../../utilities/fileUtils'
|
||||
|
||||
jest.mock('../../types/kubectl')
|
||||
|
||||
describe('ingress blue green helpers', () => {
|
||||
let testObjects
|
||||
const betaFilepath = ['test/unit/manifests/test-ingress.yml']
|
||||
const ingressFilepath = ['test/unit/manifests/test-ingress-new.yml']
|
||||
|
||||
beforeEach(() => {
|
||||
//@ts-ignore
|
||||
Kubectl.mockClear()
|
||||
testObjects = getManifestObjects(ingressFilepath)
|
||||
jest
|
||||
.spyOn(fileHelper, 'writeObjectsToFile')
|
||||
.mockImplementationOnce(() => [''])
|
||||
})
|
||||
|
||||
test('it should correctly classify ingresses', () => {
|
||||
expect(
|
||||
isIngressRouted(
|
||||
testObjects.ingressEntityList[0],
|
||||
testObjects.serviceNameMap
|
||||
)
|
||||
).toBe(true)
|
||||
testObjects.ingressEntityList[0].spec.rules[0].http.paths = {}
|
||||
expect(
|
||||
isIngressRouted(
|
||||
testObjects.ingressEntityList[0],
|
||||
testObjects.serviceNameMap
|
||||
)
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
isIngressRouted(
|
||||
getManifestObjects(betaFilepath).ingressEntityList[0],
|
||||
testObjects.serviceNameMap
|
||||
)
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
test('it should correctly update ingresses', () => {
|
||||
const updatedIng = getUpdatedBlueGreenIngress(
|
||||
testObjects.ingressEntityList[0],
|
||||
testObjects.serviceNameMap,
|
||||
GREEN_LABEL_VALUE
|
||||
)
|
||||
//@ts-ignore
|
||||
expect(updatedIng.metadata.labels['k8s.deploy.color']).toBe('green')
|
||||
//@ts-ignore
|
||||
expect(updatedIng.spec.rules[0].http.paths[0].backend.service.name).toBe(
|
||||
'nginx-service-green'
|
||||
)
|
||||
})
|
||||
|
||||
test('correctly prepares blue/green ingresses for deployment', () => {
|
||||
const kc = new Kubectl('')
|
||||
const generatedObjects = routeBlueGreenIngress(
|
||||
kc,
|
||||
GREEN_LABEL_VALUE,
|
||||
testObjects.serviceNameMap,
|
||||
testObjects.ingressEntityList
|
||||
)
|
||||
generatedObjects.then((value) => {
|
||||
expect(value).toHaveLength(1)
|
||||
//@ts-ignore
|
||||
expect(value[0].metadata.name).toBe('nginx-ingress')
|
||||
})
|
||||
})
|
||||
test('correctly deploys services', () => {
|
||||
const kc = new Kubectl('')
|
||||
const result = deployBlueGreenIngress(kc, ingressFilepath)
|
||||
|
||||
result.then((value) => {
|
||||
const nol = value.newObjectsList
|
||||
//@ts-ignore
|
||||
expect(nol[0].metadata.name).toBe('nginx-service-green')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from './blueGreenHelper'
|
||||
import * as core from '@actions/core'
|
||||
|
||||
const BACKEND = 'BACKEND'
|
||||
const BACKEND = 'backend'
|
||||
|
||||
export async function deployBlueGreenIngress(
|
||||
kubectl: Kubectl,
|
||||
@@ -24,13 +24,12 @@ export async function deployBlueGreenIngress(
|
||||
const manifestObjects: BlueGreenManifests = getManifestObjects(filePaths)
|
||||
|
||||
// create deployments with green label value
|
||||
const result = createWorkloadsWithLabel(
|
||||
const workloadDeployment = await createWorkloadsWithLabel(
|
||||
kubectl,
|
||||
manifestObjects.deploymentEntityList,
|
||||
GREEN_LABEL_VALUE
|
||||
)
|
||||
|
||||
// create new services and other objects
|
||||
let newObjectsList = []
|
||||
manifestObjects.serviceEntityList.forEach((inputObject) => {
|
||||
const newBlueGreenObject = getNewBlueGreenObject(
|
||||
@@ -46,7 +45,12 @@ export async function deployBlueGreenIngress(
|
||||
const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList)
|
||||
await kubectl.apply(manifestFiles)
|
||||
|
||||
return result
|
||||
core.debug(
|
||||
'new objects after processing services and other objects: \n' +
|
||||
JSON.stringify(newObjectsList)
|
||||
)
|
||||
|
||||
return {workloadDeployment, newObjectsList}
|
||||
}
|
||||
|
||||
export async function promoteBlueGreenIngress(
|
||||
@@ -54,14 +58,13 @@ export async function promoteBlueGreenIngress(
|
||||
manifestObjects
|
||||
) {
|
||||
//checking if anything to promote
|
||||
if (
|
||||
!validateIngressesState(
|
||||
kubectl,
|
||||
manifestObjects.ingressEntityList,
|
||||
manifestObjects.serviceNameMap
|
||||
)
|
||||
) {
|
||||
throw 'Ingress not in promote state'
|
||||
const {areValid, invalidIngresses} = validateIngresses(
|
||||
kubectl,
|
||||
manifestObjects.ingressEntityList,
|
||||
manifestObjects.serviceNameMap
|
||||
)
|
||||
if (!areValid) {
|
||||
throw 'Ingresses are not in promote state' + invalidIngresses.toString()
|
||||
}
|
||||
|
||||
// create stable deployments with new configuration
|
||||
@@ -138,17 +141,18 @@ export async function routeBlueGreenIngress(
|
||||
})
|
||||
}
|
||||
|
||||
core.debug('New objects: ' + JSON.stringify(newObjectsList))
|
||||
const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList)
|
||||
await kubectl.apply(manifestFiles)
|
||||
return newObjectsList
|
||||
}
|
||||
|
||||
export function validateIngressesState(
|
||||
export function validateIngresses(
|
||||
kubectl: Kubectl,
|
||||
ingressEntityList: any[],
|
||||
serviceNameMap: Map<string, string>
|
||||
): boolean {
|
||||
let areIngressesTargetingNewServices: boolean = true
|
||||
): {areValid: boolean; invalidIngresses: string[]} {
|
||||
let areValid: boolean = true
|
||||
const invalidIngresses = []
|
||||
ingressEntityList.forEach(async (inputObject) => {
|
||||
if (isIngressRouted(inputObject, serviceNameMap)) {
|
||||
//querying existing ingress
|
||||
@@ -158,33 +162,32 @@ export function validateIngressesState(
|
||||
inputObject.metadata.name
|
||||
)
|
||||
|
||||
if (!!existingIngress) {
|
||||
const currentLabel: string =
|
||||
existingIngress?.metadata?.labels[BLUE_GREEN_VERSION_LABEL]
|
||||
|
||||
// if not green label, then wrong configuration
|
||||
if (currentLabel != GREEN_LABEL_VALUE)
|
||||
areIngressesTargetingNewServices = false
|
||||
} else {
|
||||
// no ingress at all, so nothing to promote
|
||||
areIngressesTargetingNewServices = false
|
||||
let isValid =
|
||||
!!existingIngress &&
|
||||
existingIngress?.metadata?.labels[BLUE_GREEN_VERSION_LABEL] ===
|
||||
GREEN_LABEL_VALUE
|
||||
if (!isValid) {
|
||||
invalidIngresses.push(inputObject.metadata.name)
|
||||
}
|
||||
// to be valid, ingress should exist and should be green
|
||||
areValid = areValid && isValid
|
||||
}
|
||||
})
|
||||
|
||||
return areIngressesTargetingNewServices
|
||||
return {areValid, invalidIngresses}
|
||||
}
|
||||
|
||||
function isIngressRouted(
|
||||
export function isIngressRouted(
|
||||
ingressObject: any,
|
||||
serviceNameMap: Map<string, string>
|
||||
): boolean {
|
||||
let isIngressRouted: boolean = false
|
||||
// check if ingress targets a service in the given manifests
|
||||
JSON.parse(JSON.stringify(ingressObject), (key, value) => {
|
||||
if (key === 'serviceName' && serviceNameMap.has(value)) {
|
||||
isIngressRouted = true
|
||||
}
|
||||
isIngressRouted =
|
||||
isIngressRouted || (key === 'service' && value.hasOwnProperty('name'))
|
||||
isIngressRouted =
|
||||
isIngressRouted || (key === 'serviceName' && serviceNameMap.has(value))
|
||||
|
||||
return value
|
||||
})
|
||||
@@ -206,15 +209,18 @@ export function getUpdatedBlueGreenIngress(
|
||||
addBlueGreenLabelsAndAnnotations(newObject, type)
|
||||
|
||||
// update ingress labels
|
||||
if (inputObject.apiVersion === 'networking.k8s.io/v1beta1') {
|
||||
return updateIngressBackendBetaV1(newObject, serviceNameMap)
|
||||
}
|
||||
return updateIngressBackend(newObject, serviceNameMap)
|
||||
}
|
||||
|
||||
export function updateIngressBackend(
|
||||
export function updateIngressBackendBetaV1(
|
||||
inputObject: any,
|
||||
serviceNameMap: Map<string, string>
|
||||
): any {
|
||||
inputObject = JSON.parse(JSON.stringify(inputObject), (key, value) => {
|
||||
if (key.toUpperCase() === BACKEND) {
|
||||
if (key.toLowerCase() === BACKEND) {
|
||||
const {serviceName} = value
|
||||
if (serviceNameMap.has(serviceName)) {
|
||||
// update service name with corresponding bluegreen name only if service is provied in given manifests
|
||||
@@ -227,3 +233,20 @@ export function updateIngressBackend(
|
||||
|
||||
return inputObject
|
||||
}
|
||||
|
||||
export function updateIngressBackend(
|
||||
inputObject: any,
|
||||
serviceNameMap: Map<string, string>
|
||||
): any {
|
||||
inputObject = JSON.parse(JSON.stringify(inputObject), (key, value) => {
|
||||
if (
|
||||
key.toLowerCase() === BACKEND &&
|
||||
serviceNameMap.has(value?.service?.name)
|
||||
) {
|
||||
value.service.name = serviceNameMap.get(value.service.name)
|
||||
}
|
||||
return value
|
||||
})
|
||||
|
||||
return inputObject
|
||||
}
|
||||
|
||||
@@ -19,21 +19,21 @@ export async function deployBlueGreenService(
|
||||
const manifestObjects: BlueGreenManifests = getManifestObjects(filePaths)
|
||||
|
||||
// create deployments with green label value
|
||||
const result = await createWorkloadsWithLabel(
|
||||
const workloadDeployment = await createWorkloadsWithLabel(
|
||||
kubectl,
|
||||
manifestObjects.deploymentEntityList,
|
||||
GREEN_LABEL_VALUE
|
||||
)
|
||||
|
||||
// create other non deployment and non service entities
|
||||
const newObjectsList = manifestObjects.otherObjects
|
||||
.concat(manifestObjects.ingressEntityList)
|
||||
.concat(manifestObjects.unroutedServiceEntityList)
|
||||
const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList)
|
||||
|
||||
if (manifestFiles.length > 0) await kubectl.apply(manifestFiles)
|
||||
|
||||
// returning deployment details to check for rollout stability
|
||||
return result
|
||||
return {workloadDeployment, newObjectsList}
|
||||
}
|
||||
|
||||
export async function promoteBlueGreenService(
|
||||
@@ -76,7 +76,6 @@ export async function rejectBlueGreenService(
|
||||
manifestObjects.deploymentEntityList
|
||||
)
|
||||
}
|
||||
|
||||
export async function routeBlueGreenService(
|
||||
kubectl: Kubectl,
|
||||
nextLabel: string,
|
||||
|
||||
@@ -23,7 +23,8 @@ const MAX_VAL = 100
|
||||
|
||||
export async function deployBlueGreenSMI(
|
||||
kubectl: Kubectl,
|
||||
filePaths: string[]
|
||||
filePaths: string[],
|
||||
annotations: {[key: string]: string} = {}
|
||||
) {
|
||||
// get all kubernetes objects defined in manifest files
|
||||
const manifestObjects: BlueGreenManifests = getManifestObjects(filePaths)
|
||||
@@ -37,14 +38,16 @@ export async function deployBlueGreenSMI(
|
||||
await kubectl.apply(manifestFiles)
|
||||
|
||||
// make extraservices and trafficsplit
|
||||
await setupSMI(kubectl, manifestObjects.serviceEntityList)
|
||||
await setupSMI(kubectl, manifestObjects.serviceEntityList, annotations)
|
||||
|
||||
// create new deloyments
|
||||
return await createWorkloadsWithLabel(
|
||||
const workloadDeployment = await createWorkloadsWithLabel(
|
||||
kubectl,
|
||||
manifestObjects.deploymentEntityList,
|
||||
GREEN_LABEL_VALUE
|
||||
)
|
||||
|
||||
return {workloadDeployment, newObjectsList}
|
||||
}
|
||||
|
||||
export async function promoteBlueGreenSMI(kubectl: Kubectl, manifestObjects) {
|
||||
@@ -68,16 +71,18 @@ export async function promoteBlueGreenSMI(kubectl: Kubectl, manifestObjects) {
|
||||
|
||||
export async function rejectBlueGreenSMI(
|
||||
kubectl: Kubectl,
|
||||
filePaths: string[]
|
||||
filePaths: string[],
|
||||
annotations: {[key: string]: string} = {}
|
||||
) {
|
||||
// get all kubernetes objects defined in manifest files
|
||||
const manifestObjects: BlueGreenManifests = getManifestObjects(filePaths)
|
||||
|
||||
// route trafficsplit to stable deploymetns
|
||||
// route trafficsplit to stable deployments
|
||||
await routeBlueGreenSMI(
|
||||
kubectl,
|
||||
NONE_LABEL_VALUE,
|
||||
manifestObjects.serviceEntityList
|
||||
manifestObjects.serviceEntityList,
|
||||
annotations
|
||||
)
|
||||
|
||||
// delete rejected new bluegreen deployments
|
||||
@@ -91,7 +96,11 @@ export async function rejectBlueGreenSMI(
|
||||
await cleanupSMI(kubectl, manifestObjects.serviceEntityList)
|
||||
}
|
||||
|
||||
export async function setupSMI(kubectl: Kubectl, serviceEntityList: any[]) {
|
||||
export async function setupSMI(
|
||||
kubectl: Kubectl,
|
||||
serviceEntityList: any[],
|
||||
annotations: {[key: string]: string} = {}
|
||||
) {
|
||||
const newObjectsList = []
|
||||
const trafficObjectList = []
|
||||
|
||||
@@ -117,7 +126,8 @@ export async function setupSMI(kubectl: Kubectl, serviceEntityList: any[]) {
|
||||
createTrafficSplitObject(
|
||||
kubectl,
|
||||
inputObject.metadata.name,
|
||||
NONE_LABEL_VALUE
|
||||
NONE_LABEL_VALUE,
|
||||
annotations
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -127,7 +137,8 @@ let trafficSplitAPIVersion = ''
|
||||
async function createTrafficSplitObject(
|
||||
kubectl: Kubectl,
|
||||
name: string,
|
||||
nextLabel: string
|
||||
nextLabel: string,
|
||||
annotations: {[key: string]: string} = {}
|
||||
): Promise<any> {
|
||||
// cache traffic split api version
|
||||
if (!trafficSplitAPIVersion)
|
||||
@@ -145,7 +156,8 @@ async function createTrafficSplitObject(
|
||||
apiVersion: trafficSplitAPIVersion,
|
||||
kind: 'TrafficSplit',
|
||||
metadata: {
|
||||
name: getBlueGreenResourceName(name, TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX)
|
||||
name: getBlueGreenResourceName(name, TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX),
|
||||
annotations: annotations
|
||||
},
|
||||
spec: {
|
||||
service: name,
|
||||
@@ -194,14 +206,16 @@ export function getSMIServiceResource(
|
||||
export async function routeBlueGreenSMI(
|
||||
kubectl: Kubectl,
|
||||
nextLabel: string,
|
||||
serviceEntityList: any[]
|
||||
serviceEntityList: any[],
|
||||
annotations: {[key: string]: string} = {}
|
||||
) {
|
||||
for (const serviceObject of serviceEntityList) {
|
||||
// route trafficsplit to given label
|
||||
await createTrafficSplitObject(
|
||||
kubectl,
|
||||
serviceObject.metadata.name,
|
||||
nextLabel
|
||||
nextLabel,
|
||||
annotations
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +288,8 @@ async function getTrafficSplitObject(
|
||||
name: string,
|
||||
stableWeight: number,
|
||||
baselineWeight: number,
|
||||
canaryWeight: number
|
||||
canaryWeight: number,
|
||||
annotations: {[key: string]: string} = {}
|
||||
): Promise<string> {
|
||||
// cached version
|
||||
if (!trafficSplitAPIVersion) {
|
||||
@@ -301,7 +302,8 @@ async function getTrafficSplitObject(
|
||||
apiVersion: trafficSplitAPIVersion,
|
||||
kind: 'TrafficSplit',
|
||||
metadata: {
|
||||
name: getTrafficSplitResourceName(name)
|
||||
name: getTrafficSplitResourceName(name),
|
||||
annotations: annotations
|
||||
},
|
||||
spec: {
|
||||
backends: [
|
||||
|
||||
@@ -41,7 +41,8 @@ export async function deployManifests(
|
||||
files: string[],
|
||||
deploymentStrategy: DeploymentStrategy,
|
||||
kubectl: Kubectl,
|
||||
trafficSplitMethod: TrafficSplitMethod
|
||||
trafficSplitMethod: TrafficSplitMethod,
|
||||
annotations: {[key: string]: string} = {}
|
||||
): Promise<string[]> {
|
||||
switch (deploymentStrategy) {
|
||||
case DeploymentStrategy.CANARY: {
|
||||
@@ -59,16 +60,16 @@ export async function deployManifests(
|
||||
core.getInput('route-method', {required: true})
|
||||
)
|
||||
|
||||
const {result, newFilePaths} = await Promise.resolve(
|
||||
const {workloadDeployment, newObjectsList} = await Promise.resolve(
|
||||
(routeStrategy == RouteStrategy.INGRESS &&
|
||||
deployBlueGreenIngress(kubectl, files)) ||
|
||||
(routeStrategy == RouteStrategy.SMI &&
|
||||
deployBlueGreenSMI(kubectl, files)) ||
|
||||
deployBlueGreenSMI(kubectl, files, annotations)) ||
|
||||
deployBlueGreenService(kubectl, files)
|
||||
)
|
||||
|
||||
checkForErrors([result])
|
||||
return newFilePaths
|
||||
checkForErrors([workloadDeployment.result])
|
||||
return workloadDeployment.newFilePaths
|
||||
}
|
||||
|
||||
case DeploymentStrategy.BASIC: {
|
||||
@@ -142,7 +143,7 @@ export async function annotateAndLabelResources(
|
||||
const workflowFilePath = await getWorkflowFilePath(githubToken)
|
||||
|
||||
const deploymentConfig = await getDeploymentConfig()
|
||||
const annotationKeyLabel = getWorkflowAnnotationKeyLabel(workflowFilePath)
|
||||
const annotationKeyLabel = getWorkflowAnnotationKeyLabel()
|
||||
|
||||
await annotateResources(
|
||||
files,
|
||||
|
||||
Reference in New Issue
Block a user