mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-06-25 05:59:26 +08:00
d89c89ba4e
* 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>
233 lines
6.2 KiB
TypeScript
233 lines
6.2 KiB
TypeScript
import {Kubectl} from '../../types/kubectl'
|
|
import * as fs from 'fs'
|
|
import * as yaml from 'js-yaml'
|
|
import * as core from '@actions/core'
|
|
import {ExecOutput} from '@actions/exec'
|
|
import {
|
|
isDeploymentEntity,
|
|
isServiceEntity,
|
|
KubernetesWorkload
|
|
} from '../../types/kubernetesTypes'
|
|
import * as utils from '../../utilities/manifestUpdateUtils'
|
|
import {
|
|
updateObjectAnnotations,
|
|
updateObjectLabels,
|
|
updateSelectorLabels
|
|
} from '../../utilities/manifestUpdateUtils'
|
|
import {updateSpecLabels} from '../../utilities/manifestSpecLabelUtils'
|
|
import {checkForErrors} from '../../utilities/kubectlUtils'
|
|
|
|
export const CANARY_VERSION_LABEL = 'workflow/version'
|
|
const BASELINE_SUFFIX = '-baseline'
|
|
export const BASELINE_LABEL_VALUE = 'baseline'
|
|
const CANARY_SUFFIX = '-canary'
|
|
export const CANARY_LABEL_VALUE = 'canary'
|
|
export const STABLE_SUFFIX = '-stable'
|
|
export const STABLE_LABEL_VALUE = 'stable'
|
|
|
|
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')
|
|
}
|
|
|
|
const deletedFiles = await cleanUpCanary(
|
|
kubectl,
|
|
manifestFilePaths,
|
|
includeServices
|
|
)
|
|
return deletedFiles
|
|
}
|
|
|
|
export function markResourceAsStable(inputObject: any): object {
|
|
if (isResourceMarkedAsStable(inputObject)) {
|
|
return inputObject
|
|
}
|
|
|
|
const newObject = JSON.parse(JSON.stringify(inputObject))
|
|
addCanaryLabelsAndAnnotations(newObject, STABLE_LABEL_VALUE)
|
|
return newObject
|
|
}
|
|
|
|
export function isResourceMarkedAsStable(inputObject: any): boolean {
|
|
return (
|
|
inputObject?.metadata?.labels[CANARY_VERSION_LABEL] === STABLE_LABEL_VALUE
|
|
)
|
|
}
|
|
|
|
export function getStableResource(inputObject: any): object {
|
|
const replicaCount = specContainsReplicas(inputObject.kind)
|
|
? inputObject.spec.replicas
|
|
: 0
|
|
|
|
return getNewCanaryObject(inputObject, replicaCount, STABLE_LABEL_VALUE)
|
|
}
|
|
|
|
export function getNewBaselineResource(
|
|
stableObject: any,
|
|
replicas?: number
|
|
): object {
|
|
return getNewCanaryObject(stableObject, replicas, BASELINE_LABEL_VALUE)
|
|
}
|
|
|
|
export function getNewCanaryResource(
|
|
inputObject: any,
|
|
replicas?: number
|
|
): object {
|
|
return getNewCanaryObject(inputObject, replicas, CANARY_LABEL_VALUE)
|
|
}
|
|
|
|
export async function fetchResource(
|
|
kubectl: Kubectl,
|
|
kind: string,
|
|
name: string
|
|
) {
|
|
let result: ExecOutput
|
|
try {
|
|
result = await kubectl.getResource(kind, name)
|
|
} catch (e) {
|
|
core.debug(`detected error while fetching resources: ${e}`)
|
|
}
|
|
|
|
if (!result || result?.stderr) {
|
|
return null
|
|
}
|
|
|
|
if (result.stdout) {
|
|
const resource = JSON.parse(result.stdout)
|
|
|
|
try {
|
|
utils.UnsetClusterSpecificDetails(resource)
|
|
return resource
|
|
} catch (ex) {
|
|
core.debug(
|
|
`Exception occurred while parsing ${resource} in JSON object: ${ex}`
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function getCanaryResourceName(name: string) {
|
|
return name + CANARY_SUFFIX
|
|
}
|
|
|
|
export function getBaselineResourceName(name: string) {
|
|
return name + BASELINE_SUFFIX
|
|
}
|
|
|
|
export function getStableResourceName(name: string) {
|
|
return name + STABLE_SUFFIX
|
|
}
|
|
|
|
export function getBaselineDeploymentFromStableDeployment(
|
|
inputObject: any,
|
|
replicaCount: number
|
|
): object {
|
|
// TODO: REFACTOR TO MAKE EVERYTHING TYPE SAFE
|
|
const oldName = inputObject.metadata.name
|
|
const newName =
|
|
oldName.substring(0, oldName.length - STABLE_SUFFIX.length) +
|
|
BASELINE_SUFFIX
|
|
|
|
const newObject = getNewCanaryObject(
|
|
inputObject,
|
|
replicaCount,
|
|
BASELINE_LABEL_VALUE
|
|
) as any
|
|
newObject.metadata.name = newName
|
|
|
|
return newObject
|
|
}
|
|
|
|
function getNewCanaryObject(
|
|
inputObject: any,
|
|
replicas: number,
|
|
type: string
|
|
): object {
|
|
const newObject = JSON.parse(JSON.stringify(inputObject))
|
|
|
|
// Updating name
|
|
if (type === CANARY_LABEL_VALUE) {
|
|
newObject.metadata.name = getCanaryResourceName(inputObject.metadata.name)
|
|
} else if (type === STABLE_LABEL_VALUE) {
|
|
newObject.metadata.name = getStableResourceName(inputObject.metadata.name)
|
|
} else {
|
|
newObject.metadata.name = getBaselineResourceName(
|
|
inputObject.metadata.name
|
|
)
|
|
}
|
|
|
|
addCanaryLabelsAndAnnotations(newObject, type)
|
|
|
|
if (specContainsReplicas(newObject.kind)) {
|
|
newObject.spec.replicas = replicas
|
|
}
|
|
|
|
return newObject
|
|
}
|
|
|
|
function specContainsReplicas(kind: string) {
|
|
return (
|
|
kind.toLowerCase() !== KubernetesWorkload.POD.toLowerCase() &&
|
|
kind.toLowerCase() !== KubernetesWorkload.DAEMON_SET.toLowerCase() &&
|
|
!isServiceEntity(kind)
|
|
)
|
|
}
|
|
|
|
function addCanaryLabelsAndAnnotations(inputObject: any, type: string) {
|
|
const newLabels = new Map<string, string>()
|
|
newLabels[CANARY_VERSION_LABEL] = type
|
|
|
|
updateObjectLabels(inputObject, newLabels, false)
|
|
updateObjectAnnotations(inputObject, newLabels, false)
|
|
updateSelectorLabels(inputObject, newLabels, false)
|
|
|
|
if (!isServiceEntity(inputObject.kind)) {
|
|
updateSpecLabels(inputObject, newLabels, false)
|
|
}
|
|
}
|
|
|
|
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])
|
|
checkForErrors([result])
|
|
} catch (ex) {
|
|
// Ignore failures of delete if it doesn't exist
|
|
}
|
|
}
|
|
|
|
const deletedFiles: string[] = []
|
|
|
|
for (const filePath of files) {
|
|
const fileContents = fs.readFileSync(filePath).toString()
|
|
|
|
const parsedYaml = yaml.safeLoadAll(fileContents)
|
|
for (const inputObject of parsedYaml) {
|
|
const name = inputObject.metadata.name
|
|
const kind = inputObject.kind
|
|
|
|
if (
|
|
isDeploymentEntity(kind) ||
|
|
(includeServices && isServiceEntity(kind))
|
|
) {
|
|
deletedFiles.push(filePath)
|
|
const canaryObjectName = getCanaryResourceName(name)
|
|
const baselineObjectName = getBaselineResourceName(name)
|
|
|
|
await deleteObject(kind, canaryObjectName)
|
|
await deleteObject(kind, baselineObjectName)
|
|
}
|
|
}
|
|
}
|
|
|
|
return deletedFiles
|
|
}
|