mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-04-11 00:40:08 +08:00
Initial commit for config files annotations
This commit is contained in:
parent
b371791f3a
commit
bfca26e368
103
lib/constants.js
103
lib/constants.js
@ -1,51 +1,52 @@
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getWorkflowAnnotationKeyLabel = exports.getWorkflowAnnotationsJson = exports.workloadTypesWithRolloutStatus = exports.workloadTypes = exports.deploymentTypes = exports.ServiceTypes = exports.DiscoveryAndLoadBalancerResource = exports.KubernetesWorkload = void 0;
|
||||
class KubernetesWorkload {
|
||||
}
|
||||
exports.KubernetesWorkload = KubernetesWorkload;
|
||||
KubernetesWorkload.pod = 'Pod';
|
||||
KubernetesWorkload.replicaset = 'Replicaset';
|
||||
KubernetesWorkload.deployment = 'Deployment';
|
||||
KubernetesWorkload.statefulSet = 'StatefulSet';
|
||||
KubernetesWorkload.daemonSet = 'DaemonSet';
|
||||
KubernetesWorkload.job = 'job';
|
||||
KubernetesWorkload.cronjob = 'cronjob';
|
||||
class DiscoveryAndLoadBalancerResource {
|
||||
}
|
||||
exports.DiscoveryAndLoadBalancerResource = DiscoveryAndLoadBalancerResource;
|
||||
DiscoveryAndLoadBalancerResource.service = 'service';
|
||||
DiscoveryAndLoadBalancerResource.ingress = 'ingress';
|
||||
class ServiceTypes {
|
||||
}
|
||||
exports.ServiceTypes = ServiceTypes;
|
||||
ServiceTypes.loadBalancer = 'LoadBalancer';
|
||||
ServiceTypes.nodePort = 'NodePort';
|
||||
ServiceTypes.clusterIP = 'ClusterIP';
|
||||
exports.deploymentTypes = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset'];
|
||||
exports.workloadTypes = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset', 'job', 'cronjob'];
|
||||
exports.workloadTypesWithRolloutStatus = ['deployment', 'daemonset', 'statefulset'];
|
||||
function getWorkflowAnnotationsJson(lastSuccessRunSha, workflowFilePath) {
|
||||
return `{`
|
||||
+ `'run': '${process.env.GITHUB_RUN_ID}',`
|
||||
+ `'repository': '${process.env.GITHUB_REPOSITORY}',`
|
||||
+ `'workflow': '${process.env.GITHUB_WORKFLOW}',`
|
||||
+ `'workflowFileName': '${workflowFilePath.replace(".github/workflows/", "")}',`
|
||||
+ `'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}',`
|
||||
+ `'lastSuccessRunCommit': '${lastSuccessRunSha}',`
|
||||
+ `'branch': '${process.env.GITHUB_REF}',`
|
||||
+ `'deployTimestamp': '${Date.now()}',`
|
||||
+ `'provider': 'GitHub'`
|
||||
+ `}`;
|
||||
}
|
||||
exports.getWorkflowAnnotationsJson = getWorkflowAnnotationsJson;
|
||||
function getWorkflowAnnotationKeyLabel(workflowFilePath) {
|
||||
const hashKey = require("crypto").createHash("MD5")
|
||||
.update(`${process.env.GITHUB_REPOSITORY}/${workflowFilePath}`)
|
||||
.digest("hex");
|
||||
return `githubWorkflow_${hashKey}`;
|
||||
}
|
||||
exports.getWorkflowAnnotationKeyLabel = getWorkflowAnnotationKeyLabel;
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getWorkflowAnnotationKeyLabel = exports.getWorkflowAnnotationsJson = exports.workloadTypesWithRolloutStatus = exports.workloadTypes = exports.deploymentTypes = exports.ServiceTypes = exports.DiscoveryAndLoadBalancerResource = exports.KubernetesWorkload = void 0;
|
||||
class KubernetesWorkload {
|
||||
}
|
||||
exports.KubernetesWorkload = KubernetesWorkload;
|
||||
KubernetesWorkload.pod = 'Pod';
|
||||
KubernetesWorkload.replicaset = 'Replicaset';
|
||||
KubernetesWorkload.deployment = 'Deployment';
|
||||
KubernetesWorkload.statefulSet = 'StatefulSet';
|
||||
KubernetesWorkload.daemonSet = 'DaemonSet';
|
||||
KubernetesWorkload.job = 'job';
|
||||
KubernetesWorkload.cronjob = 'cronjob';
|
||||
class DiscoveryAndLoadBalancerResource {
|
||||
}
|
||||
exports.DiscoveryAndLoadBalancerResource = DiscoveryAndLoadBalancerResource;
|
||||
DiscoveryAndLoadBalancerResource.service = 'service';
|
||||
DiscoveryAndLoadBalancerResource.ingress = 'ingress';
|
||||
class ServiceTypes {
|
||||
}
|
||||
exports.ServiceTypes = ServiceTypes;
|
||||
ServiceTypes.loadBalancer = 'LoadBalancer';
|
||||
ServiceTypes.nodePort = 'NodePort';
|
||||
ServiceTypes.clusterIP = 'ClusterIP';
|
||||
exports.deploymentTypes = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset'];
|
||||
exports.workloadTypes = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset', 'job', 'cronjob'];
|
||||
exports.workloadTypesWithRolloutStatus = ['deployment', 'daemonset', 'statefulset'];
|
||||
function getWorkflowAnnotationsJson(lastSuccessRunSha, workflowFilePath, filePathConfigs) {
|
||||
return `{`
|
||||
+ `'run': '${process.env.GITHUB_RUN_ID}',`
|
||||
+ `'repository': '${process.env.GITHUB_REPOSITORY}',`
|
||||
+ `'workflow': '${process.env.GITHUB_WORKFLOW}',`
|
||||
+ `'workflowFileName': '${workflowFilePath.replace(".github/workflows/", "")}',`
|
||||
+ `'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}',`
|
||||
+ `'lastSuccessRunCommit': '${lastSuccessRunSha}',`
|
||||
+ `'branch': '${process.env.GITHUB_REF}',`
|
||||
+ `'deployTimestamp': '${Date.now()}',`
|
||||
+ `'filePathConfigs': '${JSON.stringify(filePathConfigs)}',`
|
||||
+ `'provider': 'GitHub'`
|
||||
+ `}`;
|
||||
}
|
||||
exports.getWorkflowAnnotationsJson = getWorkflowAnnotationsJson;
|
||||
function getWorkflowAnnotationKeyLabel(workflowFilePath) {
|
||||
const hashKey = require("crypto").createHash("MD5")
|
||||
.update(`${process.env.GITHUB_REPOSITORY}/${workflowFilePath}`)
|
||||
.digest("hex");
|
||||
return `githubWorkflow_${hashKey}`;
|
||||
}
|
||||
exports.getWorkflowAnnotationKeyLabel = getWorkflowAnnotationKeyLabel;
|
||||
|
||||
35
lib/utilities/exec.js
Normal file
35
lib/utilities/exec.js
Normal file
@ -0,0 +1,35 @@
|
||||
"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 });
|
||||
exports.exec = void 0;
|
||||
const aexec = require("@actions/exec");
|
||||
exports.exec = (command, args = [], silent) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
const options = {
|
||||
silent: silent,
|
||||
ignoreReturnCode: true
|
||||
};
|
||||
options.listeners = {
|
||||
stdout: (data) => {
|
||||
stdout += data.toString();
|
||||
},
|
||||
stderr: (data) => {
|
||||
stderr += data.toString();
|
||||
}
|
||||
};
|
||||
const returnCode = yield aexec.exec(command, args, options);
|
||||
return {
|
||||
success: returnCode === 0,
|
||||
stdout: stdout.trim(),
|
||||
stderr: stderr.trim()
|
||||
};
|
||||
});
|
||||
@ -1,176 +1,177 @@
|
||||
'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 });
|
||||
exports.deploy = void 0;
|
||||
const fs = require("fs");
|
||||
const core = require("@actions/core");
|
||||
const yaml = require("js-yaml");
|
||||
const canaryDeploymentHelper = require("./canary-deployment-helper");
|
||||
const KubernetesObjectUtility = require("../resource-object-utility");
|
||||
const TaskInputParameters = require("../../input-parameters");
|
||||
const models = require("../../constants");
|
||||
const fileHelper = require("../files-helper");
|
||||
const utils = require("../manifest-utilities");
|
||||
const KubernetesManifestUtility = require("../manifest-stability-utility");
|
||||
const KubernetesConstants = require("../../constants");
|
||||
const string_comparison_1 = require("./../string-comparison");
|
||||
const pod_canary_deployment_helper_1 = require("./pod-canary-deployment-helper");
|
||||
const smi_canary_deployment_helper_1 = require("./smi-canary-deployment-helper");
|
||||
const utility_1 = require("../utility");
|
||||
function deploy(kubectl, manifestFilePaths, deploymentStrategy) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// get manifest files
|
||||
let inputManifestFiles = getManifestFiles(manifestFilePaths);
|
||||
// artifact substitution
|
||||
inputManifestFiles = updateResourceObjects(inputManifestFiles, TaskInputParameters.imagePullSecrets, TaskInputParameters.containers);
|
||||
// deployment
|
||||
const deployedManifestFiles = deployManifests(inputManifestFiles, kubectl, isCanaryDeploymentStrategy(deploymentStrategy));
|
||||
// check manifest stability
|
||||
const resourceTypes = KubernetesObjectUtility.getResources(deployedManifestFiles, models.deploymentTypes.concat([KubernetesConstants.DiscoveryAndLoadBalancerResource.service]));
|
||||
yield checkManifestStability(kubectl, resourceTypes);
|
||||
// print ingress resources
|
||||
const ingressResources = KubernetesObjectUtility.getResources(deployedManifestFiles, [KubernetesConstants.DiscoveryAndLoadBalancerResource.ingress]);
|
||||
ingressResources.forEach(ingressResource => {
|
||||
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);
|
||||
}
|
||||
annotateAndLabelResources(deployedManifestFiles, kubectl, resourceTypes, allPods);
|
||||
});
|
||||
}
|
||||
exports.deploy = deploy;
|
||||
function getManifestFiles(manifestFilePaths) {
|
||||
const files = utils.getManifestFiles(manifestFilePaths);
|
||||
if (files == null || files.length === 0) {
|
||||
throw new Error(`ManifestFileNotFound : ${manifestFilePaths}`);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
function deployManifests(files, kubectl, isCanaryDeploymentStrategy) {
|
||||
let result;
|
||||
if (isCanaryDeploymentStrategy) {
|
||||
let canaryDeploymentOutput;
|
||||
if (canaryDeploymentHelper.isSMICanaryStrategy()) {
|
||||
canaryDeploymentOutput = smi_canary_deployment_helper_1.deploySMICanary(kubectl, files);
|
||||
}
|
||||
else {
|
||||
canaryDeploymentOutput = pod_canary_deployment_helper_1.deployPodCanary(kubectl, files);
|
||||
}
|
||||
result = canaryDeploymentOutput.result;
|
||||
files = canaryDeploymentOutput.newFilePaths;
|
||||
}
|
||||
else {
|
||||
if (canaryDeploymentHelper.isSMICanaryStrategy()) {
|
||||
const updatedManifests = appendStableVersionLabelToResource(files, kubectl);
|
||||
result = kubectl.apply(updatedManifests, TaskInputParameters.forceDeployment);
|
||||
}
|
||||
else {
|
||||
result = kubectl.apply(files, TaskInputParameters.forceDeployment);
|
||||
}
|
||||
}
|
||||
utility_1.checkForErrors([result]);
|
||||
return files;
|
||||
}
|
||||
function appendStableVersionLabelToResource(files, kubectl) {
|
||||
const manifestFiles = [];
|
||||
const newObjectsList = [];
|
||||
files.forEach((filePath) => {
|
||||
const fileContents = fs.readFileSync(filePath);
|
||||
yaml.safeLoadAll(fileContents, function (inputObject) {
|
||||
const kind = inputObject.kind;
|
||||
if (KubernetesObjectUtility.isDeploymentEntity(kind)) {
|
||||
const updatedObject = canaryDeploymentHelper.markResourceAsStable(inputObject);
|
||||
newObjectsList.push(updatedObject);
|
||||
}
|
||||
else {
|
||||
manifestFiles.push(filePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
const updatedManifestFiles = fileHelper.writeObjectsToFile(newObjectsList);
|
||||
manifestFiles.push(...updatedManifestFiles);
|
||||
return manifestFiles;
|
||||
}
|
||||
function checkManifestStability(kubectl, resources) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield KubernetesManifestUtility.checkManifestStability(kubectl, resources);
|
||||
});
|
||||
}
|
||||
function annotateAndLabelResources(files, kubectl, resourceTypes, allPods) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const workflowFilePath = yield utility_1.getWorkflowFilePath(TaskInputParameters.githubToken);
|
||||
const annotationKeyLabel = models.getWorkflowAnnotationKeyLabel(workflowFilePath);
|
||||
annotateResources(files, kubectl, resourceTypes, allPods, annotationKeyLabel, workflowFilePath);
|
||||
labelResources(files, kubectl, annotationKeyLabel);
|
||||
});
|
||||
}
|
||||
function annotateResources(files, kubectl, resourceTypes, allPods, annotationKey, workflowFilePath) {
|
||||
const annotateResults = [];
|
||||
const lastSuccessSha = utility_1.getLastSuccessfulRunSha(kubectl, TaskInputParameters.namespace, annotationKey);
|
||||
let annotationKeyValStr = annotationKey + '=' + models.getWorkflowAnnotationsJson(lastSuccessSha, workflowFilePath);
|
||||
annotateResults.push(kubectl.annotate('namespace', TaskInputParameters.namespace, annotationKeyValStr));
|
||||
annotateResults.push(kubectl.annotateFiles(files, annotationKeyValStr));
|
||||
resourceTypes.forEach(resource => {
|
||||
if (resource.type.toUpperCase() !== models.KubernetesWorkload.pod.toUpperCase()) {
|
||||
utility_1.annotateChildPods(kubectl, resource.type, resource.name, annotationKeyValStr, allPods)
|
||||
.forEach(execResult => annotateResults.push(execResult));
|
||||
}
|
||||
});
|
||||
utility_1.checkForErrors(annotateResults, true);
|
||||
}
|
||||
function labelResources(files, kubectl, label) {
|
||||
let workflowName = process.env.GITHUB_WORKFLOW;
|
||||
workflowName = workflowName.startsWith('.github/workflows/') ?
|
||||
workflowName.replace(".github/workflows/", "") : workflowName;
|
||||
const labels = [`workflowFriendlyName=${workflowName}`, `workflow=${label}`];
|
||||
utility_1.checkForErrors([kubectl.labelFiles(files, labels)], true);
|
||||
}
|
||||
function updateResourceObjects(filePaths, imagePullSecrets, containers) {
|
||||
const newObjectsList = [];
|
||||
const updateResourceObject = (inputObject) => {
|
||||
if (!!imagePullSecrets && imagePullSecrets.length > 0) {
|
||||
KubernetesObjectUtility.updateImagePullSecrets(inputObject, imagePullSecrets, false);
|
||||
}
|
||||
if (!!containers && containers.length > 0) {
|
||||
KubernetesObjectUtility.updateImageDetails(inputObject, containers);
|
||||
}
|
||||
};
|
||||
filePaths.forEach((filePath) => {
|
||||
const fileContents = fs.readFileSync(filePath).toString();
|
||||
yaml.safeLoadAll(fileContents, function (inputObject) {
|
||||
if (inputObject && inputObject.kind) {
|
||||
const kind = inputObject.kind;
|
||||
if (KubernetesObjectUtility.isWorkloadEntity(kind)) {
|
||||
updateResourceObject(inputObject);
|
||||
}
|
||||
else if (string_comparison_1.isEqual(kind, 'list', string_comparison_1.StringComparer.OrdinalIgnoreCase)) {
|
||||
let items = inputObject.items;
|
||||
if (items.length > 0) {
|
||||
items.forEach((item) => updateResourceObject(item));
|
||||
}
|
||||
}
|
||||
newObjectsList.push(inputObject);
|
||||
}
|
||||
});
|
||||
});
|
||||
core.debug('New K8s objects after adding imagePullSecrets are :' + JSON.stringify(newObjectsList));
|
||||
const newFilePaths = fileHelper.writeObjectsToFile(newObjectsList);
|
||||
return newFilePaths;
|
||||
}
|
||||
function isCanaryDeploymentStrategy(deploymentStrategy) {
|
||||
return deploymentStrategy != null && deploymentStrategy.toUpperCase() === canaryDeploymentHelper.CANARY_DEPLOYMENT_STRATEGY.toUpperCase();
|
||||
}
|
||||
'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 });
|
||||
exports.deploy = void 0;
|
||||
const fs = require("fs");
|
||||
const core = require("@actions/core");
|
||||
const yaml = require("js-yaml");
|
||||
const canaryDeploymentHelper = require("./canary-deployment-helper");
|
||||
const KubernetesObjectUtility = require("../resource-object-utility");
|
||||
const TaskInputParameters = require("../../input-parameters");
|
||||
const models = require("../../constants");
|
||||
const fileHelper = require("../files-helper");
|
||||
const utils = require("../manifest-utilities");
|
||||
const KubernetesManifestUtility = require("../manifest-stability-utility");
|
||||
const KubernetesConstants = require("../../constants");
|
||||
const string_comparison_1 = require("./../string-comparison");
|
||||
const pod_canary_deployment_helper_1 = require("./pod-canary-deployment-helper");
|
||||
const smi_canary_deployment_helper_1 = require("./smi-canary-deployment-helper");
|
||||
const utility_1 = require("../utility");
|
||||
function deploy(kubectl, manifestFilePaths, deploymentStrategy) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// get manifest files
|
||||
let inputManifestFiles = getManifestFiles(manifestFilePaths);
|
||||
// artifact substitution
|
||||
inputManifestFiles = updateResourceObjects(inputManifestFiles, TaskInputParameters.imagePullSecrets, TaskInputParameters.containers);
|
||||
// deployment
|
||||
const deployedManifestFiles = deployManifests(inputManifestFiles, kubectl, isCanaryDeploymentStrategy(deploymentStrategy));
|
||||
// check manifest stability
|
||||
const resourceTypes = KubernetesObjectUtility.getResources(deployedManifestFiles, models.deploymentTypes.concat([KubernetesConstants.DiscoveryAndLoadBalancerResource.service]));
|
||||
yield checkManifestStability(kubectl, resourceTypes);
|
||||
// print ingress resources
|
||||
const ingressResources = KubernetesObjectUtility.getResources(deployedManifestFiles, [KubernetesConstants.DiscoveryAndLoadBalancerResource.ingress]);
|
||||
ingressResources.forEach(ingressResource => {
|
||||
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);
|
||||
}
|
||||
annotateAndLabelResources(deployedManifestFiles, kubectl, resourceTypes, allPods);
|
||||
});
|
||||
}
|
||||
exports.deploy = deploy;
|
||||
function getManifestFiles(manifestFilePaths) {
|
||||
const files = utils.getManifestFiles(manifestFilePaths);
|
||||
if (files == null || files.length === 0) {
|
||||
throw new Error(`ManifestFileNotFound : ${manifestFilePaths}`);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
function deployManifests(files, kubectl, isCanaryDeploymentStrategy) {
|
||||
let result;
|
||||
if (isCanaryDeploymentStrategy) {
|
||||
let canaryDeploymentOutput;
|
||||
if (canaryDeploymentHelper.isSMICanaryStrategy()) {
|
||||
canaryDeploymentOutput = smi_canary_deployment_helper_1.deploySMICanary(kubectl, files);
|
||||
}
|
||||
else {
|
||||
canaryDeploymentOutput = pod_canary_deployment_helper_1.deployPodCanary(kubectl, files);
|
||||
}
|
||||
result = canaryDeploymentOutput.result;
|
||||
files = canaryDeploymentOutput.newFilePaths;
|
||||
}
|
||||
else {
|
||||
if (canaryDeploymentHelper.isSMICanaryStrategy()) {
|
||||
const updatedManifests = appendStableVersionLabelToResource(files, kubectl);
|
||||
result = kubectl.apply(updatedManifests, TaskInputParameters.forceDeployment);
|
||||
}
|
||||
else {
|
||||
result = kubectl.apply(files, TaskInputParameters.forceDeployment);
|
||||
}
|
||||
}
|
||||
utility_1.checkForErrors([result]);
|
||||
return files;
|
||||
}
|
||||
function appendStableVersionLabelToResource(files, kubectl) {
|
||||
const manifestFiles = [];
|
||||
const newObjectsList = [];
|
||||
files.forEach((filePath) => {
|
||||
const fileContents = fs.readFileSync(filePath);
|
||||
yaml.safeLoadAll(fileContents, function (inputObject) {
|
||||
const kind = inputObject.kind;
|
||||
if (KubernetesObjectUtility.isDeploymentEntity(kind)) {
|
||||
const updatedObject = canaryDeploymentHelper.markResourceAsStable(inputObject);
|
||||
newObjectsList.push(updatedObject);
|
||||
}
|
||||
else {
|
||||
manifestFiles.push(filePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
const updatedManifestFiles = fileHelper.writeObjectsToFile(newObjectsList);
|
||||
manifestFiles.push(...updatedManifestFiles);
|
||||
return manifestFiles;
|
||||
}
|
||||
function checkManifestStability(kubectl, resources) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield KubernetesManifestUtility.checkManifestStability(kubectl, resources);
|
||||
});
|
||||
}
|
||||
function annotateAndLabelResources(files, kubectl, resourceTypes, allPods) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const workflowFilePath = yield utility_1.getWorkflowFilePath(TaskInputParameters.githubToken);
|
||||
const filePathsConfig = yield utility_1.getFilePathsConfigs();
|
||||
const annotationKeyLabel = models.getWorkflowAnnotationKeyLabel(workflowFilePath);
|
||||
annotateResources(files, kubectl, resourceTypes, allPods, annotationKeyLabel, workflowFilePath, filePathsConfig);
|
||||
labelResources(files, kubectl, annotationKeyLabel);
|
||||
});
|
||||
}
|
||||
function annotateResources(files, kubectl, resourceTypes, allPods, annotationKey, workflowFilePath, filePathsConfig) {
|
||||
const annotateResults = [];
|
||||
const lastSuccessSha = utility_1.getLastSuccessfulRunSha(kubectl, TaskInputParameters.namespace, annotationKey);
|
||||
let annotationKeyValStr = annotationKey + '=' + models.getWorkflowAnnotationsJson(lastSuccessSha, workflowFilePath, filePathsConfig);
|
||||
annotateResults.push(kubectl.annotate('namespace', TaskInputParameters.namespace, annotationKeyValStr));
|
||||
annotateResults.push(kubectl.annotateFiles(files, annotationKeyValStr));
|
||||
resourceTypes.forEach(resource => {
|
||||
if (resource.type.toUpperCase() !== models.KubernetesWorkload.pod.toUpperCase()) {
|
||||
utility_1.annotateChildPods(kubectl, resource.type, resource.name, annotationKeyValStr, allPods)
|
||||
.forEach(execResult => annotateResults.push(execResult));
|
||||
}
|
||||
});
|
||||
utility_1.checkForErrors(annotateResults, true);
|
||||
}
|
||||
function labelResources(files, kubectl, label) {
|
||||
let workflowName = process.env.GITHUB_WORKFLOW;
|
||||
workflowName = workflowName.startsWith('.github/workflows/') ?
|
||||
workflowName.replace(".github/workflows/", "") : workflowName;
|
||||
const labels = [`workflowFriendlyName=${workflowName}`, `workflow=${label}`];
|
||||
utility_1.checkForErrors([kubectl.labelFiles(files, labels)], true);
|
||||
}
|
||||
function updateResourceObjects(filePaths, imagePullSecrets, containers) {
|
||||
const newObjectsList = [];
|
||||
const updateResourceObject = (inputObject) => {
|
||||
if (!!imagePullSecrets && imagePullSecrets.length > 0) {
|
||||
KubernetesObjectUtility.updateImagePullSecrets(inputObject, imagePullSecrets, false);
|
||||
}
|
||||
if (!!containers && containers.length > 0) {
|
||||
KubernetesObjectUtility.updateImageDetails(inputObject, containers);
|
||||
}
|
||||
};
|
||||
filePaths.forEach((filePath) => {
|
||||
const fileContents = fs.readFileSync(filePath).toString();
|
||||
yaml.safeLoadAll(fileContents, function (inputObject) {
|
||||
if (inputObject && inputObject.kind) {
|
||||
const kind = inputObject.kind;
|
||||
if (KubernetesObjectUtility.isWorkloadEntity(kind)) {
|
||||
updateResourceObject(inputObject);
|
||||
}
|
||||
else if (string_comparison_1.isEqual(kind, 'list', string_comparison_1.StringComparer.OrdinalIgnoreCase)) {
|
||||
let items = inputObject.items;
|
||||
if (items.length > 0) {
|
||||
items.forEach((item) => updateResourceObject(item));
|
||||
}
|
||||
}
|
||||
newObjectsList.push(inputObject);
|
||||
}
|
||||
});
|
||||
});
|
||||
core.debug('New K8s objects after adding imagePullSecrets are :' + JSON.stringify(newObjectsList));
|
||||
const newFilePaths = fileHelper.writeObjectsToFile(newObjectsList);
|
||||
return newFilePaths;
|
||||
}
|
||||
function isCanaryDeploymentStrategy(deploymentStrategy) {
|
||||
return deploymentStrategy != null && deploymentStrategy.toUpperCase() === canaryDeploymentHelper.CANARY_DEPLOYMENT_STRATEGY.toUpperCase();
|
||||
}
|
||||
|
||||
@ -1,151 +1,214 @@
|
||||
"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 });
|
||||
exports.getCurrentTime = exports.getRandomInt = exports.sleep = exports.annotateChildPods = exports.getWorkflowFilePath = exports.getLastSuccessfulRunSha = exports.checkForErrors = exports.isEqual = exports.getExecutableExtension = void 0;
|
||||
const os = require("os");
|
||||
const core = require("@actions/core");
|
||||
const githubClient_1 = require("../githubClient");
|
||||
const httpClient_1 = require("./httpClient");
|
||||
function getExecutableExtension() {
|
||||
if (os.type().match(/^Win/)) {
|
||||
return '.exe';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
exports.getExecutableExtension = getExecutableExtension;
|
||||
function isEqual(str1, str2, ignoreCase) {
|
||||
if (str1 == null && str2 == null) {
|
||||
return true;
|
||||
}
|
||||
if (str1 == null || str2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (ignoreCase) {
|
||||
return str1.toUpperCase() === str2.toUpperCase();
|
||||
}
|
||||
else {
|
||||
return str1 === str2;
|
||||
}
|
||||
}
|
||||
exports.isEqual = isEqual;
|
||||
function checkForErrors(execResults, warnIfError) {
|
||||
if (execResults.length !== 0) {
|
||||
let stderr = '';
|
||||
execResults.forEach(result => {
|
||||
if (result && result.stderr) {
|
||||
if (result.code !== 0) {
|
||||
stderr += result.stderr + '\n';
|
||||
}
|
||||
else {
|
||||
core.warning(result.stderr);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (stderr.length > 0) {
|
||||
if (warnIfError) {
|
||||
core.warning(stderr.trim());
|
||||
}
|
||||
else {
|
||||
throw new Error(stderr.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.checkForErrors = checkForErrors;
|
||||
function getLastSuccessfulRunSha(kubectl, namespaceName, annotationKey) {
|
||||
try {
|
||||
const result = kubectl.getResource('namespace', namespaceName);
|
||||
if (result) {
|
||||
if (result.stderr) {
|
||||
core.warning(`${result.stderr}`);
|
||||
return process.env.GITHUB_SHA;
|
||||
}
|
||||
else if (result.stdout) {
|
||||
const annotationsSet = JSON.parse(result.stdout).metadata.annotations;
|
||||
if (annotationsSet && annotationsSet[annotationKey]) {
|
||||
return JSON.parse(annotationsSet[annotationKey].replace(/'/g, '"')).commit;
|
||||
}
|
||||
else {
|
||||
return 'NA';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
core.warning(`Failed to get commits from cluster. ${JSON.stringify(ex)}`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
exports.getLastSuccessfulRunSha = getLastSuccessfulRunSha;
|
||||
function getWorkflowFilePath(githubToken) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let workflowFilePath = process.env.GITHUB_WORKFLOW;
|
||||
if (!workflowFilePath.startsWith('.github/workflows/')) {
|
||||
const githubClient = new githubClient_1.GitHubClient(process.env.GITHUB_REPOSITORY, githubToken);
|
||||
const response = yield githubClient.getWorkflows();
|
||||
if (response) {
|
||||
if (response.statusCode == httpClient_1.StatusCodes.OK
|
||||
&& response.body
|
||||
&& response.body.total_count) {
|
||||
if (response.body.total_count > 0) {
|
||||
for (let workflow of response.body.workflows) {
|
||||
if (process.env.GITHUB_WORKFLOW === workflow.name) {
|
||||
workflowFilePath = workflow.path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (response.statusCode != httpClient_1.StatusCodes.OK) {
|
||||
core.debug(`An error occured while getting list of workflows on the repo. Statuscode: ${response.statusCode}, StatusMessage: ${response.statusMessage}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
core.warning(`Failed to get response from workflow list API`);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(workflowFilePath);
|
||||
});
|
||||
}
|
||||
exports.getWorkflowFilePath = getWorkflowFilePath;
|
||||
function annotateChildPods(kubectl, resourceType, resourceName, annotationKeyValStr, 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, annotationKeyValStr));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return commandExecutionResults;
|
||||
}
|
||||
exports.annotateChildPods = annotateChildPods;
|
||||
function sleep(timeout) {
|
||||
return new Promise(resolve => setTimeout(resolve, timeout));
|
||||
}
|
||||
exports.sleep = sleep;
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * Math.floor(max));
|
||||
}
|
||||
exports.getRandomInt = getRandomInt;
|
||||
function getCurrentTime() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
exports.getCurrentTime = getCurrentTime;
|
||||
"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 });
|
||||
exports.getCurrentTime = exports.getRandomInt = exports.sleep = exports.getFilePathsConfigs = exports.annotateChildPods = exports.getWorkflowFilePath = exports.getLastSuccessfulRunSha = exports.checkForErrors = exports.isEqual = exports.getExecutableExtension = void 0;
|
||||
const os = require("os");
|
||||
const core = require("@actions/core");
|
||||
const githubClient_1 = require("../githubClient");
|
||||
const httpClient_1 = require("./httpClient");
|
||||
const exec = require("./exec");
|
||||
const inputParams = require("../input-parameters");
|
||||
function getExecutableExtension() {
|
||||
if (os.type().match(/^Win/)) {
|
||||
return '.exe';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
exports.getExecutableExtension = getExecutableExtension;
|
||||
function isEqual(str1, str2, ignoreCase) {
|
||||
if (str1 == null && str2 == null) {
|
||||
return true;
|
||||
}
|
||||
if (str1 == null || str2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (ignoreCase) {
|
||||
return str1.toUpperCase() === str2.toUpperCase();
|
||||
}
|
||||
else {
|
||||
return str1 === str2;
|
||||
}
|
||||
}
|
||||
exports.isEqual = isEqual;
|
||||
function checkForErrors(execResults, warnIfError) {
|
||||
if (execResults.length !== 0) {
|
||||
let stderr = '';
|
||||
execResults.forEach(result => {
|
||||
if (result && result.stderr) {
|
||||
if (result.code !== 0) {
|
||||
stderr += result.stderr + '\n';
|
||||
}
|
||||
else {
|
||||
core.warning(result.stderr);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (stderr.length > 0) {
|
||||
if (warnIfError) {
|
||||
core.warning(stderr.trim());
|
||||
}
|
||||
else {
|
||||
throw new Error(stderr.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.checkForErrors = checkForErrors;
|
||||
function getLastSuccessfulRunSha(kubectl, namespaceName, annotationKey) {
|
||||
try {
|
||||
const result = kubectl.getResource('namespace', namespaceName);
|
||||
if (result) {
|
||||
if (result.stderr) {
|
||||
core.warning(`${result.stderr}`);
|
||||
return process.env.GITHUB_SHA;
|
||||
}
|
||||
else if (result.stdout) {
|
||||
const annotationsSet = JSON.parse(result.stdout).metadata.annotations;
|
||||
if (annotationsSet && annotationsSet[annotationKey]) {
|
||||
return JSON.parse(annotationsSet[annotationKey].replace(/'/g, '"')).commit;
|
||||
}
|
||||
else {
|
||||
return 'NA';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
core.warning(`Failed to get commits from cluster. ${JSON.stringify(ex)}`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
exports.getLastSuccessfulRunSha = getLastSuccessfulRunSha;
|
||||
function getWorkflowFilePath(githubToken) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let workflowFilePath = process.env.GITHUB_WORKFLOW;
|
||||
if (!workflowFilePath.startsWith('.github/workflows/')) {
|
||||
const githubClient = new githubClient_1.GitHubClient(process.env.GITHUB_REPOSITORY, githubToken);
|
||||
const response = yield githubClient.getWorkflows();
|
||||
if (response) {
|
||||
if (response.statusCode == httpClient_1.StatusCodes.OK
|
||||
&& response.body
|
||||
&& response.body.total_count) {
|
||||
if (response.body.total_count > 0) {
|
||||
for (let workflow of response.body.workflows) {
|
||||
if (process.env.GITHUB_WORKFLOW === workflow.name) {
|
||||
workflowFilePath = workflow.path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (response.statusCode != httpClient_1.StatusCodes.OK) {
|
||||
core.debug(`An error occured while getting list of workflows on the repo. Statuscode: ${response.statusCode}, StatusMessage: ${response.statusMessage}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
core.warning(`Failed to get response from workflow list API`);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(workflowFilePath);
|
||||
});
|
||||
}
|
||||
exports.getWorkflowFilePath = getWorkflowFilePath;
|
||||
function annotateChildPods(kubectl, resourceType, resourceName, annotationKeyValStr, 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, annotationKeyValStr));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return commandExecutionResults;
|
||||
}
|
||||
exports.annotateChildPods = annotateChildPods;
|
||||
function getFilePathsConfigs() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let filePathsConfig = {};
|
||||
const BUILD_CONFIG_KEY = 'buildConfigs';
|
||||
const MANIFEST_PATHS_KEY = 'manifestFilePaths';
|
||||
const HELM_CHART_KEY = 'helmChartFilePaths';
|
||||
const DOCKERFILE_PATH_LABEL_KEY = 'dockerfile-path';
|
||||
const DOCKERFILE_PATH_KEY = 'dockerfilePath';
|
||||
const CONTAINER_REG_KEY = 'containerRegistryServer';
|
||||
let inputManifestFiles = inputParams.manifests;
|
||||
filePathsConfig[MANIFEST_PATHS_KEY] = inputManifestFiles || '';
|
||||
let helmChartPath = process.env.HELM_CHART_PATH || '';
|
||||
filePathsConfig[HELM_CHART_KEY] = helmChartPath;
|
||||
//Fetch labels from each image
|
||||
let imageToBuildConfigMap = {};
|
||||
let imageNames = core.getInput('images').split('\n');
|
||||
for (const image of imageNames) {
|
||||
let args = [image];
|
||||
let resultObj;
|
||||
let buildConfigMap = {};
|
||||
let containerRegistryName = image.toString().split('/')[0];
|
||||
try {
|
||||
let usrname = process.env.CR_USERNAME || null;
|
||||
let pwd = process.env.CR_PASSWORD || null;
|
||||
if (pwd && usrname) {
|
||||
let loginArgs = [containerRegistryName, '--username', usrname, '--password', pwd];
|
||||
yield exec.exec('docker login ', loginArgs, true).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
throw new Error(`docker login failed with: ${res.stderr.match(/(.*)\s*$/)[0]}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
yield exec.exec('docker pull ', args, true).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
throw new Error(`docker images pull failed with: ${res.stderr.match(/(.*)\s*$/)[0]}`);
|
||||
}
|
||||
});
|
||||
yield exec.exec('docker inspect --type=image', args, true).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
throw new Error(`docker inspect call failed with: ${res.stderr.match(/(.*)\s*$/)[0]}`);
|
||||
}
|
||||
resultObj = JSON.parse(res.stdout)[0];
|
||||
});
|
||||
}
|
||||
catch (ex) {
|
||||
core.warning(`Failed to get dockerfile paths for image ${image.toString()} | ` + ex);
|
||||
}
|
||||
if (resultObj != null && resultObj.Config != null && resultObj.Config.Labels != null) {
|
||||
if (resultObj.Config.Labels[DOCKERFILE_PATH_LABEL_KEY] != null) {
|
||||
buildConfigMap[DOCKERFILE_PATH_KEY] = resultObj.Config.Labels[DOCKERFILE_PATH_LABEL_KEY];
|
||||
}
|
||||
//Add CR server name to build config
|
||||
buildConfigMap[CONTAINER_REG_KEY] = containerRegistryName;
|
||||
imageToBuildConfigMap[resultObj.Id] = buildConfigMap;
|
||||
}
|
||||
}
|
||||
filePathsConfig[BUILD_CONFIG_KEY] = imageToBuildConfigMap;
|
||||
return Promise.resolve(filePathsConfig);
|
||||
});
|
||||
}
|
||||
exports.getFilePathsConfigs = getFilePathsConfigs;
|
||||
function sleep(timeout) {
|
||||
return new Promise(resolve => setTimeout(resolve, timeout));
|
||||
}
|
||||
exports.sleep = sleep;
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * Math.floor(max));
|
||||
}
|
||||
exports.getRandomInt = getRandomInt;
|
||||
function getCurrentTime() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
exports.getCurrentTime = getCurrentTime;
|
||||
|
||||
15873
package-lock.json
generated
15873
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -8,16 +8,16 @@
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/tool-cache": "^1.0.0",
|
||||
"@actions/io": "^1.0.0",
|
||||
"@actions/core": "^1.2.6",
|
||||
"@actions/exec": "^1.0.0",
|
||||
"@actions/exec": "^1.0.4",
|
||||
"@actions/io": "^1.0.0",
|
||||
"@actions/tool-cache": "^1.0.0",
|
||||
"js-yaml": "3.13.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^25.2.2",
|
||||
"@types/node": "^12.0.10",
|
||||
"jest": "^25.0.0",
|
||||
"@types/jest": "^25.2.2",
|
||||
"ts-jest": "^25.5.1",
|
||||
"typescript": "3.9.5"
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ export const deploymentTypes: string[] = ['deployment', 'replicaset', 'daemonset
|
||||
export const workloadTypes: string[] = ['deployment', 'replicaset', 'daemonset', 'pod', 'statefulset', 'job', 'cronjob'];
|
||||
export const workloadTypesWithRolloutStatus: string[] = ['deployment', 'daemonset', 'statefulset'];
|
||||
|
||||
export function getWorkflowAnnotationsJson(lastSuccessRunSha: string, workflowFilePath: string): string {
|
||||
export function getWorkflowAnnotationsJson(lastSuccessRunSha: string, workflowFilePath: string, filePathConfigs: any): string {
|
||||
return `{`
|
||||
+ `'run': '${process.env.GITHUB_RUN_ID}',`
|
||||
+ `'repository': '${process.env.GITHUB_REPOSITORY}',`
|
||||
@ -38,6 +38,7 @@ export function getWorkflowAnnotationsJson(lastSuccessRunSha: string, workflowFi
|
||||
+ `'lastSuccessRunCommit': '${lastSuccessRunSha}',`
|
||||
+ `'branch': '${process.env.GITHUB_REF}',`
|
||||
+ `'deployTimestamp': '${Date.now()}',`
|
||||
+ `'filePathConfigs': '${JSON.stringify(filePathConfigs)}',`
|
||||
+ `'provider': 'GitHub'`
|
||||
+ `}`;
|
||||
}
|
||||
|
||||
34
src/utilities/exec.ts
Normal file
34
src/utilities/exec.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import * as aexec from '@actions/exec';
|
||||
import {ExecOptions} from '@actions/exec';
|
||||
|
||||
export interface ExecResult {
|
||||
success: boolean;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
|
||||
export const exec = async (command: string, args: string[] = [], silent?: boolean): Promise<ExecResult> => {
|
||||
let stdout: string = '';
|
||||
let stderr: string = '';
|
||||
|
||||
const options: ExecOptions = {
|
||||
silent: silent,
|
||||
ignoreReturnCode: true
|
||||
};
|
||||
options.listeners = {
|
||||
stdout: (data: Buffer) => {
|
||||
stdout += data.toString();
|
||||
},
|
||||
stderr: (data: Buffer) => {
|
||||
stderr += data.toString();
|
||||
}
|
||||
};
|
||||
|
||||
const returnCode: number = await aexec.exec(command, args, options);
|
||||
|
||||
return {
|
||||
success: returnCode === 0,
|
||||
stdout: stdout.trim(),
|
||||
stderr: stderr.trim()
|
||||
};
|
||||
};
|
||||
@ -17,7 +17,7 @@ import { IExecSyncResult } from '../../utilities/tool-runner';
|
||||
|
||||
import { deployPodCanary } from './pod-canary-deployment-helper';
|
||||
import { deploySMICanary } from './smi-canary-deployment-helper';
|
||||
import { checkForErrors, annotateChildPods, getWorkflowFilePath, getLastSuccessfulRunSha } from "../utility";
|
||||
import { checkForErrors, annotateChildPods, getWorkflowFilePath, getLastSuccessfulRunSha, getFilePathsConfigs } from "../utility";
|
||||
|
||||
|
||||
export async function deploy(kubectl: Kubectl, manifestFilePaths: string[], deploymentStrategy: string) {
|
||||
@ -114,15 +114,16 @@ async function checkManifestStability(kubectl: Kubectl, resources: Resource[]):
|
||||
|
||||
async function annotateAndLabelResources(files: string[], kubectl: Kubectl, resourceTypes: Resource[], allPods: any) {
|
||||
const workflowFilePath = await getWorkflowFilePath(TaskInputParameters.githubToken);
|
||||
const filePathsConfig = await getFilePathsConfigs();
|
||||
const annotationKeyLabel = models.getWorkflowAnnotationKeyLabel(workflowFilePath);
|
||||
annotateResources(files, kubectl, resourceTypes, allPods, annotationKeyLabel, workflowFilePath);
|
||||
annotateResources(files, kubectl, resourceTypes, allPods, annotationKeyLabel, workflowFilePath, filePathsConfig);
|
||||
labelResources(files, kubectl, annotationKeyLabel);
|
||||
}
|
||||
|
||||
function annotateResources(files: string[], kubectl: Kubectl, resourceTypes: Resource[], allPods: any, annotationKey: string, workflowFilePath: string) {
|
||||
function annotateResources(files: string[], kubectl: Kubectl, resourceTypes: Resource[], allPods: any, annotationKey: string, workflowFilePath: string, filePathsConfig: string) {
|
||||
const annotateResults: IExecSyncResult[] = [];
|
||||
const lastSuccessSha = getLastSuccessfulRunSha(kubectl, TaskInputParameters.namespace, annotationKey);
|
||||
let annotationKeyValStr = annotationKey + '=' + models.getWorkflowAnnotationsJson(lastSuccessSha, workflowFilePath);
|
||||
let annotationKeyValStr = annotationKey + '=' + models.getWorkflowAnnotationsJson(lastSuccessSha, workflowFilePath, filePathsConfig);
|
||||
annotateResults.push(kubectl.annotate('namespace', TaskInputParameters.namespace, annotationKeyValStr));
|
||||
annotateResults.push(kubectl.annotateFiles(files, annotationKeyValStr));
|
||||
resourceTypes.forEach(resource => {
|
||||
|
||||
@ -4,6 +4,8 @@ import { IExecSyncResult } from './tool-runner';
|
||||
import { Kubectl } from '../kubectl-object-model';
|
||||
import { GitHubClient } from '../githubClient';
|
||||
import { StatusCodes } from "./httpClient";
|
||||
import * as exec from "./exec";
|
||||
import * as inputParams from "../input-parameters";
|
||||
|
||||
export function getExecutableExtension(): string {
|
||||
if (os.type().match(/^Win/)) {
|
||||
@ -127,6 +129,78 @@ export function annotateChildPods(kubectl: Kubectl, resourceType: string, resour
|
||||
return commandExecutionResults;
|
||||
}
|
||||
|
||||
export async function getFilePathsConfigs(): Promise<any> {
|
||||
|
||||
let filePathsConfig: any = {};
|
||||
const BUILD_CONFIG_KEY = 'buildConfigs';
|
||||
const MANIFEST_PATHS_KEY = 'manifestFilePaths';
|
||||
const HELM_CHART_KEY = 'helmChartFilePaths';
|
||||
const DOCKERFILE_PATH_LABEL_KEY = 'dockerfile-path';
|
||||
const DOCKERFILE_PATH_KEY = 'dockerfilePath';
|
||||
const CONTAINER_REG_KEY = 'containerRegistryServer';
|
||||
|
||||
let inputManifestFiles = inputParams.manifests;
|
||||
filePathsConfig[MANIFEST_PATHS_KEY] = inputManifestFiles || '';
|
||||
|
||||
let helmChartPath = process.env.HELM_CHART_PATH || '';
|
||||
filePathsConfig[HELM_CHART_KEY] = helmChartPath;
|
||||
|
||||
//Fetch labels from each image
|
||||
let imageToBuildConfigMap: any = {};
|
||||
let imageNames = core.getInput('images').split('\n');
|
||||
|
||||
for(const image of imageNames){
|
||||
let args: string[] = [image];
|
||||
let resultObj: any;
|
||||
let buildConfigMap : any = {};
|
||||
let containerRegistryName = image.toString().split('/')[0];
|
||||
|
||||
try{
|
||||
|
||||
let usrname = process.env.CR_USERNAME || null;
|
||||
let pwd = process.env.CR_PASSWORD || null;
|
||||
if(pwd && usrname)
|
||||
{
|
||||
let loginArgs: string[] = [containerRegistryName, '--username', usrname, '--password', pwd];
|
||||
await exec.exec('docker login ', loginArgs, true).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
throw new Error(`docker login failed with: ${res.stderr.match(/(.*)\s*$/)![0]}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await exec.exec('docker pull ', args, true).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
throw new Error(`docker images pull failed with: ${res.stderr.match(/(.*)\s*$/)![0]}`);
|
||||
}
|
||||
});
|
||||
|
||||
await exec.exec('docker inspect --type=image', args, true).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
throw new Error(`docker inspect call failed with: ${res.stderr.match(/(.*)\s*$/)![0]}`);
|
||||
}
|
||||
resultObj = JSON.parse(res.stdout)[0];
|
||||
});
|
||||
}
|
||||
catch (ex) {
|
||||
core.warning(`Failed to get dockerfile paths for image ${image.toString()} | ` + ex);
|
||||
}
|
||||
|
||||
if(resultObj != null && resultObj.Config != null && resultObj.Config.Labels != null ){
|
||||
if(resultObj.Config.Labels[DOCKERFILE_PATH_LABEL_KEY] !=null){
|
||||
buildConfigMap[DOCKERFILE_PATH_KEY] = resultObj.Config.Labels[DOCKERFILE_PATH_LABEL_KEY];
|
||||
}
|
||||
|
||||
//Add CR server name to build config
|
||||
buildConfigMap[CONTAINER_REG_KEY] = containerRegistryName;
|
||||
imageToBuildConfigMap[resultObj.Id] = buildConfigMap;
|
||||
}
|
||||
}
|
||||
filePathsConfig[BUILD_CONFIG_KEY] = imageToBuildConfigMap;
|
||||
|
||||
return Promise.resolve(filePathsConfig);
|
||||
}
|
||||
|
||||
export function sleep(timeout: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, timeout));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user