mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-04-13 10:02:19 +08:00
Add yaml parser to image substitution logic (#103)
* Updating image substitution logic to use yaml parser * Updating L0s * Fixing input parameter logic for empty images
This commit is contained in:
parent
564f76cfe3
commit
0bdc00d5b0
@ -6,7 +6,6 @@ import * as deployment from '../src/utilities/strategy-helpers/deployment-helper
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as io from '@actions/io';
|
import * as io from '@actions/io';
|
||||||
import * as toolCache from '@actions/tool-cache';
|
import * as toolCache from '@actions/tool-cache';
|
||||||
import * as fileHelper from '../src/utilities/files-helper';
|
|
||||||
import * as glob from 'glob';
|
import * as glob from 'glob';
|
||||||
import { getWorkflowAnnotationKeyLabel, getWorkflowAnnotationsJson } from '../src/constants';
|
import { getWorkflowAnnotationKeyLabel, getWorkflowAnnotationsJson } from '../src/constants';
|
||||||
import * as inputParam from '../src/input-parameters';
|
import * as inputParam from '../src/input-parameters';
|
||||||
@ -113,7 +112,7 @@ test("setKubectlPath() - install a latest version", async () => {
|
|||||||
const kubectlVersion = 'latest'
|
const kubectlVersion = 'latest'
|
||||||
//Mocks
|
//Mocks
|
||||||
coreMock.getInput = jest.fn().mockReturnValue(kubectlVersion);
|
coreMock.getInput = jest.fn().mockReturnValue(kubectlVersion);
|
||||||
jest.spyOn(fs, 'readFileSync').mockImplementation(() => "");
|
const readFileSpy = jest.spyOn(fs, 'readFileSync').mockImplementation(() => "");
|
||||||
toolCacheMock.find = jest.fn().mockReturnValue(undefined);
|
toolCacheMock.find = jest.fn().mockReturnValue(undefined);
|
||||||
toolCacheMock.downloadTool = jest.fn().mockResolvedValue('');
|
toolCacheMock.downloadTool = jest.fn().mockResolvedValue('');
|
||||||
toolCacheMock.cacheFile = jest.fn().mockReturnValue('cachepath');
|
toolCacheMock.cacheFile = jest.fn().mockReturnValue('cachepath');
|
||||||
@ -123,7 +122,7 @@ test("setKubectlPath() - install a latest version", async () => {
|
|||||||
await expect(action.run()).resolves.not.toThrow();
|
await expect(action.run()).resolves.not.toThrow();
|
||||||
expect(toolCacheMock.find).toBeCalledWith('kubectl', kubectlVersion);
|
expect(toolCacheMock.find).toBeCalledWith('kubectl', kubectlVersion);
|
||||||
expect(toolCacheMock.downloadTool).toBeCalledWith(stableVersionUrl);
|
expect(toolCacheMock.downloadTool).toBeCalledWith(stableVersionUrl);
|
||||||
|
readFileSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("setKubectlPath() - kubectl version already avilable", async () => {
|
test("setKubectlPath() - kubectl version already avilable", async () => {
|
||||||
@ -255,6 +254,7 @@ test("deployment - deploy() - Invokes with manifestfiles", async () => {
|
|||||||
kubeCtl.annotate = jest.fn().mockReturnValue("");
|
kubeCtl.annotate = jest.fn().mockReturnValue("");
|
||||||
kubeCtl.labelFiles = jest.fn().mockReturnValue("");
|
kubeCtl.labelFiles = jest.fn().mockReturnValue("");
|
||||||
KubernetesManifestUtilityMock.checkManifestStability = jest.fn().mockReturnValue("");
|
KubernetesManifestUtilityMock.checkManifestStability = jest.fn().mockReturnValue("");
|
||||||
|
inputParamMock.containers = ['testcr.azurecr.io/testapp:2.0'];
|
||||||
|
|
||||||
const readFileSpy = jest.spyOn(fs, 'readFileSync').mockImplementation(() => deploymentYaml);
|
const readFileSpy = jest.spyOn(fs, 'readFileSync').mockImplementation(() => deploymentYaml);
|
||||||
jest.spyOn(httpClient, 'sendRequest').mockImplementation(() => Promise.resolve(getWorkflowsUrlResponse));
|
jest.spyOn(httpClient, 'sendRequest').mockImplementation(() => Promise.resolve(getWorkflowsUrlResponse));
|
||||||
@ -263,6 +263,8 @@ test("deployment - deploy() - Invokes with manifestfiles", async () => {
|
|||||||
await expect(deployment.deploy(kubeCtl, ['manifests/deployment.yaml'], undefined)).resolves.not.toThrowError();
|
await expect(deployment.deploy(kubeCtl, ['manifests/deployment.yaml'], undefined)).resolves.not.toThrowError();
|
||||||
expect(readFileSpy).toBeCalledWith("manifests/deployment.yaml");
|
expect(readFileSpy).toBeCalledWith("manifests/deployment.yaml");
|
||||||
expect(kubeCtl.getResource).toBeCalledWith("ingress", "AppName");
|
expect(kubeCtl.getResource).toBeCalledWith("ingress", "AppName");
|
||||||
|
readFileSpy.mockRestore();
|
||||||
|
inputParamMock.containers = [];
|
||||||
});
|
});
|
||||||
|
|
||||||
test("deployment - deploy() - deploy force flag on", async () => {
|
test("deployment - deploy() - deploy force flag on", async () => {
|
||||||
@ -301,11 +303,10 @@ test("deployment - deploy() - Annotate & label resources", async () => {
|
|||||||
KubernetesManifestUtilityMock.checkManifestStability = jest.fn().mockReturnValue("");
|
KubernetesManifestUtilityMock.checkManifestStability = jest.fn().mockReturnValue("");
|
||||||
const KubernetesObjectUtilityMock = mocked(KubernetesObjectUtility, true);
|
const KubernetesObjectUtilityMock = mocked(KubernetesObjectUtility, true);
|
||||||
KubernetesObjectUtilityMock.getResources = jest.fn().mockReturnValue(resources);
|
KubernetesObjectUtilityMock.getResources = jest.fn().mockReturnValue(resources);
|
||||||
const fileHelperMock = mocked(fileHelper, true);
|
|
||||||
const fsMock = (mocked(fs, true));
|
const fsMock = (mocked(fs, true));
|
||||||
fileHelperMock.getTempDirectory = jest.fn().mockReturnValue("~/Deployment_testapp_currentTimestamp");
|
|
||||||
fsMock.writeFileSync =jest.fn().mockReturnValue("");
|
fsMock.writeFileSync =jest.fn().mockReturnValue("");
|
||||||
jest.spyOn(utility, 'getWorkflowFilePath').mockImplementation(() => Promise.resolve(process.env.GITHUB_WORKFLOW));
|
jest.spyOn(utility, 'getWorkflowFilePath').mockImplementation(() => Promise.resolve(process.env.GITHUB_WORKFLOW));
|
||||||
|
const readFileSpy = jest.spyOn(fs, 'readFileSync').mockImplementation(() => deploymentYaml);
|
||||||
|
|
||||||
const kubeCtl: jest.Mocked<Kubectl> = new Kubectl("") as any;
|
const kubeCtl: jest.Mocked<Kubectl> = new Kubectl("") as any;
|
||||||
kubeCtl.apply = jest.fn().mockReturnValue("");
|
kubeCtl.apply = jest.fn().mockReturnValue("");
|
||||||
@ -318,10 +319,11 @@ test("deployment - deploy() - Annotate & label resources", async () => {
|
|||||||
//Invoke and assert
|
//Invoke and assert
|
||||||
await expect(deployment.deploy(kubeCtl, ['manifests/deployment.yaml'], undefined)).resolves.not.toThrowError();
|
await expect(deployment.deploy(kubeCtl, ['manifests/deployment.yaml'], undefined)).resolves.not.toThrowError();
|
||||||
expect(kubeCtl.annotate).toHaveBeenNthCalledWith(1, 'namespace', 'default', annotationKeyValStr);
|
expect(kubeCtl.annotate).toHaveBeenNthCalledWith(1, 'namespace', 'default', annotationKeyValStr);
|
||||||
expect(kubeCtl.annotateFiles).toBeCalledWith(["~/Deployment_testapp_currentTimestamp/deployment.yaml"], annotationKeyValStr);
|
expect(kubeCtl.annotateFiles).toBeCalledWith(["manifests/deployment.yaml"], annotationKeyValStr);
|
||||||
expect(kubeCtl.annotate).toBeCalledTimes(2);
|
expect(kubeCtl.annotate).toBeCalledTimes(2);
|
||||||
expect(kubeCtl.labelFiles).toBeCalledWith(["~/Deployment_testapp_currentTimestamp/deployment.yaml"],
|
expect(kubeCtl.labelFiles).toBeCalledWith(["manifests/deployment.yaml"],
|
||||||
[`workflowFriendlyName=workflow.yml`, `workflow=${getWorkflowAnnotationKeyLabel(process.env.GITHUB_WORKFLOW)}`]);
|
[`workflowFriendlyName=workflow.yml`, `workflow=${getWorkflowAnnotationKeyLabel(process.env.GITHUB_WORKFLOW)}`]);
|
||||||
|
readFileSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("deployment - deploy() - Annotate & label resources for a new workflow", async () => {
|
test("deployment - deploy() - Annotate & label resources for a new workflow", async () => {
|
||||||
@ -331,11 +333,10 @@ test("deployment - deploy() - Annotate & label resources for a new workflow", as
|
|||||||
KubernetesManifestUtilityMock.checkManifestStability = jest.fn().mockReturnValue("");
|
KubernetesManifestUtilityMock.checkManifestStability = jest.fn().mockReturnValue("");
|
||||||
const KubernetesObjectUtilityMock = mocked(KubernetesObjectUtility, true);
|
const KubernetesObjectUtilityMock = mocked(KubernetesObjectUtility, true);
|
||||||
KubernetesObjectUtilityMock.getResources = jest.fn().mockReturnValue(resources);
|
KubernetesObjectUtilityMock.getResources = jest.fn().mockReturnValue(resources);
|
||||||
const fileHelperMock = mocked(fileHelper, true);
|
|
||||||
const fsMock = (mocked(fs, true));
|
const fsMock = (mocked(fs, true));
|
||||||
fileHelperMock.getTempDirectory = jest.fn().mockReturnValue("~/Deployment_testapp_currentTimestamp");
|
|
||||||
fsMock.writeFileSync =jest.fn().mockReturnValue("");
|
fsMock.writeFileSync =jest.fn().mockReturnValue("");
|
||||||
jest.spyOn(httpClient, 'sendRequest').mockImplementation(() => Promise.resolve(getWorkflowsUrlResponse));
|
jest.spyOn(httpClient, 'sendRequest').mockImplementation(() => Promise.resolve(getWorkflowsUrlResponse));
|
||||||
|
const readFileSpy = jest.spyOn(fs, 'readFileSync').mockImplementation(() => deploymentYaml);
|
||||||
|
|
||||||
const kubeCtl: jest.Mocked<Kubectl> = new Kubectl("") as any;
|
const kubeCtl: jest.Mocked<Kubectl> = new Kubectl("") as any;
|
||||||
kubeCtl.apply = jest.fn().mockReturnValue("");
|
kubeCtl.apply = jest.fn().mockReturnValue("");
|
||||||
@ -348,10 +349,11 @@ test("deployment - deploy() - Annotate & label resources for a new workflow", as
|
|||||||
//Invoke and assert
|
//Invoke and assert
|
||||||
await expect(deployment.deploy(kubeCtl, ['manifests/deployment.yaml'], undefined)).resolves.not.toThrowError();
|
await expect(deployment.deploy(kubeCtl, ['manifests/deployment.yaml'], undefined)).resolves.not.toThrowError();
|
||||||
expect(kubeCtl.annotate).toHaveBeenNthCalledWith(1, 'namespace', 'default', annotationKeyValStr);
|
expect(kubeCtl.annotate).toHaveBeenNthCalledWith(1, 'namespace', 'default', annotationKeyValStr);
|
||||||
expect(kubeCtl.annotateFiles).toBeCalledWith(["~/Deployment_testapp_currentTimestamp/deployment.yaml"], annotationKeyValStr);
|
expect(kubeCtl.annotateFiles).toBeCalledWith(["manifests/deployment.yaml"], annotationKeyValStr);
|
||||||
expect(kubeCtl.annotate).toBeCalledTimes(2);
|
expect(kubeCtl.annotate).toBeCalledTimes(2);
|
||||||
expect(kubeCtl.labelFiles).toBeCalledWith(["~/Deployment_testapp_currentTimestamp/deployment.yaml"],
|
expect(kubeCtl.labelFiles).toBeCalledWith(["manifests/deployment.yaml"],
|
||||||
[`workflowFriendlyName=NewWorkflow.yml`, `workflow=${getWorkflowAnnotationKeyLabel(process.env.GITHUB_WORKFLOW)}`]);
|
[`workflowFriendlyName=NewWorkflow.yml`, `workflow=${getWorkflowAnnotationKeyLabel(process.env.GITHUB_WORKFLOW)}`]);
|
||||||
|
readFileSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("deployment - deploy() - Annotate resources failed", async () => {
|
test("deployment - deploy() - Annotate resources failed", async () => {
|
||||||
|
|||||||
@ -4,7 +4,8 @@ exports.githubToken = exports.forceDeployment = exports.args = exports.baselineA
|
|||||||
const core = require("@actions/core");
|
const core = require("@actions/core");
|
||||||
const utility_1 = require("./utilities/utility");
|
const utility_1 = require("./utilities/utility");
|
||||||
exports.namespace = core.getInput('namespace');
|
exports.namespace = core.getInput('namespace');
|
||||||
exports.containers = core.getInput('images').split('\n');
|
exports.containers = core.getInput('images').split('\n').filter(image => image.trim().length > 0);
|
||||||
|
;
|
||||||
exports.imagePullSecrets = core.getInput('imagepullsecrets').split('\n').filter(secret => secret.trim().length > 0);
|
exports.imagePullSecrets = core.getInput('imagepullsecrets').split('\n').filter(secret => secret.trim().length > 0);
|
||||||
exports.manifests = utility_1.resolveGlobPatterns(core.getInput('manifests'));
|
exports.manifests = utility_1.resolveGlobPatterns(core.getInput('manifests'));
|
||||||
exports.canaryPercentage = core.getInput('percentage');
|
exports.canaryPercentage = core.getInput('percentage');
|
||||||
|
|||||||
@ -9,11 +9,10 @@ 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.getUpdatedManifestFiles = exports.updateImagePullSecrets = exports.substituteImageNameInSpecFile = exports.getDeleteCmdArgs = exports.createKubectlArgs = exports.getKubectl = exports.getManifestFiles = void 0;
|
exports.isWorkloadEntity = exports.getUpdatedManifestFiles = exports.updateImagePullSecrets = exports.getDeleteCmdArgs = exports.createKubectlArgs = exports.getKubectl = exports.getManifestFiles = 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");
|
||||||
const path = require("path");
|
|
||||||
const kubectlutility = require("./kubectl-util");
|
const kubectlutility = require("./kubectl-util");
|
||||||
const io = require("@actions/io");
|
const io = require("@actions/io");
|
||||||
const utility_1 = require("./utility");
|
const utility_1 = require("./utility");
|
||||||
@ -73,30 +72,6 @@ exports.getDeleteCmdArgs = getDeleteCmdArgs;
|
|||||||
This substituteImageNameInSpecFile function would return
|
This substituteImageNameInSpecFile function would return
|
||||||
return Value: `image: "example/example-image:identifiertag"`
|
return Value: `image: "example/example-image:identifiertag"`
|
||||||
*/
|
*/
|
||||||
function substituteImageNameInSpecFile(currentString, imageName, imageNameWithNewTag) {
|
|
||||||
if (currentString.indexOf(imageName) < 0) {
|
|
||||||
core.debug(`No occurence of replacement token: ${imageName} found`);
|
|
||||||
return currentString;
|
|
||||||
}
|
|
||||||
return currentString.split('\n').reduce((acc, line) => {
|
|
||||||
const imageKeyword = line.match(/^ *image:/);
|
|
||||||
if (imageKeyword) {
|
|
||||||
let [currentImageName, currentImageTag] = line
|
|
||||||
.substring(imageKeyword[0].length) // consume the line from keyword onwards
|
|
||||||
.trim()
|
|
||||||
.replace(/[',"]/g, '') // replace allowed quotes with nothing
|
|
||||||
.split(':');
|
|
||||||
if (!currentImageTag && currentImageName.indexOf(' ') > 0) {
|
|
||||||
currentImageName = currentImageName.split(' ')[0]; // Stripping off comments
|
|
||||||
}
|
|
||||||
if (currentImageName === imageName) {
|
|
||||||
return acc + `${imageKeyword[0]} ${imageNameWithNewTag}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return acc + line + '\n';
|
|
||||||
}, '');
|
|
||||||
}
|
|
||||||
exports.substituteImageNameInSpecFile = substituteImageNameInSpecFile;
|
|
||||||
function createInlineArray(str) {
|
function createInlineArray(str) {
|
||||||
if (typeof str === 'string') {
|
if (typeof str === 'string') {
|
||||||
return str;
|
return str;
|
||||||
@ -195,29 +170,6 @@ function substituteImageNameInSpecContent(currentString, imageName, imageNameWit
|
|||||||
return acc + line + '\n';
|
return acc + line + '\n';
|
||||||
}, '');
|
}, '');
|
||||||
}
|
}
|
||||||
function updateContainerImagesInManifestFiles(filePaths, containers) {
|
|
||||||
if (!!containers && containers.length > 0) {
|
|
||||||
const newFilePaths = [];
|
|
||||||
const tempDirectory = fileHelper.getTempDirectory();
|
|
||||||
filePaths.forEach((filePath) => {
|
|
||||||
let contents = fs.readFileSync(filePath).toString();
|
|
||||||
containers.forEach((container) => {
|
|
||||||
let imageName = container.split(':')[0];
|
|
||||||
if (imageName.indexOf('@') > 0) {
|
|
||||||
imageName = imageName.split('@')[0];
|
|
||||||
}
|
|
||||||
if (contents.indexOf(imageName) > 0) {
|
|
||||||
contents = substituteImageNameInSpecFile(contents, imageName, container);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const fileName = path.join(tempDirectory, path.basename(filePath));
|
|
||||||
fs.writeFileSync(path.join(fileName), contents);
|
|
||||||
newFilePaths.push(fileName);
|
|
||||||
});
|
|
||||||
return newFilePaths;
|
|
||||||
}
|
|
||||||
return filePaths;
|
|
||||||
}
|
|
||||||
function updateImagePullSecrets(inputObject, newImagePullSecrets) {
|
function updateImagePullSecrets(inputObject, newImagePullSecrets) {
|
||||||
if (!inputObject || !inputObject.spec || !newImagePullSecrets) {
|
if (!inputObject || !inputObject.spec || !newImagePullSecrets) {
|
||||||
return;
|
return;
|
||||||
@ -237,22 +189,40 @@ function updateImagePullSecrets(inputObject, newImagePullSecrets) {
|
|||||||
setImagePullSecrets(inputObject, existingImagePullSecretObjects);
|
setImagePullSecrets(inputObject, existingImagePullSecretObjects);
|
||||||
}
|
}
|
||||||
exports.updateImagePullSecrets = updateImagePullSecrets;
|
exports.updateImagePullSecrets = updateImagePullSecrets;
|
||||||
function updateImagePullSecretsInManifestFiles(filePaths, imagePullSecrets) {
|
function updateResourceObjects(filePaths, imagePullSecrets, containers) {
|
||||||
if (!!imagePullSecrets && imagePullSecrets.length > 0) {
|
if ((!!imagePullSecrets && imagePullSecrets.length > 0) || (!!containers && containers.length > 0)) {
|
||||||
const newObjectsList = [];
|
let newObjectsList = [];
|
||||||
filePaths.forEach((filePath) => {
|
filePaths.forEach((filePath) => {
|
||||||
const fileContents = fs.readFileSync(filePath).toString();
|
const fileContents = fs.readFileSync(filePath).toString();
|
||||||
yaml.safeLoadAll(fileContents, function (inputObject) {
|
yaml.safeLoadAll(fileContents, function (inputObject) {
|
||||||
if (!!inputObject && !!inputObject.kind) {
|
if (!!inputObject && !!inputObject.kind) {
|
||||||
const kind = inputObject.kind;
|
const kind = inputObject.kind;
|
||||||
if (KubernetesObjectUtility.isWorkloadEntity(kind)) {
|
if (KubernetesObjectUtility.isWorkloadEntity(kind)) {
|
||||||
KubernetesObjectUtility.updateImagePullSecrets(inputObject, imagePullSecrets, false);
|
if (!!imagePullSecrets && imagePullSecrets.length > 0) {
|
||||||
|
KubernetesObjectUtility.updateImagePullSecrets(inputObject, imagePullSecrets, false);
|
||||||
|
}
|
||||||
|
if (!!containers && containers.length > 0) {
|
||||||
|
KubernetesObjectUtility.substituteImageNameInSpecFile(inputObject, containers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (utility_1.isEqual(kind, 'list', true)) {
|
||||||
|
let items = inputObject.items;
|
||||||
|
if (items.length > 0) {
|
||||||
|
items.forEach((item) => {
|
||||||
|
if (!!imagePullSecrets && imagePullSecrets.length > 0) {
|
||||||
|
KubernetesObjectUtility.updateImagePullSecrets(item, imagePullSecrets, false);
|
||||||
|
}
|
||||||
|
if (!!containers && containers.length > 0) {
|
||||||
|
KubernetesObjectUtility.substituteImageNameInSpecFile(item, containers);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
newObjectsList.push(inputObject);
|
newObjectsList.push(inputObject);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
core.debug('New K8s objects after adding imagePullSecrets are :' + JSON.stringify(newObjectsList));
|
core.debug('New K8s objects after adding imagePullSecrets and updating container images are :' + JSON.stringify(newObjectsList));
|
||||||
const newFilePaths = fileHelper.writeObjectsToFile(newObjectsList);
|
const newFilePaths = fileHelper.writeObjectsToFile(newObjectsList);
|
||||||
return newFilePaths;
|
return newFilePaths;
|
||||||
}
|
}
|
||||||
@ -263,10 +233,7 @@ function getUpdatedManifestFiles(manifestFilePaths) {
|
|||||||
if (!inputManifestFiles || inputManifestFiles.length === 0) {
|
if (!inputManifestFiles || inputManifestFiles.length === 0) {
|
||||||
throw new Error(`ManifestFileNotFound : ${manifestFilePaths}`);
|
throw new Error(`ManifestFileNotFound : ${manifestFilePaths}`);
|
||||||
}
|
}
|
||||||
// artifact substitution
|
inputManifestFiles = updateResourceObjects(inputManifestFiles, TaskInputParameters.imagePullSecrets, TaskInputParameters.containers);
|
||||||
inputManifestFiles = updateContainerImagesInManifestFiles(inputManifestFiles, TaskInputParameters.containers);
|
|
||||||
// imagePullSecrets addition
|
|
||||||
inputManifestFiles = updateImagePullSecretsInManifestFiles(inputManifestFiles, TaskInputParameters.imagePullSecrets);
|
|
||||||
return inputManifestFiles;
|
return inputManifestFiles;
|
||||||
}
|
}
|
||||||
exports.getUpdatedManifestFiles = getUpdatedManifestFiles;
|
exports.getUpdatedManifestFiles = getUpdatedManifestFiles;
|
||||||
|
|||||||
@ -1,6 +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.updateImagePullSecrets = exports.updateObjectAnnotations = exports.updateObjectLabels = exports.getReplicaCount = exports.isIngressEntity = exports.isServiceEntity = exports.isWorkloadEntity = exports.isDeploymentEntity = void 0;
|
exports.substituteImageNameInSpecFile = exports.getResources = exports.updateSelectorLabels = exports.updateSpecLabels = exports.updateImagePullSecrets = exports.updateObjectAnnotations = exports.updateObjectLabels = exports.getReplicaCount = exports.isIngressEntity = 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");
|
||||||
@ -195,6 +195,61 @@ function getResources(filePaths, filterResourceTypes) {
|
|||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
exports.getResources = getResources;
|
exports.getResources = getResources;
|
||||||
|
function substituteImageNameInSpecFile(inputObject, containers) {
|
||||||
|
if (!inputObject || !inputObject.spec || !containers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inputObject.spec.template && !!inputObject.spec.template.spec) {
|
||||||
|
if (inputObject.spec.template.spec.containers) {
|
||||||
|
updateContainers(inputObject.spec.template.spec.containers, containers);
|
||||||
|
}
|
||||||
|
if (inputObject.spec.template.spec.initContainers) {
|
||||||
|
updateContainers(inputObject.spec.template.spec.initContainers, containers);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inputObject.spec.jobTemplate && inputObject.spec.jobTemplate.spec && inputObject.spec.jobTemplate.spec.template && inputObject.spec.jobTemplate.spec.template.spec) {
|
||||||
|
if (inputObject.spec.jobTemplate.spec.template.spec.containers) {
|
||||||
|
updateContainers(inputObject.spec.jobTemplate.spec.template.spec.containers, containers);
|
||||||
|
}
|
||||||
|
if (inputObject.spec.jobTemplate.spec.template.spec.initContainers) {
|
||||||
|
updateContainers(inputObject.spec.jobTemplate.spec.template.spec.initContainers, containers);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inputObject.spec.containers) {
|
||||||
|
updateContainers(inputObject.spec.containers, containers);
|
||||||
|
}
|
||||||
|
if (inputObject.spec.initContainers) {
|
||||||
|
updateContainers(inputObject.spec.initContainers, containers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.substituteImageNameInSpecFile = substituteImageNameInSpecFile;
|
||||||
|
function updateContainers(inputContainers, images) {
|
||||||
|
if (!inputContainers || inputContainers.length === 0) {
|
||||||
|
return inputContainers;
|
||||||
|
}
|
||||||
|
inputContainers.forEach((inputContainer) => {
|
||||||
|
const imageName = extractImageName(inputContainer.image.trim());
|
||||||
|
images.forEach(image => {
|
||||||
|
if (extractImageName(image) === imageName) {
|
||||||
|
inputContainer.image = image;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function extractImageName(imageName) {
|
||||||
|
let img = '';
|
||||||
|
if (imageName.indexOf('/') > 0) {
|
||||||
|
const registry = imageName.substring(0, imageName.indexOf('/'));
|
||||||
|
const imgName = imageName.substring(imageName.indexOf('/') + 1).split(':')[0];
|
||||||
|
img = `${registry}/${imgName}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
img = imageName.split(':')[0];
|
||||||
|
}
|
||||||
|
return img;
|
||||||
|
}
|
||||||
function getSpecLabels(inputObject) {
|
function getSpecLabels(inputObject) {
|
||||||
if (!inputObject) {
|
if (!inputObject) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import * as core from '@actions/core';
|
|||||||
import { resolveGlobPatterns } from './utilities/utility';
|
import { resolveGlobPatterns } from './utilities/utility';
|
||||||
|
|
||||||
export let namespace: string = core.getInput('namespace');
|
export let namespace: string = core.getInput('namespace');
|
||||||
export const containers: string[] = core.getInput('images').split('\n');
|
export const containers: string[] = core.getInput('images').split('\n').filter(image => image.trim().length > 0);;
|
||||||
export const imagePullSecrets: string[] = core.getInput('imagepullsecrets').split('\n').filter(secret => secret.trim().length > 0);
|
export const imagePullSecrets: string[] = core.getInput('imagepullsecrets').split('\n').filter(secret => secret.trim().length > 0);
|
||||||
export const manifests = resolveGlobPatterns(core.getInput('manifests'));
|
export const manifests = resolveGlobPatterns(core.getInput('manifests'));
|
||||||
export const canaryPercentage: string = core.getInput('percentage');
|
export const canaryPercentage: string = core.getInput('percentage');
|
||||||
|
|||||||
@ -69,34 +69,6 @@ export function getDeleteCmdArgs(argsPrefix: string, inputArgs: string): string
|
|||||||
return Value: `image: "example/example-image:identifiertag"`
|
return Value: `image: "example/example-image:identifiertag"`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function substituteImageNameInSpecFile(currentString: string, imageName: string, imageNameWithNewTag: string) {
|
|
||||||
if (currentString.indexOf(imageName) < 0) {
|
|
||||||
core.debug(`No occurence of replacement token: ${imageName} found`);
|
|
||||||
return currentString;
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentString.split('\n').reduce((acc, line) => {
|
|
||||||
const imageKeyword = line.match(/^ *image:/);
|
|
||||||
if (imageKeyword) {
|
|
||||||
let [currentImageName, currentImageTag] = line
|
|
||||||
.substring(imageKeyword[0].length) // consume the line from keyword onwards
|
|
||||||
.trim()
|
|
||||||
.replace(/[',"]/g, '') // replace allowed quotes with nothing
|
|
||||||
.split(':');
|
|
||||||
|
|
||||||
if (!currentImageTag && currentImageName.indexOf(' ') > 0) {
|
|
||||||
currentImageName = currentImageName.split(' ')[0]; // Stripping off comments
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentImageName === imageName) {
|
|
||||||
return acc + `${imageKeyword[0]} ${imageNameWithNewTag}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc + line + '\n';
|
|
||||||
}, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function createInlineArray(str: string | string[]): string {
|
function createInlineArray(str: string | string[]): string {
|
||||||
if (typeof str === 'string') { return str; }
|
if (typeof str === 'string') { return str; }
|
||||||
return str.join(',');
|
return str.join(',');
|
||||||
@ -198,36 +170,6 @@ function substituteImageNameInSpecContent(currentString: string, imageName: stri
|
|||||||
}, '');
|
}, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateContainerImagesInManifestFiles(filePaths: string[], containers: string[]): string[] {
|
|
||||||
if (!!containers && containers.length > 0) {
|
|
||||||
const newFilePaths = [];
|
|
||||||
const tempDirectory = fileHelper.getTempDirectory();
|
|
||||||
filePaths.forEach((filePath: string) => {
|
|
||||||
let contents = fs.readFileSync(filePath).toString();
|
|
||||||
containers.forEach((container: string) => {
|
|
||||||
let imageName = container.split(':')[0];
|
|
||||||
if (imageName.indexOf('@') > 0) {
|
|
||||||
imageName = imageName.split('@')[0];
|
|
||||||
}
|
|
||||||
if (contents.indexOf(imageName) > 0) {
|
|
||||||
contents = substituteImageNameInSpecFile(contents, imageName, container);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const fileName = path.join(tempDirectory, path.basename(filePath));
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(fileName),
|
|
||||||
contents
|
|
||||||
);
|
|
||||||
newFilePaths.push(fileName);
|
|
||||||
});
|
|
||||||
|
|
||||||
return newFilePaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
return filePaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateImagePullSecrets(inputObject: any, newImagePullSecrets: string[]) {
|
export function updateImagePullSecrets(inputObject: any, newImagePullSecrets: string[]) {
|
||||||
if (!inputObject || !inputObject.spec || !newImagePullSecrets) {
|
if (!inputObject || !inputObject.spec || !newImagePullSecrets) {
|
||||||
return;
|
return;
|
||||||
@ -248,40 +190,54 @@ export function updateImagePullSecrets(inputObject: any, newImagePullSecrets: st
|
|||||||
setImagePullSecrets(inputObject, existingImagePullSecretObjects);
|
setImagePullSecrets(inputObject, existingImagePullSecretObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateImagePullSecretsInManifestFiles(filePaths: string[], imagePullSecrets: string[]): string[] {
|
function updateResourceObjects(filePaths: string[], imagePullSecrets: string[], containers: string[]): string[] {
|
||||||
if (!!imagePullSecrets && imagePullSecrets.length > 0) {
|
if ((!!imagePullSecrets && imagePullSecrets.length > 0) || (!!containers && containers.length > 0)) {
|
||||||
const newObjectsList = [];
|
let newObjectsList = [];
|
||||||
filePaths.forEach((filePath: string) => {
|
filePaths.forEach((filePath: string) => {
|
||||||
const fileContents = fs.readFileSync(filePath).toString();
|
const fileContents = fs.readFileSync(filePath).toString();
|
||||||
yaml.safeLoadAll(fileContents, function (inputObject: any) {
|
yaml.safeLoadAll(fileContents, function (inputObject: any) {
|
||||||
if (!!inputObject && !!inputObject.kind) {
|
if (!!inputObject && !!inputObject.kind) {
|
||||||
const kind = inputObject.kind;
|
const kind = inputObject.kind;
|
||||||
if (KubernetesObjectUtility.isWorkloadEntity(kind)) {
|
if (KubernetesObjectUtility.isWorkloadEntity(kind)) {
|
||||||
KubernetesObjectUtility.updateImagePullSecrets(inputObject, imagePullSecrets, false);
|
if (!!imagePullSecrets && imagePullSecrets.length > 0) {
|
||||||
|
KubernetesObjectUtility.updateImagePullSecrets(inputObject, imagePullSecrets, false);
|
||||||
|
}
|
||||||
|
if (!!containers && containers.length > 0) {
|
||||||
|
KubernetesObjectUtility.substituteImageNameInSpecFile(inputObject, containers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isEqual(kind, 'list', true)) {
|
||||||
|
let items = inputObject.items;
|
||||||
|
if (items.length > 0) {
|
||||||
|
items.forEach((item) => {
|
||||||
|
if (!!imagePullSecrets && imagePullSecrets.length > 0) {
|
||||||
|
KubernetesObjectUtility.updateImagePullSecrets(item, imagePullSecrets, false);
|
||||||
|
}
|
||||||
|
if (!!containers && containers.length > 0) {
|
||||||
|
KubernetesObjectUtility.substituteImageNameInSpecFile(item, containers);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
newObjectsList.push(inputObject);
|
newObjectsList.push(inputObject);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
core.debug('New K8s objects after adding imagePullSecrets are :' + JSON.stringify(newObjectsList));
|
core.debug('New K8s objects after adding imagePullSecrets and updating container images are :' + JSON.stringify(newObjectsList));
|
||||||
const newFilePaths = fileHelper.writeObjectsToFile(newObjectsList);
|
const newFilePaths = fileHelper.writeObjectsToFile(newObjectsList);
|
||||||
return newFilePaths;
|
return newFilePaths;
|
||||||
}
|
}
|
||||||
return filePaths;
|
return filePaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUpdatedManifestFiles (manifestFilePaths: string[]) {
|
export function getUpdatedManifestFiles(manifestFilePaths: string[]) {
|
||||||
let inputManifestFiles: string[] = getManifestFiles(manifestFilePaths);
|
let inputManifestFiles: string[] = getManifestFiles(manifestFilePaths);
|
||||||
|
|
||||||
if (!inputManifestFiles || inputManifestFiles.length === 0) {
|
if (!inputManifestFiles || inputManifestFiles.length === 0) {
|
||||||
throw new Error(`ManifestFileNotFound : ${manifestFilePaths}`);
|
throw new Error(`ManifestFileNotFound : ${manifestFilePaths}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// artifact substitution
|
inputManifestFiles = updateResourceObjects(inputManifestFiles, TaskInputParameters.imagePullSecrets, TaskInputParameters.containers);
|
||||||
inputManifestFiles = updateContainerImagesInManifestFiles(inputManifestFiles, TaskInputParameters.containers);
|
|
||||||
|
|
||||||
// imagePullSecrets addition
|
|
||||||
inputManifestFiles = updateImagePullSecretsInManifestFiles(inputManifestFiles, TaskInputParameters.imagePullSecrets);
|
|
||||||
|
|
||||||
return inputManifestFiles;
|
return inputManifestFiles;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -226,6 +226,67 @@ export function getResources(filePaths: string[], filterResourceTypes: string[])
|
|||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function substituteImageNameInSpecFile(inputObject: any, containers: string[]) {
|
||||||
|
if (!inputObject || !inputObject.spec || !containers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputObject.spec.template && !!inputObject.spec.template.spec) {
|
||||||
|
if (inputObject.spec.template.spec.containers) {
|
||||||
|
updateContainers(inputObject.spec.template.spec.containers, containers);
|
||||||
|
}
|
||||||
|
if (inputObject.spec.template.spec.initContainers) {
|
||||||
|
updateContainers(inputObject.spec.template.spec.initContainers, containers);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputObject.spec.jobTemplate && inputObject.spec.jobTemplate.spec && inputObject.spec.jobTemplate.spec.template && inputObject.spec.jobTemplate.spec.template.spec) {
|
||||||
|
if (inputObject.spec.jobTemplate.spec.template.spec.containers) {
|
||||||
|
updateContainers(inputObject.spec.jobTemplate.spec.template.spec.containers, containers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputObject.spec.jobTemplate.spec.template.spec.initContainers) {
|
||||||
|
updateContainers(inputObject.spec.jobTemplate.spec.template.spec.initContainers, containers);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputObject.spec.containers) {
|
||||||
|
updateContainers(inputObject.spec.containers, containers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputObject.spec.initContainers) {
|
||||||
|
updateContainers(inputObject.spec.initContainers, containers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateContainers(inputContainers: any[], images: string[]) {
|
||||||
|
if (!inputContainers || inputContainers.length === 0) {
|
||||||
|
return inputContainers;
|
||||||
|
}
|
||||||
|
inputContainers.forEach((inputContainer) => {
|
||||||
|
const imageName: string = extractImageName(inputContainer.image.trim());
|
||||||
|
images.forEach(image => {
|
||||||
|
if (extractImageName(image) === imageName) {
|
||||||
|
inputContainer.image = image;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractImageName(imageName) {
|
||||||
|
let img = '';
|
||||||
|
if (imageName.indexOf('/') > 0) {
|
||||||
|
const registry = imageName.substring(0, imageName.indexOf('/'));
|
||||||
|
const imgName = imageName.substring(imageName.indexOf('/') + 1).split(':')[0];
|
||||||
|
img = `${registry}/${imgName}`;
|
||||||
|
} else {
|
||||||
|
img = imageName.split(':')[0];
|
||||||
|
}
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
function getSpecLabels(inputObject: any) {
|
function getSpecLabels(inputObject: any) {
|
||||||
|
|
||||||
if (!inputObject) {
|
if (!inputObject) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user