mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-06-26 14:49:26 +08:00
v4 new release (#261)
* 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> * Blue/Green Refactor (#229) * fresh new branch * Added coverage to gitignore Signed-off-by: Jaiveer Katariya <jaiveerkatariya@Jaiveers-MBP.lan> * reverted package-lock.json Signed-off-by: Jaiveer Katariya <jaiveerkatariya@Jaiveers-MBP.lan> Co-authored-by: Jaiveer Katariya <jaiveerkatariya@Jaiveers-MBP.lan> * consider slashes while cleaning labels (#231) fix prettier format check errors * Fix README.md typo (#235) * Bump @actions/core from 1.9.0 to 1.9.1 (#233) Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.9.0 to 1.9.1. - [Release notes](https://github.com/actions/toolkit/releases) - [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md) - [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core) --- updated-dependencies: - dependency-name: "@actions/core" dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Add permissions to README.md (#236) * Add permissions to README.md * remove space * prettier * remove extra changes * fix spacing * Add the bug report and feature request form (#237) * Added the bug report and feature request form * updated the url * Fix issue form (#238) * Fix description about baseline-and-canary-replicas (#241) * Resolved issue with Canary deploy (#247) * Added support message (#249) * Deploy with Manifests from URLs (#251) * added functionality, need to add/modify existing tests * added tests * updated readme * prettier * Fix private cluster kubectl exit code bug (#252) * add private cluster exitCode check * add proper output * Added Integration Tests, Resolved Bugs With Annotations (#255) * First commit - made manifests for test deployments, made manifests for i tests for other deployment strategies * broke down blue/green * added latest tags to test manifests for new tags * remade tester * ready to test bgi * using all but first index of argv * careless error with dicts * added test to namespace * realized i was silencing error * indexing containers * keyerror * logging bc python errors are weird * expected still string * parsed args behaving weirdly * test seems to be working now, applying changes to other YAMLs now * blue/green ready to test * oops * oops * Added additional labels to check * hyphen * Added our annotations * lol * added our labels to services too * nonetype issue' * nonetype issue' * narrowing down parameter * fixed annotations issue with promote * adding debhug statement to figure out why services aren't getting annotations * this should fix annotations issue for service * not sure why this wasn't caught by intellisense * should be fixed with removing comma but adding logs in case * added linkerd install * verification * upgraded kubernetes version * removing crds * proxy option * Added smi extension * logging service * smi svcs also getting labeled now * matching ts type * not sure where stable service is going * remaining svc and deployment should match * keeping stable service and ts object * updated tests to reflect keeping ts object * no green svc after promote * duh * lol * canary work * canary test ready * logging for ing, filename for canary * changed ingress svc key and returning svc files from smi canary deployment * ts name * forgot about baseline in first deploy * * * * * smi canary should annotate, fixed cleanup * typescript issue plus percentage * forgot to type extra method * removed cleaned up objects from annotate list * logging because services aren't getting removed * moving to try/catch strategy of annotation since deletion can fail silently/with warnings * moved label to individual * removing canary service check after promote * pod ready for testing * set weights to 1000 * selectors * * * percentage * * * typing * mixed up pod and smi * fixed tests * prettier * forgot to remove canary * cleanup * Added oliver's feedback + more cleanup * ncc as dev dependency * npx * going back to global ncc install bc npm is being weird * prettier * removed unnecessary post step * new commit with all changes (#258) * Fixing Ubuntu Runner Issue (#259) * changed ubuntu runner * changed minikube action * Version formatting * nonedriveR * update kube version * installing conntrack' * updated other actions * update bg ingress api version * prettify * updated ingress backend for new api version * Added path type * prettify * Add skip tls flag (#260) * Add node modules and compiled JavaScript from main Signed-off-by: Jaiveer Katariya <jaiveerkatariya@Jaiveers-MBP.lan> Signed-off-by: dependabot[bot] <support@github.com> 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> Co-authored-by: Alexander Bartsch <alex@dashlabs.de> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kenta Nakase <parroty@users.noreply.github.com> Co-authored-by: Asa Gayle <azmatch.gayle@gmail.com>
This commit is contained in:
committed by
GitHub
parent
a2de818915
commit
d89c89ba4e
@@ -57,7 +57,7 @@ describe('deploy tests', () => {
|
||||
RouteStrategy.SMI
|
||||
)
|
||||
|
||||
expect(smiResult.objects.length).toBe(3)
|
||||
expect(smiResult.objects.length).toBe(6)
|
||||
})
|
||||
|
||||
test('correctly deploys blue/green ingress', async () => {
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import {setupSMI} from './smiBlueGreenHelper'
|
||||
|
||||
import {routeBlueGreenForDeploy} from './route'
|
||||
import {DeployResult} from '../../types/deployResult'
|
||||
|
||||
export async function deployBlueGreen(
|
||||
kubectl: Kubectl,
|
||||
@@ -35,9 +36,17 @@ export async function deployBlueGreen(
|
||||
})()
|
||||
|
||||
core.startGroup('Routing blue green')
|
||||
await routeBlueGreenForDeploy(kubectl, files, routeStrategy)
|
||||
const routeDeployment = await routeBlueGreenForDeploy(
|
||||
kubectl,
|
||||
files,
|
||||
routeStrategy
|
||||
)
|
||||
core.endGroup()
|
||||
|
||||
blueGreenDeployment.objects.push(...routeDeployment.objects)
|
||||
blueGreenDeployment.deployResult.manifestFiles.push(
|
||||
...routeDeployment.deployResult.manifestFiles
|
||||
)
|
||||
return blueGreenDeployment
|
||||
}
|
||||
|
||||
@@ -56,10 +65,16 @@ export async function deployBlueGreenSMI(
|
||||
manifestObjects.unroutedServiceEntityList
|
||||
)
|
||||
|
||||
await deployObjects(kubectl, newObjectsList)
|
||||
const otherObjDeployment: DeployResult = await deployObjects(
|
||||
kubectl,
|
||||
newObjectsList
|
||||
)
|
||||
|
||||
// make extraservices and trafficsplit
|
||||
await setupSMI(kubectl, manifestObjects.serviceEntityList)
|
||||
const smiAndSvcDeployment = await setupSMI(
|
||||
kubectl,
|
||||
manifestObjects.serviceEntityList
|
||||
)
|
||||
|
||||
// create new deloyments
|
||||
const blueGreenDeployment: BlueGreenDeployment = await deployWithLabel(
|
||||
@@ -67,10 +82,18 @@ export async function deployBlueGreenSMI(
|
||||
manifestObjects.deploymentEntityList,
|
||||
GREEN_LABEL_VALUE
|
||||
)
|
||||
return {
|
||||
deployResult: blueGreenDeployment.deployResult,
|
||||
objects: [].concat(blueGreenDeployment.objects, newObjectsList)
|
||||
}
|
||||
|
||||
blueGreenDeployment.objects.push(...newObjectsList)
|
||||
blueGreenDeployment.objects.push(...smiAndSvcDeployment.objects)
|
||||
|
||||
blueGreenDeployment.deployResult.manifestFiles.push(
|
||||
...otherObjDeployment.manifestFiles
|
||||
)
|
||||
blueGreenDeployment.deployResult.manifestFiles.push(
|
||||
...smiAndSvcDeployment.deployResult.manifestFiles
|
||||
)
|
||||
|
||||
return blueGreenDeployment
|
||||
}
|
||||
|
||||
export async function deployBlueGreenIngress(
|
||||
|
||||
@@ -61,6 +61,6 @@ describe('reject tests', () => {
|
||||
.spyOn(TSutils, 'getTrafficSplitAPIVersion')
|
||||
.mockImplementation(() => Promise.resolve('v1alpha3'))
|
||||
const rejectResult = await rejectBlueGreenSMI(kubectl, testObjects)
|
||||
expect(rejectResult.deleteResult).toHaveLength(4)
|
||||
expect(rejectResult.deleteResult).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -193,11 +193,8 @@ describe('SMI Helper tests', () => {
|
||||
|
||||
test('cleanupSMI test', async () => {
|
||||
const deleteObjects = await cleanupSMI(kc, testObjects.serviceEntityList)
|
||||
expect(deleteObjects).toHaveLength(3)
|
||||
expect(deleteObjects[0].name).toBe('nginx-service-trafficsplit')
|
||||
expect(deleteObjects[1].name).toBe('nginx-service-green')
|
||||
expect(deleteObjects[1].kind).toBe('Service')
|
||||
expect(deleteObjects[2].name).toBe('nginx-service-stable')
|
||||
expect(deleteObjects[2].kind).toBe('Service')
|
||||
expect(deleteObjects).toHaveLength(1)
|
||||
expect(deleteObjects[0].name).toBe('nginx-service-green')
|
||||
expect(deleteObjects[0].kind).toBe('Service')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -178,14 +178,6 @@ export async function cleanupSMI(
|
||||
const deleteList: K8sDeleteObject[] = []
|
||||
|
||||
serviceEntityList.forEach((serviceObject) => {
|
||||
deleteList.push({
|
||||
name: getBlueGreenResourceName(
|
||||
serviceObject.metadata.name,
|
||||
TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX
|
||||
),
|
||||
kind: TRAFFIC_SPLIT_OBJECT
|
||||
})
|
||||
|
||||
deleteList.push({
|
||||
name: getBlueGreenResourceName(
|
||||
serviceObject.metadata.name,
|
||||
@@ -193,14 +185,6 @@ export async function cleanupSMI(
|
||||
),
|
||||
kind: serviceObject.kind
|
||||
})
|
||||
|
||||
deleteList.push({
|
||||
name: getBlueGreenResourceName(
|
||||
serviceObject.metadata.name,
|
||||
STABLE_SUFFIX
|
||||
),
|
||||
kind: serviceObject.kind
|
||||
})
|
||||
})
|
||||
|
||||
// delete all objects
|
||||
|
||||
@@ -29,12 +29,17 @@ export async function deleteCanaryDeployment(
|
||||
kubectl: Kubectl,
|
||||
manifestFilePaths: string[],
|
||||
includeServices: boolean
|
||||
) {
|
||||
): Promise<string[]> {
|
||||
if (manifestFilePaths == null || manifestFilePaths.length == 0) {
|
||||
throw new Error('Manifest files for deleting canary deployment not found')
|
||||
}
|
||||
|
||||
await cleanUpCanary(kubectl, manifestFilePaths, includeServices)
|
||||
const deletedFiles = await cleanUpCanary(
|
||||
kubectl,
|
||||
manifestFilePaths,
|
||||
includeServices
|
||||
)
|
||||
return deletedFiles
|
||||
}
|
||||
|
||||
export function markResourceAsStable(inputObject: any): object {
|
||||
@@ -189,7 +194,7 @@ async function cleanUpCanary(
|
||||
kubectl: Kubectl,
|
||||
files: string[],
|
||||
includeServices: boolean
|
||||
) {
|
||||
): Promise<string[]> {
|
||||
const deleteObject = async function (kind, name) {
|
||||
try {
|
||||
const result = await kubectl.delete([kind, name])
|
||||
@@ -199,6 +204,8 @@ async function cleanUpCanary(
|
||||
}
|
||||
}
|
||||
|
||||
const deletedFiles: string[] = []
|
||||
|
||||
for (const filePath of files) {
|
||||
const fileContents = fs.readFileSync(filePath).toString()
|
||||
|
||||
@@ -211,6 +218,7 @@ async function cleanUpCanary(
|
||||
isDeploymentEntity(kind) ||
|
||||
(includeServices && isServiceEntity(kind))
|
||||
) {
|
||||
deletedFiles.push(filePath)
|
||||
const canaryObjectName = getCanaryResourceName(name)
|
||||
const baselineObjectName = getBaselineResourceName(name)
|
||||
|
||||
@@ -219,4 +227,6 @@ async function cleanUpCanary(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deletedFiles
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ import * as fileHelper from '../../utilities/fileUtils'
|
||||
import * as canaryDeploymentHelper from './canaryHelper'
|
||||
import {isDeploymentEntity} from '../../types/kubernetesTypes'
|
||||
import {getReplicaCount} from '../../utilities/manifestUpdateUtils'
|
||||
import {DeployResult} from '../../types/deployResult'
|
||||
|
||||
export async function deployPodCanary(
|
||||
filePaths: string[],
|
||||
kubectl: Kubectl,
|
||||
onlyDeployStable: boolean = false
|
||||
) {
|
||||
): Promise<DeployResult> {
|
||||
const newObjectsList = []
|
||||
const percentage = parseInt(core.getInput('percentage', {required: true}))
|
||||
|
||||
@@ -71,8 +72,8 @@ export async function deployPodCanary(
|
||||
const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList)
|
||||
const forceDeployment = core.getInput('force').toLowerCase() === 'true'
|
||||
|
||||
const result = await kubectl.apply(manifestFiles, forceDeployment)
|
||||
return {result, newFilePaths: manifestFiles}
|
||||
const execResult = await kubectl.apply(manifestFiles, forceDeployment)
|
||||
return {execResult, manifestFiles}
|
||||
}
|
||||
|
||||
export function calculateReplicaCountForCanary(
|
||||
|
||||
@@ -10,6 +10,7 @@ import * as podCanaryHelper from './podCanaryHelper'
|
||||
import {isDeploymentEntity, isServiceEntity} from '../../types/kubernetesTypes'
|
||||
import {checkForErrors} from '../../utilities/kubectlUtils'
|
||||
import {inputAnnotations} from '../../inputUtils'
|
||||
import {DeployResult} from '../../types/deployResult'
|
||||
|
||||
const TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX = '-workflow-rollout'
|
||||
const TRAFFIC_SPLIT_OBJECT = 'TrafficSplit'
|
||||
@@ -18,7 +19,7 @@ export async function deploySMICanary(
|
||||
filePaths: string[],
|
||||
kubectl: Kubectl,
|
||||
onlyDeployStable: boolean = false
|
||||
) {
|
||||
): Promise<DeployResult> {
|
||||
const canaryReplicasInput = core.getInput('baseline-and-canary-replicas')
|
||||
let canaryReplicaCount
|
||||
let calculateReplicas = true
|
||||
@@ -97,11 +98,15 @@ export async function deploySMICanary(
|
||||
const newFilePaths = fileHelper.writeObjectsToFile(newObjectsList)
|
||||
const forceDeployment = core.getInput('force').toLowerCase() === 'true'
|
||||
const result = await kubectl.apply(newFilePaths, forceDeployment)
|
||||
await createCanaryService(kubectl, filePaths)
|
||||
return {result, newFilePaths}
|
||||
const svcDeploymentFiles = await createCanaryService(kubectl, filePaths)
|
||||
newFilePaths.push(...svcDeploymentFiles)
|
||||
return {execResult: result, manifestFiles: newFilePaths}
|
||||
}
|
||||
|
||||
async function createCanaryService(kubectl: Kubectl, filePaths: string[]) {
|
||||
async function createCanaryService(
|
||||
kubectl: Kubectl,
|
||||
filePaths: string[]
|
||||
): Promise<string[]> {
|
||||
const newObjectsList = []
|
||||
const trafficObjectsList: string[] = []
|
||||
|
||||
@@ -190,6 +195,7 @@ async function createCanaryService(kubectl: Kubectl, filePaths: string[]) {
|
||||
|
||||
const result = await kubectl.apply(manifestFiles, forceDeployment)
|
||||
checkForErrors([result])
|
||||
return manifestFiles
|
||||
}
|
||||
|
||||
export async function redirectTrafficToCanaryDeployment(
|
||||
@@ -202,8 +208,8 @@ export async function redirectTrafficToCanaryDeployment(
|
||||
export async function redirectTrafficToStableDeployment(
|
||||
kubectl: Kubectl,
|
||||
manifestFilePaths: string[]
|
||||
) {
|
||||
await adjustTraffic(kubectl, manifestFilePaths, 1000, 0)
|
||||
): Promise<string[]> {
|
||||
return await adjustTraffic(kubectl, manifestFilePaths, 1000, 0)
|
||||
}
|
||||
|
||||
async function adjustTraffic(
|
||||
@@ -245,6 +251,7 @@ async function adjustTraffic(
|
||||
const forceDeployment = core.getInput('force').toLowerCase() === 'true'
|
||||
const result = await kubectl.apply(trafficSplitManifests, forceDeployment)
|
||||
checkForErrors([result])
|
||||
return trafficSplitManifests
|
||||
}
|
||||
|
||||
async function updateTrafficSplitObject(
|
||||
|
||||
@@ -39,6 +39,8 @@ import {
|
||||
normalizeWorkflowStrLabel
|
||||
} from '../utilities/githubUtils'
|
||||
import {getDeploymentConfig} from '../utilities/dockerUtils'
|
||||
import {deploy} from '../actions/deploy'
|
||||
import {DeployResult} from '../types/deployResult'
|
||||
|
||||
export async function deployManifests(
|
||||
files: string[],
|
||||
@@ -48,13 +50,13 @@ export async function deployManifests(
|
||||
): Promise<string[]> {
|
||||
switch (deploymentStrategy) {
|
||||
case DeploymentStrategy.CANARY: {
|
||||
const {result, newFilePaths} =
|
||||
const canaryDeployResult: DeployResult =
|
||||
trafficSplitMethod == TrafficSplitMethod.SMI
|
||||
? await deploySMICanary(files, kubectl)
|
||||
: await deployPodCanary(files, kubectl)
|
||||
|
||||
checkForErrors([result])
|
||||
return newFilePaths
|
||||
checkForErrors([canaryDeployResult.execResult])
|
||||
return canaryDeployResult.manifestFiles
|
||||
}
|
||||
|
||||
case DeploymentStrategy.BLUE_GREEN: {
|
||||
@@ -73,7 +75,12 @@ export async function deployManifests(
|
||||
)
|
||||
|
||||
checkForErrors([blueGreenDeployment.deployResult.execResult])
|
||||
return blueGreenDeployment.deployResult.manifestFiles
|
||||
const deployedManifestFiles =
|
||||
blueGreenDeployment.deployResult.manifestFiles
|
||||
core.debug(
|
||||
`from blue-green service, deployed manifest files are ${deployedManifestFiles}`
|
||||
)
|
||||
return deployedManifestFiles
|
||||
}
|
||||
|
||||
case DeploymentStrategy.BASIC: {
|
||||
@@ -178,6 +185,18 @@ async function annotateResources(
|
||||
annotationKey
|
||||
)
|
||||
|
||||
if (core.isDebug()) {
|
||||
core.debug(`files getting annotated are ${JSON.stringify(files)}`)
|
||||
for (const filePath of files) {
|
||||
core.debug('printing objects getting annotated...')
|
||||
const fileContents = fs.readFileSync(filePath).toString()
|
||||
const inputObjects = yaml.safeLoadAll(fileContents)
|
||||
for (const inputObject of inputObjects) {
|
||||
core.debug(`object: ${JSON.stringify(inputObject)}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const annotationKeyValStr = `${annotationKey}=${getWorkflowAnnotations(
|
||||
lastSuccessSha,
|
||||
workflowFilePath,
|
||||
@@ -192,7 +211,17 @@ async function annotateResources(
|
||||
await kubectl.annotate('namespace', namespace, annotationKeyValStr)
|
||||
)
|
||||
}
|
||||
annotateResults.push(await kubectl.annotateFiles(files, annotationKeyValStr))
|
||||
for (const file of files) {
|
||||
try {
|
||||
const annotateResult = await kubectl.annotateFiles(
|
||||
file,
|
||||
annotationKeyValStr
|
||||
)
|
||||
annotateResults.push(annotateResult)
|
||||
} catch (e) {
|
||||
core.warning(`failed to annotate resource: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
for (const resource of resourceTypes) {
|
||||
if (
|
||||
@@ -226,5 +255,14 @@ async function labelResources(
|
||||
`workflow=${cleanLabel(label)}`
|
||||
]
|
||||
|
||||
checkForErrors([await kubectl.labelFiles(files, labels)], true)
|
||||
const labelResults = []
|
||||
for (const file of files) {
|
||||
try {
|
||||
const labelResult = await kubectl.labelFiles(files, labels)
|
||||
labelResults.push(labelResult)
|
||||
} catch (e) {
|
||||
core.warning(`failed to annotate resource: ${e}`)
|
||||
}
|
||||
}
|
||||
checkForErrors(labelResults, true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user