diff --git a/commands/azureCommands/acr-build-logs-utils/logProvider.ts b/commands/azureCommands/acr-build-logs-utils/logProvider.ts index 57d4e87f3b..657b2b1aa2 100644 --- a/commands/azureCommands/acr-build-logs-utils/logProvider.ts +++ b/commands/azureCommands/acr-build-logs-utils/logProvider.ts @@ -51,22 +51,24 @@ export class LogContentProvider implements vscode.TextDocumentContentProvider { font-size: var(--vscode-editor-font-size); font-family: var(--vscode-editor-font-family); } - pre{ + #force{ font-size: var(--vscode-editor-font-size); - font-family: var(--vscode-editor-font-family); + font-family: monospace; + font-size: var(--font-size); + font-weight: var(--font-weight); } .r{ - color:lightcoral; + color:var(--vscode-terminal-ansiBrightRed); } .g{ - color:lightgreen; + color:var(--vscode-terminal-ansiBrightGreen); } -
${processedLog}
+
${processedLog}
` } diff --git a/commands/azureCommands/acr-build-logs-utils/logScripts.js b/commands/azureCommands/acr-build-logs-utils/logScripts.js index 7c25b76c9b..81385974ba 100644 --- a/commands/azureCommands/acr-build-logs-utils/logScripts.js +++ b/commands/azureCommands/acr-build-logs-utils/logScripts.js @@ -13,12 +13,16 @@ var modalObject = { overlay: document.querySelector('.overlay') }; +var triangles = { + 'down': ' △', + 'up': ' ▽' +} + // Main let content = document.querySelector('#core'); const vscode = acquireVsCodeApi(); setLoadMoreListener(); setTableSorter(); -window.addEventListener("resize", manageWidth); modalObject.overlay.addEventListener('click', (event) => { if (event.target === modalObject.overlay) { @@ -42,13 +46,13 @@ function sortTable(n, dir = "asc", holdDir = false) { currentN = n; let table, rows, switching, i, x, y, shouldSwitch, switchcount = 0; let cmpFunc = acquireCompareFunction(n); - table = document.getElementById("coreParent"); + table = document.getElementById("core"); switching = true; //Set the sorting direction to ascending: while (switching) { switching = false; - rows = table.querySelectorAll(".accordion"); + rows = table.querySelectorAll(".holder"); for (i = 0; i < rows.length - 1; i++) { shouldSwitch = false; x = rows[i].getElementsByTagName("TD")[n]; @@ -77,6 +81,19 @@ function sortTable(n, dir = "asc", holdDir = false) { } } } + + let sortColumns = document.querySelectorAll(".sort"); + if (sortColumns[n - 1].innerHTML === triangles['down']) { + sortColumns[n - 1].innerHTML = triangles['up']; + } else if (sortColumns[n - 1].innerHTML === triangles['up']) { + sortColumns[n - 1].innerHTML = triangles['down']; + } else { + for (cell of sortColumns) { + cell.innerHTML = ' '; + } + sortColumns[n - 1].innerHTML = triangles['down']; + } + } function acquireCompareFunction(n) { @@ -133,6 +150,7 @@ window.addEventListener('message', event => { } else if (message.type === 'endContinued') { sortTable(currentN, currentDir, true); } else if (message.type === 'end') { + window.addEventListener("resize", manageWidth); manageWidth(); } @@ -142,11 +160,17 @@ function setSingleAccordion(item) { item.addEventListener('click', function () { this.classList.toggle('active'); this.querySelector('.arrow').classList.toggle('activeArrow'); - var panel = this.nextElementSibling; + let panel = this.nextElementSibling; if (panel.style.maxHeight) { panel.style.display = 'none'; panel.style.maxHeight = null; + let index = openAccordions.indexOf(panel); + if (index > -1) { + openAccordions.splice(index, 1); + } } else { + openAccordions.push(panel); + setAccordionTableWidth(); panel.style.display = 'table-row'; let paddingTop = +panel.style.paddingTop.split('px')[0]; let paddingBottom = +panel.style.paddingBottom.split('px')[0]; @@ -202,4 +226,33 @@ function manageWidth() { let width = parseInt(getComputedStyle(topRowCells[i]).width); headerCells[i].style.width = width + "px"; } + setAccordionTableWidth(); +} + +let openAccordions = []; + +function setAccordionTableWidth() { + let topRow = document.querySelector("#core tr"); + let topRowCells = topRow.querySelectorAll("td"); + let topWidths = []; + for (let cell of topRowCells) { + topWidths.push(parseInt(getComputedStyle(cell).width)); + } + for (acc of openAccordions) { + let cells = acc.querySelectorAll(".innerTable td"); + cells[0].style.width = topWidths[0]; + cells[5].style.width = topWidths[1] + topWidths[2] + topWidths[3] + topWidths[4] + topWidths[5]; + cells[2].style.width = topWidths[6]; + for (let i = 3; i < cells.length; i++) { + if ((i + 2) % 4 === 1) { + cells[i].style.width = topWidths[0] + "px"; + } else if ((i + 2) % 4 === 2) { + cells[i].style.width = (topWidths[1] + topWidths[2]) + "px"; + } else if ((i + 2) % 4 === 3) { + cells[i].style.width = (topWidths[3] + topWidths[4]) + "px"; + } else if ((i + 2) % 4 === 0) { + cells[i].style.width = topWidths[5] + "px"; + } + } + } } diff --git a/commands/azureCommands/acr-build-logs-utils/stylesheet.css b/commands/azureCommands/acr-build-logs-utils/stylesheet.css index 99bdc81be7..782b635804 100644 --- a/commands/azureCommands/acr-build-logs-utils/stylesheet.css +++ b/commands/azureCommands/acr-build-logs-utils/stylesheet.css @@ -100,11 +100,10 @@ h2 { font-family: var(--vscode-editor-font-family); } -#coreParent{ +#core { margin-top: 1cm; } - #headerTable { font-size: var(--vscode-editor-font-size); font-family: var(--vscode-editor-font-family); diff --git a/commands/azureCommands/acr-build-logs.ts b/commands/azureCommands/acr-build-logs.ts index 2963f93094..c1c6fa37ae 100644 --- a/commands/azureCommands/acr-build-logs.ts +++ b/commands/azureCommands/acr-build-logs.ts @@ -27,6 +27,7 @@ export async function viewBuildLogs(context: AzureRegistryNode | AzureRepository let resourceGroup: string = registry.id.slice(registry.id.search('resourceGroups/') + 'resourceGroups/'.length, registry.id.search('/providers/')); const client = AzureUtilityManager.getInstance().getContainerRegistryManagementClient(subscription); + let logData: LogData = new LogData(client, registry, resourceGroup); const filterFunction = context ? getFilterFunction(context) : undefined; try { @@ -43,22 +44,26 @@ export async function viewBuildLogs(context: AzureRegistryNode | AzureRepository itemType = 'repository'; } else if (context && context instanceof AzureImageNode) { itemType = 'image'; + } else { itemType = 'registry'; } vscode.window.showInformationMessage(`This ${itemType} has no associated build logs`); return; } - - let links: { url?: string, id: number }[] = []; - - links.sort((a, b): number => { return a.id - b.id }); - let webViewTitle: string = registry.name; - if (context instanceof AzureRepositoryNode || context instanceof AzureImageNode) { - webViewTitle += (context ? '/' + context.label : ''); + if (context && context instanceof AzureImageNode) { + logData.getLink(0).then((url) => { + if (url !== 'requesting') { + openLog(url, logData.logs[0].buildId); //-----------------------------------------------------Need to use filter + } + }); + } else { + let webViewTitle: string = registry.name; + if (context instanceof AzureRepositoryNode || context instanceof AzureImageNode) { + webViewTitle += (context ? '/' + context.label : ''); + } + createWebview(webViewTitle, logData); } - createWebview(webViewTitle, logData); - } //# WEBVIEW COMPONENTS @@ -95,39 +100,41 @@ function addLogsToWebView(panel: vscode.WebviewPanel, logData: LogData, startIte 'type': 'populate', 'id': i, 'logComponent': ` - -
- ${name} - ${buildTask} - ${log.status} - ${createTime} - ${timeElapsed} - ${osType} - - - -
- - - - - - - - - - - - ${imageOutput} -
 Output Images -
- -
-
 Tag - RepositoryDigest
-
- - ` + + +
+ ${name} + ${buildTask} + ${log.status} + ${createTime} + ${timeElapsed} + ${osType} + + + +
+ + + + + + + + + + + + ${imageOutput} +
 Output Images +
+ +
+
 Tag + RepositoryDigest
+
+ + + ` }); } if (startItem) { @@ -190,19 +197,16 @@ function getWebviewContent(scriptFile: vscode.Uri, stylesheet: vscode.Uri): stri - - - - +
@@ -215,8 +219,7 @@ function getWebviewContent(scriptFile: vscode.Uri, stylesheet: vscode.Uri): stri
- -`; + `; } /** Setup communication with the webview sorting out received mesages from its javascript file */ function setupCommunication(panel: vscode.WebviewPanel, logData: LogData): void { @@ -252,7 +255,13 @@ function createLogView(text: string, title: string): void { console.log(error); } + // ///TODO: temporarily testing with the opentext, trying to save + // let bool; + // console.log("here"); // vscode.workspace.openTextDocument(uri).then((doc) => { + // console.log("inside openTextDocument lambda function"); + // bool = doc.save(); ///want to make this async, wasn't able to make lambda asyc + // console.log(bool); // return vscode.window.showTextDocument(doc, vscode.ViewColumn.Active + 1, true); // }); diff --git a/commands/azureCommands/acr-build.ts b/commands/azureCommands/acr-build.ts index 3f13a778b5..385d8840c0 100644 --- a/commands/azureCommands/acr-build.ts +++ b/commands/azureCommands/acr-build.ts @@ -1,13 +1,14 @@ import { ContainerRegistryManagementClient } from 'azure-arm-containerregistry'; -import { QuickBuildRequest } from "azure-arm-containerregistry/lib/models"; -import { Registry } from 'azure-arm-containerregistry/lib/models'; +import { Build, Registry } from 'azure-arm-containerregistry/lib/models'; +import { BuildGetLogResult, QuickBuildRequest } from "azure-arm-containerregistry/lib/models"; import { BlobService, createBlobServiceWithSas } from "azure-storage"; import * as fs from 'fs'; import * as os from 'os'; +import { Readable, Writable } from 'stream'; import * as tar from 'tar'; import * as url from 'url'; import * as vscode from "vscode"; - +import { ResourceGroup } from '../../node_modules/azure-arm-resource/lib/resource/models'; import { getBlobInfo, getResourceGroupName } from "../../utils/Azure/acrTools"; import { AzureUtilityManager } from "../../utils/azureUtilityManager"; import { quickPickACRRegistry, quickPickResourceGroup, quickPickSubscription } from '../utils/quick-pick-azure'; @@ -32,7 +33,7 @@ export async function queueBuild(dockerFileUri?: vscode.Uri): Promise { } else { folder = await (vscode).window.showWorkspaceFolderPick(); } - let sourceLocation: string = folder.uri.path; + let sourceLocation: string = '.' + folder.uri.path; let relativeDockerPath = 'Dockerfile'; if (dockerFileUri.path.indexOf(sourceLocation) !== 0) { //Currently, there is no support for selecting source location folders that don't contain a path to the triggered dockerfile. @@ -72,6 +73,10 @@ export async function queueBuild(dockerFileUri?: vscode.Uri): Promise { terminal.show(); await terminal.sendText('az acr build -r ' + registry.name + ' -t ' + name + ' .'); status.appendLine('Success'); + //const build: Build = await client.registries.queueBuild(resourceGroupName, registry.name, buildRequest); + //status.show(); + //await streamLogs2(client, resourceGroupName, registry, build); + //status.show(); } async function uploadSourceCode(client: ContainerRegistryManagementClient, registryName: string, resourceGroupName: string, sourceLocation: string, tarFilePath: string): Promise { @@ -92,15 +97,10 @@ async function uploadSourceCode(client: ContainerRegistryManagementClient, regis status.appendLine(" Getting blob info from Upload Url "); // Right now, accountName and endpointSuffix are unused, but will be used for streaming logs later. let { accountName, endpointSuffix, containerName, blobName, sasToken, host } = getBlobInfo(upload_url); - status.appendLine(" Creating Blob Service "); let blob: BlobService = createBlobServiceWithSas(host, sasToken); - status.appendLine(" Creating Block Blob "); - blob.createBlockBlobFromLocalFile(containerName, blobName, tarFilePath, (): void => { }); - - status.appendLine(" Success "); return relative_path; } @@ -122,3 +122,78 @@ function loadDockerignoreFile(sourceLocation) { } */ +async function streamLogs(client: ContainerRegistryManagementClient, resourceGroupName: string, registry: Registry, build: Build): Promise { + const temp: BuildGetLogResult = await client.builds.getLogLink(resourceGroupName, registry.name, build.buildId); + const link = temp.logLink; + let blobInfo = getBlobInfo(link); + let blob: BlobService = createBlobServiceWithSas(blobInfo.host, blobInfo.sasToken); + let stream: Readable = new Readable(); + try { + stream = blob.createReadStream(blobInfo.containerName, blobInfo.blobName, (error, response) => { + if (response) { + console.log(response.name + 'has Completed'); + } else { + console.log(error); + } + }); + console.log(stream); + } catch (error) { + console.log('a' + error); + } + stream.on('data', (chunk) => { + status.appendLine(chunk.toString()); + status.show(); + }); + +} + +async function streamLogs2(client: ContainerRegistryManagementClient, resourceGroupName: string, registry: Registry, build: Build): Promise { + const temp: BuildGetLogResult = await client.builds.getLogLink(resourceGroupName, registry.name, build.buildId); + const link = temp.logLink; + let blobInfo = getBlobInfo(link); + let blob: BlobService = createBlobServiceWithSas(blobInfo.host, blobInfo.sasToken); + let stream: Readable = blob.createReadStream(blobInfo.containerName, blobInfo.blobName, (error, response) => { + if (response) { + status.appendLine(response.name + 'has Completed'); + } else { + status.appendLine(error.message); + } + status.show(); + }); + + stream.on('data', (chunk) => { + status.appendLine(chunk.toString()); + console.log(chunk.toString()); + status.show(); + }); + +} + +export async function streamLogs3(client: ContainerRegistryManagementClient, resourceGroupName: string, registry: Registry, build: Build): Promise { + const temp: BuildGetLogResult = await client.builds.getLogLink(resourceGroupName, registry.name, build.buildId); + return new Promise((resolve, reject) => { + const link = temp.logLink; + let blobInfo = getBlobInfo(link); + let blob: BlobService = createBlobServiceWithSas(blobInfo.host, blobInfo.sasToken); + let stream: Readable = new Readable(); + stream = blob.createReadStream(blobInfo.containerName, blobInfo.blobName, (error, response) => { + if (response) { + //.appendLine(chunk.toString()); + status.show(); + } else { + status.appendLine(error.message); + reject(); + } + status.show(); + }); + + stream.on('data', (chunk) => { + status.appendLine(chunk.toString()); + status.show(); + }); + stream.on('finish', () => { + resolve(); + }); + + }); +} diff --git a/commands/azureCommands/delete-repository.ts b/commands/azureCommands/delete-repository.ts index 1ef5bb4648..22d2828a00 100644 --- a/commands/azureCommands/delete-repository.ts +++ b/commands/azureCommands/delete-repository.ts @@ -32,7 +32,7 @@ export async function deleteRepository(context?: AzureRepositoryNode): Promise { terminal.show(); // Step 2: docker login command - await terminal.sendText(`docker login ${registry} -u ${username} -p ${password}`); + let cont = (err, stdout, stderr) => { + console.log(err); + // Step 3: docker pull command + //await terminal.sendText(`docker login ${registry} -u ${username} -p ${password}`); - // Step 3: docker pull command - await terminal.sendText(`docker pull ${registry}/${context.label}`); + terminal.sendText(`docker pull ${registry}/${context.label}`); - //Acquiring telemetry data here - if (reporter) { - reporter.sendTelemetryEvent('command', { - command: teleCmdId - }); + //Acquiring telemetry data here + if (reporter) { + reporter.sendTelemetryEvent('command', { + command: teleCmdId + }); + } + // let jsonStdout = JSON.parse(stdout); + // let soughtsrvr: string = ""; + // for (let i = 0; i < jsonStdout.length; i++) { + // let srvrName: string = jsonStdout[i].acrLoginServer; + // let searchIndex: number = srvrName.search(`${regName}`); + // if (searchIndex === 0 && srvrName[regName.length] === '.') { // can names include . ? + // soughtsrvr = srvrName; + // break; + // } + // } } + exec(`docker login ${registry} -u ${username} -p ${password}`, cont); + + //await terminal.sendText(`docker login ${registry} -u ${username} -p ${password}`); + } diff --git a/package.json b/package.json index 45617a893e..971f0613b5 100644 --- a/package.json +++ b/package.json @@ -64,8 +64,7 @@ "main": "./out/dockerExtension", "contributes": { "menus": { - "commandPalette": [ - { + "commandPalette": [{ "command": "vscode-docker.browseDockerHub", "when": "false" }, @@ -74,8 +73,7 @@ "when": "false" } ], - "editor/context": [ - { + "editor/context": [{ "when": "editorLangId == dockerfile", "command": "vscode-docker.image.build", "group": "docker" @@ -116,8 +114,7 @@ "group": "docker" } ], - "explorer/context": [ - { + "explorer/context": [{ "when": "resourceFilename =~ /[dD]ocker[fF]ile/", "command": "vscode-docker.image.build", "group": "docker" @@ -143,8 +140,7 @@ "group": "docker" } ], - "view/title": [ - { + "view/title": [{ "command": "vscode-docker.explorer.refresh", "when": "view == dockerExplorer", "group": "navigation" @@ -155,8 +151,7 @@ "group": "navigation" } ], - "view/item/context": [ - { + "view/item/context": [{ "command": "vscode-docker.container.start", "when": "view == dockerExplorer && viewItem =~ /^(localImageNode|imagesRootNode)$/" }, @@ -248,46 +243,44 @@ "command": "vscode-docker.acrBuildLogs", "when": "view == dockerExplorer && viewItem == azureRepositoryNode" }, + { + "command": "vscode-docker.delete-ACR-Repository", + "when": "view == dockerExplorer && viewItem == azureRepositoryNode" + }, { "command": "vscode-docker.acrBuildLogs", "when": "view == dockerExplorer && viewItem == azureImageNode" } ] }, - "debuggers": [ - { - "type": "docker", - "label": "Docker", - "configurationSnippets": [ - { - "label": "Docker: Attach to Node", - "description": "Docker: Attach to Node", - "body": { - "type": "node", - "request": "attach", - "name": "Docker: Attach to Node", - "port": 9229, - "address": "localhost", - "localRoot": "^\"\\${workspaceFolder}\"", - "remoteRoot": "/usr/src/app", - "protocol": "inspector" - } - } - ] - } - ], - "languages": [ - { - "id": "dockerfile", - "aliases": [ - "Dockerfile" - ], - "filenamePatterns": [ - "*.dockerfile", - "Dockerfile" - ] - } - ], + "debuggers": [{ + "type": "docker", + "label": "Docker", + "configurationSnippets": [{ + "label": "Docker: Attach to Node", + "description": "Docker: Attach to Node", + "body": { + "type": "node", + "request": "attach", + "name": "Docker: Attach to Node", + "port": 9229, + "address": "localhost", + "localRoot": "^\"\\${workspaceFolder}\"", + "remoteRoot": "/usr/src/app", + "protocol": "inspector" + } + }] + }], + "languages": [{ + "id": "dockerfile", + "aliases": [ + "Dockerfile" + ], + "filenamePatterns": [ + "*.dockerfile", + "Dockerfile" + ] + }], "configuration": { "type": "object", "title": "Docker configuration options", @@ -447,8 +440,7 @@ } } }, - "commands": [ - { + "commands": [{ "command": "vscode-docker.configure", "title": "Add Docker files to Workspace", "description": "Add Dockerfile, docker-compose.yml files", @@ -630,22 +622,18 @@ } ], "views": { - "dockerView": [ - { - "id": "dockerExplorer", - "name": "Explorer", - "when": "config.docker.showExplorer == true" - } - ] + "dockerView": [{ + "id": "dockerExplorer", + "name": "Explorer", + "when": "config.docker.showExplorer == true" + }] }, "viewsContainers": { - "activitybar": [ - { - "icon": "images/docker.svg", - "id": "dockerView", - "title": "Docker" - } - ] + "activitybar": [{ + "icon": "images/docker.svg", + "id": "dockerView", + "title": "Docker" + }] } }, "engines": { diff --git a/utils/Azure/acrTools.ts b/utils/Azure/acrTools.ts index 31ff278a4f..6cd55763fd 100644 --- a/utils/Azure/acrTools.ts +++ b/utils/Azure/acrTools.ts @@ -94,12 +94,21 @@ export async function sendRequestToRegistry(http_method: string, login_server: s //Credential management /** Obtains registry username and password compatible with docker login */ export async function loginCredentials(registry: Registry): Promise<{ password: string, username: string }> { - const subscription: Subscription = getSubscriptionFromRegistry(registry); - const session: AzureSession = AzureUtilityManager.getInstance().getSession(subscription) - const { aadAccessToken, aadRefreshToken } = await acquireAADTokens(session); - const acrRefreshToken = await acquireACRRefreshToken(registry.loginServer, session.tenantId, aadRefreshToken, aadAccessToken); - return { 'password': acrRefreshToken, 'username': NULL_GUID }; + if (registry.adminUserEnabled) { + const subscription: Subscription = getSubscriptionFromRegistry(registry); + const client = await AzureUtilityManager.getInstance().getContainerRegistryManagementClient(subscription); + const resourceGroup: string = getResourceGroupName(registry); + let creds = await client.registries.listCredentials(resourceGroup, registry.name); + return { 'password': creds.passwords[0].value, 'username': creds.username }; + } else { + const subscription: Subscription = getSubscriptionFromRegistry(registry); + const session: AzureSession = AzureUtilityManager.getInstance().getSession(subscription) + const { aadAccessToken, aadRefreshToken } = await acquireAADTokens(session); + const acrRefreshToken = await acquireACRRefreshToken(registry.loginServer, session.tenantId, aadRefreshToken, aadAccessToken); + return { 'password': acrRefreshToken, 'username': NULL_GUID }; + } } + /** Obtains tokens for using the Docker Registry v2 Api * @param registry The targeted Azure Container Registry * @param scope String determining the scope of the access token