mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-06-22 03:09:27 +08:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff21bd2d58 | |||
| 172f1e16bd | |||
| e52890db9e | |||
| dd4bbd13a5 | |||
| ecb488266d | |||
| 756cc0a511 | |||
| dcaec012e2 | |||
| 7dae909398 | |||
| e8a841df59 | |||
| da1e907ad7 | |||
| 8ce7d1dcdd | |||
| b9a9965750 | |||
| 47445fb82f | |||
| c875a14bde | |||
| 58ba3f0665 | |||
| e9693a7cdd | |||
| a6cfc31f7a | |||
| e917b5a666 | |||
| 57d0489e1f | |||
| d64c205796 | |||
| c8f050230d | |||
| a0b037b13e | |||
| 7fd0e52a8b | |||
| 659bbb3802 | |||
| 3c0579b484 | |||
| b11eda66ea | |||
| c117b29f9e | |||
| 01a65512ea | |||
| 531cfdcc3d | |||
| 0b5795551a | |||
| bb0278db72 | |||
| 71e93a71d4 | |||
| 19d66d6bdb | |||
| 72a09f4051 | |||
| a17f35ba63 | |||
| 7b11ddb1d5 | |||
| ecec5912ba | |||
| dcd9bc6b1a | |||
| 976c5c4981 |
@@ -13,20 +13,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# We must fetch at least the immediate parents so that if this is
|
# We must fetch at least the immediate parents so that if this is
|
||||||
# a pull request then we can checkout the head.
|
# a pull request then we can checkout the head.
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
# If this run was triggered by a pull request event, then checkout
|
|
||||||
# the head of the pull request instead of the merge commit.
|
|
||||||
- run: git checkout HEAD^2
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
# Override language selection by uncommenting this and choosing your languages
|
# Override language selection by uncommenting this and choosing your languages
|
||||||
# with:
|
# with:
|
||||||
# languages: go, javascript, csharp, python, cpp, java
|
# languages: go, javascript, csharp, python, cpp, java
|
||||||
@@ -34,7 +29,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@@ -48,4 +43,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ on: # rebuild any PRs and main branch changes
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build: # make sure build/ci works properly
|
build: # make sure build/ci works properly
|
||||||
|
name: Run Unit Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
- run: |
|
- run: |
|
||||||
npm install
|
npm install
|
||||||
npm test
|
npm test
|
||||||
|
|||||||
+102
-86
@@ -20210,7 +20210,7 @@ function deploy(kubectl, manifestFilePaths, deploymentStrategy) {
|
|||||||
KubernetesConstants.DiscoveryAndLoadBalancerResource.INGRESS
|
KubernetesConstants.DiscoveryAndLoadBalancerResource.INGRESS
|
||||||
]);
|
]);
|
||||||
for (const ingressResource of ingressResources) {
|
for (const ingressResource of ingressResources) {
|
||||||
yield kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.INGRESS, ingressResource.name);
|
yield kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.INGRESS, ingressResource.name, false, ingressResource.namespace);
|
||||||
}
|
}
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
// annotate resources
|
// annotate resources
|
||||||
@@ -20593,7 +20593,8 @@ function deleteGreenObjects(kubectl, toDelete) {
|
|||||||
const resourcesToDelete = toDelete.map((obj) => {
|
const resourcesToDelete = toDelete.map((obj) => {
|
||||||
return {
|
return {
|
||||||
name: getBlueGreenResourceName(obj.metadata.name, exports.GREEN_SUFFIX),
|
name: getBlueGreenResourceName(obj.metadata.name, exports.GREEN_SUFFIX),
|
||||||
kind: obj.kind
|
kind: obj.kind,
|
||||||
|
namespace: obj.metadata.namespace
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
core.debug(`deleting green objects: ${JSON.stringify(resourcesToDelete)}`);
|
core.debug(`deleting green objects: ${JSON.stringify(resourcesToDelete)}`);
|
||||||
@@ -20620,28 +20621,24 @@ exports.deleteObjects = deleteObjects;
|
|||||||
// other common functions
|
// other common functions
|
||||||
function getManifestObjects(filePaths) {
|
function getManifestObjects(filePaths) {
|
||||||
const deploymentEntityList = [];
|
const deploymentEntityList = [];
|
||||||
|
const serviceEntityList = [];
|
||||||
const routedServiceEntityList = [];
|
const routedServiceEntityList = [];
|
||||||
const unroutedServiceEntityList = [];
|
const unroutedServiceEntityList = [];
|
||||||
const ingressEntityList = [];
|
const ingressEntityList = [];
|
||||||
const otherEntitiesList = [];
|
const otherEntitiesList = [];
|
||||||
const serviceNameMap = new Map();
|
const serviceNameMap = new Map();
|
||||||
|
// Manifest objects per type. All resources should be parsed and
|
||||||
|
// organized before we can check if services are “routed” or not.
|
||||||
filePaths.forEach((filePath) => {
|
filePaths.forEach((filePath) => {
|
||||||
const fileContents = fs.readFileSync(filePath).toString();
|
const fileContents = fs.readFileSync(filePath).toString();
|
||||||
yaml.safeLoadAll(fileContents, (inputObject) => {
|
yaml.safeLoadAll(fileContents, (inputObject) => {
|
||||||
if (!!inputObject) {
|
if (!!inputObject) {
|
||||||
const kind = inputObject.kind;
|
const kind = inputObject.kind;
|
||||||
const name = inputObject.metadata.name;
|
|
||||||
if (kubernetesTypes_1.isDeploymentEntity(kind)) {
|
if (kubernetesTypes_1.isDeploymentEntity(kind)) {
|
||||||
deploymentEntityList.push(inputObject);
|
deploymentEntityList.push(inputObject);
|
||||||
}
|
}
|
||||||
else if (kubernetesTypes_1.isServiceEntity(kind)) {
|
else if (kubernetesTypes_1.isServiceEntity(kind)) {
|
||||||
if (isServiceRouted(inputObject, deploymentEntityList)) {
|
serviceEntityList.push(inputObject);
|
||||||
routedServiceEntityList.push(inputObject);
|
|
||||||
serviceNameMap.set(name, getBlueGreenResourceName(name, exports.GREEN_SUFFIX));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unroutedServiceEntityList.push(inputObject);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (kubernetesTypes_1.isIngressEntity(kind)) {
|
else if (kubernetesTypes_1.isIngressEntity(kind)) {
|
||||||
ingressEntityList.push(inputObject);
|
ingressEntityList.push(inputObject);
|
||||||
@@ -20652,6 +20649,16 @@ function getManifestObjects(filePaths) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
serviceEntityList.forEach((inputObject) => {
|
||||||
|
if (isServiceRouted(inputObject, deploymentEntityList)) {
|
||||||
|
const name = inputObject.metadata.name;
|
||||||
|
routedServiceEntityList.push(inputObject);
|
||||||
|
serviceNameMap.set(name, getBlueGreenResourceName(name, exports.GREEN_SUFFIX));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unroutedServiceEntityList.push(inputObject);
|
||||||
|
}
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
serviceEntityList: routedServiceEntityList,
|
serviceEntityList: routedServiceEntityList,
|
||||||
serviceNameMap: serviceNameMap,
|
serviceNameMap: serviceNameMap,
|
||||||
@@ -20746,9 +20753,9 @@ function isServiceSelectorSubsetOfMatchLabel(serviceSelector, matchLabels) {
|
|||||||
return isMatch;
|
return isMatch;
|
||||||
}
|
}
|
||||||
exports.isServiceSelectorSubsetOfMatchLabel = isServiceSelectorSubsetOfMatchLabel;
|
exports.isServiceSelectorSubsetOfMatchLabel = isServiceSelectorSubsetOfMatchLabel;
|
||||||
function fetchResource(kubectl, kind, name) {
|
function fetchResource(kubectl, kind, name, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const result = yield kubectl.getResource(kind, name);
|
const result = yield kubectl.getResource(kind, name, false, namespace);
|
||||||
if (result == null || !!result.stderr) {
|
if (result == null || !!result.stderr) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -20948,16 +20955,16 @@ function isIngressRouted(ingressObject, serviceNameMap) {
|
|||||||
}
|
}
|
||||||
exports.isIngressRouted = isIngressRouted;
|
exports.isIngressRouted = isIngressRouted;
|
||||||
function validateIngresses(kubectl, ingressEntityList, serviceNameMap) {
|
function validateIngresses(kubectl, ingressEntityList, serviceNameMap) {
|
||||||
var _a;
|
var _a, _b;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let areValid = true;
|
let areValid = true;
|
||||||
const invalidIngresses = [];
|
const invalidIngresses = [];
|
||||||
for (const inputObject of ingressEntityList) {
|
for (const inputObject of ingressEntityList) {
|
||||||
if (isIngressRouted(inputObject, serviceNameMap)) {
|
if (isIngressRouted(inputObject, serviceNameMap)) {
|
||||||
//querying existing ingress
|
//querying existing ingress
|
||||||
const existingIngress = yield blueGreenHelper_1.fetchResource(kubectl, inputObject.kind, inputObject.metadata.name);
|
const existingIngress = yield blueGreenHelper_1.fetchResource(kubectl, inputObject.kind, inputObject.metadata.name, (_a = inputObject === null || inputObject === void 0 ? void 0 : inputObject.metadata) === null || _a === void 0 ? void 0 : _a.namespace);
|
||||||
const isValid = !!existingIngress &&
|
const isValid = !!existingIngress &&
|
||||||
((_a = existingIngress === null || existingIngress === void 0 ? void 0 : existingIngress.metadata) === null || _a === void 0 ? void 0 : _a.labels[blueGreenHelper_1.BLUE_GREEN_VERSION_LABEL]) ===
|
((_b = existingIngress === null || existingIngress === void 0 ? void 0 : existingIngress.metadata) === null || _b === void 0 ? void 0 : _b.labels[blueGreenHelper_1.BLUE_GREEN_VERSION_LABEL]) ===
|
||||||
blueGreenHelper_1.GREEN_LABEL_VALUE;
|
blueGreenHelper_1.GREEN_LABEL_VALUE;
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
core.debug(`Invalid ingress detected (must be in green state): ${JSON.stringify(inputObject)}`);
|
core.debug(`Invalid ingress detected (must be in green state): ${JSON.stringify(inputObject)}`);
|
||||||
@@ -21215,11 +21222,12 @@ function getUpdatedBlueGreenService(inputObject, labelValue) {
|
|||||||
}
|
}
|
||||||
exports.getUpdatedBlueGreenService = getUpdatedBlueGreenService;
|
exports.getUpdatedBlueGreenService = getUpdatedBlueGreenService;
|
||||||
function validateServicesState(kubectl, serviceEntityList) {
|
function validateServicesState(kubectl, serviceEntityList) {
|
||||||
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let areServicesGreen = true;
|
let areServicesGreen = true;
|
||||||
for (const serviceObject of serviceEntityList) {
|
for (const serviceObject of serviceEntityList) {
|
||||||
// finding the existing routed service
|
// finding the existing routed service
|
||||||
const existingService = yield blueGreenHelper_1.fetchResource(kubectl, serviceObject.kind, serviceObject.metadata.name);
|
const existingService = yield blueGreenHelper_1.fetchResource(kubectl, serviceObject.kind, serviceObject.metadata.name, (_a = serviceObject === null || serviceObject === void 0 ? void 0 : serviceObject.metadata) === null || _a === void 0 ? void 0 : _a.namespace);
|
||||||
let isServiceGreen = !!existingService &&
|
let isServiceGreen = !!existingService &&
|
||||||
getServiceSpecLabel(existingService) ==
|
getServiceSpecLabel(existingService) ==
|
||||||
blueGreenHelper_1.GREEN_LABEL_VALUE;
|
blueGreenHelper_1.GREEN_LABEL_VALUE;
|
||||||
@@ -21340,11 +21348,12 @@ function getGreenSMIServiceResource(inputObject) {
|
|||||||
}
|
}
|
||||||
exports.getGreenSMIServiceResource = getGreenSMIServiceResource;
|
exports.getGreenSMIServiceResource = getGreenSMIServiceResource;
|
||||||
function validateTrafficSplitsState(kubectl, serviceEntityList) {
|
function validateTrafficSplitsState(kubectl, serviceEntityList) {
|
||||||
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let trafficSplitsInRightState = true;
|
let trafficSplitsInRightState = true;
|
||||||
for (const serviceObject of serviceEntityList) {
|
for (const serviceObject of serviceEntityList) {
|
||||||
const name = serviceObject.metadata.name;
|
const name = serviceObject.metadata.name;
|
||||||
let trafficSplitObject = yield blueGreenHelper_1.fetchResource(kubectl, exports.TRAFFIC_SPLIT_OBJECT, blueGreenHelper_1.getBlueGreenResourceName(name, exports.TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX));
|
let trafficSplitObject = yield blueGreenHelper_1.fetchResource(kubectl, exports.TRAFFIC_SPLIT_OBJECT, blueGreenHelper_1.getBlueGreenResourceName(name, exports.TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX), (_a = serviceObject === null || serviceObject === void 0 ? void 0 : serviceObject.metadata) === null || _a === void 0 ? void 0 : _a.namespace);
|
||||||
core.debug(`ts object extracted was ${JSON.stringify(trafficSplitObject)}`);
|
core.debug(`ts object extracted was ${JSON.stringify(trafficSplitObject)}`);
|
||||||
if (!trafficSplitObject) {
|
if (!trafficSplitObject) {
|
||||||
core.debug(`no traffic split exits for ${name}`);
|
core.debug(`no traffic split exits for ${name}`);
|
||||||
@@ -21371,9 +21380,11 @@ function cleanupSMI(kubectl, serviceEntityList) {
|
|||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const deleteList = [];
|
const deleteList = [];
|
||||||
serviceEntityList.forEach((serviceObject) => {
|
serviceEntityList.forEach((serviceObject) => {
|
||||||
|
var _a;
|
||||||
deleteList.push({
|
deleteList.push({
|
||||||
name: blueGreenHelper_1.getBlueGreenResourceName(serviceObject.metadata.name, blueGreenHelper_1.GREEN_SUFFIX),
|
name: blueGreenHelper_1.getBlueGreenResourceName(serviceObject.metadata.name, blueGreenHelper_1.GREEN_SUFFIX),
|
||||||
kind: serviceObject.kind
|
kind: serviceObject.kind,
|
||||||
|
namespace: (_a = serviceObject === null || serviceObject === void 0 ? void 0 : serviceObject.metadata) === null || _a === void 0 ? void 0 : _a.namespace
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// delete all objects
|
// delete all objects
|
||||||
@@ -21537,11 +21548,12 @@ function addCanaryLabelsAndAnnotations(inputObject, type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function cleanUpCanary(kubectl, files, includeServices) {
|
function cleanUpCanary(kubectl, files, includeServices) {
|
||||||
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const deleteObject = function (kind, name) {
|
const deleteObject = function (kind, name, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
const result = yield kubectl.delete([kind, name]);
|
const result = yield kubectl.delete([kind, name], namespace);
|
||||||
kubectlUtils_1.checkForErrors([result]);
|
kubectlUtils_1.checkForErrors([result]);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
@@ -21556,13 +21568,14 @@ function cleanUpCanary(kubectl, files, includeServices) {
|
|||||||
for (const inputObject of parsedYaml) {
|
for (const inputObject of parsedYaml) {
|
||||||
const name = inputObject.metadata.name;
|
const name = inputObject.metadata.name;
|
||||||
const kind = inputObject.kind;
|
const kind = inputObject.kind;
|
||||||
|
const namespace = (_a = inputObject === null || inputObject === void 0 ? void 0 : inputObject.metadata) === null || _a === void 0 ? void 0 : _a.namespace;
|
||||||
if (kubernetesTypes_1.isDeploymentEntity(kind) ||
|
if (kubernetesTypes_1.isDeploymentEntity(kind) ||
|
||||||
(includeServices && kubernetesTypes_1.isServiceEntity(kind))) {
|
(includeServices && kubernetesTypes_1.isServiceEntity(kind))) {
|
||||||
deletedFiles.push(filePath);
|
deletedFiles.push(filePath);
|
||||||
const canaryObjectName = getCanaryResourceName(name);
|
const canaryObjectName = getCanaryResourceName(name);
|
||||||
const baselineObjectName = getBaselineResourceName(name);
|
const baselineObjectName = getBaselineResourceName(name);
|
||||||
yield deleteObject(kind, canaryObjectName);
|
yield deleteObject(kind, canaryObjectName, namespace);
|
||||||
yield deleteObject(kind, baselineObjectName);
|
yield deleteObject(kind, baselineObjectName, namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22053,7 +22066,7 @@ function annotateResources(files, kubectl, resourceTypes, allPods, annotationKey
|
|||||||
const annotationKeyValStr = `${annotationKey}=${workflowAnnotationUtils_1.getWorkflowAnnotations(lastSuccessSha, workflowFilePath, deploymentConfig)}`;
|
const annotationKeyValStr = `${annotationKey}=${workflowAnnotationUtils_1.getWorkflowAnnotations(lastSuccessSha, workflowFilePath, deploymentConfig)}`;
|
||||||
const annotateNamespace = !(core.getInput('annotate-namespace').toLowerCase() === 'false');
|
const annotateNamespace = !(core.getInput('annotate-namespace').toLowerCase() === 'false');
|
||||||
if (annotateNamespace) {
|
if (annotateNamespace) {
|
||||||
annotateResults.push(yield kubectl.annotate('namespace', namespace, annotationKeyValStr));
|
annotateResults.push(yield kubectl.annotate('namespace', namespace, annotationKeyValStr, namespace));
|
||||||
}
|
}
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
try {
|
try {
|
||||||
@@ -22068,7 +22081,7 @@ function annotateResources(files, kubectl, resourceTypes, allPods, annotationKey
|
|||||||
if (resource.type.toLowerCase() !==
|
if (resource.type.toLowerCase() !==
|
||||||
models.KubernetesWorkload.POD.toLowerCase()) {
|
models.KubernetesWorkload.POD.toLowerCase()) {
|
||||||
;
|
;
|
||||||
(yield kubectlUtils_1.annotateChildPods(kubectl, resource.type, resource.name, annotationKeyValStr, allPods)).forEach((execResult) => annotateResults.push(execResult));
|
(yield kubectlUtils_1.annotateChildPods(kubectl, resource.type, resource.name, resource.namespace, annotationKeyValStr, allPods)).forEach((execResult) => annotateResults.push(execResult));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kubectlUtils_1.checkForErrors(annotateResults, true);
|
kubectlUtils_1.checkForErrors(annotateResults, true);
|
||||||
@@ -22331,7 +22344,7 @@ const core = __nccwpck_require__(6024);
|
|||||||
const toolCache = __nccwpck_require__(3594);
|
const toolCache = __nccwpck_require__(3594);
|
||||||
const io = __nccwpck_require__(6202);
|
const io = __nccwpck_require__(6202);
|
||||||
class Kubectl {
|
class Kubectl {
|
||||||
constructor(kubectlPath, namespace = 'default', ignoreSSLErrors = false, resourceGroup = '', name = '') {
|
constructor(kubectlPath, namespace = '', ignoreSSLErrors = false, resourceGroup = '', name = '') {
|
||||||
this.kubectlPath = kubectlPath;
|
this.kubectlPath = kubectlPath;
|
||||||
this.ignoreSSLErrors = !!ignoreSSLErrors;
|
this.ignoreSSLErrors = !!ignoreSSLErrors;
|
||||||
this.namespace = namespace;
|
this.namespace = namespace;
|
||||||
@@ -22350,21 +22363,21 @@ class Kubectl {
|
|||||||
];
|
];
|
||||||
if (force)
|
if (force)
|
||||||
applyArgs.push('--force');
|
applyArgs.push('--force');
|
||||||
return yield this.execute(applyArgs);
|
return yield this.execute(applyArgs.concat(this.getFlags()));
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
core.debug('Kubectl apply failed:' + err);
|
core.debug('Kubectl apply failed:' + err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
describe(resourceType, resourceName, silent = false) {
|
describe(resourceType, resourceName, silent = false, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
return yield this.execute(['describe', resourceType, resourceName], silent);
|
return yield this.execute(['describe', resourceType, resourceName].concat(this.getFlags(namespace)), silent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getNewReplicaSet(deployment) {
|
getNewReplicaSet(deployment, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const result = yield this.describe('deployment', deployment, true);
|
const result = yield this.describe('deployment', deployment, true, namespace);
|
||||||
let newReplicaSet = '';
|
let newReplicaSet = '';
|
||||||
if (result === null || result === void 0 ? void 0 : result.stdout) {
|
if (result === null || result === void 0 ? void 0 : result.stdout) {
|
||||||
const stdout = result.stdout.split('\n');
|
const stdout = result.stdout.split('\n');
|
||||||
@@ -22384,7 +22397,7 @@ class Kubectl {
|
|||||||
return newReplicaSet;
|
return newReplicaSet;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
annotate(resourceType, resourceName, annotation) {
|
annotate(resourceType, resourceName, annotation, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const args = [
|
const args = [
|
||||||
'annotate',
|
'annotate',
|
||||||
@@ -22392,11 +22405,11 @@ class Kubectl {
|
|||||||
resourceName,
|
resourceName,
|
||||||
annotation,
|
annotation,
|
||||||
'--overwrite'
|
'--overwrite'
|
||||||
];
|
].concat(this.getFlags(namespace));
|
||||||
return yield this.execute(args);
|
return yield this.execute(args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
annotateFiles(files, annotation) {
|
annotateFiles(files, annotation, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const filesToAnnotate = arrayUtils_1.createInlineArray(files);
|
const filesToAnnotate = arrayUtils_1.createInlineArray(files);
|
||||||
core.debug(`annotating ${filesToAnnotate} with annotation ${annotation}`);
|
core.debug(`annotating ${filesToAnnotate} with annotation ${annotation}`);
|
||||||
@@ -22406,12 +22419,11 @@ class Kubectl {
|
|||||||
filesToAnnotate,
|
filesToAnnotate,
|
||||||
annotation,
|
annotation,
|
||||||
'--overwrite'
|
'--overwrite'
|
||||||
];
|
].concat(this.getFlags(namespace));
|
||||||
core.debug(`sending args from annotate to execute: ${JSON.stringify(args)}`);
|
|
||||||
return yield this.execute(args);
|
return yield this.execute(args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
labelFiles(files, labels) {
|
labelFiles(files, labels, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const args = [
|
const args = [
|
||||||
'label',
|
'label',
|
||||||
@@ -22419,56 +22431,53 @@ class Kubectl {
|
|||||||
arrayUtils_1.createInlineArray(files),
|
arrayUtils_1.createInlineArray(files),
|
||||||
...labels,
|
...labels,
|
||||||
'--overwrite'
|
'--overwrite'
|
||||||
];
|
].concat(this.getFlags(namespace));
|
||||||
return yield this.execute(args);
|
return yield this.execute(args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getAllPods() {
|
getAllPods() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
return yield this.execute(['get', 'pods', '-o', 'json'], true);
|
return yield this.execute(['get', 'pods', '-o', 'json'].concat(this.getFlags()), true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
checkRolloutStatus(resourceType, name) {
|
checkRolloutStatus(resourceType, name, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
return yield this.execute([
|
return yield this.execute(['rollout', 'status', `${resourceType}/${name}`].concat(this.getFlags(namespace)));
|
||||||
'rollout',
|
|
||||||
'status',
|
|
||||||
`${resourceType}/${name}`
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getResource(resourceType, name, silentFailure = false) {
|
getResource(resourceType, name, silentFailure = false, namespace) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
core.debug('fetching resource of type ' + resourceType + ' and name ' + name);
|
core.debug('fetching resource of type ' + resourceType + ' and name ' + name);
|
||||||
return yield this.execute(['get', `${resourceType}/${name}`, '-o', 'json'], silentFailure);
|
return yield this.execute(['get', `${resourceType}/${name}`, '-o', 'json'].concat(this.getFlags(namespace)), silentFailure);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
executeCommand(command, args) {
|
executeCommand(command, args) {
|
||||||
if (!command)
|
if (!command)
|
||||||
throw new Error('Command must be defined');
|
throw new Error('Command must be defined');
|
||||||
return args ? this.execute([command, args]) : this.execute([command]);
|
const a = args ? [args] : [];
|
||||||
|
return this.execute([command, ...a.concat(this.getFlags())]);
|
||||||
}
|
}
|
||||||
delete(args) {
|
delete(args, namespace) {
|
||||||
if (typeof args === 'string')
|
if (typeof args === 'string')
|
||||||
return this.execute(['delete', args]);
|
return this.execute(['delete', args].concat(this.getFlags(namespace)));
|
||||||
return this.execute(['delete', ...args]);
|
return this.execute(['delete', ...args.concat(this.getFlags(namespace))]);
|
||||||
}
|
}
|
||||||
execute(args, silent = false) {
|
execute(args, silent = false) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
args = args.concat(this.getExecuteFlags());
|
|
||||||
core.debug(`Kubectl run with command: ${this.kubectlPath} ${args}`);
|
core.debug(`Kubectl run with command: ${this.kubectlPath} ${args}`);
|
||||||
return yield exec_1.getExecOutput(this.kubectlPath, args, {
|
return yield exec_1.getExecOutput(this.kubectlPath, args, {
|
||||||
silent
|
silent
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getExecuteFlags() {
|
getFlags(namespaceOverride) {
|
||||||
const flags = [];
|
const flags = [];
|
||||||
if (this.ignoreSSLErrors) {
|
if (this.ignoreSSLErrors) {
|
||||||
flags.push('--insecure-skip-tls-verify');
|
flags.push('--insecure-skip-tls-verify');
|
||||||
}
|
}
|
||||||
if (this.namespace) {
|
const ns = namespaceOverride || this.namespace;
|
||||||
flags.push('--namespace', this.namespace);
|
if (ns) {
|
||||||
|
flags.push('--namespace', ns);
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
@@ -22599,7 +22608,6 @@ const path = __nccwpck_require__(1017);
|
|||||||
class PrivateKubectl extends kubectl_1.Kubectl {
|
class PrivateKubectl extends kubectl_1.Kubectl {
|
||||||
execute(args, silent = false) {
|
execute(args, silent = false) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
args = args.concat(this.getExecuteFlags());
|
|
||||||
args.unshift('kubectl');
|
args.unshift('kubectl');
|
||||||
let kubectlCmd = args.join(' ');
|
let kubectlCmd = args.join(' ');
|
||||||
let addFileFlag = false;
|
let addFileFlag = false;
|
||||||
@@ -22649,10 +22657,13 @@ class PrivateKubectl extends kubectl_1.Kubectl {
|
|||||||
core.debug(`full form of az command: az ${allArgs.join(' ')}`);
|
core.debug(`full form of az command: az ${allArgs.join(' ')}`);
|
||||||
const runOutput = yield exec_1.getExecOutput('az', allArgs, eo);
|
const runOutput = yield exec_1.getExecOutput('az', allArgs, eo);
|
||||||
core.debug(`from kubectl private cluster command got run output ${JSON.stringify(runOutput)}`);
|
core.debug(`from kubectl private cluster command got run output ${JSON.stringify(runOutput)}`);
|
||||||
|
if (runOutput.exitCode !== 0) {
|
||||||
|
throw Error(`Call to private cluster failed. Command: '${kubectlCmd}', errormessage: ${runOutput.stderr}`);
|
||||||
|
}
|
||||||
const runObj = JSON.parse(runOutput.stdout);
|
const runObj = JSON.parse(runOutput.stdout);
|
||||||
if (!silent)
|
if (!silent)
|
||||||
core.info(runObj.logs);
|
core.info(runObj.logs);
|
||||||
if (runOutput.exitCode !== 0 && runObj.exitCode !== 0) {
|
if (runObj.exitCode !== 0) {
|
||||||
throw Error(`failed private cluster Kubectl command: ${kubectlCmd}`);
|
throw Error(`failed private cluster Kubectl command: ${kubectlCmd}`);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -23160,6 +23171,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.annotateChildPods = exports.getLastSuccessfulRunSha = exports.checkForErrors = void 0;
|
exports.annotateChildPods = exports.getLastSuccessfulRunSha = exports.checkForErrors = void 0;
|
||||||
const core = __nccwpck_require__(6024);
|
const core = __nccwpck_require__(6024);
|
||||||
|
const NAMESPACE = 'namespace';
|
||||||
function checkForErrors(execResults, warnIfError) {
|
function checkForErrors(execResults, warnIfError) {
|
||||||
let stderr = '';
|
let stderr = '';
|
||||||
execResults.forEach((result) => {
|
execResults.forEach((result) => {
|
||||||
@@ -23183,7 +23195,7 @@ exports.checkForErrors = checkForErrors;
|
|||||||
function getLastSuccessfulRunSha(kubectl, namespaceName, annotationKey) {
|
function getLastSuccessfulRunSha(kubectl, namespaceName, annotationKey) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
const result = yield kubectl.getResource('namespace', namespaceName);
|
const result = yield kubectl.getResource(NAMESPACE, namespaceName, false, namespaceName);
|
||||||
if (result === null || result === void 0 ? void 0 : result.stderr) {
|
if (result === null || result === void 0 ? void 0 : result.stderr) {
|
||||||
core.warning(result.stderr);
|
core.warning(result.stderr);
|
||||||
return process.env.GITHUB_SHA;
|
return process.env.GITHUB_SHA;
|
||||||
@@ -23206,12 +23218,12 @@ function getLastSuccessfulRunSha(kubectl, namespaceName, annotationKey) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.getLastSuccessfulRunSha = getLastSuccessfulRunSha;
|
exports.getLastSuccessfulRunSha = getLastSuccessfulRunSha;
|
||||||
function annotateChildPods(kubectl, resourceType, resourceName, annotationKeyValStr, allPods) {
|
function annotateChildPods(kubectl, resourceType, resourceName, namespace, annotationKeyValStr, allPods) {
|
||||||
var _a;
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let owner = resourceName;
|
let owner = resourceName;
|
||||||
if (resourceType.toLowerCase().indexOf('deployment') > -1) {
|
if (resourceType.toLowerCase().indexOf('deployment') > -1) {
|
||||||
owner = yield kubectl.getNewReplicaSet(resourceName);
|
owner = yield kubectl.getNewReplicaSet(resourceName, namespace);
|
||||||
}
|
}
|
||||||
const commandExecutionResults = [];
|
const commandExecutionResults = [];
|
||||||
if ((allPods === null || allPods === void 0 ? void 0 : allPods.items) && ((_a = allPods.items) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
if ((allPods === null || allPods === void 0 ? void 0 : allPods.items) && ((_a = allPods.items) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
||||||
@@ -23221,7 +23233,7 @@ function annotateChildPods(kubectl, resourceType, resourceName, annotationKeyVal
|
|||||||
if (owners) {
|
if (owners) {
|
||||||
for (const ownerRef of owners) {
|
for (const ownerRef of owners) {
|
||||||
if (ownerRef.name === owner) {
|
if (ownerRef.name === owner) {
|
||||||
commandExecutionResults.push(kubectl.annotate('pod', pod.metadata.name, annotationKeyValStr));
|
commandExecutionResults.push(kubectl.annotate('pod', pod.metadata.name, annotationKeyValStr, namespace));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23376,6 +23388,8 @@ const core = __nccwpck_require__(6024);
|
|||||||
const KubernetesConstants = __nccwpck_require__(6583);
|
const KubernetesConstants = __nccwpck_require__(6583);
|
||||||
const kubectlUtils_1 = __nccwpck_require__(5474);
|
const kubectlUtils_1 = __nccwpck_require__(5474);
|
||||||
const timeUtils_1 = __nccwpck_require__(4046);
|
const timeUtils_1 = __nccwpck_require__(4046);
|
||||||
|
const IS_SILENT = false;
|
||||||
|
const POD = 'pod';
|
||||||
function checkManifestStability(kubectl, resources) {
|
function checkManifestStability(kubectl, resources) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let rolloutStatusHasErrors = false;
|
let rolloutStatusHasErrors = false;
|
||||||
@@ -23383,32 +23397,32 @@ function checkManifestStability(kubectl, resources) {
|
|||||||
const resource = resources[i];
|
const resource = resources[i];
|
||||||
if (KubernetesConstants.WORKLOAD_TYPES_WITH_ROLLOUT_STATUS.indexOf(resource.type.toLowerCase()) >= 0) {
|
if (KubernetesConstants.WORKLOAD_TYPES_WITH_ROLLOUT_STATUS.indexOf(resource.type.toLowerCase()) >= 0) {
|
||||||
try {
|
try {
|
||||||
const result = yield kubectl.checkRolloutStatus(resource.type, resource.name);
|
const result = yield kubectl.checkRolloutStatus(resource.type, resource.name, resource.namespace);
|
||||||
kubectlUtils_1.checkForErrors([result]);
|
kubectlUtils_1.checkForErrors([result]);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
core.error(ex);
|
core.error(ex);
|
||||||
yield kubectl.describe(resource.type, resource.name);
|
yield kubectl.describe(resource.type, resource.name, IS_SILENT, resource.namespace);
|
||||||
rolloutStatusHasErrors = true;
|
rolloutStatusHasErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (resource.type == KubernetesConstants.KubernetesWorkload.POD) {
|
if (resource.type == KubernetesConstants.KubernetesWorkload.POD) {
|
||||||
try {
|
try {
|
||||||
yield checkPodStatus(kubectl, resource.name);
|
yield checkPodStatus(kubectl, resource);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
core.warning(`Could not determine pod status: ${JSON.stringify(ex)}`);
|
core.warning(`Could not determine pod status: ${JSON.stringify(ex)}`);
|
||||||
yield kubectl.describe(resource.type, resource.name);
|
yield kubectl.describe(resource.type, resource.name, IS_SILENT, resource.namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (resource.type ==
|
if (resource.type ==
|
||||||
KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE) {
|
KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE) {
|
||||||
try {
|
try {
|
||||||
const service = yield getService(kubectl, resource.name);
|
const service = yield getService(kubectl, resource);
|
||||||
const { spec, status } = service;
|
const { spec, status } = service;
|
||||||
if (spec.type === KubernetesConstants.ServiceTypes.LOAD_BALANCER) {
|
if (spec.type === KubernetesConstants.ServiceTypes.LOAD_BALANCER) {
|
||||||
if (!isLoadBalancerIPAssigned(status)) {
|
if (!isLoadBalancerIPAssigned(status)) {
|
||||||
yield waitForServiceExternalIPAssignment(kubectl, resource.name);
|
yield waitForServiceExternalIPAssignment(kubectl, resource);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
core.info(`ServiceExternalIP ${resource.name} ${status.loadBalancer.ingress[0].ip}`);
|
core.info(`ServiceExternalIP ${resource.name} ${status.loadBalancer.ingress[0].ip}`);
|
||||||
@@ -23417,7 +23431,7 @@ function checkManifestStability(kubectl, resources) {
|
|||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
core.warning(`Could not determine service status of: ${resource.name} Error: ${ex}`);
|
core.warning(`Could not determine service status of: ${resource.name} Error: ${ex}`);
|
||||||
yield kubectl.describe(resource.type, resource.name);
|
yield kubectl.describe(resource.type, resource.name, IS_SILENT, resource.namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23427,7 +23441,7 @@ function checkManifestStability(kubectl, resources) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.checkManifestStability = checkManifestStability;
|
exports.checkManifestStability = checkManifestStability;
|
||||||
function checkPodStatus(kubectl, podName) {
|
function checkPodStatus(kubectl, pod) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const sleepTimeout = 10 * 1000; // 10 seconds
|
const sleepTimeout = 10 * 1000; // 10 seconds
|
||||||
const iterations = 60; // 60 * 10 seconds timeout = 10 minutes max timeout
|
const iterations = 60; // 60 * 10 seconds timeout = 10 minutes max timeout
|
||||||
@@ -23435,20 +23449,20 @@ function checkPodStatus(kubectl, podName) {
|
|||||||
let kubectlDescribeNeeded = false;
|
let kubectlDescribeNeeded = false;
|
||||||
for (let i = 0; i < iterations; i++) {
|
for (let i = 0; i < iterations; i++) {
|
||||||
yield timeUtils_1.sleep(sleepTimeout);
|
yield timeUtils_1.sleep(sleepTimeout);
|
||||||
core.debug(`Polling for pod status: ${podName}`);
|
core.debug(`Polling for pod status: ${pod.name}`);
|
||||||
podStatus = yield getPodStatus(kubectl, podName);
|
podStatus = yield getPodStatus(kubectl, pod);
|
||||||
if (podStatus &&
|
if (podStatus &&
|
||||||
(podStatus === null || podStatus === void 0 ? void 0 : podStatus.phase) !== 'Pending' &&
|
(podStatus === null || podStatus === void 0 ? void 0 : podStatus.phase) !== 'Pending' &&
|
||||||
(podStatus === null || podStatus === void 0 ? void 0 : podStatus.phase) !== 'Unknown') {
|
(podStatus === null || podStatus === void 0 ? void 0 : podStatus.phase) !== 'Unknown') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
podStatus = yield getPodStatus(kubectl, podName);
|
podStatus = yield getPodStatus(kubectl, pod);
|
||||||
switch (podStatus.phase) {
|
switch (podStatus.phase) {
|
||||||
case 'Succeeded':
|
case 'Succeeded':
|
||||||
case 'Running':
|
case 'Running':
|
||||||
if (isPodReady(podStatus)) {
|
if (isPodReady(podStatus)) {
|
||||||
console.log(`pod/${podName} is successfully rolled out`);
|
console.log(`pod/${pod.name} is successfully rolled out`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
kubectlDescribeNeeded = true;
|
kubectlDescribeNeeded = true;
|
||||||
@@ -23456,26 +23470,26 @@ function checkPodStatus(kubectl, podName) {
|
|||||||
break;
|
break;
|
||||||
case 'Pending':
|
case 'Pending':
|
||||||
if (!isPodReady(podStatus)) {
|
if (!isPodReady(podStatus)) {
|
||||||
core.warning(`pod/${podName} rollout status check timed out`);
|
core.warning(`pod/${pod.name} rollout status check timed out`);
|
||||||
kubectlDescribeNeeded = true;
|
kubectlDescribeNeeded = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Failed':
|
case 'Failed':
|
||||||
core.error(`pod/${podName} rollout failed`);
|
core.error(`pod/${pod.name} rollout failed`);
|
||||||
kubectlDescribeNeeded = true;
|
kubectlDescribeNeeded = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
core.warning(`pod/${podName} rollout status: ${podStatus.phase}`);
|
core.warning(`pod/${pod.name} rollout status: ${podStatus.phase}`);
|
||||||
}
|
}
|
||||||
if (kubectlDescribeNeeded) {
|
if (kubectlDescribeNeeded) {
|
||||||
yield kubectl.describe('pod', podName);
|
yield kubectl.describe(POD, pod.name, IS_SILENT, pod.namespace);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.checkPodStatus = checkPodStatus;
|
exports.checkPodStatus = checkPodStatus;
|
||||||
function getPodStatus(kubectl, podName) {
|
function getPodStatus(kubectl, pod) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const podResult = yield kubectl.getResource('pod', podName);
|
const podResult = yield kubectl.getResource(POD, pod.name, IS_SILENT, pod.namespace);
|
||||||
kubectlUtils_1.checkForErrors([podResult]);
|
kubectlUtils_1.checkForErrors([podResult]);
|
||||||
return JSON.parse(podResult.stdout).status;
|
return JSON.parse(podResult.stdout).status;
|
||||||
});
|
});
|
||||||
@@ -23493,27 +23507,27 @@ function isPodReady(podStatus) {
|
|||||||
}
|
}
|
||||||
return allContainersAreReady;
|
return allContainersAreReady;
|
||||||
}
|
}
|
||||||
function getService(kubectl, serviceName) {
|
function getService(kubectl, service) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const serviceResult = yield kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE, serviceName);
|
const serviceResult = yield kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE, service.name, IS_SILENT, service.namespace);
|
||||||
kubectlUtils_1.checkForErrors([serviceResult]);
|
kubectlUtils_1.checkForErrors([serviceResult]);
|
||||||
return JSON.parse(serviceResult.stdout);
|
return JSON.parse(serviceResult.stdout);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function waitForServiceExternalIPAssignment(kubectl, serviceName) {
|
function waitForServiceExternalIPAssignment(kubectl, service) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const sleepTimeout = 10 * 1000; // 10 seconds
|
const sleepTimeout = 10 * 1000; // 10 seconds
|
||||||
const iterations = 18; // 18 * 10 seconds timeout = 3 minutes max timeout
|
const iterations = 18; // 18 * 10 seconds timeout = 3 minutes max timeout
|
||||||
for (let i = 0; i < iterations; i++) {
|
for (let i = 0; i < iterations; i++) {
|
||||||
core.info(`Wait for service ip assignment : ${serviceName}`);
|
core.info(`Wait for service ip assignment : ${service.name}`);
|
||||||
yield timeUtils_1.sleep(sleepTimeout);
|
yield timeUtils_1.sleep(sleepTimeout);
|
||||||
const status = (yield getService(kubectl, serviceName)).status;
|
const status = (yield getService(kubectl, service)).status;
|
||||||
if (isLoadBalancerIPAssigned(status)) {
|
if (isLoadBalancerIPAssigned(status)) {
|
||||||
core.info(`ServiceExternalIP ${serviceName} ${status.loadBalancer.ingress[0].ip}`);
|
core.info(`ServiceExternalIP ${service.name} ${status.loadBalancer.ingress[0].ip}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
core.warning(`Wait for service ip assignment timed out${serviceName}`);
|
core.warning(`Wait for service ip assignment timed out ${service.name}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function isLoadBalancerIPAssigned(status) {
|
function isLoadBalancerIPAssigned(status) {
|
||||||
@@ -23722,11 +23736,13 @@ function getResources(filePaths, filterResourceTypes) {
|
|||||||
filePaths.forEach((filePath) => {
|
filePaths.forEach((filePath) => {
|
||||||
const fileContents = fs.readFileSync(filePath).toString();
|
const fileContents = fs.readFileSync(filePath).toString();
|
||||||
yaml.safeLoadAll(fileContents, (inputObject) => {
|
yaml.safeLoadAll(fileContents, (inputObject) => {
|
||||||
|
var _a;
|
||||||
const inputObjectKind = (inputObject === null || inputObject === void 0 ? void 0 : inputObject.kind) || '';
|
const inputObjectKind = (inputObject === null || inputObject === void 0 ? void 0 : inputObject.kind) || '';
|
||||||
if (filterResourceTypes.filter((type) => inputObjectKind.toLowerCase() === type.toLowerCase()).length > 0) {
|
if (filterResourceTypes.filter((type) => inputObjectKind.toLowerCase() === type.toLowerCase()).length > 0) {
|
||||||
resources.push({
|
resources.push({
|
||||||
type: inputObject.kind,
|
type: inputObject.kind,
|
||||||
name: inputObject.metadata.name
|
name: inputObject.metadata.name,
|
||||||
|
namespace: (_a = inputObject === null || inputObject === void 0 ? void 0 : inputObject.metadata) === null || _a === void 0 ? void 0 : _a.namespace
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Generated
+16
-208
@@ -22,8 +22,8 @@
|
|||||||
"@types/jest": "^26.0.0",
|
"@types/jest": "^26.0.0",
|
||||||
"@types/js-yaml": "^3.12.7",
|
"@types/js-yaml": "^3.12.7",
|
||||||
"@types/node": "^12.20.41",
|
"@types/node": "^12.20.41",
|
||||||
|
"@vercel/ncc": "^0.36.1",
|
||||||
"jest": "^26.0.0",
|
"jest": "^26.0.0",
|
||||||
"ncc": "^0.3.6",
|
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"ts-jest": "^26.0.0",
|
"ts-jest": "^26.0.0",
|
||||||
"typescript": "3.9.5"
|
"typescript": "3.9.5"
|
||||||
@@ -1183,6 +1183,15 @@
|
|||||||
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
|
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@vercel/ncc": {
|
||||||
|
"version": "0.36.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.1.tgz",
|
||||||
|
"integrity": "sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"ncc": "dist/ncc/cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/abab": {
|
"node_modules/abab": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||||
@@ -1875,15 +1884,6 @@
|
|||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/colors": {
|
|
||||||
"version": "1.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.2.3.tgz",
|
|
||||||
"integrity": "sha512-qTfM2pNFeMZcLvf/RbrVAzDEVttZjFhaApfx9dplNjvHSX88Ui66zBRb/4YGob/xUWxDceirgoC1lT676asfCQ==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.1.90"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/combined-stream": {
|
"node_modules/combined-stream": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
@@ -1978,15 +1978,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dateformat": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
@@ -4091,58 +4082,6 @@
|
|||||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/ncc": {
|
|
||||||
"version": "0.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/ncc/-/ncc-0.3.6.tgz",
|
|
||||||
"integrity": "sha512-OXudTB2Ebt/FnOuDoPQbaa17+tdVqSOWA+gLfPxccWwsNED1uA2zEhpoB1hwdFC9yYbio/mdV5cvOtQI3Zrx1w==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"mkdirp": "^0.5.1",
|
|
||||||
"rimraf": "^2.6.1",
|
|
||||||
"tracer": "^0.8.7",
|
|
||||||
"ws": "^2.3.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ncc/node_modules/mkdirp": {
|
|
||||||
"version": "0.5.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
|
||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"minimist": "^1.2.6"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"mkdirp": "bin/cmd.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ncc/node_modules/rimraf": {
|
|
||||||
"version": "2.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
|
||||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"glob": "^7.1.3"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"rimraf": "bin.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ncc/node_modules/safe-buffer": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-cr7dZWLwOeaFBLTIuZeYdkfO7UzGIKhjYENJFAxUOMKWGaWDm2nJM2rzxNRm5Owu0DH3ApwNo6kx5idXZfb/Iw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/ncc/node_modules/ws": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-61a+9LgtYZxTq1hAonhX8Xwpo2riK4IOR/BIVxioFbCfc3QFKmpE4x9dLExfLHKtUfVZigYa36tThVhO57erEw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"safe-buffer": "~5.0.1",
|
|
||||||
"ultron": "~1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/nice-try": {
|
"node_modules/nice-try": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||||
@@ -5883,15 +5822,6 @@
|
|||||||
"integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
|
"integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/tinytim": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/tinytim/-/tinytim-0.1.1.tgz",
|
|
||||||
"integrity": "sha512-NIpsp9lBIxPNzB++HnMmUd4byzJSVbbO4F+As1Gb1IG/YQT5QvmBDjpx8SpDS8fhGC+t+Qw8ldQgbcAIaU+2cA==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tmpl": {
|
"node_modules/tmpl": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||||
@@ -5984,33 +5914,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tracer": {
|
|
||||||
"version": "0.8.15",
|
|
||||||
"resolved": "https://registry.npmjs.org/tracer/-/tracer-0.8.15.tgz",
|
|
||||||
"integrity": "sha512-ZQzlhd6zZFIpAhACiZkxLjl65XqVwi8t8UEBVGRIHAQN6nj55ftJWiFell+WSqWCP/vEycrIbUSuiyMwul+TFw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"colors": "1.2.3",
|
|
||||||
"dateformat": "3.0.3",
|
|
||||||
"mkdirp": "^0.5.1",
|
|
||||||
"tinytim": "0.1.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tracer/node_modules/mkdirp": {
|
|
||||||
"version": "0.5.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
|
||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"minimist": "^1.2.6"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"mkdirp": "bin/cmd.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ts-jest": {
|
"node_modules/ts-jest": {
|
||||||
"version": "26.5.6",
|
"version": "26.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
|
||||||
@@ -6127,12 +6030,6 @@
|
|||||||
"node": ">=4.2.0"
|
"node": ">=4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ultron": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/underscore": {
|
"node_modules/underscore": {
|
||||||
"version": "1.13.4",
|
"version": "1.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
|
||||||
@@ -7493,6 +7390,12 @@
|
|||||||
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
|
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@vercel/ncc": {
|
||||||
|
"version": "0.36.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.1.tgz",
|
||||||
|
"integrity": "sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"abab": {
|
"abab": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||||
@@ -8020,12 +7923,6 @@
|
|||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"colors": {
|
|
||||||
"version": "1.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.2.3.tgz",
|
|
||||||
"integrity": "sha512-qTfM2pNFeMZcLvf/RbrVAzDEVttZjFhaApfx9dplNjvHSX88Ui66zBRb/4YGob/xUWxDceirgoC1lT676asfCQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"combined-stream": {
|
"combined-stream": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
@@ -8107,12 +8004,6 @@
|
|||||||
"whatwg-url": "^8.0.0"
|
"whatwg-url": "^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dateformat": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
@@ -9728,54 +9619,6 @@
|
|||||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ncc": {
|
|
||||||
"version": "0.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/ncc/-/ncc-0.3.6.tgz",
|
|
||||||
"integrity": "sha512-OXudTB2Ebt/FnOuDoPQbaa17+tdVqSOWA+gLfPxccWwsNED1uA2zEhpoB1hwdFC9yYbio/mdV5cvOtQI3Zrx1w==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"mkdirp": "^0.5.1",
|
|
||||||
"rimraf": "^2.6.1",
|
|
||||||
"tracer": "^0.8.7",
|
|
||||||
"ws": "^2.3.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"mkdirp": {
|
|
||||||
"version": "0.5.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
|
||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"minimist": "^1.2.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rimraf": {
|
|
||||||
"version": "2.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
|
||||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"glob": "^7.1.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"safe-buffer": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-cr7dZWLwOeaFBLTIuZeYdkfO7UzGIKhjYENJFAxUOMKWGaWDm2nJM2rzxNRm5Owu0DH3ApwNo6kx5idXZfb/Iw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"ws": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-61a+9LgtYZxTq1hAonhX8Xwpo2riK4IOR/BIVxioFbCfc3QFKmpE4x9dLExfLHKtUfVZigYa36tThVhO57erEw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"safe-buffer": "~5.0.1",
|
|
||||||
"ultron": "~1.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nice-try": {
|
"nice-try": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||||
@@ -11139,12 +10982,6 @@
|
|||||||
"integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
|
"integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"tinytim": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/tinytim/-/tinytim-0.1.1.tgz",
|
|
||||||
"integrity": "sha512-NIpsp9lBIxPNzB++HnMmUd4byzJSVbbO4F+As1Gb1IG/YQT5QvmBDjpx8SpDS8fhGC+t+Qw8ldQgbcAIaU+2cA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"tmpl": {
|
"tmpl": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||||
@@ -11218,29 +11055,6 @@
|
|||||||
"punycode": "^2.1.1"
|
"punycode": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tracer": {
|
|
||||||
"version": "0.8.15",
|
|
||||||
"resolved": "https://registry.npmjs.org/tracer/-/tracer-0.8.15.tgz",
|
|
||||||
"integrity": "sha512-ZQzlhd6zZFIpAhACiZkxLjl65XqVwi8t8UEBVGRIHAQN6nj55ftJWiFell+WSqWCP/vEycrIbUSuiyMwul+TFw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"colors": "1.2.3",
|
|
||||||
"dateformat": "3.0.3",
|
|
||||||
"mkdirp": "^0.5.1",
|
|
||||||
"tinytim": "0.1.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"mkdirp": {
|
|
||||||
"version": "0.5.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
|
||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"minimist": "^1.2.6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ts-jest": {
|
"ts-jest": {
|
||||||
"version": "26.5.6",
|
"version": "26.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
|
||||||
@@ -11321,12 +11135,6 @@
|
|||||||
"integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
|
"integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ultron": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"underscore": {
|
"underscore": {
|
||||||
"version": "1.13.4",
|
"version": "1.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
|
||||||
|
|||||||
+1
-1
@@ -24,8 +24,8 @@
|
|||||||
"@types/jest": "^26.0.0",
|
"@types/jest": "^26.0.0",
|
||||||
"@types/js-yaml": "^3.12.7",
|
"@types/js-yaml": "^3.12.7",
|
||||||
"@types/node": "^12.20.41",
|
"@types/node": "^12.20.41",
|
||||||
|
"@vercel/ncc": "^0.36.1",
|
||||||
"jest": "^26.0.0",
|
"jest": "^26.0.0",
|
||||||
"ncc": "^0.3.6",
|
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"ts-jest": "^26.0.0",
|
"ts-jest": "^26.0.0",
|
||||||
"typescript": "3.9.5"
|
"typescript": "3.9.5"
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ export async function deploy(
|
|||||||
for (const ingressResource of ingressResources) {
|
for (const ingressResource of ingressResources) {
|
||||||
await kubectl.getResource(
|
await kubectl.getResource(
|
||||||
KubernetesConstants.DiscoveryAndLoadBalancerResource.INGRESS,
|
KubernetesConstants.DiscoveryAndLoadBalancerResource.INGRESS,
|
||||||
ingressResource.name
|
ingressResource.name,
|
||||||
|
false,
|
||||||
|
ingressResource.namespace
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ export async function deleteGreenObjects(
|
|||||||
const resourcesToDelete: K8sDeleteObject[] = toDelete.map((obj) => {
|
const resourcesToDelete: K8sDeleteObject[] = toDelete.map((obj) => {
|
||||||
return {
|
return {
|
||||||
name: getBlueGreenResourceName(obj.metadata.name, GREEN_SUFFIX),
|
name: getBlueGreenResourceName(obj.metadata.name, GREEN_SUFFIX),
|
||||||
kind: obj.kind
|
kind: obj.kind,
|
||||||
|
namespace: obj.metadata.namespace
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -66,31 +67,25 @@ export async function deleteObjects(
|
|||||||
// other common functions
|
// other common functions
|
||||||
export function getManifestObjects(filePaths: string[]): BlueGreenManifests {
|
export function getManifestObjects(filePaths: string[]): BlueGreenManifests {
|
||||||
const deploymentEntityList: K8sObject[] = []
|
const deploymentEntityList: K8sObject[] = []
|
||||||
|
const serviceEntityList: K8sObject[] = []
|
||||||
const routedServiceEntityList: K8sObject[] = []
|
const routedServiceEntityList: K8sObject[] = []
|
||||||
const unroutedServiceEntityList: K8sObject[] = []
|
const unroutedServiceEntityList: K8sObject[] = []
|
||||||
const ingressEntityList: K8sObject[] = []
|
const ingressEntityList: K8sObject[] = []
|
||||||
const otherEntitiesList: K8sObject[] = []
|
const otherEntitiesList: K8sObject[] = []
|
||||||
const serviceNameMap = new Map<string, string>()
|
const serviceNameMap = new Map<string, string>()
|
||||||
|
|
||||||
|
// Manifest objects per type. All resources should be parsed and
|
||||||
|
// organized before we can check if services are “routed” or not.
|
||||||
filePaths.forEach((filePath: string) => {
|
filePaths.forEach((filePath: string) => {
|
||||||
const fileContents = fs.readFileSync(filePath).toString()
|
const fileContents = fs.readFileSync(filePath).toString()
|
||||||
yaml.safeLoadAll(fileContents, (inputObject) => {
|
yaml.safeLoadAll(fileContents, (inputObject) => {
|
||||||
if (!!inputObject) {
|
if (!!inputObject) {
|
||||||
const kind = inputObject.kind
|
const kind = inputObject.kind
|
||||||
const name = inputObject.metadata.name
|
|
||||||
|
|
||||||
if (isDeploymentEntity(kind)) {
|
if (isDeploymentEntity(kind)) {
|
||||||
deploymentEntityList.push(inputObject)
|
deploymentEntityList.push(inputObject)
|
||||||
} else if (isServiceEntity(kind)) {
|
} else if (isServiceEntity(kind)) {
|
||||||
if (isServiceRouted(inputObject, deploymentEntityList)) {
|
serviceEntityList.push(inputObject)
|
||||||
routedServiceEntityList.push(inputObject)
|
|
||||||
serviceNameMap.set(
|
|
||||||
name,
|
|
||||||
getBlueGreenResourceName(name, GREEN_SUFFIX)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
unroutedServiceEntityList.push(inputObject)
|
|
||||||
}
|
|
||||||
} else if (isIngressEntity(kind)) {
|
} else if (isIngressEntity(kind)) {
|
||||||
ingressEntityList.push(inputObject)
|
ingressEntityList.push(inputObject)
|
||||||
} else {
|
} else {
|
||||||
@@ -100,6 +95,16 @@ export function getManifestObjects(filePaths: string[]): BlueGreenManifests {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
serviceEntityList.forEach((inputObject: any) => {
|
||||||
|
if (isServiceRouted(inputObject, deploymentEntityList)) {
|
||||||
|
const name = inputObject.metadata.name
|
||||||
|
routedServiceEntityList.push(inputObject)
|
||||||
|
serviceNameMap.set(name, getBlueGreenResourceName(name, GREEN_SUFFIX))
|
||||||
|
} else {
|
||||||
|
unroutedServiceEntityList.push(inputObject)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
serviceEntityList: routedServiceEntityList,
|
serviceEntityList: routedServiceEntityList,
|
||||||
serviceNameMap: serviceNameMap,
|
serviceNameMap: serviceNameMap,
|
||||||
@@ -234,9 +239,10 @@ export function isServiceSelectorSubsetOfMatchLabel(
|
|||||||
export async function fetchResource(
|
export async function fetchResource(
|
||||||
kubectl: Kubectl,
|
kubectl: Kubectl,
|
||||||
kind: string,
|
kind: string,
|
||||||
name: string
|
name: string,
|
||||||
|
namespace?: string
|
||||||
): Promise<K8sObject> {
|
): Promise<K8sObject> {
|
||||||
const result = await kubectl.getResource(kind, name)
|
const result = await kubectl.getResource(kind, name, false, namespace)
|
||||||
if (result == null || !!result.stderr) {
|
if (result == null || !!result.stderr) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ export async function validateIngresses(
|
|||||||
const existingIngress = await fetchResource(
|
const existingIngress = await fetchResource(
|
||||||
kubectl,
|
kubectl,
|
||||||
inputObject.kind,
|
inputObject.kind,
|
||||||
inputObject.metadata.name
|
inputObject.metadata.name,
|
||||||
|
inputObject?.metadata?.namespace
|
||||||
)
|
)
|
||||||
|
|
||||||
const isValid =
|
const isValid =
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ export async function validateServicesState(
|
|||||||
const existingService = await fetchResource(
|
const existingService = await fetchResource(
|
||||||
kubectl,
|
kubectl,
|
||||||
serviceObject.kind,
|
serviceObject.kind,
|
||||||
serviceObject.metadata.name
|
serviceObject.metadata.name,
|
||||||
|
serviceObject?.metadata?.namespace
|
||||||
)
|
)
|
||||||
|
|
||||||
let isServiceGreen =
|
let isServiceGreen =
|
||||||
|
|||||||
@@ -142,7 +142,8 @@ export async function validateTrafficSplitsState(
|
|||||||
let trafficSplitObject = await fetchResource(
|
let trafficSplitObject = await fetchResource(
|
||||||
kubectl,
|
kubectl,
|
||||||
TRAFFIC_SPLIT_OBJECT,
|
TRAFFIC_SPLIT_OBJECT,
|
||||||
getBlueGreenResourceName(name, TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX)
|
getBlueGreenResourceName(name, TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX),
|
||||||
|
serviceObject?.metadata?.namespace
|
||||||
)
|
)
|
||||||
core.debug(
|
core.debug(
|
||||||
`ts object extracted was ${JSON.stringify(trafficSplitObject)}`
|
`ts object extracted was ${JSON.stringify(trafficSplitObject)}`
|
||||||
@@ -183,7 +184,8 @@ export async function cleanupSMI(
|
|||||||
serviceObject.metadata.name,
|
serviceObject.metadata.name,
|
||||||
GREEN_SUFFIX
|
GREEN_SUFFIX
|
||||||
),
|
),
|
||||||
kind: serviceObject.kind
|
kind: serviceObject.kind,
|
||||||
|
namespace: serviceObject?.metadata?.namespace
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -195,9 +195,13 @@ async function cleanUpCanary(
|
|||||||
files: string[],
|
files: string[],
|
||||||
includeServices: boolean
|
includeServices: boolean
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
const deleteObject = async function (kind, name) {
|
const deleteObject = async function (
|
||||||
|
kind: string,
|
||||||
|
name: string,
|
||||||
|
namespace: string | undefined
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const result = await kubectl.delete([kind, name])
|
const result = await kubectl.delete([kind, name], namespace)
|
||||||
checkForErrors([result])
|
checkForErrors([result])
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
// Ignore failures of delete if it doesn't exist
|
// Ignore failures of delete if it doesn't exist
|
||||||
@@ -213,6 +217,7 @@ async function cleanUpCanary(
|
|||||||
for (const inputObject of parsedYaml) {
|
for (const inputObject of parsedYaml) {
|
||||||
const name = inputObject.metadata.name
|
const name = inputObject.metadata.name
|
||||||
const kind = inputObject.kind
|
const kind = inputObject.kind
|
||||||
|
const namespace: string | undefined = inputObject?.metadata?.namespace
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isDeploymentEntity(kind) ||
|
isDeploymentEntity(kind) ||
|
||||||
@@ -222,8 +227,8 @@ async function cleanUpCanary(
|
|||||||
const canaryObjectName = getCanaryResourceName(name)
|
const canaryObjectName = getCanaryResourceName(name)
|
||||||
const baselineObjectName = getBaselineResourceName(name)
|
const baselineObjectName = getBaselineResourceName(name)
|
||||||
|
|
||||||
await deleteObject(kind, canaryObjectName)
|
await deleteObject(kind, canaryObjectName, namespace)
|
||||||
await deleteObject(kind, baselineObjectName)
|
await deleteObject(kind, baselineObjectName, namespace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,12 @@ async function annotateResources(
|
|||||||
)
|
)
|
||||||
if (annotateNamespace) {
|
if (annotateNamespace) {
|
||||||
annotateResults.push(
|
annotateResults.push(
|
||||||
await kubectl.annotate('namespace', namespace, annotationKeyValStr)
|
await kubectl.annotate(
|
||||||
|
'namespace',
|
||||||
|
namespace,
|
||||||
|
annotationKeyValStr,
|
||||||
|
namespace
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
@@ -243,6 +248,7 @@ async function annotateResources(
|
|||||||
kubectl,
|
kubectl,
|
||||||
resource.type,
|
resource.type,
|
||||||
resource.name,
|
resource.name,
|
||||||
|
resource.namespace,
|
||||||
annotationKeyValStr,
|
annotationKeyValStr,
|
||||||
allPods
|
allPods
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export interface K8sObject {
|
|||||||
metadata: {
|
metadata: {
|
||||||
name: string
|
name: string
|
||||||
labels: Map<string, string>
|
labels: Map<string, string>
|
||||||
|
namespace?: string
|
||||||
}
|
}
|
||||||
kind: string
|
kind: string
|
||||||
spec: any
|
spec: any
|
||||||
@@ -16,6 +17,7 @@ export interface K8sServiceObject extends K8sObject {
|
|||||||
export interface K8sDeleteObject {
|
export interface K8sDeleteObject {
|
||||||
name: string
|
name: string
|
||||||
kind: string
|
kind: string
|
||||||
|
namespace?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface K8sIngress extends K8sObject {
|
export interface K8sIngress extends K8sObject {
|
||||||
|
|||||||
+176
-1
@@ -3,7 +3,6 @@ import * as exec from '@actions/exec'
|
|||||||
import * as io from '@actions/io'
|
import * as io from '@actions/io'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as toolCache from '@actions/tool-cache'
|
import * as toolCache from '@actions/tool-cache'
|
||||||
import {config} from 'process'
|
|
||||||
|
|
||||||
describe('Kubectl path', () => {
|
describe('Kubectl path', () => {
|
||||||
const version = '1.1'
|
const version = '1.1'
|
||||||
@@ -38,6 +37,7 @@ describe('Kubectl path', () => {
|
|||||||
const kubectlPath = 'kubectlPath'
|
const kubectlPath = 'kubectlPath'
|
||||||
const testNamespace = 'testNamespace'
|
const testNamespace = 'testNamespace'
|
||||||
const defaultNamespace = 'default'
|
const defaultNamespace = 'default'
|
||||||
|
const otherNamespace = 'otherns'
|
||||||
describe('Kubectl class', () => {
|
describe('Kubectl class', () => {
|
||||||
describe('default namespace behavior', () => {
|
describe('default namespace behavior', () => {
|
||||||
const kubectl = new Kubectl(kubectlPath, defaultNamespace)
|
const kubectl = new Kubectl(kubectlPath, defaultNamespace)
|
||||||
@@ -122,6 +122,26 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// overrided ns
|
||||||
|
const silent = false
|
||||||
|
await kubectl.describe(
|
||||||
|
resourceType,
|
||||||
|
resourceName,
|
||||||
|
silent,
|
||||||
|
otherNamespace
|
||||||
|
)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'describe',
|
||||||
|
resourceType,
|
||||||
|
resourceName,
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('describes a resource silently', async () => {
|
it('describes a resource silently', async () => {
|
||||||
@@ -140,6 +160,26 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: true}
|
{silent: true}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// overrided ns
|
||||||
|
const silent = false
|
||||||
|
await kubectl.describe(
|
||||||
|
resourceType,
|
||||||
|
resourceName,
|
||||||
|
silent,
|
||||||
|
otherNamespace
|
||||||
|
)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'describe',
|
||||||
|
resourceType,
|
||||||
|
resourceName,
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('annotates resource', async () => {
|
it('annotates resource', async () => {
|
||||||
@@ -165,6 +205,27 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// override ns
|
||||||
|
await kubectl.annotate(
|
||||||
|
resourceType,
|
||||||
|
resourceName,
|
||||||
|
annotation,
|
||||||
|
otherNamespace
|
||||||
|
)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'annotate',
|
||||||
|
resourceType,
|
||||||
|
resourceName,
|
||||||
|
annotation,
|
||||||
|
'--overwrite',
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent: false}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('annotates files with single file', async () => {
|
it('annotates files with single file', async () => {
|
||||||
@@ -185,6 +246,22 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// override ns
|
||||||
|
await kubectl.annotateFiles(file, annotation, otherNamespace)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'annotate',
|
||||||
|
'-f',
|
||||||
|
file,
|
||||||
|
annotation,
|
||||||
|
'--overwrite',
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent: false}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('annotates files with mulitple files', async () => {
|
it('annotates files with mulitple files', async () => {
|
||||||
@@ -205,6 +282,22 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// override ns
|
||||||
|
await kubectl.annotateFiles(files, annotation, otherNamespace)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'annotate',
|
||||||
|
'-f',
|
||||||
|
files.join(','),
|
||||||
|
annotation,
|
||||||
|
'--overwrite',
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent: false}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('labels files with single file', async () => {
|
it('labels files with single file', async () => {
|
||||||
@@ -225,6 +318,21 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await kubectl.labelFiles(file, labels, otherNamespace)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'label',
|
||||||
|
'-f',
|
||||||
|
file,
|
||||||
|
...labels,
|
||||||
|
'--overwrite',
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent: false}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('labels files with multiple files', async () => {
|
it('labels files with multiple files', async () => {
|
||||||
@@ -245,6 +353,21 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await kubectl.labelFiles(files, labels, otherNamespace)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'label',
|
||||||
|
'-f',
|
||||||
|
files.join(','),
|
||||||
|
...labels,
|
||||||
|
'--overwrite',
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent: false}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('gets all pods', async () => {
|
it('gets all pods', async () => {
|
||||||
@@ -273,6 +396,20 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// override ns
|
||||||
|
await kubectl.checkRolloutStatus(resourceType, name, otherNamespace)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'rollout',
|
||||||
|
'status',
|
||||||
|
`${resourceType}/${name}`,
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent: false}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('gets resource', async () => {
|
it('gets resource', async () => {
|
||||||
@@ -291,6 +428,22 @@ describe('Kubectl class', () => {
|
|||||||
],
|
],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// override ns
|
||||||
|
const silent = true
|
||||||
|
await kubectl.getResource(resourceType, name, silent, otherNamespace)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
[
|
||||||
|
'get',
|
||||||
|
`${resourceType}/${name}`,
|
||||||
|
'-o',
|
||||||
|
'json',
|
||||||
|
'--namespace',
|
||||||
|
otherNamespace
|
||||||
|
],
|
||||||
|
{silent}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('executes a command', async () => {
|
it('executes a command', async () => {
|
||||||
@@ -321,6 +474,14 @@ describe('Kubectl class', () => {
|
|||||||
['delete', arg, '--namespace', testNamespace],
|
['delete', arg, '--namespace', testNamespace],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// override ns
|
||||||
|
await kubectl.delete(arg, otherNamespace)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
['delete', arg, '--namespace', otherNamespace],
|
||||||
|
{silent: false}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('deletes with multiple arguments', async () => {
|
it('deletes with multiple arguments', async () => {
|
||||||
@@ -331,6 +492,14 @@ describe('Kubectl class', () => {
|
|||||||
['delete', ...args, '--namespace', testNamespace],
|
['delete', ...args, '--namespace', testNamespace],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// override ns
|
||||||
|
await kubectl.delete(args, otherNamespace)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(
|
||||||
|
kubectlPath,
|
||||||
|
['delete', ...args, '--namespace', otherNamespace],
|
||||||
|
{silent: false}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -369,5 +538,11 @@ describe('Kubectl class', () => {
|
|||||||
[command, '--insecure-skip-tls-verify', '--namespace', testNamespace],
|
[command, '--insecure-skip-tls-verify', '--namespace', testNamespace],
|
||||||
{silent: false}
|
{silent: false}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const kubectlNoFlags = new Kubectl(kubectlPath)
|
||||||
|
kubectlNoFlags.executeCommand(command)
|
||||||
|
expect(exec.getExecOutput).toBeCalledWith(kubectlPath, [command], {
|
||||||
|
silent: false
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+51
-33
@@ -3,11 +3,11 @@ import {createInlineArray} from '../utilities/arrayUtils'
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as toolCache from '@actions/tool-cache'
|
import * as toolCache from '@actions/tool-cache'
|
||||||
import * as io from '@actions/io'
|
import * as io from '@actions/io'
|
||||||
import {exec} from 'child_process'
|
|
||||||
|
|
||||||
export interface Resource {
|
export interface Resource {
|
||||||
name: string
|
name: string
|
||||||
type: string
|
type: string
|
||||||
|
namespace?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Kubectl {
|
export class Kubectl {
|
||||||
@@ -20,7 +20,7 @@ export class Kubectl {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
kubectlPath: string,
|
kubectlPath: string,
|
||||||
namespace: string = 'default',
|
namespace: string = '',
|
||||||
ignoreSSLErrors: boolean = false,
|
ignoreSSLErrors: boolean = false,
|
||||||
resourceGroup: string = '',
|
resourceGroup: string = '',
|
||||||
name: string = ''
|
name: string = ''
|
||||||
@@ -47,7 +47,7 @@ export class Kubectl {
|
|||||||
]
|
]
|
||||||
if (force) applyArgs.push('--force')
|
if (force) applyArgs.push('--force')
|
||||||
|
|
||||||
return await this.execute(applyArgs)
|
return await this.execute(applyArgs.concat(this.getFlags()))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.debug('Kubectl apply failed:' + err)
|
core.debug('Kubectl apply failed:' + err)
|
||||||
}
|
}
|
||||||
@@ -56,16 +56,24 @@ export class Kubectl {
|
|||||||
public async describe(
|
public async describe(
|
||||||
resourceType: string,
|
resourceType: string,
|
||||||
resourceName: string,
|
resourceName: string,
|
||||||
silent: boolean = false
|
silent: boolean = false,
|
||||||
|
namespace?: string
|
||||||
): Promise<ExecOutput> {
|
): Promise<ExecOutput> {
|
||||||
return await this.execute(
|
return await this.execute(
|
||||||
['describe', resourceType, resourceName],
|
['describe', resourceType, resourceName].concat(
|
||||||
|
this.getFlags(namespace)
|
||||||
|
),
|
||||||
silent
|
silent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getNewReplicaSet(deployment: string) {
|
public async getNewReplicaSet(deployment: string, namespace?: string) {
|
||||||
const result = await this.describe('deployment', deployment, true)
|
const result = await this.describe(
|
||||||
|
'deployment',
|
||||||
|
deployment,
|
||||||
|
true,
|
||||||
|
namespace
|
||||||
|
)
|
||||||
|
|
||||||
let newReplicaSet = ''
|
let newReplicaSet = ''
|
||||||
if (result?.stdout) {
|
if (result?.stdout) {
|
||||||
@@ -94,7 +102,8 @@ export class Kubectl {
|
|||||||
public async annotate(
|
public async annotate(
|
||||||
resourceType: string,
|
resourceType: string,
|
||||||
resourceName: string,
|
resourceName: string,
|
||||||
annotation: string
|
annotation: string,
|
||||||
|
namespace?: string
|
||||||
): Promise<ExecOutput> {
|
): Promise<ExecOutput> {
|
||||||
const args = [
|
const args = [
|
||||||
'annotate',
|
'annotate',
|
||||||
@@ -102,13 +111,14 @@ export class Kubectl {
|
|||||||
resourceName,
|
resourceName,
|
||||||
annotation,
|
annotation,
|
||||||
'--overwrite'
|
'--overwrite'
|
||||||
]
|
].concat(this.getFlags(namespace))
|
||||||
return await this.execute(args)
|
return await this.execute(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async annotateFiles(
|
public async annotateFiles(
|
||||||
files: string | string[],
|
files: string | string[],
|
||||||
annotation: string
|
annotation: string,
|
||||||
|
namespace?: string
|
||||||
): Promise<ExecOutput> {
|
): Promise<ExecOutput> {
|
||||||
const filesToAnnotate = createInlineArray(files)
|
const filesToAnnotate = createInlineArray(files)
|
||||||
core.debug(`annotating ${filesToAnnotate} with annotation ${annotation}`)
|
core.debug(`annotating ${filesToAnnotate} with annotation ${annotation}`)
|
||||||
@@ -118,16 +128,14 @@ export class Kubectl {
|
|||||||
filesToAnnotate,
|
filesToAnnotate,
|
||||||
annotation,
|
annotation,
|
||||||
'--overwrite'
|
'--overwrite'
|
||||||
]
|
].concat(this.getFlags(namespace))
|
||||||
core.debug(
|
|
||||||
`sending args from annotate to execute: ${JSON.stringify(args)}`
|
|
||||||
)
|
|
||||||
return await this.execute(args)
|
return await this.execute(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async labelFiles(
|
public async labelFiles(
|
||||||
files: string | string[],
|
files: string | string[],
|
||||||
labels: string[]
|
labels: string[],
|
||||||
|
namespace?: string
|
||||||
): Promise<ExecOutput> {
|
): Promise<ExecOutput> {
|
||||||
const args = [
|
const args = [
|
||||||
'label',
|
'label',
|
||||||
@@ -135,51 +143,59 @@ export class Kubectl {
|
|||||||
createInlineArray(files),
|
createInlineArray(files),
|
||||||
...labels,
|
...labels,
|
||||||
'--overwrite'
|
'--overwrite'
|
||||||
]
|
].concat(this.getFlags(namespace))
|
||||||
return await this.execute(args)
|
return await this.execute(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAllPods(): Promise<ExecOutput> {
|
public async getAllPods(): Promise<ExecOutput> {
|
||||||
return await this.execute(['get', 'pods', '-o', 'json'], true)
|
return await this.execute(
|
||||||
|
['get', 'pods', '-o', 'json'].concat(this.getFlags()),
|
||||||
|
true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async checkRolloutStatus(
|
public async checkRolloutStatus(
|
||||||
resourceType: string,
|
resourceType: string,
|
||||||
name: string
|
name: string,
|
||||||
|
namespace?: string
|
||||||
): Promise<ExecOutput> {
|
): Promise<ExecOutput> {
|
||||||
return await this.execute([
|
return await this.execute(
|
||||||
'rollout',
|
['rollout', 'status', `${resourceType}/${name}`].concat(
|
||||||
'status',
|
this.getFlags(namespace)
|
||||||
`${resourceType}/${name}`
|
)
|
||||||
])
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getResource(
|
public async getResource(
|
||||||
resourceType: string,
|
resourceType: string,
|
||||||
name: string,
|
name: string,
|
||||||
silentFailure: boolean = false
|
silentFailure: boolean = false,
|
||||||
|
namespace?: string
|
||||||
): Promise<ExecOutput> {
|
): Promise<ExecOutput> {
|
||||||
core.debug(
|
core.debug(
|
||||||
'fetching resource of type ' + resourceType + ' and name ' + name
|
'fetching resource of type ' + resourceType + ' and name ' + name
|
||||||
)
|
)
|
||||||
return await this.execute(
|
return await this.execute(
|
||||||
['get', `${resourceType}/${name}`, '-o', 'json'],
|
['get', `${resourceType}/${name}`, '-o', 'json'].concat(
|
||||||
|
this.getFlags(namespace)
|
||||||
|
),
|
||||||
silentFailure
|
silentFailure
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public executeCommand(command: string, args?: string) {
|
public executeCommand(command: string, args?: string) {
|
||||||
if (!command) throw new Error('Command must be defined')
|
if (!command) throw new Error('Command must be defined')
|
||||||
return args ? this.execute([command, args]) : this.execute([command])
|
const a = args ? [args] : []
|
||||||
|
return this.execute([command, ...a.concat(this.getFlags())])
|
||||||
}
|
}
|
||||||
|
|
||||||
public delete(args: string | string[]) {
|
public delete(args: string | string[], namespace?: string) {
|
||||||
if (typeof args === 'string') return this.execute(['delete', args])
|
if (typeof args === 'string')
|
||||||
return this.execute(['delete', ...args])
|
return this.execute(['delete', args].concat(this.getFlags(namespace)))
|
||||||
|
return this.execute(['delete', ...args.concat(this.getFlags(namespace))])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async execute(args: string[], silent: boolean = false) {
|
protected async execute(args: string[], silent: boolean = false) {
|
||||||
args = args.concat(this.getExecuteFlags())
|
|
||||||
core.debug(`Kubectl run with command: ${this.kubectlPath} ${args}`)
|
core.debug(`Kubectl run with command: ${this.kubectlPath} ${args}`)
|
||||||
|
|
||||||
return await getExecOutput(this.kubectlPath, args, {
|
return await getExecOutput(this.kubectlPath, args, {
|
||||||
@@ -187,13 +203,15 @@ export class Kubectl {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getExecuteFlags(): string[] {
|
protected getFlags(namespaceOverride?: string): string[] {
|
||||||
const flags = []
|
const flags = []
|
||||||
if (this.ignoreSSLErrors) {
|
if (this.ignoreSSLErrors) {
|
||||||
flags.push('--insecure-skip-tls-verify')
|
flags.push('--insecure-skip-tls-verify')
|
||||||
}
|
}
|
||||||
if (this.namespace) {
|
|
||||||
flags.push('--namespace', this.namespace)
|
const ns = namespaceOverride || this.namespace
|
||||||
|
if (ns) {
|
||||||
|
flags.push('--namespace', ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
return flags
|
return flags
|
||||||
|
|||||||
@@ -1,12 +1,32 @@
|
|||||||
import {PrivateKubectl} from './privatekubectl'
|
import {PrivateKubectl} from './privatekubectl'
|
||||||
|
import * as exec from '@actions/exec'
|
||||||
|
|
||||||
describe('Private kubectl', () => {
|
describe('Private kubectl', () => {
|
||||||
const testString = `kubectl annotate -f test.yml,test2.yml,test3.yml -f test4.yml --filename test5.yml actions.github.com/k8s-deploy={"run":"3498366832","repository":"jaiveerk/k8s-deploy","workflow":"Minikube Integration Tests - private cluster","workflowFileName":"run-integration-tests-private.yml","jobName":"run-integration-test","createdBy":"jaiveerk","runUri":"https://github.com/jaiveerk/k8s-deploy/actions/runs/3498366832","commit":"c63b323186ea1320a31290de6dcc094c06385e75","lastSuccessRunCommit":"NA","branch":"refs/heads/main","deployTimestamp":1668787848577,"dockerfilePaths":{"nginx:1.14.2":""},"manifestsPaths":["https://github.com/jaiveerk/k8s-deploy/blob/c63b323186ea1320a31290de6dcc094c06385e75/test/integration/manifests/test.yml"],"helmChartPaths":[],"provider":"GitHub"} --overwrite --namespace test-3498366832`
|
const testString = `kubectl annotate -f test.yml,test2.yml,test3.yml -f test4.yml --filename test5.yml actions.github.com/k8s-deploy={"run":"3498366832","repository":"jaiveerk/k8s-deploy","workflow":"Minikube Integration Tests - private cluster","workflowFileName":"run-integration-tests-private.yml","jobName":"run-integration-test","createdBy":"jaiveerk","runUri":"https://github.com/jaiveerk/k8s-deploy/actions/runs/3498366832","commit":"c63b323186ea1320a31290de6dcc094c06385e75","lastSuccessRunCommit":"NA","branch":"refs/heads/main","deployTimestamp":1668787848577,"dockerfilePaths":{"nginx:1.14.2":""},"manifestsPaths":["https://github.com/jaiveerk/k8s-deploy/blob/c63b323186ea1320a31290de6dcc094c06385e75/test/integration/manifests/test.yml"],"helmChartPaths":[],"provider":"GitHub"} --overwrite --namespace test-3498366832`
|
||||||
const mockKube = new PrivateKubectl('')
|
const mockKube = new PrivateKubectl(
|
||||||
|
'kubectlPath',
|
||||||
|
'namespace',
|
||||||
|
true,
|
||||||
|
'resourceGroup',
|
||||||
|
'resourceName'
|
||||||
|
)
|
||||||
|
|
||||||
it('should extract filenames correctly', () => {
|
it('should extract filenames correctly', () => {
|
||||||
expect(mockKube.extractFilesnames(testString)).toEqual(
|
expect(mockKube.extractFilesnames(testString)).toEqual(
|
||||||
'test.yml test2.yml test3.yml test4.yml test5.yml'
|
'test.yml test2.yml test3.yml test4.yml test5.yml'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Should throw well defined Error on error from Azure', async () => {
|
||||||
|
const errorMsg = 'An error message'
|
||||||
|
jest.spyOn(exec, 'getExecOutput').mockImplementation(async () => {
|
||||||
|
return {exitCode: 1, stdout: '', stderr: errorMsg}
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(mockKube.executeCommand('az', 'test')).rejects.toThrow(
|
||||||
|
Error(
|
||||||
|
`Call to private cluster failed. Command: 'kubectl az test --insecure-skip-tls-verify --namespace namespace', errormessage: ${errorMsg}`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import * as path from 'path'
|
|||||||
|
|
||||||
export class PrivateKubectl extends Kubectl {
|
export class PrivateKubectl extends Kubectl {
|
||||||
protected async execute(args: string[], silent: boolean = false) {
|
protected async execute(args: string[], silent: boolean = false) {
|
||||||
args = args.concat(this.getExecuteFlags())
|
|
||||||
|
|
||||||
args.unshift('kubectl')
|
args.unshift('kubectl')
|
||||||
let kubectlCmd = args.join(' ')
|
let kubectlCmd = args.join(' ')
|
||||||
let addFileFlag = false
|
let addFileFlag = false
|
||||||
@@ -75,11 +73,18 @@ export class PrivateKubectl extends Kubectl {
|
|||||||
runOutput
|
runOutput
|
||||||
)}`
|
)}`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (runOutput.exitCode !== 0) {
|
||||||
|
throw Error(
|
||||||
|
`Call to private cluster failed. Command: '${kubectlCmd}', errormessage: ${runOutput.stderr}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const runObj: {logs: string; exitCode: number} = JSON.parse(
|
const runObj: {logs: string; exitCode: number} = JSON.parse(
|
||||||
runOutput.stdout
|
runOutput.stdout
|
||||||
)
|
)
|
||||||
if (!silent) core.info(runObj.logs)
|
if (!silent) core.info(runObj.logs)
|
||||||
if (runOutput.exitCode !== 0 && runObj.exitCode !== 0) {
|
if (runObj.exitCode !== 0) {
|
||||||
throw Error(`failed private cluster Kubectl command: ${kubectlCmd}`)
|
throw Error(`failed private cluster Kubectl command: ${kubectlCmd}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import * as core from '@actions/core'
|
|||||||
import {ExecOutput} from '@actions/exec'
|
import {ExecOutput} from '@actions/exec'
|
||||||
import {Kubectl} from '../types/kubectl'
|
import {Kubectl} from '../types/kubectl'
|
||||||
|
|
||||||
|
const NAMESPACE = 'namespace'
|
||||||
|
|
||||||
export function checkForErrors(
|
export function checkForErrors(
|
||||||
execResults: ExecOutput[],
|
execResults: ExecOutput[],
|
||||||
warnIfError?: boolean
|
warnIfError?: boolean
|
||||||
@@ -30,7 +32,12 @@ export async function getLastSuccessfulRunSha(
|
|||||||
annotationKey: string
|
annotationKey: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
try {
|
try {
|
||||||
const result = await kubectl.getResource('namespace', namespaceName)
|
const result = await kubectl.getResource(
|
||||||
|
NAMESPACE,
|
||||||
|
namespaceName,
|
||||||
|
false,
|
||||||
|
namespaceName
|
||||||
|
)
|
||||||
if (result?.stderr) {
|
if (result?.stderr) {
|
||||||
core.warning(result.stderr)
|
core.warning(result.stderr)
|
||||||
return process.env.GITHUB_SHA
|
return process.env.GITHUB_SHA
|
||||||
@@ -53,12 +60,13 @@ export async function annotateChildPods(
|
|||||||
kubectl: Kubectl,
|
kubectl: Kubectl,
|
||||||
resourceType: string,
|
resourceType: string,
|
||||||
resourceName: string,
|
resourceName: string,
|
||||||
|
namespace: string | undefined,
|
||||||
annotationKeyValStr: string,
|
annotationKeyValStr: string,
|
||||||
allPods
|
allPods
|
||||||
): Promise<ExecOutput[]> {
|
): Promise<ExecOutput[]> {
|
||||||
let owner = resourceName
|
let owner = resourceName
|
||||||
if (resourceType.toLowerCase().indexOf('deployment') > -1) {
|
if (resourceType.toLowerCase().indexOf('deployment') > -1) {
|
||||||
owner = await kubectl.getNewReplicaSet(resourceName)
|
owner = await kubectl.getNewReplicaSet(resourceName, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
const commandExecutionResults = []
|
const commandExecutionResults = []
|
||||||
@@ -72,7 +80,8 @@ export async function annotateChildPods(
|
|||||||
kubectl.annotate(
|
kubectl.annotate(
|
||||||
'pod',
|
'pod',
|
||||||
pod.metadata.name,
|
pod.metadata.name,
|
||||||
annotationKeyValStr
|
annotationKeyValStr,
|
||||||
|
namespace
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import {Kubectl, Resource} from '../types/kubectl'
|
|||||||
import {checkForErrors} from './kubectlUtils'
|
import {checkForErrors} from './kubectlUtils'
|
||||||
import {sleep} from './timeUtils'
|
import {sleep} from './timeUtils'
|
||||||
|
|
||||||
|
const IS_SILENT = false
|
||||||
|
const POD = 'pod'
|
||||||
|
|
||||||
export async function checkManifestStability(
|
export async function checkManifestStability(
|
||||||
kubectl: Kubectl,
|
kubectl: Kubectl,
|
||||||
resources: Resource[]
|
resources: Resource[]
|
||||||
@@ -20,24 +23,35 @@ export async function checkManifestStability(
|
|||||||
try {
|
try {
|
||||||
const result = await kubectl.checkRolloutStatus(
|
const result = await kubectl.checkRolloutStatus(
|
||||||
resource.type,
|
resource.type,
|
||||||
resource.name
|
resource.name,
|
||||||
|
resource.namespace
|
||||||
)
|
)
|
||||||
checkForErrors([result])
|
checkForErrors([result])
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
core.error(ex)
|
core.error(ex)
|
||||||
await kubectl.describe(resource.type, resource.name)
|
await kubectl.describe(
|
||||||
|
resource.type,
|
||||||
|
resource.name,
|
||||||
|
IS_SILENT,
|
||||||
|
resource.namespace
|
||||||
|
)
|
||||||
rolloutStatusHasErrors = true
|
rolloutStatusHasErrors = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.type == KubernetesConstants.KubernetesWorkload.POD) {
|
if (resource.type == KubernetesConstants.KubernetesWorkload.POD) {
|
||||||
try {
|
try {
|
||||||
await checkPodStatus(kubectl, resource.name)
|
await checkPodStatus(kubectl, resource)
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
core.warning(
|
core.warning(
|
||||||
`Could not determine pod status: ${JSON.stringify(ex)}`
|
`Could not determine pod status: ${JSON.stringify(ex)}`
|
||||||
)
|
)
|
||||||
await kubectl.describe(resource.type, resource.name)
|
await kubectl.describe(
|
||||||
|
resource.type,
|
||||||
|
resource.name,
|
||||||
|
IS_SILENT,
|
||||||
|
resource.namespace
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -45,14 +59,11 @@ export async function checkManifestStability(
|
|||||||
KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE
|
KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const service = await getService(kubectl, resource.name)
|
const service = await getService(kubectl, resource)
|
||||||
const {spec, status} = service
|
const {spec, status} = service
|
||||||
if (spec.type === KubernetesConstants.ServiceTypes.LOAD_BALANCER) {
|
if (spec.type === KubernetesConstants.ServiceTypes.LOAD_BALANCER) {
|
||||||
if (!isLoadBalancerIPAssigned(status)) {
|
if (!isLoadBalancerIPAssigned(status)) {
|
||||||
await waitForServiceExternalIPAssignment(
|
await waitForServiceExternalIPAssignment(kubectl, resource)
|
||||||
kubectl,
|
|
||||||
resource.name
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
core.info(
|
core.info(
|
||||||
`ServiceExternalIP ${resource.name} ${status.loadBalancer.ingress[0].ip}`
|
`ServiceExternalIP ${resource.name} ${status.loadBalancer.ingress[0].ip}`
|
||||||
@@ -63,7 +74,12 @@ export async function checkManifestStability(
|
|||||||
core.warning(
|
core.warning(
|
||||||
`Could not determine service status of: ${resource.name} Error: ${ex}`
|
`Could not determine service status of: ${resource.name} Error: ${ex}`
|
||||||
)
|
)
|
||||||
await kubectl.describe(resource.type, resource.name)
|
await kubectl.describe(
|
||||||
|
resource.type,
|
||||||
|
resource.name,
|
||||||
|
IS_SILENT,
|
||||||
|
resource.namespace
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +91,7 @@ export async function checkManifestStability(
|
|||||||
|
|
||||||
export async function checkPodStatus(
|
export async function checkPodStatus(
|
||||||
kubectl: Kubectl,
|
kubectl: Kubectl,
|
||||||
podName: string
|
pod: Resource
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const sleepTimeout = 10 * 1000 // 10 seconds
|
const sleepTimeout = 10 * 1000 // 10 seconds
|
||||||
const iterations = 60 // 60 * 10 seconds timeout = 10 minutes max timeout
|
const iterations = 60 // 60 * 10 seconds timeout = 10 minutes max timeout
|
||||||
@@ -85,8 +101,8 @@ export async function checkPodStatus(
|
|||||||
for (let i = 0; i < iterations; i++) {
|
for (let i = 0; i < iterations; i++) {
|
||||||
await sleep(sleepTimeout)
|
await sleep(sleepTimeout)
|
||||||
|
|
||||||
core.debug(`Polling for pod status: ${podName}`)
|
core.debug(`Polling for pod status: ${pod.name}`)
|
||||||
podStatus = await getPodStatus(kubectl, podName)
|
podStatus = await getPodStatus(kubectl, pod)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
podStatus &&
|
podStatus &&
|
||||||
@@ -97,37 +113,42 @@ export async function checkPodStatus(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
podStatus = await getPodStatus(kubectl, podName)
|
podStatus = await getPodStatus(kubectl, pod)
|
||||||
switch (podStatus.phase) {
|
switch (podStatus.phase) {
|
||||||
case 'Succeeded':
|
case 'Succeeded':
|
||||||
case 'Running':
|
case 'Running':
|
||||||
if (isPodReady(podStatus)) {
|
if (isPodReady(podStatus)) {
|
||||||
console.log(`pod/${podName} is successfully rolled out`)
|
console.log(`pod/${pod.name} is successfully rolled out`)
|
||||||
} else {
|
} else {
|
||||||
kubectlDescribeNeeded = true
|
kubectlDescribeNeeded = true
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'Pending':
|
case 'Pending':
|
||||||
if (!isPodReady(podStatus)) {
|
if (!isPodReady(podStatus)) {
|
||||||
core.warning(`pod/${podName} rollout status check timed out`)
|
core.warning(`pod/${pod.name} rollout status check timed out`)
|
||||||
kubectlDescribeNeeded = true
|
kubectlDescribeNeeded = true
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'Failed':
|
case 'Failed':
|
||||||
core.error(`pod/${podName} rollout failed`)
|
core.error(`pod/${pod.name} rollout failed`)
|
||||||
kubectlDescribeNeeded = true
|
kubectlDescribeNeeded = true
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
core.warning(`pod/${podName} rollout status: ${podStatus.phase}`)
|
core.warning(`pod/${pod.name} rollout status: ${podStatus.phase}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kubectlDescribeNeeded) {
|
if (kubectlDescribeNeeded) {
|
||||||
await kubectl.describe('pod', podName)
|
await kubectl.describe(POD, pod.name, IS_SILENT, pod.namespace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPodStatus(kubectl: Kubectl, podName: string) {
|
async function getPodStatus(kubectl: Kubectl, pod: Resource) {
|
||||||
const podResult = await kubectl.getResource('pod', podName)
|
const podResult = await kubectl.getResource(
|
||||||
|
POD,
|
||||||
|
pod.name,
|
||||||
|
IS_SILENT,
|
||||||
|
pod.namespace
|
||||||
|
)
|
||||||
checkForErrors([podResult])
|
checkForErrors([podResult])
|
||||||
|
|
||||||
return JSON.parse(podResult.stdout).status
|
return JSON.parse(podResult.stdout).status
|
||||||
@@ -151,10 +172,12 @@ function isPodReady(podStatus: any): boolean {
|
|||||||
return allContainersAreReady
|
return allContainersAreReady
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getService(kubectl: Kubectl, serviceName) {
|
async function getService(kubectl: Kubectl, service: Resource) {
|
||||||
const serviceResult = await kubectl.getResource(
|
const serviceResult = await kubectl.getResource(
|
||||||
KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE,
|
KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE,
|
||||||
serviceName
|
service.name,
|
||||||
|
IS_SILENT,
|
||||||
|
service.namespace
|
||||||
)
|
)
|
||||||
|
|
||||||
checkForErrors([serviceResult])
|
checkForErrors([serviceResult])
|
||||||
@@ -163,25 +186,25 @@ async function getService(kubectl: Kubectl, serviceName) {
|
|||||||
|
|
||||||
async function waitForServiceExternalIPAssignment(
|
async function waitForServiceExternalIPAssignment(
|
||||||
kubectl: Kubectl,
|
kubectl: Kubectl,
|
||||||
serviceName: string
|
service: Resource
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const sleepTimeout = 10 * 1000 // 10 seconds
|
const sleepTimeout = 10 * 1000 // 10 seconds
|
||||||
const iterations = 18 // 18 * 10 seconds timeout = 3 minutes max timeout
|
const iterations = 18 // 18 * 10 seconds timeout = 3 minutes max timeout
|
||||||
|
|
||||||
for (let i = 0; i < iterations; i++) {
|
for (let i = 0; i < iterations; i++) {
|
||||||
core.info(`Wait for service ip assignment : ${serviceName}`)
|
core.info(`Wait for service ip assignment : ${service.name}`)
|
||||||
await sleep(sleepTimeout)
|
await sleep(sleepTimeout)
|
||||||
|
|
||||||
const status = (await getService(kubectl, serviceName)).status
|
const status = (await getService(kubectl, service)).status
|
||||||
if (isLoadBalancerIPAssigned(status)) {
|
if (isLoadBalancerIPAssigned(status)) {
|
||||||
core.info(
|
core.info(
|
||||||
`ServiceExternalIP ${serviceName} ${status.loadBalancer.ingress[0].ip}`
|
`ServiceExternalIP ${service.name} ${status.loadBalancer.ingress[0].ip}`
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core.warning(`Wait for service ip assignment timed out${serviceName}`)
|
core.warning(`Wait for service ip assignment timed out ${service.name}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLoadBalancerIPAssigned(status: any) {
|
function isLoadBalancerIPAssigned(status: any) {
|
||||||
|
|||||||
@@ -280,7 +280,8 @@ export function getResources(
|
|||||||
) {
|
) {
|
||||||
resources.push({
|
resources.push({
|
||||||
type: inputObject.kind,
|
type: inputObject.kind,
|
||||||
name: inputObject.metadata.name
|
name: inputObject.metadata.name,
|
||||||
|
namespace: inputObject?.metadata?.namespace
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user