in src/panels/RetinaCapturePanel.ts [116:210]
async copyRetinaCaptureData(node: string, localCpPath: string) {
if (!this.kubectl || !this.kubectlVersion) {
vscode.window.showErrorMessage("Kubectl is not available");
return;
}
const createPodYaml = `
apiVersion: v1
kind: Pod
metadata:
name: node-explorer-${node}
labels:
app: node-explorer
spec:
nodeName: ${node}
tolerations:
- key: CriticalAddonsOnly
operator: Exists
- effect: NoExecute
operator: Exists
- effect: NoSchedule
operator: Exists
volumes:
- name: mnt-captures
hostPath:
path: /mnt/capture
containers:
- name: node-explorer
image: alpine
command: ["sleep", "9999999999"]
volumeMounts:
- name: mnt-captures
mountPath: /mnt/capture
`;
const applyResult = await longRunning(`Deploying pod to capture ${node} retina data.`, async () => {
return await withOptionalTempFile(createPodYaml, "YAML", async (podSpecFile) => {
const command = `apply -f ${podSpecFile}`;
return await invokeKubectlCommand(this.kubectl!, this.kubeConfigFilePath, command);
});
});
if (failed(applyResult)) {
vscode.window.showErrorMessage(`Failed to apply Pod: ${applyResult.error}`);
return;
}
const waitResult = await longRunning(`waiting for pod to get ready node-explorer-${node}.`, async () => {
const command = `wait pod -n default --for=condition=ready --timeout=300s node-explorer-${node}`;
return await invokeKubectlCommand(this.kubectl!, this.kubeConfigFilePath, command);
});
if (failed(waitResult)) {
vscode.window.showErrorMessage(`Failed to wait for Pod to be ready: ${waitResult.error}`);
return;
}
/* kubectl cp functionality is used to copy the data from the pod to the local host.
`kubectl cp` can fail with an EOF error for large files, and there's currently no good workaround:
See: https://github.com/kubernetes/kubernetes/issues/60140
The best advice I can see is to use the 'retries' option if it is supported, and the
'request-timeout' option otherwise. */
const clientVersion = this.kubectlVersion!.clientVersion.gitVersion.replace(/^v/, "");
const isRetriesOptionSupported = semver.parse(clientVersion) && semver.gte(clientVersion, "1.23.0");
const cpEOFAvoidanceFlag = isRetriesOptionSupported ? "--retries 99" : "--request-timeout=10m";
const captureHostFolderName = `${localCpPath}-${node}`;
const nodeExplorerResult = await longRunning(
`Copy captured data to local host location ${captureHostFolderName}.`,
async () => {
const cpcommand = `cp node-explorer-${node}:mnt/capture ${captureHostFolderName} ${cpEOFAvoidanceFlag}`;
return await invokeKubectlCommand(this.kubectl!, this.kubeConfigFilePath, cpcommand);
},
);
if (failed(nodeExplorerResult)) {
vscode.window.showErrorMessage(`Failed to apply copy command: ${nodeExplorerResult.error}`);
return;
}
const goToFolder = "Go to Folder";
vscode.window
.showInformationMessage(
`Successfully copied the Retina Capture data to ${captureHostFolderName}`,
goToFolder,
)
.then((selection) => {
if (selection === goToFolder) {
if (env.remoteName === "wsl") {
commands.executeCommand("remote-wsl.revealInExplorer", Uri.file(captureHostFolderName));
} else {
// opening relative file path doesn't work in WSL
open(captureHostFolderName);
}
}
});
}