diff --git a/lib/kubectl-object-model.js b/lib/kubectl-object-model.js index efaaa73f..2d551c63 100644 --- a/lib/kubectl-object-model.js +++ b/lib/kubectl-object-model.js @@ -1,5 +1,5 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } @@ -71,6 +71,9 @@ class Kubectl { }); return results; } + executeCommand(customCommand, args) { + return args ? this.execute([customCommand, args]) : this.execute([customCommand]); + } delete(args) { if (typeof args === 'string') return this.execute(['delete', args]); diff --git a/lib/kubectl-util.js b/lib/kubectl-util.js index d61d2f6f..84c00975 100644 --- a/lib/kubectl-util.js +++ b/lib/kubectl-util.js @@ -69,3 +69,12 @@ function downloadKubectl(version) { }); } exports.downloadKubectl = downloadKubectl; +function getTrafficSplitAPIVersion(kubectl) { + const result = kubectl.executeCommand('api-versions'); + const trafficSplitAPIVersion = result.stdout.split('\n').find(version => version.startsWith('split.smi-spec.io')); + if (trafficSplitAPIVersion == null || typeof trafficSplitAPIVersion == 'undefined') { + throw new Error('UnableToCreateTrafficSplitManifestFile'); + } + return trafficSplitAPIVersion; +} +exports.getTrafficSplitAPIVersion = getTrafficSplitAPIVersion; diff --git a/lib/utilities/strategy-helpers/smi-canary-deployment-helper.js b/lib/utilities/strategy-helpers/smi-canary-deployment-helper.js index a11ffc3e..0358bf69 100644 --- a/lib/utilities/strategy-helpers/smi-canary-deployment-helper.js +++ b/lib/utilities/strategy-helpers/smi-canary-deployment-helper.js @@ -8,10 +8,12 @@ const TaskInputParameters = require("../../input-parameters"); const fileHelper = require("../files-helper"); const helper = require("../resource-object-utility"); const utils = require("../manifest-utilities"); +const kubectlUtils = require("../../kubectl-util"); const canaryDeploymentHelper = require("./canary-deployment-helper"); const utility_1 = require("../utility"); const TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX = '-workflow-rollout'; const TRAFFIC_SPLIT_OBJECT = 'TrafficSplit'; +var trafficSplitAPIVersion = null; function deploySMICanary(kubectl, filePaths) { const newObjectsList = []; const canaryReplicaCount = parseInt(TaskInputParameters.baselineAndCanaryReplicas); @@ -80,7 +82,7 @@ function createCanaryService(kubectl, filePaths) { core.debug('New stable service object is: ' + JSON.stringify(newStableServiceObject)); newObjectsList.push(newStableServiceObject); core.debug('Creating the traffic object for service: ' + name); - const trafficObject = createTrafficSplitManifestFile(name, 0, 0, 1000); + const trafficObject = createTrafficSplitManifestFile(kubectl, name, 0, 0, 1000); core.debug('Creating the traffic object for service: ' + trafficObject); trafficObjectsList.push(trafficObject); } @@ -100,7 +102,7 @@ function createCanaryService(kubectl, filePaths) { } if (updateTrafficObject) { core.debug('Stable service object present so updating the traffic object for service: ' + name); - trafficObjectsList.push(updateTrafficSplitObject(name)); + trafficObjectsList.push(updateTrafficSplitObject(kubectl, name)); } } } @@ -133,7 +135,7 @@ function adjustTraffic(kubectl, manifestFilePaths, stableWeight, canaryWeight) { const name = inputObject.metadata.name; const kind = inputObject.kind; if (helper.isServiceEntity(kind)) { - trafficSplitManifests.push(createTrafficSplitManifestFile(name, stableWeight, 0, canaryWeight)); + trafficSplitManifests.push(createTrafficSplitManifestFile(kubectl, name, stableWeight, 0, canaryWeight)); serviceObjects.push(name); } }); @@ -145,24 +147,27 @@ function adjustTraffic(kubectl, manifestFilePaths, stableWeight, canaryWeight) { core.debug('serviceObjects:' + serviceObjects.join(',') + ' result:' + result); utility_1.checkForErrors([result]); } -function updateTrafficSplitObject(serviceName) { +function updateTrafficSplitObject(kubectl, serviceName) { const percentage = parseInt(TaskInputParameters.canaryPercentage) * 10; const baselineAndCanaryWeight = percentage / 2; const stableDeploymentWeight = 1000 - percentage; core.debug('Creating the traffic object with canary weight: ' + baselineAndCanaryWeight + ',baseling weight: ' + baselineAndCanaryWeight + ',stable: ' + stableDeploymentWeight); - return createTrafficSplitManifestFile(serviceName, stableDeploymentWeight, baselineAndCanaryWeight, baselineAndCanaryWeight); + return createTrafficSplitManifestFile(kubectl, serviceName, stableDeploymentWeight, baselineAndCanaryWeight, baselineAndCanaryWeight); } -function createTrafficSplitManifestFile(serviceName, stableWeight, baselineWeight, canaryWeight) { - const smiObjectString = getTrafficSplitObject(serviceName, stableWeight, baselineWeight, canaryWeight); +function createTrafficSplitManifestFile(kubectl, serviceName, stableWeight, baselineWeight, canaryWeight) { + const smiObjectString = getTrafficSplitObject(kubectl, serviceName, stableWeight, baselineWeight, canaryWeight); const manifestFile = fileHelper.writeManifestToFile(smiObjectString, TRAFFIC_SPLIT_OBJECT, serviceName); if (!manifestFile) { throw new Error('UnableToCreateTrafficSplitManifestFile'); } return manifestFile; } -function getTrafficSplitObject(name, stableWeight, baselineWeight, canaryWeight) { +function getTrafficSplitObject(kubectl, name, stableWeight, baselineWeight, canaryWeight) { + if (!trafficSplitAPIVersion) { + trafficSplitAPIVersion = kubectlUtils.getTrafficSplitAPIVersion(kubectl); + } const trafficSplitObjectJson = `{ - "apiVersion": "split.smi-spec.io/v1alpha1", + "apiVersion": "${trafficSplitAPIVersion}", "kind": "TrafficSplit", "metadata": { "name": "%s" diff --git a/src/kubectl-util.ts b/src/kubectl-util.ts index c5b17204..ec92a72c 100644 --- a/src/kubectl-util.ts +++ b/src/kubectl-util.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as toolCache from '@actions/tool-cache'; import * as core from '@actions/core'; -import { Kubectl } from 'kubectl-object-model'; +import { Kubectl } from './kubectl-object-model'; const kubectlToolName = 'kubectl'; const stableKubectlVersion = 'v1.15.0';