diff --git a/Tasks/AzureFunctionOnKubernetesV0/task.json b/Tasks/AzureFunctionOnKubernetesV0/task.json index 67abeebeb935..8fb61e0025f3 100644 --- a/Tasks/AzureFunctionOnKubernetesV0/task.json +++ b/Tasks/AzureFunctionOnKubernetesV0/task.json @@ -14,12 +14,11 @@ "author": "Microsoft Corporation", "version": { "Major": 0, - "Minor": 162, - "Patch": 1 + "Minor": 164, + "Patch": 0 }, "demands": [], - "groups": [ - { + "groups": [{ "name": "serviceConnections", "displayName": "Service Connections", "isExpanded": true @@ -30,8 +29,7 @@ "isExpanded": true } ], - "inputs": [ - { + "inputs": [{ "name": "dockerRegistryServiceConnection", "type": "connectedService:dockerregistry", "label": "Docker registry service connection", diff --git a/Tasks/AzureFunctionOnKubernetesV0/task.loc.json b/Tasks/AzureFunctionOnKubernetesV0/task.loc.json index f31f619e784f..c5df5e940837 100644 --- a/Tasks/AzureFunctionOnKubernetesV0/task.loc.json +++ b/Tasks/AzureFunctionOnKubernetesV0/task.loc.json @@ -14,12 +14,11 @@ "author": "Microsoft Corporation", "version": { "Major": 0, - "Minor": 162, - "Patch": 1 + "Minor": 164, + "Patch": 0 }, "demands": [], - "groups": [ - { + "groups": [{ "name": "serviceConnections", "displayName": "ms-resource:loc.group.displayName.serviceConnections", "isExpanded": true @@ -30,8 +29,7 @@ "isExpanded": true } ], - "inputs": [ - { + "inputs": [{ "name": "dockerRegistryServiceConnection", "type": "connectedService:dockerregistry", "label": "ms-resource:loc.input.label.dockerRegistryServiceConnection", diff --git a/Tasks/Common/kubernetes-common-v2/kubernetesmanifestutility.ts b/Tasks/Common/kubernetes-common-v2/kubernetesmanifestutility.ts index ced249de7724..eadd10ff34d3 100644 --- a/Tasks/Common/kubernetes-common-v2/kubernetesmanifestutility.ts +++ b/Tasks/Common/kubernetes-common-v2/kubernetesmanifestutility.ts @@ -7,18 +7,30 @@ import * as KubernetesConstants from './kubernetesconstants'; import { Kubectl, Resource } from './kubectl-object-model'; export async function checkManifestStability(kubectl: Kubectl, resources: Resource[], timeoutInSeconds?: string): Promise { - const rolloutStatusResults = []; + const environmentUrl = getEnvironmentUrl(); + if (environmentUrl) + tl.debug('For more information, go to ' + environmentUrl); + + let rolloutStatusHasErrors = false; const numberOfResources = resources.length; for (let i = 0; i < numberOfResources; i++) { const resource = resources[i]; if (KubernetesConstants.workloadTypesWithRolloutStatus.indexOf(resource.type.toLowerCase()) >= 0) { - rolloutStatusResults.push(kubectl.checkRolloutStatus(resource.type, resource.name, timeoutInSeconds)); + try { + let result = kubectl.checkRolloutStatus(resource.type, resource.name, timeoutInSeconds); + utils.checkForErrors([result]); + } catch (ex) { + tl.error(ex); + describeResource(kubectl, resource.type, resource.name, environmentUrl); + rolloutStatusHasErrors = true; + } } if (utils.isEqual(resource.type, KubernetesConstants.KubernetesWorkload.pod, true)) { try { await checkPodStatus(kubectl, resource.name); } catch (ex) { tl.warning(tl.loc('CouldNotDeterminePodStatus', JSON.stringify(ex))); + describeResource(kubectl, resource.type, resource.name, environmentUrl); } } if (utils.isEqual(resource.type, KubernetesConstants.DiscoveryAndLoadBalancerResource.service, true)) { @@ -35,11 +47,14 @@ export async function checkManifestStability(kubectl: Kubectl, resources: Resour } } catch (ex) { tl.warning(tl.loc('CouldNotDetermineServiceStatus', resource.name, JSON.stringify(ex))); + describeResource(kubectl, resource.type, resource.name, environmentUrl); } } } - utils.checkForErrors(rolloutStatusResults); + if (rolloutStatusHasErrors) { + throw new Error(tl.loc('RolloutStatusTimedout')); + } } export async function checkPodStatus(kubectl: Kubectl, podName: string): Promise { @@ -55,20 +70,25 @@ export async function checkPodStatus(kubectl: Kubectl, podName: string): Promise } } podStatus = getPodStatus(kubectl, podName); + const environmentUrl = getEnvironmentUrl(); switch (podStatus.phase) { case 'Succeeded': case 'Running': if (isPodReady(podStatus)) { console.log(`pod/${podName} is successfully rolled out`); + } else { + describeResource(kubectl, KubernetesConstants.KubernetesWorkload.pod, podName, environmentUrl); } break; case 'Pending': if (!isPodReady(podStatus)) { tl.warning(`pod/${podName} rollout status check timedout`); + describeResource(kubectl, KubernetesConstants.KubernetesWorkload.pod, podName, environmentUrl); } break; case 'Failed': tl.error(`pod/${podName} rollout failed`); + describeResource(kubectl, KubernetesConstants.KubernetesWorkload.pod, podName, environmentUrl); break; default: tl.warning(`pod/${podName} rollout status: ${podStatus.phase}`); @@ -124,4 +144,22 @@ function isLoadBalancerIPAssigned(status: any) { return true; } return false; +} + +function getEnvironmentUrl(): string { + const environmentId = tl.getVariable('Environment.Id'); + let requestUrl = null; + if (environmentId) { + requestUrl = tl.getVariable('System.TeamFoundationCollectionUri') + tl.getVariable('System.TeamProject') + '/_environments/' + tl.getVariable('Environment.Id'); + const resourceId = tl.getVariable('Environment.ResourceId'); + requestUrl = resourceId ? requestUrl + '/providers/kubernetes/' + resourceId : requestUrl; + } + + return requestUrl; +} + +function describeResource(kubectl: Kubectl, resourceType: string, resourceName: string, environmentUrl: string) { + kubectl.describe(resourceType, resourceName); + if (environmentUrl) + console.log(tl.loc('EnvironmentLink', environmentUrl)); } \ No newline at end of file diff --git a/Tasks/HelmDeployV0/task.json b/Tasks/HelmDeployV0/task.json index 5b8d2296a456..dd92c7b8b1c7 100644 --- a/Tasks/HelmDeployV0/task.json +++ b/Tasks/HelmDeployV0/task.json @@ -14,7 +14,7 @@ "version": { "Major": 0, "Minor": 164, - "Patch": 0 + "Patch": 1 }, "demands": [], "groups": [{ diff --git a/Tasks/HelmDeployV0/task.loc.json b/Tasks/HelmDeployV0/task.loc.json index f32ec6625173..926178c1ed0e 100644 --- a/Tasks/HelmDeployV0/task.loc.json +++ b/Tasks/HelmDeployV0/task.loc.json @@ -14,7 +14,7 @@ "version": { "Major": 0, "Minor": 164, - "Patch": 0 + "Patch": 1 }, "demands": [], "groups": [{ diff --git a/Tasks/HelmInstallerV1/task.json b/Tasks/HelmInstallerV1/task.json index 0d721ca8b9da..d2fdf20be9f9 100644 --- a/Tasks/HelmInstallerV1/task.json +++ b/Tasks/HelmInstallerV1/task.json @@ -13,8 +13,8 @@ "author": "Microsoft Corporation", "version": { "Major": 1, - "Minor": 162, - "Patch": 1 + "Minor": 164, + "Patch": 0 }, "preview": true, "demands": [], @@ -22,15 +22,13 @@ "Helm" ], "groups": [], - "inputs": [ - { - "name": "helmVersionToInstall", - "label": "Helm Version Spec", - "type": "string", - "helpMarkDown": "Specify the version of Helm to install.", - "defaultValue": "latest" - } - ], + "inputs": [{ + "name": "helmVersionToInstall", + "label": "Helm Version Spec", + "type": "string", + "helpMarkDown": "Specify the version of Helm to install.", + "defaultValue": "latest" + }], "instanceNameFormat": "Install Helm $(helmVersionToInstall)", "execution": { "Node": { @@ -41,4 +39,4 @@ "NotAValidSemverVersion": "Version not specified in correct format. E.g: 1.8.2, v1.8.2, 2.8.2, v2.8.2.", "VerifyHelmInstallation": "Verifying helm installation..." } -} +} \ No newline at end of file diff --git a/Tasks/HelmInstallerV1/task.loc.json b/Tasks/HelmInstallerV1/task.loc.json index 86e6ce6aea6e..f9ec17ddf4af 100644 --- a/Tasks/HelmInstallerV1/task.loc.json +++ b/Tasks/HelmInstallerV1/task.loc.json @@ -13,8 +13,8 @@ "author": "Microsoft Corporation", "version": { "Major": 1, - "Minor": 162, - "Patch": 1 + "Minor": 164, + "Patch": 0 }, "preview": true, "demands": [], @@ -22,15 +22,13 @@ "Helm" ], "groups": [], - "inputs": [ - { - "name": "helmVersionToInstall", - "label": "ms-resource:loc.input.label.helmVersionToInstall", - "type": "string", - "helpMarkDown": "ms-resource:loc.input.help.helmVersionToInstall", - "defaultValue": "latest" - } - ], + "inputs": [{ + "name": "helmVersionToInstall", + "label": "ms-resource:loc.input.label.helmVersionToInstall", + "type": "string", + "helpMarkDown": "ms-resource:loc.input.help.helmVersionToInstall", + "defaultValue": "latest" + }], "instanceNameFormat": "ms-resource:loc.instanceNameFormat", "execution": { "Node": { diff --git a/Tasks/KubectlInstallerV0/task.json b/Tasks/KubectlInstallerV0/task.json index 5c99b8626c61..b42c06b9eb6a 100644 --- a/Tasks/KubectlInstallerV0/task.json +++ b/Tasks/KubectlInstallerV0/task.json @@ -13,23 +13,21 @@ "author": "Microsoft Corporation", "version": { "Major": 0, - "Minor": 162, - "Patch": 1 + "Minor": 164, + "Patch": 0 }, "demands": [], "satisfies": [ "Kubectl" ], "groups": [], - "inputs": [ - { - "name": "kubectlVersion", - "label": "Kubectl Version Spec", - "type": "string", - "helpMarkDown": "Specify the version of Kubectl to install", - "defaultValue": "latest" - } - ], + "inputs": [{ + "name": "kubectlVersion", + "label": "Kubectl Version Spec", + "type": "string", + "helpMarkDown": "Specify the version of Kubectl to install", + "defaultValue": "latest" + }], "instanceNameFormat": "Install Kubectl $(kubectlVersion)", "execution": { "Node": { @@ -40,4 +38,4 @@ "NotAValidSemverVersion": "Version not specified in correct format. E.g: 1.8.2, v1.8.2, 2.8.2, v2.8.2.", "VerifyKubectlInstallation": "Verifying kubectl installation..." } -} +} \ No newline at end of file diff --git a/Tasks/KubectlInstallerV0/task.loc.json b/Tasks/KubectlInstallerV0/task.loc.json index aed7ea0abf27..987d8db72e03 100644 --- a/Tasks/KubectlInstallerV0/task.loc.json +++ b/Tasks/KubectlInstallerV0/task.loc.json @@ -13,23 +13,21 @@ "author": "Microsoft Corporation", "version": { "Major": 0, - "Minor": 162, - "Patch": 1 + "Minor": 164, + "Patch": 0 }, "demands": [], "satisfies": [ "Kubectl" ], "groups": [], - "inputs": [ - { - "name": "kubectlVersion", - "label": "ms-resource:loc.input.label.kubectlVersion", - "type": "string", - "helpMarkDown": "ms-resource:loc.input.help.kubectlVersion", - "defaultValue": "latest" - } - ], + "inputs": [{ + "name": "kubectlVersion", + "label": "ms-resource:loc.input.label.kubectlVersion", + "type": "string", + "helpMarkDown": "ms-resource:loc.input.help.kubectlVersion", + "defaultValue": "latest" + }], "instanceNameFormat": "ms-resource:loc.instanceNameFormat", "execution": { "Node": { diff --git a/Tasks/KubernetesManifestV0/Strings/resources.resjson/en-US/resources.resjson b/Tasks/KubernetesManifestV0/Strings/resources.resjson/en-US/resources.resjson index 62bf8feee2ce..4416c183b704 100644 --- a/Tasks/KubernetesManifestV0/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/KubernetesManifestV0/Strings/resources.resjson/en-US/resources.resjson @@ -89,5 +89,7 @@ "loc.messages.StableSpecSelectorNotExist": "Resource %s not deployed using SMI canary deployment.", "loc.messages.InvalidPercentage": "Invalid value for percentage.", "loc.messages.InvalidBaselineAndCanaryReplicas": "Invalid value for replica count. Enter a value greater than 0.", - "loc.messages.InvalidTimeoutValue": "Invalid value for timeout. Enter a valid number." + "loc.messages.InvalidTimeoutValue": "Invalid value for timeout. Enter a valid number.", + "loc.messages.RolloutStatusTimedout": "Rollout status check failed.", + "loc.messages.EnvironmentLink": "For more information, go to %s" } \ No newline at end of file diff --git a/Tasks/KubernetesManifestV0/task.json b/Tasks/KubernetesManifestV0/task.json index 75320c102f5a..f21e2ac78990 100644 --- a/Tasks/KubernetesManifestV0/task.json +++ b/Tasks/KubernetesManifestV0/task.json @@ -13,8 +13,8 @@ "author": "Microsoft Corporation", "version": { "Major": 0, - "Minor": 163, - "Patch": 1 + "Minor": 164, + "Patch": 0 }, "demands": [], "groups": [], @@ -377,6 +377,8 @@ "StableSpecSelectorNotExist": "Resource %s not deployed using SMI canary deployment.", "InvalidPercentage": "Invalid value for percentage.", "InvalidBaselineAndCanaryReplicas": "Invalid value for replica count. Enter a value greater than 0.", - "InvalidTimeoutValue": "Invalid value for timeout. Enter a valid number." + "InvalidTimeoutValue": "Invalid value for timeout. Enter a valid number.", + "RolloutStatusTimedout": "Rollout status check failed.", + "EnvironmentLink": "For more information, go to %s" } } \ No newline at end of file diff --git a/Tasks/KubernetesManifestV0/task.loc.json b/Tasks/KubernetesManifestV0/task.loc.json index cb220a0df329..cdd224b2456b 100644 --- a/Tasks/KubernetesManifestV0/task.loc.json +++ b/Tasks/KubernetesManifestV0/task.loc.json @@ -13,8 +13,8 @@ "author": "Microsoft Corporation", "version": { "Major": 0, - "Minor": 163, - "Patch": 1 + "Minor": 164, + "Patch": 0 }, "demands": [], "groups": [], @@ -377,6 +377,8 @@ "StableSpecSelectorNotExist": "ms-resource:loc.messages.StableSpecSelectorNotExist", "InvalidPercentage": "ms-resource:loc.messages.InvalidPercentage", "InvalidBaselineAndCanaryReplicas": "ms-resource:loc.messages.InvalidBaselineAndCanaryReplicas", - "InvalidTimeoutValue": "ms-resource:loc.messages.InvalidTimeoutValue" + "InvalidTimeoutValue": "ms-resource:loc.messages.InvalidTimeoutValue", + "RolloutStatusTimedout": "ms-resource:loc.messages.RolloutStatusTimedout", + "EnvironmentLink": "ms-resource:loc.messages.EnvironmentLink" } } \ No newline at end of file diff --git a/Tasks/KubernetesV1/task.json b/Tasks/KubernetesV1/task.json index eed7dd83ac4e..316478b01049 100644 --- a/Tasks/KubernetesV1/task.json +++ b/Tasks/KubernetesV1/task.json @@ -13,13 +13,12 @@ "author": "Microsoft Corporation", "version": { "Major": 1, - "Minor": 162, - "Patch": 8 + "Minor": 164, + "Patch": 0 }, "demands": [], "releaseNotes": "What's new in Version 1.0:
 Added new service connection type input for easy selection of Azure AKS cluster.
 Replaced output variable input with output variables section that we had added in all tasks.", - "groups": [ - { + "groups": [{ "name": "kubernetesCluster", "displayName": "Kubernetes Cluster", "isExpanded": true, @@ -54,8 +53,7 @@ "visibleRule": "command != login && command != logout" } ], - "inputs": [ - { + "inputs": [{ "name": "connectionType", "type": "pickList", "label": "Service connection type", @@ -419,8 +417,7 @@ } } ], - "dataSourceBindings": [ - { + "dataSourceBindings": [{ "target": "azureContainerRegistry", "endpointId": "$(azureSubscriptionEndpointForSecrets)", "dataSourceName": "AzureRMContainerRegistries", @@ -442,12 +439,10 @@ } ], "instanceNameFormat": "kubectl $(command)", - "outputVariables": [ - { - "name": "KubectlOutput", - "description": "Stores the output of the kubectl command" - } - ], + "outputVariables": [{ + "name": "KubectlOutput", + "description": "Stores the output of the kubectl command" + }], "execution": { "Node": { "target": "src//kubernetes.js" diff --git a/Tasks/KubernetesV1/task.loc.json b/Tasks/KubernetesV1/task.loc.json index 62b84928695d..1fd02a93b14e 100644 --- a/Tasks/KubernetesV1/task.loc.json +++ b/Tasks/KubernetesV1/task.loc.json @@ -13,13 +13,12 @@ "author": "Microsoft Corporation", "version": { "Major": 1, - "Minor": 162, - "Patch": 8 + "Minor": 164, + "Patch": 0 }, "demands": [], "releaseNotes": "ms-resource:loc.releaseNotes", - "groups": [ - { + "groups": [{ "name": "kubernetesCluster", "displayName": "ms-resource:loc.group.displayName.kubernetesCluster", "isExpanded": true, @@ -54,8 +53,7 @@ "visibleRule": "command != login && command != logout" } ], - "inputs": [ - { + "inputs": [{ "name": "connectionType", "type": "pickList", "label": "ms-resource:loc.input.label.connectionType", @@ -419,8 +417,7 @@ } } ], - "dataSourceBindings": [ - { + "dataSourceBindings": [{ "target": "azureContainerRegistry", "endpointId": "$(azureSubscriptionEndpointForSecrets)", "dataSourceName": "AzureRMContainerRegistries", @@ -442,12 +439,10 @@ } ], "instanceNameFormat": "ms-resource:loc.instanceNameFormat", - "outputVariables": [ - { - "name": "KubectlOutput", - "description": "Stores the output of the kubectl command" - } - ], + "outputVariables": [{ + "name": "KubectlOutput", + "description": "Stores the output of the kubectl command" + }], "execution": { "Node": { "target": "src//kubernetes.js"