Skip to content

Commit 43f35b3

Browse files
committed
Fixes to starting Jupyter in a Docker container. (#8715)
* Ensure we generate the right args when running in docker * Fixes to starting `Jupyter` in a `Docker` container.
1 parent 8c5c83d commit 43f35b3

File tree

3 files changed

+26
-6
lines changed

3 files changed

+26
-6
lines changed

news/2 Fixes/8661.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes to starting `Jupyter` in a `Docker` container.

src/client/datascience/jupyter/notebookStarter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ export class NotebookStarter implements Disposable {
194194
if (stdout && stdout.toString().includes('(root)')) {
195195
args.push('--allow-root');
196196
}
197-
resolve([]);
197+
resolve(args);
198198
});
199199
});
200200
} catch {

src/test/datascience/execution.unit.test.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ suite('Jupyter Execution', async () => {
280280
});
281281

282282
teardown(() => {
283+
reset(fileSystem);
283284
return cleanupDisposables();
284285
});
285286

@@ -439,7 +440,7 @@ suite('Jupyter Execution', async () => {
439440
.returns(() => result);
440441
}
441442

442-
function setupWorkingPythonService(service: TypeMoq.IMock<IPythonExecutionService>, notebookStdErr?: string[]) {
443+
function setupWorkingPythonService(service: TypeMoq.IMock<IPythonExecutionService>, notebookStdErr?: string[], runInDocker?: boolean) {
443444
setupPythonService(service, 'ipykernel', ['--version'], Promise.resolve({ stdout: '1.1.1.1' }));
444445
setupPythonService(service, 'jupyter', ['nbconvert', '--version'], Promise.resolve({ stdout: '1.1.1.1' }));
445446
setupPythonService(service, 'jupyter', ['notebook', '--version'], Promise.resolve({ stdout: '1.1.1.1' }));
@@ -462,8 +463,8 @@ suite('Jupyter Execution', async () => {
462463
const getServerInfoPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'datascience', 'getServerInfo.py');
463464
setupPythonService(service, undefined, [getServerInfoPath], Promise.resolve({ stdout: 'failure to get server infos' }));
464465
setupPythonServiceExecObservable(service, 'jupyter', ['kernelspec', 'list'], [], []);
465-
setupPythonServiceExecObservable(service, 'jupyter', ['notebook', '--no-browser', /--notebook-dir=.*/, /--config=.*/, '--NotebookApp.iopub_data_rate_limit=10000000000.0'], [], notebookStdErr ? notebookStdErr : ['http://localhost:8888/?token=198']);
466-
466+
const dockerArgs = runInDocker ? ['--ip', '127.0.0.1'] : [];
467+
setupPythonServiceExecObservable(service, 'jupyter', ['notebook', '--no-browser', /--notebook-dir=.*/, /--config=.*/, '--NotebookApp.iopub_data_rate_limit=10000000000.0', ...dockerArgs], [], notebookStdErr ? notebookStdErr : ['http://localhost:8888/?token=198']);
467468
}
468469

469470
function setupMissingKernelPythonService(service: TypeMoq.IMock<IPythonExecutionService>, notebookStdErr?: string[]) {
@@ -528,6 +529,9 @@ suite('Jupyter Execution', async () => {
528529
}
529530

530531
function createExecution(activeInterpreter: PythonInterpreter, notebookStdErr?: string[], skipSearch?: boolean): JupyterExecutionFactory {
532+
return createExecutionAndReturnProcessService(activeInterpreter, notebookStdErr, skipSearch).jupyterExecutionFactory;
533+
}
534+
function createExecutionAndReturnProcessService(activeInterpreter: PythonInterpreter, notebookStdErr?: string[], skipSearch?: boolean, runInDocker?: boolean): {workingPythonExecutionService: TypeMoq.IMock<IPythonExecutionService>; jupyterExecutionFactory: JupyterExecutionFactory} {
531535
// Setup defaults
532536
when(interpreterService.onDidChangeInterpreter).thenReturn(dummyEvent.event);
533537
when(interpreterService.getActiveInterpreter()).thenResolve(activeInterpreter);
@@ -536,10 +540,12 @@ suite('Jupyter Execution', async () => {
536540
when(interpreterService.getInterpreterDetails(match('/foo/baz/python.exe'))).thenResolve(missingKernelPython);
537541
when(interpreterService.getInterpreterDetails(match('/bar/baz/python.exe'))).thenResolve(missingNotebookPython);
538542
when(interpreterService.getInterpreterDetails(argThat(o => !o.includes || !o.includes('python')))).thenReject('Unknown interpreter');
539-
543+
if (runInDocker){
544+
when(fileSystem.readFile('/proc/self/cgroup')).thenResolve('hello docker world');
545+
}
540546
// Create our working python and process service.
541547
const workingService = createTypeMoq<IPythonExecutionService>('working');
542-
setupWorkingPythonService(workingService, notebookStdErr);
548+
setupWorkingPythonService(workingService, notebookStdErr, runInDocker);
543549
const missingKernelService = createTypeMoq<IPythonExecutionService>('missingKernel');
544550
setupMissingKernelPythonService(missingKernelService, notebookStdErr);
545551
const missingNotebookService = createTypeMoq<IPythonExecutionService>('missingNotebook');
@@ -686,6 +692,19 @@ suite('Jupyter Execution', async () => {
686692
await assert.isFulfilled(execution.connectToNotebookServer(), 'Should be able to start a server');
687693
}).timeout(10000);
688694

695+
test('Includes correct args for running in docker', async () => {
696+
const { workingPythonExecutionService, jupyterExecutionFactory} = createExecutionAndReturnProcessService(workingPython, undefined, undefined, true);
697+
when(executionFactory.createDaemon(deepEqual({ daemonModule: PythonDaemonModule, pythonPath: workingPython.path }))).thenResolve(workingPythonExecutionService.object);
698+
699+
await assert.eventually.equal(jupyterExecutionFactory.isNotebookSupported(), true, 'Notebook not supported');
700+
await assert.eventually.equal(jupyterExecutionFactory.isImportSupported(), true, 'Import not supported');
701+
await assert.eventually.equal(jupyterExecutionFactory.isKernelSpecSupported(), true, 'Kernel Spec not supported');
702+
await assert.eventually.equal(jupyterExecutionFactory.isKernelCreateSupported(), true, 'Kernel Create not supported');
703+
const usableInterpreter = await jupyterExecutionFactory.getUsableJupyterPython();
704+
assert.isOk(usableInterpreter, 'Usable interpreter not found');
705+
await assert.isFulfilled(jupyterExecutionFactory.connectToNotebookServer(), 'Should be able to start a server');
706+
}).timeout(10000);
707+
689708
test('Failing notebook throws exception', async () => {
690709
const execution = createExecution(missingNotebookPython);
691710
when(interpreterService.getInterpreters()).thenResolve([missingNotebookPython]);

0 commit comments

Comments
 (0)