Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v4 new release #212

Merged
merged 9 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,15 @@ Following are the key capabilities of this action:
<tr>
<td>manifests </br></br>(Required)</td>
<td>Path to the manifest files to be used for deployment. These can also be directories containing manifest files, in which case, all manifest files in the referenced directory at every depth will be deployed. Files not ending in .yml or .yaml will be ignored.</td>
</tr>
</tr>
<tr>
<td>strategy </br></br>(Required)</td>
<td>Acceptable values: basic/canary/blue-green. <br>
Default value: basic
<br>Deployment strategy to be used while applying manifest files on the cluster.
<br>basic - Template is force applied to all pods when deploying to cluster. NOTE: Can only be used with action == deploy
<br>canary - Canary deployment strategy is used when deploying to the cluster.<br>blue-green - Blue-Green deployment strategy is used when deploying to cluster.</td>
</tr>
<tr>
<td>namespace </br></br>(Optional)
<td>Namespace within the cluster to deploy to.</td>
Expand All @@ -62,11 +70,6 @@ Following are the key capabilities of this action:
<td>pull-images</br></br>(Optional)</td>
<td>Acceptable values: true/false</br>Default value: true</br>Switch whether to pull the images from the registry before deployment to find out Dockerfile's path in order to add it to the annotations</td>
</tr>
<tr>
<td>strategy </br></br>(Optional)</td>
<td>Acceptable values: none/canary/blue-green. <br>
Deployment strategy to be used while applying manifest files on the cluster.<br>none - No deployment strategy is used when deploying.<br>canary - Canary deployment strategy is used when deploying to the cluster.<br>blue-green - Blue-Green deployment strategy is used when deploying to cluster.</td>
</tr>
<tr>
<td>traffic-split-method </br></br>(Optional)</td>
<td>Acceptable values: pod/smi.<br> Default value: pod <br>SMI: Percentage traffic split is done at request level using service mesh. Service mesh has to be setup by cluster admin. Orchestration of <a href="https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-split/v1alpha3/traffic-split.md" data-raw-source="TrafficSplit](https://github.com/deislabs/smi-spec/blob/master/traffic-split.md)">TrafficSplit</a> objects of SMI is handled by this action. <br>Pod: Percentage split not possible at request level in the absence of service mesh. Percentage input is used to calculate the replicas for baseline and canary as a percentage of replicas specified in the input manifests for the stable variant.</td>
Expand Down
6 changes: 3 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ inputs:
required: false
default: true
strategy:
description: 'Deployment strategy to be used. Allowed values are none, canary and blue-green'
required: false
default: 'none'
description: 'Deployment strategy to be used. Allowed values are basic, canary and blue-green'
required: true
default: 'basic'
route-method:
description: 'Route based on service, ingress or SMI for blue-green strategy'
required: false
Expand Down
74 changes: 51 additions & 23 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17940,31 +17940,35 @@ function deploy(kubectl, manifestFilePaths, deploymentStrategy) {
const inputManifestFiles = manifestUpdateUtils_1.updateManifestFiles(manifestFilePaths);
core.debug('Input manifest files: ' + inputManifestFiles);
// deploy manifests
core.info('Deploying manifests');
core.startGroup('Deploying manifests');
const trafficSplitMethod = trafficSplitMethod_1.parseTrafficSplitMethod(core.getInput('traffic-split-method', { required: true }));
const deployedManifestFiles = yield deploymentHelper_1.deployManifests(inputManifestFiles, deploymentStrategy, kubectl, trafficSplitMethod);
core.endGroup();
core.debug('Deployed manifest files: ' + deployedManifestFiles);
// check manifest stability
core.info('Checking manifest stability');
core.startGroup('Checking manifest stability');
const resourceTypes = manifestUpdateUtils_1.getResources(deployedManifestFiles, models.DEPLOYMENT_TYPES.concat([
KubernetesConstants.DiscoveryAndLoadBalancerResource.SERVICE
]));
yield deploymentHelper_1.checkManifestStability(kubectl, resourceTypes);
core.endGroup();
if (deploymentStrategy == deploymentStrategy_1.DeploymentStrategy.BLUE_GREEN) {
core.info('Routing blue green');
core.startGroup('Routing blue green');
const routeStrategy = routeStrategy_1.parseRouteStrategy(core.getInput('route-method', { required: true }));
yield blueGreenHelper_1.routeBlueGreen(kubectl, inputManifestFiles, routeStrategy);
core.endGroup();
}
// print ingresses
core.info('Printing ingresses');
core.startGroup('Printing ingresses');
const ingressResources = manifestUpdateUtils_1.getResources(deployedManifestFiles, [
KubernetesConstants.DiscoveryAndLoadBalancerResource.INGRESS
]);
for (const ingressResource of ingressResources) {
yield kubectl.getResource(KubernetesConstants.DiscoveryAndLoadBalancerResource.INGRESS, ingressResource.name);
}
core.endGroup();
// annotate resources
core.info('Annotating resources');
core.startGroup('Annotating resources');
let allPods;
try {
allPods = JSON.parse((yield kubectl.getAllPods()).stdout);
Expand All @@ -17973,6 +17977,7 @@ function deploy(kubectl, manifestFilePaths, deploymentStrategy) {
core.debug('Unable to parse pods: ' + e);
}
yield deploymentHelper_1.annotateAndLabelResources(deployedManifestFiles, kubectl, resourceTypes, allPods);
core.endGroup();
});
}
exports.deploy = deploy;
Expand Down Expand Up @@ -18033,25 +18038,30 @@ function promoteCanary(kubectl, manifests) {
includeServices = true;
// In case of SMI traffic split strategy when deployment is promoted, first we will redirect traffic to
// canary deployment, then update stable deployment and then redirect traffic to stable deployment
core.info('Redirecting traffic to canary deployment');
core.startGroup('Redirecting traffic to canary deployment');
yield SMICanaryDeploymentHelper.redirectTrafficToCanaryDeployment(kubectl, manifests);
core.info('Deploying input manifests with SMI canary strategy');
core.endGroup();
core.startGroup('Deploying input manifests with SMI canary strategy');
yield deploy.deploy(kubectl, manifests, deploymentStrategy_1.DeploymentStrategy.CANARY);
core.info('Redirecting traffic to stable deployment');
core.endGroup();
core.startGroup('Redirecting traffic to stable deployment');
yield SMICanaryDeploymentHelper.redirectTrafficToStableDeployment(kubectl, manifests);
core.endGroup();
}
else {
core.info('Deploying input manifests');
core.startGroup('Deploying input manifests');
yield deploy.deploy(kubectl, manifests, deploymentStrategy_1.DeploymentStrategy.CANARY);
core.endGroup();
}
core.info('Deleting canary and baseline workloads');
core.startGroup('Deleting canary and baseline workloads');
try {
yield canaryDeploymentHelper.deleteCanaryDeployment(kubectl, manifests, includeServices);
}
catch (ex) {
core.warning('Exception occurred while deleting canary and baseline workloads: ' +
ex);
}
core.endGroup();
});
}
function promoteBlueGreen(kubectl, manifests) {
Expand All @@ -18060,7 +18070,7 @@ function promoteBlueGreen(kubectl, manifests) {
const inputManifestFiles = manifestUpdateUtils_1.updateManifestFiles(manifests);
const manifestObjects = blueGreenHelper_1.getManifestObjects(inputManifestFiles);
const routeStrategy = routeStrategy_1.parseRouteStrategy(core.getInput('route-method', { required: true }));
core.info('Deleting old deployment and making new one');
core.startGroup('Deleting old deployment and making new one');
let result;
if (routeStrategy == routeStrategy_1.RouteStrategy.INGRESS) {
result = yield ingressBlueGreenHelper_1.promoteBlueGreenIngress(kubectl, manifestObjects);
Expand All @@ -18071,14 +18081,16 @@ function promoteBlueGreen(kubectl, manifests) {
else {
result = yield serviceBlueGreenHelper_1.promoteBlueGreenService(kubectl, manifestObjects);
}
core.endGroup();
// checking stability of newly created deployments
core.info('Checking manifest stability');
core.startGroup('Checking manifest stability');
const deployedManifestFiles = result.newFilePaths;
const resources = manifestUpdateUtils_1.getResources(deployedManifestFiles, models.DEPLOYMENT_TYPES.concat([
models.DiscoveryAndLoadBalancerResource.SERVICE
]));
yield KubernetesManifestUtility.checkManifestStability(kubectl, resources);
core.info('Routing to new deployments and deleting old workloads and services');
core.endGroup();
core.startGroup('Routing to new deployments and deleting old workloads and services');
if (routeStrategy == routeStrategy_1.RouteStrategy.INGRESS) {
yield ingressBlueGreenHelper_1.routeBlueGreenIngress(kubectl, null, manifestObjects.serviceNameMap, manifestObjects.ingressEntityList);
yield blueGreenHelper_1.deleteWorkloadsAndServicesWithLabel(kubectl, blueGreenHelper_1.GREEN_LABEL_VALUE, manifestObjects.deploymentEntityList, manifestObjects.serviceEntityList);
Expand All @@ -18092,6 +18104,7 @@ function promoteBlueGreen(kubectl, manifests) {
yield serviceBlueGreenHelper_1.routeBlueGreenService(kubectl, blueGreenHelper_1.NONE_LABEL_VALUE, manifestObjects.serviceEntityList);
yield blueGreenHelper_1.deleteWorkloadsWithLabel(kubectl, blueGreenHelper_1.GREEN_LABEL_VALUE, manifestObjects.deploymentEntityList);
}
core.endGroup();
});
}

Expand Down Expand Up @@ -18143,17 +18156,19 @@ function rejectCanary(kubectl, manifests) {
let includeServices = false;
const trafficSplitMethod = trafficSplitMethod_1.parseTrafficSplitMethod(core.getInput('traffic-split-method', { required: true }));
if (trafficSplitMethod == trafficSplitMethod_1.TrafficSplitMethod.SMI) {
core.info('Rejecting deployment with SMI canary strategy');
core.startGroup('Rejecting deployment with SMI canary strategy');
includeServices = true;
yield SMICanaryDeploymentHelper.redirectTrafficToStableDeployment(kubectl, manifests);
core.endGroup();
}
core.info('Deleting baseline and canary workloads');
core.startGroup('Deleting baseline and canary workloads');
yield canaryDeploymentHelper.deleteCanaryDeployment(kubectl, manifests, includeServices);
core.endGroup();
});
}
function rejectBlueGreen(kubectl, manifests) {
return __awaiter(this, void 0, void 0, function* () {
core.info('Rejecting deployment with blue green strategy');
core.startGroup('Rejecting deployment with blue green strategy');
const routeStrategy = routeStrategy_1.parseRouteStrategy(core.getInput('route-method', { required: true }));
if (routeStrategy == routeStrategy_1.RouteStrategy.INGRESS) {
yield ingressBlueGreenHelper_1.rejectBlueGreenIngress(kubectl, manifests);
Expand All @@ -18164,6 +18179,7 @@ function rejectBlueGreen(kubectl, manifests) {
else {
yield serviceBlueGreenHelper_1.rejectBlueGreenService(kubectl, manifests);
}
core.endGroup();
});
}

Expand Down Expand Up @@ -19523,10 +19539,7 @@ function deployManifests(files, deploymentStrategy, kubectl, trafficSplitMethod)
kubectlUtils_1.checkForErrors([result]);
return newFilePaths;
}
case undefined: {
core.warning('Deployment strategy is not recognized.');
}
default: {
case deploymentStrategy_1.DeploymentStrategy.BASIC: {
const trafficSplitMethod = trafficSplitMethod_1.parseTrafficSplitMethod(core.getInput('traffic-split-method', { required: true }));
const forceDeployment = core.getInput('force').toLowerCase() === 'true';
if (trafficSplitMethod === trafficSplitMethod_1.TrafficSplitMethod.SMI) {
Expand All @@ -19540,6 +19553,9 @@ function deployManifests(files, deploymentStrategy, kubectl, trafficSplitMethod)
}
return files;
}
default: {
throw new Error('Deployment strategy is not recognized.');
}
}
});
}
Expand Down Expand Up @@ -19605,8 +19621,8 @@ function annotateResources(files, kubectl, resourceTypes, allPods, annotationKey
function labelResources(files, kubectl, label) {
return __awaiter(this, void 0, void 0, function* () {
const labels = [
`workflowFriendlyName=${githubUtils_1.normalizeWorkflowStrLabel(process.env.GITHUB_WORKFLOW)}`,
`workflow=${label}`
`workflowFriendlyName=${workflowAnnotationUtils_1.cleanLabel(githubUtils_1.normalizeWorkflowStrLabel(process.env.GITHUB_WORKFLOW))}`,
`workflow=${workflowAnnotationUtils_1.cleanLabel(label)}`
];
kubectlUtils_1.checkForErrors([yield kubectl.labelFiles(files, labels)], true);
});
Expand Down Expand Up @@ -19647,6 +19663,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.parseDeploymentStrategy = exports.DeploymentStrategy = void 0;
var DeploymentStrategy;
(function (DeploymentStrategy) {
DeploymentStrategy["BASIC"] = "basic";
DeploymentStrategy["CANARY"] = "canary";
DeploymentStrategy["BLUE_GREEN"] = "blue-green";
})(DeploymentStrategy = exports.DeploymentStrategy || (exports.DeploymentStrategy = {}));
Expand Down Expand Up @@ -21001,7 +21018,7 @@ exports.getTrafficSplitAPIVersion = getTrafficSplitAPIVersion;
"use strict";

Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getWorkflowAnnotationKeyLabel = exports.getWorkflowAnnotations = exports.prefixObjectKeys = void 0;
exports.cleanLabel = exports.getWorkflowAnnotationKeyLabel = exports.getWorkflowAnnotations = exports.prefixObjectKeys = void 0;
const ANNOTATION_PREFIX = 'actions.github.com/';
function prefixObjectKeys(obj, prefix) {
return Object.keys(obj).reduce((newObj, key) => {
Expand Down Expand Up @@ -21039,6 +21056,17 @@ function getWorkflowAnnotationKeyLabel(workflowFilePath) {
return `githubWorkflow_${hashKey}`;
}
exports.getWorkflowAnnotationKeyLabel = getWorkflowAnnotationKeyLabel;
/**
* Cleans label to match valid kubernetes label specification by removing invalid characters
* @param label
* @returns cleaned label
*/
function cleanLabel(label) {
const removedInvalidChars = label.replace(/[^-A-Za-z0-9_.]/gi, '');
const regex = /([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]/;
return regex.exec(removedInvalidChars)[0] || '';
}
exports.cleanLabel = cleanLabel;


/***/ }),
Expand Down
9 changes: 9 additions & 0 deletions node_modules/.package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions node_modules/@vercel/ncc/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node_modules/@vercel/ncc/dist/ncc/@@notfound.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading