* refactor
This commit is contained in:
Oliver King 2022-02-04 14:09:43 -05:00 коммит произвёл GitHub
Родитель dccd92cdb1
Коммит 0d17dff9ee
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 417 добавлений и 342 удалений

2
.github/workflows/unit-tests.yml поставляемый
Просмотреть файл

@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Run L0 tests.
- name: Run unit tests
run: |
npm install
npm test

4
.gitignore поставляемый
Просмотреть файл

@ -1,6 +1,4 @@
# dependencies
/node_modules
coverage
# Transpiled JS
lib/
/lib

Просмотреть файл

@ -1,24 +1,24 @@
name: 'Azure Kubernetes set context'
description: 'Sets the kubeconfig on the machine to communicate with the Azure Kubernetes cluster. Github.com/Azure/Actions'
inputs:
name: "Azure Kubernetes set context"
description: "Sets the kubeconfig on the machine to communicate with the Azure Kubernetes cluster. Github.com/Azure/Actions"
inputs:
creds:
description: 'Azure credentials i.e. output of `az ad sp create-for-rbac --sdk-auth`'
description: "Azure credentials i.e. output of `az ad sp create-for-rbac --sdk-auth`"
required: true
default: ''
default: ""
resource-group:
description: 'Resource Group Name'
description: "Resource Group Name"
required: false
default: ''
default: ""
cluster-name:
description: 'AKS Cluster Name'
description: "AKS Cluster Name"
required: false
default: ''
default: ""
subscription-id:
description: 'Subscription ID'
description: "Subscription ID"
required: false
default: ''
default: ""
branding:
color: 'green' # optional, decorates the entry in the GitHub Marketplace
color: "green" # optional, decorates the entry in the GitHub Marketplace
runs:
using: 'node12'
main: 'lib/login.js'
using: "node12"
main: "lib/run.js"

Просмотреть файл

@ -1,258 +0,0 @@
import * as login from './login'
import * as core from '@actions/core';
import * as fs from 'fs';
import * as path from 'path';
import * as azureActionsUtil from "@azure-actions/utilities/lib/http";
describe('Testing all functions in login file.', () => {
test('getAKSKubeconfig() - get kubeconfig from aks API and return it', async () => {
jest.spyOn(core, 'getInput').mockImplementation((inputName, options) => {
if (inputName == 'resource-group') return 'sample-rg';
if (inputName == 'cluster-name') return 'testing';
});
const response = {
'statusCode': 200,
'body': {
'properties': {
'kubeConfig': Buffer.from('###').toString('base64')
}
}
} as azureActionsUtil.WebResponse;
jest.spyOn(azureActionsUtil, 'sendRequest').mockResolvedValue(response);
expect(await login.getAKSKubeconfig('<access_token>', '<subscription id>', 'https://management.azure.com/')).toBe('###');
const request = {
'body': '',
'method': 'GET',
'headers': {
'Authorization': 'Bearer <access_token>',
'Content-Type': 'application/json; charset=utf-8'
},
'uri': 'https://management.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31'
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(request);
});
test('getAKSKubeconfig() - reject if response not in expected format', async () => {
jest.spyOn(core, 'getInput').mockImplementation((inputName, options) => {
if (inputName == 'resource-group') return 'sample-rg';
if (inputName == 'cluster-name') return 'testing';
});
const response = {
'statusCode': 200,
'body': {
'error': 'ErrorMessage'
}
} as azureActionsUtil.WebResponse;
jest.spyOn(azureActionsUtil, 'sendRequest').mockResolvedValue(response);
await login.getAKSKubeconfig('<access_token>', '<subscription id>', 'https://management.azure.com/')
.then(response => expect(response).toBeUndefined())
.catch(error => expect(error).toBe(JSON.stringify(response.body)));
const request = {
'body': '',
'method': 'GET',
'headers': {
'Authorization': 'Bearer <access_token>',
'Content-Type': 'application/json; charset=utf-8'
},
'uri': 'https://management.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31'
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(request);
});
test('getAKSKubeconfig() - reject if error recieved', async () => {
jest.spyOn(core, 'getInput').mockImplementation((inputName, options) => {
if (inputName == 'resource-group') return 'sample-rg';
if (inputName == 'cluster-name') return 'testing';
});
jest.spyOn(azureActionsUtil, 'sendRequest').mockRejectedValue('ErrorMessage');
await login.getAKSKubeconfig('<access_token>', '<subscription id>', 'https://management.azure.com/')
.then(response => expect(response).toBeUndefined())
.catch(error => expect(error).toBe('ErrorMessage'));
const request = {
'body': '',
'method': 'GET',
'headers': {
'Authorization': 'Bearer <access_token>',
'Content-Type': 'application/json; charset=utf-8'
},
'uri': 'https://management.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31'
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(request);
});
test('getKubeconfig() - reject if incorrect credentials', async () => {
jest.spyOn(core, 'getInput').mockReturnValue('Wrong cred.')
await expect(login.getKubeconfig()).rejects.toThrow('Credentials object is not a valid JSON');
});
test('getKubeconfig() - get access token, use it to get kubeconfig and return it ', async () => {
const creds = {
"clientId": "<client id>",
"clientSecret": "<client secret>",
"subscriptionId": "<subscription id>",
"tenantId": "<tenant id>",
"activeDirectoryEndpointUrl": "https://login.k8s.microsoftonline.com",
"resourceManagerEndpointUrl": "https://management.k8s.azure.com/",
"activeDirectoryGraphResourceId": "https://graph.windows.net/",
"sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
"galleryEndpointUrl": "https://gallery.azure.com/",
"managementEndpointUrl": "https://management.core.windows.net/"
}
const responseKube = {
'statusCode': 200,
'body': {
'properties': {
'kubeConfig': Buffer.from('###').toString('base64')
}
}
} as azureActionsUtil.WebResponse;
const responseLogin = {
'statusCode': 200,
'body': {
'access_token': '<access_token>'
}
} as azureActionsUtil.WebResponse;
jest.spyOn(core, 'getInput').mockImplementation((inputName, options) => {
if (inputName == 'resource-group') return 'sample-rg';
if (inputName == 'cluster-name') return 'testing';
if (inputName == 'creds') return JSON.stringify(creds);
});
jest.spyOn(azureActionsUtil, 'sendRequest').mockResolvedValueOnce(responseLogin).mockResolvedValueOnce(responseKube);
await login.getKubeconfig()
.then(response => expect(response).toBe('###'))
.catch(error => expect(error).toBeUndefined());
const requestForToken = {
method: 'POST',
uri: 'https://login.k8s.microsoftonline.com/<tenant id>/oauth2/token/',
body: 'resource=https%3A%2F%2Fmanagement.k8s.azure.com%2F&client_id=%3Cclient%20id%3E&grant_type=client_credentials&client_secret=%3Cclient%20secret%3E',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
}
} as azureActionsUtil.WebRequest;
let optionsForToken = {
retriableStatusCodes: [400, 408, 409, 500, 502, 503, 504],
} as azureActionsUtil.WebRequestOptions;
expect(azureActionsUtil.sendRequest).toBeCalledWith(requestForToken, optionsForToken);
const requestForKubecongig = {
'body': '',
'method': 'GET',
'headers': {
'Authorization': 'Bearer <access_token>',
'Content-Type': 'application/json; charset=utf-8'
},
'uri': 'https://management.k8s.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31'
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(requestForKubecongig);
});
test('getKubeconfig() - use default endpoints if not provided in creds', async () => {
const creds = {
"clientId": "<client id>",
"clientSecret": "<client secret>",
"subscriptionId": "<subscription id>",
"tenantId": "<tenant id>",
"activeDirectoryGraphResourceId": "https://graph.windows.net/",
"sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
"galleryEndpointUrl": "https://gallery.azure.com/",
"managementEndpointUrl": "https://management.core.windows.net/"
}
const responseKube = {
'statusCode': 200,
'body': {
'properties': {
'kubeConfig': Buffer.from('###').toString('base64')
}
}
} as azureActionsUtil.WebResponse;
const responseLogin = {
'statusCode': 200,
'body': {
'access_token': '<access_token>'
}
} as azureActionsUtil.WebResponse;
jest.spyOn(core, 'getInput').mockImplementation((inputName, options) => {
if (inputName == 'resource-group') return 'sample-rg';
if (inputName == 'cluster-name') return 'testing';
if (inputName == 'creds') return JSON.stringify(creds);
});
jest.spyOn(azureActionsUtil, 'sendRequest').mockResolvedValueOnce(responseLogin).mockResolvedValueOnce(responseKube);
await login.getKubeconfig()
.then(response => expect(response).toBe('###'))
.catch(error => expect(error).toBeUndefined());
const requestForToken = {
method: 'POST',
uri: 'https://login.microsoftonline.com/<tenant id>/oauth2/token/',
body: 'resource=https%3A%2F%2Fmanagement.azure.com%2F&client_id=%3Cclient%20id%3E&grant_type=client_credentials&client_secret=%3Cclient%20secret%3E',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
}
} as azureActionsUtil.WebRequest;
let optionsForToken = {
retriableStatusCodes: [400, 408, 409, 500, 502, 503, 504],
} as azureActionsUtil.WebRequestOptions;
expect(azureActionsUtil.sendRequest).toBeCalledWith(requestForToken, optionsForToken);
const requestForKubecongig = {
'body': '',
'method': 'GET',
'headers': {
'Authorization': 'Bearer <access_token>',
'Content-Type': 'application/json; charset=utf-8'
},
'uri': 'https://management.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31'
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(requestForKubecongig);
});
test('run() - create kubeconfig, export variable and give appropriate access', async () => {
jest.spyOn(fs, 'writeFileSync').mockImplementation();
jest.spyOn(fs, 'chmodSync').mockImplementation();
jest.spyOn(core, 'exportVariable').mockImplementation();
jest.spyOn(console, 'log').mockImplementation();
jest.spyOn(core, 'debug').mockImplementation();
jest.spyOn(core, 'getInput').mockImplementation((inputName, options) => {
if (inputName == 'resource-group') return 'sample-rg';
if (inputName == 'cluster-name') return 'testing';
if (inputName == 'creds') return JSON.stringify(creds);
});
const creds = {
"clientId": "<client id>",
"clientSecret": "<client secret>",
"subscriptionId": "<subscription id>",
"tenantId": "<tenant id>",
"activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
"resourceManagerEndpointUrl": "https://management.azure.com/",
"activeDirectoryGraphResourceId": "https://graph.windows.net/",
"sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
"galleryEndpointUrl": "https://gallery.azure.com/",
"managementEndpointUrl": "https://management.core.windows.net/"
}
const responseKube = {
'statusCode': 200,
'body': {
'properties': {
'kubeConfig': Buffer.from('###').toString('base64')
}
}
} as azureActionsUtil.WebResponse;
const responseLogin = {
'statusCode': 200,
'body': {
'access_token': '<access_token>'
}
} as azureActionsUtil.WebResponse;
jest.spyOn(azureActionsUtil, 'sendRequest').mockResolvedValueOnce(responseLogin).mockResolvedValueOnce(responseKube);
process.env['RUNNER_TEMP'] = 'tempDirPath'
jest.spyOn(Date, 'now').mockImplementation(() => 1234561234567);
expect(await login.run());
expect(fs.writeFileSync).toHaveBeenCalledWith(path.join('tempDirPath', 'kubeconfig_1234561234567'), '###');
expect(fs.chmodSync).toHaveBeenCalledWith(path.join('tempDirPath', 'kubeconfig_1234561234567'), '600');
expect(core.exportVariable).toHaveBeenCalledWith('KUBECONFIG', path.join('tempDirPath', 'kubeconfig_1234561234567'));
});
});

Просмотреть файл

@ -1,57 +0,0 @@
import * as core from '@actions/core';
import * as path from 'path';
import * as fs from 'fs';
import { WebRequest, WebResponse, sendRequest } from "@azure-actions/utilities/lib/http";
import { getAzureAccessToken } from '@azure-actions/auth';
export function getAKSKubeconfig(azureSessionToken: string, subscriptionId: string, managementEndpointUrl: string): Promise<string> {
const resourceGroupName = core.getInput('resource-group', { required: true });
const clusterName = core.getInput('cluster-name', { required: true });
return new Promise<string>((resolve, reject) => {
var webRequest = new WebRequest();
webRequest.method = 'GET';
webRequest.uri = `${managementEndpointUrl}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ContainerService/managedClusters/${clusterName}/accessProfiles/clusterAdmin?api-version=2017-08-31`;
webRequest.headers = {
'Authorization': 'Bearer ' + azureSessionToken,
'Content-Type': 'application/json; charset=utf-8'
}
sendRequest(webRequest).then((response: WebResponse) => {
const accessProfile = response.body;
if (accessProfile.properties && accessProfile.properties.kubeConfig) {
var kubeconfig = Buffer.from(accessProfile.properties.kubeConfig, 'base64');
resolve(kubeconfig.toString());
} else {
reject(JSON.stringify(response.body));
}
}).catch(reject);
});
}
export async function getKubeconfig(): Promise<string> {
const creds = core.getInput('creds', { required: true });
let credsObject: { [key: string]: string; };
try {
credsObject = JSON.parse(creds);
} catch (ex) {
throw new Error('Credentials object is not a valid JSON');
}
const managementEndpointUrl = credsObject["resourceManagerEndpointUrl"] || "https://management.azure.com/";
const subscriptionId = core.getInput('subscription-id') || credsObject["subscriptionId"];
const azureSessionToken = await getAzureAccessToken(creds);
const kubeconfig = await getAKSKubeconfig(azureSessionToken, subscriptionId, managementEndpointUrl);
return kubeconfig;
}
export async function run() {
const kubeconfig = await getKubeconfig();
const runnerTempDirectory = process.env['RUNNER_TEMP']; // Using process.env until the core libs are updated
const kubeconfigPath = path.join(runnerTempDirectory, `kubeconfig_${Date.now()}`);
core.debug(`Writing kubeconfig contents to ${kubeconfigPath}`);
fs.writeFileSync(kubeconfigPath, kubeconfig);
fs.chmodSync(kubeconfigPath, '600');
core.exportVariable('KUBECONFIG', kubeconfigPath);
core.debug('KUBECONFIG environment variable is set');
}
run().catch(core.setFailed);

292
src/run.test.ts Normal file
Просмотреть файл

@ -0,0 +1,292 @@
import * as login from "./run";
import * as core from "@actions/core";
import * as fs from "fs";
import * as path from "path";
import * as azureActionsUtil from "@azure-actions/utilities/lib/http";
describe("Testing all functions in login file.", () => {
test("getAKSKubeconfig() - get kubeconfig from aks API and return it", async () => {
jest.spyOn(core, "getInput").mockImplementation((inputName, options) => {
if (inputName == "resource-group") return "sample-rg";
if (inputName == "cluster-name") return "testing";
});
const response = {
statusCode: 200,
body: {
properties: {
kubeConfig: Buffer.from("###").toString("base64"),
},
},
} as azureActionsUtil.WebResponse;
jest.spyOn(azureActionsUtil, "sendRequest").mockResolvedValue(response);
expect(
await login.getAKSKubeconfig(
"<access_token>",
"<subscription id>",
"https://management.azure.com/",
"sample-rg",
"testing"
)
).toBe("###");
const request = {
body: "",
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json; charset=utf-8",
},
uri: "https://management.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31",
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(request);
});
test("getAKSKubeconfig() - reject if response not in expected format", async () => {
const response = {
statusCode: 200,
body: {
error: "ErrorMessage",
},
} as azureActionsUtil.WebResponse;
jest.spyOn(azureActionsUtil, "sendRequest").mockResolvedValue(response);
await login
.getAKSKubeconfig(
"<access_token>",
"<subscription id>",
"https://management.azure.com/",
"sample-rg",
"testing"
)
.then((response) => expect(response).toBeUndefined())
.catch((error) => expect(error).toBe(JSON.stringify(response.body)));
const request = {
body: "",
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json; charset=utf-8",
},
uri: "https://management.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31",
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(request);
});
test("getAKSKubeconfig() - reject if error recieved", async () => {
jest
.spyOn(azureActionsUtil, "sendRequest")
.mockRejectedValue("ErrorMessage");
await login
.getAKSKubeconfig(
"<access_token>",
"<subscription id>",
"https://management.azure.com/",
"sample-rg",
"testing"
)
.then((response) => expect(response).toBeUndefined())
.catch((error) => expect(error).toBe("ErrorMessage"));
const request = {
body: "",
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json; charset=utf-8",
},
uri: "https://management.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31",
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(request);
});
test("getKubeconfig() - reject if incorrect credentials", async () => {
jest.spyOn(core, "getInput").mockReturnValue("Wrong cred.");
await expect(
login.getKubeconfig({}, "subscriptionId", "sample-rg", "testing")
).rejects.toThrow();
});
test("getKubeconfig() - get access token, use it to get kubeconfig and return it ", async () => {
const creds = {
clientId: "<client id>",
clientSecret: "<client secret>",
subscriptionId: "<subscription id>",
tenantId: "<tenant id>",
activeDirectoryEndpointUrl: "https://login.k8s.microsoftonline.com",
resourceManagerEndpointUrl: "https://management.k8s.azure.com/",
activeDirectoryGraphResourceId: "https://graph.windows.net/",
sqlManagementEndpointUrl: "https://management.core.windows.net:8443/",
galleryEndpointUrl: "https://gallery.azure.com/",
managementEndpointUrl: "https://management.core.windows.net/",
};
const responseKube = {
statusCode: 200,
body: {
properties: {
kubeConfig: Buffer.from("###").toString("base64"),
},
},
} as azureActionsUtil.WebResponse;
const responseLogin = {
statusCode: 200,
body: {
access_token: "<access_token>",
},
} as azureActionsUtil.WebResponse;
jest
.spyOn(azureActionsUtil, "sendRequest")
.mockResolvedValueOnce(responseLogin)
.mockResolvedValueOnce(responseKube);
await login
.getKubeconfig(creds, creds["subscriptionId"], "sample-rg", "testing")
.then((response) => expect(response).toBe("###"))
.catch((error) => expect(error).toBeUndefined());
const requestForToken = {
method: "POST",
uri: "https://login.k8s.microsoftonline.com/<tenant id>/oauth2/token/",
body: "resource=https%3A%2F%2Fmanagement.k8s.azure.com%2F&client_id=%3Cclient%20id%3E&grant_type=client_credentials&client_secret=%3Cclient%20secret%3E",
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
},
} as azureActionsUtil.WebRequest;
let optionsForToken = {
retriableStatusCodes: [400, 408, 409, 500, 502, 503, 504],
} as azureActionsUtil.WebRequestOptions;
expect(azureActionsUtil.sendRequest).toBeCalledWith(
requestForToken,
optionsForToken
);
const requestForKubecongig = {
body: "",
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json; charset=utf-8",
},
uri: "https://management.k8s.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31",
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(requestForKubecongig);
});
test("getKubeconfig() - use default endpoints if not provided in creds", async () => {
const creds = {
clientId: "<client id>",
clientSecret: "<client secret>",
subscriptionId: "<subscription id>",
tenantId: "<tenant id>",
activeDirectoryGraphResourceId: "https://graph.windows.net/",
sqlManagementEndpointUrl: "https://management.core.windows.net:8443/",
galleryEndpointUrl: "https://gallery.azure.com/",
managementEndpointUrl: "https://management.core.windows.net/",
};
const responseKube = {
statusCode: 200,
body: {
properties: {
kubeConfig: Buffer.from("###").toString("base64"),
},
},
} as azureActionsUtil.WebResponse;
const responseLogin = {
statusCode: 200,
body: {
access_token: "<access_token>",
},
} as azureActionsUtil.WebResponse;
jest
.spyOn(azureActionsUtil, "sendRequest")
.mockResolvedValueOnce(responseLogin)
.mockResolvedValueOnce(responseKube);
await login
.getKubeconfig(creds, creds["subscriptionId"], "sample-rg", "testing")
.then((response) => expect(response).toBe("###"))
.catch((error) => expect(error).toBeUndefined());
const requestForToken = {
method: "POST",
uri: "https://login.microsoftonline.com/<tenant id>/oauth2/token/",
body: "resource=https%3A%2F%2Fmanagement.azure.com%2F&client_id=%3Cclient%20id%3E&grant_type=client_credentials&client_secret=%3Cclient%20secret%3E",
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
},
} as azureActionsUtil.WebRequest;
let optionsForToken = {
retriableStatusCodes: [400, 408, 409, 500, 502, 503, 504],
} as azureActionsUtil.WebRequestOptions;
expect(azureActionsUtil.sendRequest).toBeCalledWith(
requestForToken,
optionsForToken
);
const requestForKubecongig = {
body: "",
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json; charset=utf-8",
},
uri: "https://management.azure.com//subscriptions/<subscription id>/resourceGroups/sample-rg/providers/Microsoft.ContainerService/managedClusters/testing/accessProfiles/clusterAdmin?api-version=2017-08-31",
} as azureActionsUtil.WebRequest;
expect(azureActionsUtil.sendRequest).toBeCalledWith(requestForKubecongig);
});
test("run() - create kubeconfig, export variable and give appropriate access", async () => {
jest.spyOn(fs, "writeFileSync").mockImplementation();
jest.spyOn(fs, "chmodSync").mockImplementation();
jest.spyOn(core, "exportVariable").mockImplementation();
jest.spyOn(console, "log").mockImplementation();
jest.spyOn(core, "debug").mockImplementation();
jest.spyOn(core, "getInput").mockImplementation((inputName, options) => {
if (inputName == "resource-group") return "sample-rg";
if (inputName == "cluster-name") return "testing";
if (inputName == "creds") return JSON.stringify(creds);
});
const creds = {
clientId: "<client id>",
clientSecret: "<client secret>",
subscriptionId: "<subscription id>",
tenantId: "<tenant id>",
activeDirectoryEndpointUrl: "https://login.microsoftonline.com",
resourceManagerEndpointUrl: "https://management.azure.com/",
activeDirectoryGraphResourceId: "https://graph.windows.net/",
sqlManagementEndpointUrl: "https://management.core.windows.net:8443/",
galleryEndpointUrl: "https://gallery.azure.com/",
managementEndpointUrl: "https://management.core.windows.net/",
};
const responseKube = {
statusCode: 200,
body: {
properties: {
kubeConfig: Buffer.from("###").toString("base64"),
},
},
} as azureActionsUtil.WebResponse;
const responseLogin = {
statusCode: 200,
body: {
access_token: "<access_token>",
},
} as azureActionsUtil.WebResponse;
jest
.spyOn(azureActionsUtil, "sendRequest")
.mockResolvedValueOnce(responseLogin)
.mockResolvedValueOnce(responseKube);
process.env["RUNNER_TEMP"] = "tempDirPath";
jest.spyOn(Date, "now").mockImplementation(() => 1234561234567);
expect(await login.run());
expect(fs.writeFileSync).toHaveBeenCalledWith(
path.join("tempDirPath", "kubeconfig_1234561234567"),
"###"
);
expect(fs.chmodSync).toHaveBeenCalledWith(
path.join("tempDirPath", "kubeconfig_1234561234567"),
"600"
);
expect(core.exportVariable).toHaveBeenCalledWith(
"KUBECONFIG",
path.join("tempDirPath", "kubeconfig_1234561234567")
);
});
});

103
src/run.ts Normal file
Просмотреть файл

@ -0,0 +1,103 @@
import * as core from "@actions/core";
import * as path from "path";
import * as fs from "fs";
import {
WebRequest,
WebResponse,
sendRequest,
} from "@azure-actions/utilities/lib/http";
import { getAzureAccessToken } from "@azure-actions/auth";
export async function run() {
// get inputs
const creds = core.getInput("creds", { required: true });
let credsObject: { [key: string]: string };
try {
credsObject = JSON.parse(creds);
} catch (ex) {
throw new Error("Credentials object is not a valid JSON: " + ex);
}
const subscriptionId =
core.getInput("subscription-id") || credsObject["subscriptionId"];
const resourceGroupName = core.getInput("resource-group", { required: true });
const clusterName = core.getInput("cluster-name", { required: true });
// get kubeconfig
core.debug("Getting kubeconfig");
const kubeconfig = await getKubeconfig(
credsObject,
subscriptionId,
resourceGroupName,
clusterName
);
// create file
const runnerTempDirectory = process.env["RUNNER_TEMP"]; // use process.env until the core libs are updated
const kubeconfigPath = path.join(
runnerTempDirectory,
`kubeconfig_${Date.now()}`
);
core.debug(`Writing kubeconfig to ${kubeconfigPath}`);
fs.writeFileSync(kubeconfigPath, kubeconfig);
fs.chmodSync(kubeconfigPath, "600");
// export
core.exportVariable("KUBECONFIG", kubeconfigPath);
core.debug("KUBECONFIG environment variable is set");
}
export async function getKubeconfig(
creds: {
[key: string]: string;
},
subscriptionId: string,
resourceGroupName: string,
clusterName: string
): Promise<string> {
const managementEndpointUrl =
creds["resourceManagerEndpointUrl"] || "https://management.azure.com/";
const azureSessionToken = await getAzureAccessToken(JSON.stringify(creds));
return await getAKSKubeconfig(
azureSessionToken,
subscriptionId,
managementEndpointUrl,
resourceGroupName,
clusterName
);
}
export function getAKSKubeconfig(
azureSessionToken: string,
subscriptionId: string,
managementEndpointUrl: string,
resourceGroupName: string,
clusterName: string
): Promise<string> {
return new Promise<string>((resolve, reject) => {
const webRequest = new WebRequest();
webRequest.method = "GET";
webRequest.uri = `${managementEndpointUrl}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ContainerService/managedClusters/${clusterName}/accessProfiles/clusterAdmin?api-version=2017-08-31`;
webRequest.headers = {
Authorization: "Bearer " + azureSessionToken,
"Content-Type": "application/json; charset=utf-8",
};
sendRequest(webRequest)
.then((response: WebResponse) => {
const accessProfile = response.body;
if (accessProfile?.properties?.kubeConfig) {
const kubeconfig = Buffer.from(
accessProfile.properties.kubeConfig,
"base64"
);
resolve(kubeconfig.toString());
} else {
reject(JSON.stringify(response.body));
}
})
.catch(reject);
});
}
run().catch(core.setFailed);

Просмотреть файл

@ -1,12 +1,9 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./lib"
"target": "ES6",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./lib"
},
"exclude": [
"node_modules",
"**/*.test.ts"
]
}
"exclude": ["node_modules", "tests", "**/*.test.ts"]
}