diff --git a/common-npm-packages/azure-arm-rest/Tests/L0-azure-arm-aks-service-tests.d.ts b/common-npm-packages/azure-arm-rest/Tests/L0-azure-arm-aks-service-tests.d.ts new file mode 100644 index 00000000..5d111c4d --- /dev/null +++ b/common-npm-packages/azure-arm-rest/Tests/L0-azure-arm-aks-service-tests.d.ts @@ -0,0 +1 @@ +export declare function AksServiceTests(): void; diff --git a/common-npm-packages/azure-arm-rest/Tests/L0-azure-arm-aks-service-tests.ts b/common-npm-packages/azure-arm-rest/Tests/L0-azure-arm-aks-service-tests.ts new file mode 100644 index 00000000..7a173c1d --- /dev/null +++ b/common-npm-packages/azure-arm-rest/Tests/L0-azure-arm-aks-service-tests.ts @@ -0,0 +1,29 @@ +import assert = require("assert"); +import * as ttm from 'azure-pipelines-task-lib/mock-test'; +import tl = require('azure-pipelines-task-lib'); +import * as path from 'path'; + +export function AksServiceTests() { + it('azure-arm-aks-service AksService', (done: Mocha.Done) => { + let tp = path.join(__dirname, 'azure-arm-aks-service-tests.js'); + let tr : ttm.MockTestRunner = new ttm.MockTestRunner(tp); + let passed: boolean = true; + + try { + tr.run(); + assert(tr.stdOutContained("Aks Cluster Credential Found: clusterAdmin"), "Should have printed: Aks Cluster Credential Found: clusterAdmin"); + assert(tr.stdOutContained("Aks Cluster Credential Found: clusterUser"), "Should have printed: Aks Cluster Credential Found: clusterUser"); + assert(tr.stdOutContained("Aks Cluster Credential Found: customUser"), "Should have printed: Aks Cluster Credential Found: customUser"); + } + catch(error) { + passed = false; + console.log(tr.stdout); + console.log(tr.stderr); + done(error); + } + + if(passed) { + done(); + } + }); +} \ No newline at end of file diff --git a/common-npm-packages/azure-arm-rest/Tests/azure-arm-aks-service-tests.d.ts b/common-npm-packages/azure-arm-rest/Tests/azure-arm-aks-service-tests.d.ts new file mode 100644 index 00000000..4d3d5fae --- /dev/null +++ b/common-npm-packages/azure-arm-rest/Tests/azure-arm-aks-service-tests.d.ts @@ -0,0 +1,5 @@ +export declare class AksServiceTests { + static credentialsByClusterAdmin(): Promise; + static credentialsByClusterUser(): Promise; + static credentialsByCustomClusterUser(): Promise; +} diff --git a/common-npm-packages/azure-arm-rest/Tests/azure-arm-aks-service-tests.ts b/common-npm-packages/azure-arm-rest/Tests/azure-arm-aks-service-tests.ts new file mode 100644 index 00000000..11f999fa --- /dev/null +++ b/common-npm-packages/azure-arm-rest/Tests/azure-arm-aks-service-tests.ts @@ -0,0 +1,54 @@ +import { getMockEndpoint, nock, mockAzureAksServiceTests } from './mock_utils'; +import tl = require('azure-pipelines-task-lib'); +import { AzureAksService } from '../azure-arm-aks-service'; + +var endpoint = getMockEndpoint(); + +// Mock all calls for Azure AKS Service +mockAzureAksServiceTests(); + +export class AksServiceTests { + public static async credentialsByClusterAdmin() { + let aksService: AzureAksService = new AzureAksService(endpoint); + try { + let result = await aksService.getClusterCredential("MOCK_RESOURCE_GROUP_NAME", "MOCK_CLUSTER", true); + console.log(`Aks Cluster Credential Found: ${result.name}`); + } + catch(error) { + console.log(error); + tl.setResult(tl.TaskResult.Failed, 'AksServiceTests.credentialsByClusterAdmin() should have passed but failed'); + } + } + + public static async credentialsByClusterUser() { + let aksService: AzureAksService = new AzureAksService(endpoint); + try { + let result = await aksService.getClusterCredential("MOCK_RESOURCE_GROUP_NAME", "MOCK_CLUSTER", false); + console.log(`Aks Cluster Credential Found: ${result.name}`); + } + catch(error) { + console.log(error); + tl.setResult(tl.TaskResult.Failed, 'AksServiceTests.credentialsByClusterUser() should have passed but failed'); + } + } + + public static async credentialsByCustomClusterUser() { + let aksService: AzureAksService = new AzureAksService(endpoint); + try { + let result = await aksService.getClusterCredential("MOCK_RESOURCE_GROUP_NAME", "MOCK_CLUSTER", false, 'customUser'); + console.log(`Aks Cluster Credential Found: ${result.name}`); + } + catch(error) { + console.log(error); + tl.setResult(tl.TaskResult.Failed, 'AksServiceTests.credentialsByCustomClusterUser() should have passed but failed'); + } + } +} + +async function RUNTESTS() { + await AksServiceTests.credentialsByClusterAdmin(); + await AksServiceTests.credentialsByClusterUser(); + await AksServiceTests.credentialsByCustomClusterUser(); +} + +RUNTESTS(); diff --git a/common-npm-packages/azure-arm-rest/Tests/mock_utils.ts b/common-npm-packages/azure-arm-rest/Tests/mock_utils.ts index 81111e70..ab74ca36 100644 --- a/common-npm-packages/azure-arm-rest/Tests/mock_utils.ts +++ b/common-npm-packages/azure-arm-rest/Tests/mock_utils.ts @@ -708,7 +708,7 @@ export function mockAzureARMResourcesTests() { "authorization": "Bearer DUMMY_ACCESS_TOKEN", "content-type": "application/json; charset=utf-8" } - }).get("/subscriptions/MOCK_SUBSCRIPTION_ID/resources?$filter=resourceType%20EQ%20%27Microsoft.Web%2Fsites%27%20AND%20name%20EQ%20%27g%C3%B6m-mig-fr%C3%A5n-omv%C3%A4rlden%27&api-version=2016-07-01") + }).get("/subscriptions/MOCK_SUBSCRIPTION_ID/resources?&api-version=2016-07-01") .reply(200, { value: [{ id: "subscriptions/MOCK_SUBSCRIPTION_ID/resourceGroups/MOCK_RESOURCE_GROUP_NAME/providers/microsoft.web/sites/göm-mig-från-omvär", @@ -718,4 +718,48 @@ export function mockAzureARMResourcesTests() { properties: {} }] }).persist(); + + +} + +export function mockAzureAksServiceTests() { + nock('https://management.azure.com', { + reqheaders: { + "authorization": "Bearer DUMMY_ACCESS_TOKEN", + "content-type": "application/json; charset=utf-8" + } + }).get("/subscriptions/MOCK_SUBSCRIPTION_ID/resourceGroups/MOCK_RESOURCE_GROUP_NAME/providers/Microsoft.ContainerService/managedClusters/MOCK_CLUSTER/listClusterUserCredential?api-version=2024-05-01") + .reply(200, { + kubeconfigs: [{ + name: "clusterUser", + value: "base46kubeconfig" + }] + }).persist(); + + nock('https://management.azure.com', { + reqheaders: { + "authorization": "Bearer DUMMY_ACCESS_TOKEN", + "content-type": "application/json; charset=utf-8" + } + }).get("/subscriptions/MOCK_SUBSCRIPTION_ID/resourceGroups/MOCK_RESOURCE_GROUP_NAME/providers/Microsoft.ContainerService/managedClusters/MOCK_CLUSTER/listClusterAdminCredential?api-version=2024-05-01") + .reply(200, { + kubeconfigs: [{ + name: "clusterAdmin", + value: "base46kubeconfig" + }] + }).persist(); + + nock('https://management.azure.com', { + reqheaders: { + "authorization": "Bearer DUMMY_ACCESS_TOKEN", + "content-type": "application/json; charset=utf-8" + } + }).get("/subscriptions/MOCK_SUBSCRIPTION_ID/resourceGroups/MOCK_RESOURCE_GROUP_NAME/providers/Microsoft.ContainerService/managedClusters/MOCK_CLUSTER/listClusterUserCredential?api-version=2024-05-01") + .reply(200, { + kubeconfigs: [{ + name: "customUser", + value: "base46kubeconfig" + }] + }).persist(); + } \ No newline at end of file diff --git a/common-npm-packages/azure-arm-rest/azure-arm-aks-service.ts b/common-npm-packages/azure-arm-rest/azure-arm-aks-service.ts index 58bcb576..70b66860 100644 --- a/common-npm-packages/azure-arm-rest/azure-arm-aks-service.ts +++ b/common-npm-packages/azure-arm-rest/azure-arm-aks-service.ts @@ -28,10 +28,10 @@ export class AzureAksService { this._client = new ServiceClient(endpoint.applicationTokenCredentials, endpoint.subscriptionID, 30); } - public beginRequest(uri: string, parameters: {}) : Promise { + public beginRequest(uri: string, parameters: {}, apiVersion: string) : Promise { var webRequest = new webClient.WebRequest(); webRequest.method = 'GET'; - webRequest.uri = this._client.getRequestUri(uri, parameters, null,'2017-08-31'); + webRequest.uri = this._client.getRequestUri(uri, parameters, null, apiVersion); return this._client.beginRequestExpBackoff(webRequest, 3).then((response)=>{ if(response.statusCode >= 200 && response.statusCode < 300) { return response; @@ -48,10 +48,36 @@ export class AzureAksService { '{ResourceGroupName}': resourceGroup, '{ClusterName}': clusterName, '{AccessProfileName}': accessProfileName - }).then((response) => { + }, '2017-08-31').then((response) => { return response.body; }, (reason) => { throw Error(tl.loc('CantDownloadAccessProfile',clusterName, this._client.getFormattedError(reason))); }); } -} \ No newline at end of file + + public getClusterCredentials(resourceGroup : string , clusterName : string, useClusterAdmin?: boolean): Promise { + var credentialAction = !!useClusterAdmin ? 'listClusterAdminCredential' : 'listClusterUserCredential'; + return this.beginRequest(`//subscriptions/{subscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.ContainerService/managedClusters/{ClusterName}/{CredentialAction}`, + { + '{ResourceGroupName}': resourceGroup, + '{ClusterName}': clusterName, + '{CredentialAction}': credentialAction + }, '2024-05-01').then((response) => { + return response.body; + }, (reason) => { + throw Error(tl.loc('CantDownloadClusterCredentials',clusterName, this._client.getFormattedError(reason))); + }); + } + + public getClusterCredential(resourceGroup : string , clusterName : string, useClusterAdmin?: boolean, credentialName?: string): Promise { + var credentialName = !!credentialName ? credentialName : !!useClusterAdmin ? 'clusterAdmin' : 'clusterUser'; + var clusterCredentials = this.getClusterCredentials(resourceGroup, clusterName, useClusterAdmin) + return clusterCredentials.then((credentials) => { + var credential = credentials.kubeconfigs.find(credential => credential.name == credentialName) + if (credential === undefined) { + throw Error(tl.loc('CantDownloadClusterCredentials', clusterName, `${credentialName} not found in the list of cluster credentials.`)); + } + return credential; + }) + } +} diff --git a/common-npm-packages/azure-arm-rest/azureModels.ts b/common-npm-packages/azure-arm-rest/azureModels.ts index 612753d0..03a40381 100644 --- a/common-npm-packages/azure-arm-rest/azureModels.ts +++ b/common-npm-packages/azure-arm-rest/azureModels.ts @@ -305,6 +305,15 @@ export interface AKSClusterAccessProfile extends AzureBaseObject { properties: AKSClusterAccessProfileProperties } +export interface AKSCredentialResult { + name: string; + value: string; +} + +export interface AKSCredentialResults extends AzureBaseObject { + kubeconfigs: Array +} + export interface IThresholdRuleConditionDataSource { "odata.type": string; resourceUri: string;