mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-04-17 03:56:04 +08:00
Added changes to introduce annotations during deploy
This commit is contained in:
parent
b9a4b99a0c
commit
fc977b0f8b
@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.promote = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const deploymentHelper = require("../utilities/strategy-helpers/deployment-helper");
|
const deploymentHelper = require("../utilities/strategy-helpers/deployment-helper");
|
||||||
const canaryDeploymentHelper = require("../utilities/strategy-helpers/canary-deployment-helper");
|
const canaryDeploymentHelper = require("../utilities/strategy-helpers/canary-deployment-helper");
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.reject = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const canaryDeploymentHelper = require("../utilities/strategy-helpers/canary-deployment-helper");
|
const canaryDeploymentHelper = require("../utilities/strategy-helpers/canary-deployment-helper");
|
||||||
const SMICanaryDeploymentHelper = require("../utilities/strategy-helpers/smi-canary-deployment-helper");
|
const SMICanaryDeploymentHelper = require("../utilities/strategy-helpers/smi-canary-deployment-helper");
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.workflowAnnotations = exports.workloadTypesWithRolloutStatus = exports.workloadTypes = exports.deploymentTypes = exports.ServiceTypes = exports.DiscoveryAndLoadBalancerResource = exports.KubernetesWorkload = void 0;
|
||||||
class KubernetesWorkload {
|
class KubernetesWorkload {
|
||||||
}
|
}
|
||||||
exports.KubernetesWorkload = KubernetesWorkload;
|
exports.KubernetesWorkload = KubernetesWorkload;
|
||||||
@ -24,3 +25,12 @@ ServiceTypes.clusterIP = 'ClusterIP';
|
|||||||
exports.deploymentTypes = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset'];
|
exports.deploymentTypes = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset'];
|
||||||
exports.workloadTypes = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset', 'job', 'cronjob'];
|
exports.workloadTypes = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset', 'job', 'cronjob'];
|
||||||
exports.workloadTypesWithRolloutStatus = ['deployment', 'daemonset', 'statefulset'];
|
exports.workloadTypesWithRolloutStatus = ['deployment', 'daemonset', 'statefulset'];
|
||||||
|
exports.workflowAnnotations = [
|
||||||
|
`run=${process.env['GITHUB_RUN_ID']}`,
|
||||||
|
`workflow="${process.env['GITHUB_WORKFLOW']}"`,
|
||||||
|
`jobName="${process.env['GITHUB_JOB']}"`,
|
||||||
|
`createdBy=${process.env['GITHUB_ACTOR']}`,
|
||||||
|
`runUri=https://github.com/${process.env['GITHUB_REPOSITORY']}/actions/runs/${process.env['GITHUB_RUN_ID']}`,
|
||||||
|
`commit=${process.env['GITHUB_SHA']}`,
|
||||||
|
`branch=${process.env['GITHUB_REF']}`
|
||||||
|
];
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.args = exports.baselineAndCanaryReplicas = exports.trafficSplitMethod = exports.deploymentStrategy = exports.canaryPercentage = exports.manifests = exports.imagePullSecrets = exports.containers = exports.namespace = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
exports.namespace = core.getInput('namespace');
|
exports.namespace = core.getInput('namespace');
|
||||||
exports.containers = core.getInput('images').split('\n');
|
exports.containers = core.getInput('images').split('\n');
|
||||||
|
|||||||
@ -1,14 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.Kubectl = void 0;
|
||||||
const tool_runner_1 = require("./utilities/tool-runner");
|
const tool_runner_1 = require("./utilities/tool-runner");
|
||||||
class Kubectl {
|
class Kubectl {
|
||||||
constructor(kubectlPath, namespace, ignoreSSLErrors) {
|
constructor(kubectlPath, namespace, ignoreSSLErrors) {
|
||||||
@ -28,9 +20,8 @@ class Kubectl {
|
|||||||
return this.execute(['describe', resourceType, resourceName], silent);
|
return this.execute(['describe', resourceType, resourceName], silent);
|
||||||
}
|
}
|
||||||
getNewReplicaSet(deployment) {
|
getNewReplicaSet(deployment) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
let newReplicaSet = '';
|
let newReplicaSet = '';
|
||||||
const result = yield this.describe('deployment', deployment, true);
|
const result = this.describe('deployment', deployment, true);
|
||||||
if (result && result.stdout) {
|
if (result && result.stdout) {
|
||||||
const stdout = result.stdout.split('\n');
|
const stdout = result.stdout.split('\n');
|
||||||
stdout.forEach((line) => {
|
stdout.forEach((line) => {
|
||||||
@ -40,7 +31,23 @@ class Kubectl {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return newReplicaSet;
|
return newReplicaSet;
|
||||||
});
|
}
|
||||||
|
annotate(resourceType, resourceName, annotations, overwrite) {
|
||||||
|
let args = ['annotate', resourceType, resourceName];
|
||||||
|
args = args.concat(annotations);
|
||||||
|
if (!!overwrite) {
|
||||||
|
args.push(`--overwrite`);
|
||||||
|
}
|
||||||
|
return this.execute(args);
|
||||||
|
}
|
||||||
|
annotateFiles(files, annotations, overwrite) {
|
||||||
|
let args = ['annotate'];
|
||||||
|
args = args.concat(['-f', this.createInlineArray(files)]);
|
||||||
|
args = args.concat(annotations);
|
||||||
|
if (!!overwrite) {
|
||||||
|
args.push(`--overwrite`);
|
||||||
|
}
|
||||||
|
return this.execute(args);
|
||||||
}
|
}
|
||||||
getAllPods() {
|
getAllPods() {
|
||||||
return this.execute(['get', 'pods', '-o', 'json'], true);
|
return this.execute(['get', 'pods', '-o', 'json'], true);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.run = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const io = require("@actions/io");
|
const io = require("@actions/io");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.writeManifestToFile = exports.writeObjectsToFile = exports.assertFileExists = exports.ensureDirExists = exports.getNewUserDirPath = exports.getTempDirectory = void 0;
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.getTrafficSplitAPIVersion = exports.downloadKubectl = exports.getStableKubectlVersion = exports.getkubectlDownloadURL = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const os = require("os");
|
const os = require("os");
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.checkPodStatus = exports.checkManifestStability = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const utils = require("./utility");
|
const utils = require("./utility");
|
||||||
const KubernetesConstants = require("../constants");
|
const KubernetesConstants = require("../constants");
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.isWorkloadEntity = exports.updateImagePullSecrets = exports.updateContainerImagesInManifestFiles = exports.substituteImageNameInSpecFile = exports.getDeleteCmdArgs = exports.createKubectlArgs = exports.getKubectl = exports.getManifestFiles = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const kubectlutility = require("./kubectl-util");
|
const kubectlutility = require("./kubectl-util");
|
||||||
const io = require("@actions/io");
|
const io = require("@actions/io");
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.getResources = exports.updateSelectorLabels = exports.updateSpecLabels = exports.updateImageDetails = exports.updateImagePullSecrets = exports.updateObjectAnnotations = exports.updateObjectLabels = exports.getReplicaCount = exports.isServiceEntity = exports.isWorkloadEntity = exports.isDeploymentEntity = void 0;
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const yaml = require("js-yaml");
|
const yaml = require("js-yaml");
|
||||||
@ -69,6 +70,31 @@ function updateObjectLabels(inputObject, newLabels, override) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.updateObjectLabels = updateObjectLabels;
|
exports.updateObjectLabels = updateObjectLabels;
|
||||||
|
function updateObjectAnnotations(inputObject, newAnnotations, override) {
|
||||||
|
if (!inputObject) {
|
||||||
|
throw ('NullInputObject');
|
||||||
|
}
|
||||||
|
if (!inputObject.metadata) {
|
||||||
|
throw ('NullInputObjectMetadata');
|
||||||
|
}
|
||||||
|
if (!newAnnotations) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (override) {
|
||||||
|
inputObject.metadata.annotations = newAnnotations;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let existingAnnotations = inputObject.metadata.annotations;
|
||||||
|
if (!existingAnnotations) {
|
||||||
|
existingAnnotations = new Map();
|
||||||
|
}
|
||||||
|
Object.keys(newAnnotations).forEach(function (key) {
|
||||||
|
existingAnnotations[key] = newAnnotations[key];
|
||||||
|
});
|
||||||
|
inputObject.metadata.annotations = existingAnnotations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.updateObjectAnnotations = updateObjectAnnotations;
|
||||||
function updateImagePullSecrets(inputObject, newImagePullSecrets, override) {
|
function updateImagePullSecrets(inputObject, newImagePullSecrets, override) {
|
||||||
if (!inputObject || !inputObject.spec || !newImagePullSecrets) {
|
if (!inputObject || !inputObject.spec || !newImagePullSecrets) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.getStableResourceName = exports.getBaselineResourceName = exports.getCanaryResourceName = exports.isSMICanaryStrategy = exports.isCanaryDeploymentStrategy = exports.fetchResource = exports.fetchCanaryResource = exports.getNewCanaryResource = exports.getNewBaselineResource = exports.getStableResource = exports.isResourceMarkedAsStable = exports.markResourceAsStable = exports.deleteCanaryDeployment = exports.STABLE_LABEL_VALUE = exports.STABLE_SUFFIX = exports.CANARY_LABEL_VALUE = exports.BASELINE_LABEL_VALUE = exports.CANARY_VERSION_LABEL = exports.TRAFFIC_SPLIT_STRATEGY = exports.CANARY_DEPLOYMENT_STRATEGY = void 0;
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const yaml = require("js-yaml");
|
const yaml = require("js-yaml");
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
@ -154,6 +155,7 @@ function addCanaryLabelsAndAnnotations(inputObject, type) {
|
|||||||
const newLabels = new Map();
|
const newLabels = new Map();
|
||||||
newLabels[exports.CANARY_VERSION_LABEL] = type;
|
newLabels[exports.CANARY_VERSION_LABEL] = type;
|
||||||
helper.updateObjectLabels(inputObject, newLabels, false);
|
helper.updateObjectLabels(inputObject, newLabels, false);
|
||||||
|
helper.updateObjectAnnotations(inputObject, newLabels, false);
|
||||||
helper.updateSelectorLabels(inputObject, newLabels, false);
|
helper.updateSelectorLabels(inputObject, newLabels, false);
|
||||||
if (!helper.isServiceEntity(inputObject.kind)) {
|
if (!helper.isServiceEntity(inputObject.kind)) {
|
||||||
helper.updateSpecLabels(inputObject, newLabels, false);
|
helper.updateSpecLabels(inputObject, newLabels, false);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.deploy = void 0;
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const yaml = require("js-yaml");
|
const yaml = require("js-yaml");
|
||||||
@ -40,6 +41,15 @@ function deploy(kubectl, manifestFilePaths, deploymentStrategy) {
|
|||||||
ingressResources.forEach(ingressResource => {
|
ingressResources.forEach(ingressResource => {
|
||||||
kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.ingress, ingressResource.name);
|
kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.ingress, ingressResource.name);
|
||||||
});
|
});
|
||||||
|
// annotate resources
|
||||||
|
let allPods;
|
||||||
|
try {
|
||||||
|
allPods = JSON.parse((kubectl.getAllPods()).stdout);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
core.debug("Unable to parse pods; Error: " + e);
|
||||||
|
}
|
||||||
|
annotateResources(deployedManifestFiles, kubectl, resourceTypes, allPods);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.deploy = deploy;
|
exports.deploy = deploy;
|
||||||
@ -100,6 +110,17 @@ function checkManifestStability(kubectl, resources) {
|
|||||||
yield KubernetesManifestUtility.checkManifestStability(kubectl, resources);
|
yield KubernetesManifestUtility.checkManifestStability(kubectl, resources);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function annotateResources(files, kubectl, resourceTypes, allPods) {
|
||||||
|
const annotateResults = [];
|
||||||
|
annotateResults.push(kubectl.annotateFiles(files, models.workflowAnnotations, true));
|
||||||
|
resourceTypes.forEach(resource => {
|
||||||
|
if (resource.type.toUpperCase() !== models.KubernetesWorkload.pod.toUpperCase()) {
|
||||||
|
utility_1.annotateChildPods(kubectl, resource.type, resource.name, allPods)
|
||||||
|
.forEach(execResult => annotateResults.push(execResult));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
utility_1.checkForErrors(annotateResults, true);
|
||||||
|
}
|
||||||
function updateResourceObjects(filePaths, imagePullSecrets, containers) {
|
function updateResourceObjects(filePaths, imagePullSecrets, containers) {
|
||||||
const newObjectsList = [];
|
const newObjectsList = [];
|
||||||
const updateResourceObject = (inputObject) => {
|
const updateResourceObject = (inputObject) => {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.deployPodCanary = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const yaml = require("js-yaml");
|
const yaml = require("js-yaml");
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.redirectTrafficToStableDeployment = exports.redirectTrafficToCanaryDeployment = exports.deploySMICanary = void 0;
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const yaml = require("js-yaml");
|
const yaml = require("js-yaml");
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.isEqual = exports.StringComparer = void 0;
|
||||||
var StringComparer;
|
var StringComparer;
|
||||||
(function (StringComparer) {
|
(function (StringComparer) {
|
||||||
StringComparer[StringComparer["Ordinal"] = 0] = "Ordinal";
|
StringComparer[StringComparer["Ordinal"] = 0] = "Ordinal";
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.ToolRunner = void 0;
|
||||||
const os = require("os");
|
const os = require("os");
|
||||||
const events = require("events");
|
const events = require("events");
|
||||||
const child = require("child_process");
|
const child = require("child_process");
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.getCurrentTime = exports.getRandomInt = exports.sleep = exports.annotateChildPods = exports.checkForErrors = exports.isEqual = exports.getExecutableExtension = void 0;
|
||||||
const os = require("os");
|
const os = require("os");
|
||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
|
const constants_1 = require("../constants");
|
||||||
function getExecutableExtension() {
|
function getExecutableExtension() {
|
||||||
if (os.type().match(/^Win/)) {
|
if (os.type().match(/^Win/)) {
|
||||||
return '.exe';
|
return '.exe';
|
||||||
@ -48,6 +50,27 @@ function checkForErrors(execResults, warnIfError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkForErrors = checkForErrors;
|
exports.checkForErrors = checkForErrors;
|
||||||
|
function annotateChildPods(kubectl, resourceType, resourceName, allPods) {
|
||||||
|
const commandExecutionResults = [];
|
||||||
|
let owner = resourceName;
|
||||||
|
if (resourceType.toLowerCase().indexOf('deployment') > -1) {
|
||||||
|
owner = kubectl.getNewReplicaSet(resourceName);
|
||||||
|
}
|
||||||
|
if (!!allPods && !!allPods.items && allPods.items.length > 0) {
|
||||||
|
allPods.items.forEach((pod) => {
|
||||||
|
const owners = pod.metadata.ownerReferences;
|
||||||
|
if (!!owners) {
|
||||||
|
owners.forEach(ownerRef => {
|
||||||
|
if (ownerRef.name === owner) {
|
||||||
|
commandExecutionResults.push(kubectl.annotate('pod', pod.metadata.name, constants_1.workflowAnnotations, true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return commandExecutionResults;
|
||||||
|
}
|
||||||
|
exports.annotateChildPods = annotateChildPods;
|
||||||
function sleep(timeout) {
|
function sleep(timeout) {
|
||||||
return new Promise(resolve => setTimeout(resolve, timeout));
|
return new Promise(resolve => setTimeout(resolve, timeout));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,6 @@
|
|||||||
"jest": "^25.0.0",
|
"jest": "^25.0.0",
|
||||||
"@types/jest": "^25.2.2",
|
"@types/jest": "^25.2.2",
|
||||||
"ts-jest": "^25.5.1",
|
"ts-jest": "^25.5.1",
|
||||||
"typescript": "^3.9.2"
|
"typescript": "3.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,3 +24,13 @@ export class ServiceTypes {
|
|||||||
export const deploymentTypes: string[] = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset'];
|
export const deploymentTypes: string[] = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset'];
|
||||||
export const workloadTypes: string[] = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset', 'job', 'cronjob'];
|
export const workloadTypes: string[] = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset', 'job', 'cronjob'];
|
||||||
export const workloadTypesWithRolloutStatus: string[] = ['deployment', 'daemonset', 'statefulset'];
|
export const workloadTypesWithRolloutStatus: string[] = ['deployment', 'daemonset', 'statefulset'];
|
||||||
|
|
||||||
|
export let workflowAnnotations = [
|
||||||
|
`run=${process.env['GITHUB_RUN_ID']}`,
|
||||||
|
`workflow="${process.env['GITHUB_WORKFLOW']}"`,
|
||||||
|
`jobName="${process.env['GITHUB_JOB']}"`,
|
||||||
|
`createdBy=${process.env['GITHUB_ACTOR']}`,
|
||||||
|
`runUri=https://github.com/${process.env['GITHUB_REPOSITORY']}/actions/runs/${process.env['GITHUB_RUN_ID']}`,
|
||||||
|
`commit=${process.env['GITHUB_SHA']}`,
|
||||||
|
`branch=${process.env['GITHUB_REF']}`
|
||||||
|
];
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { ToolRunner, IExecOptions } from "./utilities/tool-runner";
|
import { ToolRunner, IExecOptions, IExecSyncResult } from "./utilities/tool-runner";
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
|
||||||
export interface Resource {
|
export interface Resource {
|
||||||
name: string;
|
name: string;
|
||||||
@ -20,17 +21,17 @@ export class Kubectl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public apply(configurationPaths: string | string[]) {
|
public apply(configurationPaths: string | string[]): IExecSyncResult {
|
||||||
return this.execute(['apply', '-f', this.createInlineArray(configurationPaths)]);
|
return this.execute(['apply', '-f', this.createInlineArray(configurationPaths)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public describe(resourceType: string, resourceName: string, silent?: boolean) {
|
public describe(resourceType: string, resourceName: string, silent?: boolean): IExecSyncResult {
|
||||||
return this.execute(['describe', resourceType, resourceName], silent);
|
return this.execute(['describe', resourceType, resourceName], silent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getNewReplicaSet(deployment: string) {
|
public getNewReplicaSet(deployment: string) {
|
||||||
let newReplicaSet = '';
|
let newReplicaSet = '';
|
||||||
const result = await this.describe('deployment', deployment, true);
|
const result = this.describe('deployment', deployment, true);
|
||||||
if (result && result.stdout) {
|
if (result && result.stdout) {
|
||||||
const stdout = result.stdout.split('\n');
|
const stdout = result.stdout.split('\n');
|
||||||
stdout.forEach((line: string) => {
|
stdout.forEach((line: string) => {
|
||||||
@ -43,19 +44,34 @@ export class Kubectl {
|
|||||||
return newReplicaSet;
|
return newReplicaSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAllPods() {
|
public annotate(resourceType: string, resourceName: string, annotations: string[], overwrite?: boolean): IExecSyncResult {
|
||||||
|
let args = ['annotate', resourceType, resourceName];
|
||||||
|
args = args.concat(annotations);
|
||||||
|
if (!!overwrite) { args.push(`--overwrite`); }
|
||||||
|
return this.execute(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public annotateFiles(files: string | string[], annotations: string[], overwrite?: boolean): IExecSyncResult {
|
||||||
|
let args = ['annotate'];
|
||||||
|
args = args.concat(['-f', this.createInlineArray(files)]);
|
||||||
|
args = args.concat(annotations);
|
||||||
|
if (!!overwrite) { args.push(`--overwrite`); }
|
||||||
|
return this.execute(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAllPods(): IExecSyncResult {
|
||||||
return this.execute(['get', 'pods', '-o', 'json'], true);
|
return this.execute(['get', 'pods', '-o', 'json'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getClusterInfo() {
|
public getClusterInfo(): IExecSyncResult {
|
||||||
return this.execute(['cluster-info'], true);
|
return this.execute(['cluster-info'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkRolloutStatus(resourceType: string, name: string) {
|
public checkRolloutStatus(resourceType: string, name: string): IExecSyncResult {
|
||||||
return this.execute(['rollout', 'status', resourceType + '/' + name]);
|
return this.execute(['rollout', 'status', resourceType + '/' + name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getResource(resourceType: string, name: string) {
|
public getResource(resourceType: string, name: string): IExecSyncResult {
|
||||||
return this.execute(['get', resourceType + '/' + name, '-o', 'json']);
|
return this.execute(['get', resourceType + '/' + name, '-o', 'json']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +96,7 @@ export class Kubectl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public executeCommand(customCommand: string, args?: string) {
|
public executeCommand(customCommand: string, args?: string) {
|
||||||
if(!customCommand)
|
if (!customCommand)
|
||||||
throw new Error('NullCommandForKubectl');
|
throw new Error('NullCommandForKubectl');
|
||||||
return args ? this.execute([customCommand, args]) : this.execute([customCommand]);
|
return args ? this.execute([customCommand, args]) : this.execute([customCommand]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,6 +81,34 @@ export function updateObjectLabels(inputObject: any, newLabels: Map<string, stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateObjectAnnotations(inputObject: any, newAnnotations: Map<string, string>, override: boolean) {
|
||||||
|
if (!inputObject) {
|
||||||
|
throw ('NullInputObject');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inputObject.metadata) {
|
||||||
|
throw ('NullInputObjectMetadata');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newAnnotations) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (override) {
|
||||||
|
inputObject.metadata.annotations = newAnnotations;
|
||||||
|
} else {
|
||||||
|
let existingAnnotations = inputObject.metadata.annotations;
|
||||||
|
if (!existingAnnotations) {
|
||||||
|
existingAnnotations = new Map<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(newAnnotations).forEach(function (key) {
|
||||||
|
existingAnnotations[key] = newAnnotations[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
inputObject.metadata.annotations = existingAnnotations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function updateImagePullSecrets(inputObject: any, newImagePullSecrets: string[], override: boolean) {
|
export function updateImagePullSecrets(inputObject: any, newImagePullSecrets: string[], override: boolean) {
|
||||||
if (!inputObject || !inputObject.spec || !newImagePullSecrets) {
|
if (!inputObject || !inputObject.spec || !newImagePullSecrets) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -177,6 +177,7 @@ function addCanaryLabelsAndAnnotations(inputObject: any, type: string) {
|
|||||||
newLabels[CANARY_VERSION_LABEL] = type;
|
newLabels[CANARY_VERSION_LABEL] = type;
|
||||||
|
|
||||||
helper.updateObjectLabels(inputObject, newLabels, false);
|
helper.updateObjectLabels(inputObject, newLabels, false);
|
||||||
|
helper.updateObjectAnnotations(inputObject, newLabels, false);
|
||||||
helper.updateSelectorLabels(inputObject, newLabels, false);
|
helper.updateSelectorLabels(inputObject, newLabels, false);
|
||||||
|
|
||||||
if (!helper.isServiceEntity(inputObject.kind)) {
|
if (!helper.isServiceEntity(inputObject.kind)) {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
import * as canaryDeploymentHelper from './canary-deployment-helper';
|
import * as canaryDeploymentHelper from './canary-deployment-helper';
|
||||||
@ -14,10 +13,11 @@ import * as KubernetesManifestUtility from '../manifest-stability-utility';
|
|||||||
import * as KubernetesConstants from '../../constants';
|
import * as KubernetesConstants from '../../constants';
|
||||||
import { Kubectl, Resource } from '../../kubectl-object-model';
|
import { Kubectl, Resource } from '../../kubectl-object-model';
|
||||||
import { StringComparer, isEqual } from './../string-comparison';
|
import { StringComparer, isEqual } from './../string-comparison';
|
||||||
|
import { IExecSyncResult } from '../../utilities/tool-runner';
|
||||||
|
|
||||||
import { deployPodCanary } from './pod-canary-deployment-helper';
|
import { deployPodCanary } from './pod-canary-deployment-helper';
|
||||||
import { deploySMICanary } from './smi-canary-deployment-helper';
|
import { deploySMICanary } from './smi-canary-deployment-helper';
|
||||||
import { checkForErrors } from "../utility";
|
import { checkForErrors, annotateChildPods } from "../utility";
|
||||||
|
|
||||||
|
|
||||||
export async function deploy(kubectl: Kubectl, manifestFilePaths: string[], deploymentStrategy: string) {
|
export async function deploy(kubectl: Kubectl, manifestFilePaths: string[], deploymentStrategy: string) {
|
||||||
@ -40,6 +40,16 @@ export async function deploy(kubectl: Kubectl, manifestFilePaths: string[], depl
|
|||||||
ingressResources.forEach(ingressResource => {
|
ingressResources.forEach(ingressResource => {
|
||||||
kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.ingress, ingressResource.name);
|
kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.ingress, ingressResource.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// annotate resources
|
||||||
|
let allPods: any;
|
||||||
|
try {
|
||||||
|
allPods = JSON.parse((kubectl.getAllPods()).stdout);
|
||||||
|
} catch (e) {
|
||||||
|
core.debug("Unable to parse pods; Error: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
annotateResources(deployedManifestFiles, kubectl, resourceTypes, allPods);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getManifestFiles(manifestFilePaths: string[]): string[] {
|
function getManifestFiles(manifestFilePaths: string[]): string[] {
|
||||||
@ -102,6 +112,18 @@ async function checkManifestStability(kubectl: Kubectl, resources: Resource[]):
|
|||||||
await KubernetesManifestUtility.checkManifestStability(kubectl, resources);
|
await KubernetesManifestUtility.checkManifestStability(kubectl, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function annotateResources(files: string[], kubectl: Kubectl, resourceTypes: Resource[], allPods: any) {
|
||||||
|
const annotateResults: IExecSyncResult[] = [];
|
||||||
|
annotateResults.push(kubectl.annotateFiles(files, models.workflowAnnotations, true));
|
||||||
|
resourceTypes.forEach(resource => {
|
||||||
|
if (resource.type.toUpperCase() !== models.KubernetesWorkload.pod.toUpperCase()) {
|
||||||
|
annotateChildPods(kubectl, resource.type, resource.name, allPods)
|
||||||
|
.forEach(execResult => annotateResults.push(execResult));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkForErrors(annotateResults, true);
|
||||||
|
}
|
||||||
|
|
||||||
function updateResourceObjects(filePaths: string[], imagePullSecrets: string[], containers: string[]): string[] {
|
function updateResourceObjects(filePaths: string[], imagePullSecrets: string[], containers: string[]): string[] {
|
||||||
const newObjectsList = [];
|
const newObjectsList = [];
|
||||||
const updateResourceObject = (inputObject) => {
|
const updateResourceObject = (inputObject) => {
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
import { IExecSyncResult } from './tool-runner';
|
||||||
|
import { Kubectl } from '../kubectl-object-model';
|
||||||
|
import { workflowAnnotations } from '../constants';
|
||||||
|
|
||||||
export function getExecutableExtension(): string {
|
export function getExecutableExtension(): string {
|
||||||
if (os.type().match(/^Win/)) {
|
if (os.type().match(/^Win/)) {
|
||||||
@ -25,7 +28,7 @@ export function isEqual(str1: string, str2: string, ignoreCase?: boolean): boole
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkForErrors(execResults, warnIfError?: boolean) {
|
export function checkForErrors(execResults: IExecSyncResult[], warnIfError?: boolean) {
|
||||||
if (execResults.length !== 0) {
|
if (execResults.length !== 0) {
|
||||||
let stderr = '';
|
let stderr = '';
|
||||||
execResults.forEach(result => {
|
execResults.forEach(result => {
|
||||||
@ -47,6 +50,29 @@ export function checkForErrors(execResults, warnIfError?: boolean) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function annotateChildPods(kubectl: Kubectl, resourceType: string, resourceName: string, allPods): IExecSyncResult[] {
|
||||||
|
const commandExecutionResults = [];
|
||||||
|
let owner = resourceName;
|
||||||
|
if (resourceType.toLowerCase().indexOf('deployment') > -1) {
|
||||||
|
owner = kubectl.getNewReplicaSet(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!allPods && !!allPods.items && allPods.items.length > 0) {
|
||||||
|
allPods.items.forEach((pod) => {
|
||||||
|
const owners = pod.metadata.ownerReferences;
|
||||||
|
if (!!owners) {
|
||||||
|
owners.forEach(ownerRef => {
|
||||||
|
if (ownerRef.name === owner) {
|
||||||
|
commandExecutionResults.push(kubectl.annotate('pod', pod.metadata.name, workflowAnnotations, true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return commandExecutionResults;
|
||||||
|
}
|
||||||
|
|
||||||
export function sleep(timeout: number) {
|
export function sleep(timeout: number) {
|
||||||
return new Promise(resolve => setTimeout(resolve, timeout));
|
return new Promise(resolve => setTimeout(resolve, timeout));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user