mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Add acquireLoginSession API for Azdata (#13985)
* wip * fix tests * add tests * PR comments
This commit is contained in:
@@ -61,10 +61,11 @@ export class ControllerModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls azdata login to set the context to this controller
|
* Calls azdata login to set the context to this controller and acquires a login session to prevent other
|
||||||
|
* calls from changing the context while commands for this session are being executed.
|
||||||
* @param promptReconnect
|
* @param promptReconnect
|
||||||
*/
|
*/
|
||||||
public async azdataLogin(promptReconnect: boolean = false): Promise<void> {
|
public async acquireAzdataSession(promptReconnect: boolean = false): Promise<azdataExt.AzdataSession> {
|
||||||
let promptForValidClusterContext: boolean = false;
|
let promptForValidClusterContext: boolean = false;
|
||||||
try {
|
try {
|
||||||
const contexts = await getKubeConfigClusterContexts(this.info.kubeConfigFilePath);
|
const contexts = await getKubeConfigClusterContexts(this.info.kubeConfigFilePath);
|
||||||
@@ -102,7 +103,7 @@ export class ControllerModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._azdataApi.azdata.login(this.info.url, this.info.username, this._password, this.azdataAdditionalEnvVars);
|
return this._azdataApi.azdata.acquireSession(this.info.url, this.info.username, this._password, this.azdataAdditionalEnvVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,64 +124,68 @@ export class ControllerModel {
|
|||||||
}
|
}
|
||||||
// create a new in progress promise object
|
// create a new in progress promise object
|
||||||
ControllerModel._refreshInProgress = new Deferred<void>();
|
ControllerModel._refreshInProgress = new Deferred<void>();
|
||||||
await this.azdataLogin(promptReconnect);
|
const session = await this.acquireAzdataSession(promptReconnect);
|
||||||
const newRegistrations: Registration[] = [];
|
const newRegistrations: Registration[] = [];
|
||||||
await Promise.all([
|
try {
|
||||||
this._azdataApi.azdata.arc.dc.config.show().then(result => {
|
await Promise.all([
|
||||||
this._controllerConfig = result.result;
|
this._azdataApi.azdata.arc.dc.config.show(this.azdataAdditionalEnvVars, session).then(result => {
|
||||||
this.configLastUpdated = new Date();
|
this._controllerConfig = result.result;
|
||||||
this._onConfigUpdated.fire(this._controllerConfig);
|
this.configLastUpdated = new Date();
|
||||||
}).catch(err => {
|
this._onConfigUpdated.fire(this._controllerConfig);
|
||||||
// If an error occurs show a message so the user knows something failed but still
|
}).catch(err => {
|
||||||
// fire the event so callers can know to update (e.g. so dashboards don't show the
|
// If an error occurs show a message so the user knows something failed but still
|
||||||
// loading icon forever)
|
// fire the event so callers hooking into this can handle the error (e.g. so dashboards don't show the
|
||||||
if (showErrors) {
|
// loading icon forever)
|
||||||
vscode.window.showErrorMessage(loc.fetchConfigFailed(this.info.name, err));
|
if (showErrors) {
|
||||||
}
|
vscode.window.showErrorMessage(loc.fetchConfigFailed(this.info.name, err));
|
||||||
this._onConfigUpdated.fire(this._controllerConfig);
|
}
|
||||||
throw err;
|
this._onConfigUpdated.fire(this._controllerConfig);
|
||||||
}),
|
throw err;
|
||||||
this._azdataApi.azdata.arc.dc.endpoint.list(this.azdataAdditionalEnvVars).then(result => {
|
|
||||||
this._endpoints = result.result;
|
|
||||||
this.endpointsLastUpdated = new Date();
|
|
||||||
this._onEndpointsUpdated.fire(this._endpoints);
|
|
||||||
}).catch(err => {
|
|
||||||
// If an error occurs show a message so the user knows something failed but still
|
|
||||||
// fire the event so callers can know to update (e.g. so dashboards don't show the
|
|
||||||
// loading icon forever)
|
|
||||||
if (showErrors) {
|
|
||||||
vscode.window.showErrorMessage(loc.fetchEndpointsFailed(this.info.name, err));
|
|
||||||
}
|
|
||||||
this._onEndpointsUpdated.fire(this._endpoints);
|
|
||||||
throw err;
|
|
||||||
}),
|
|
||||||
Promise.all([
|
|
||||||
this._azdataApi.azdata.arc.postgres.server.list(this.azdataAdditionalEnvVars).then(result => {
|
|
||||||
newRegistrations.push(...result.result.map(r => {
|
|
||||||
return {
|
|
||||||
instanceName: r.name,
|
|
||||||
state: r.state,
|
|
||||||
instanceType: ResourceType.postgresInstances
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
}),
|
}),
|
||||||
this._azdataApi.azdata.arc.sql.mi.list().then(result => {
|
this._azdataApi.azdata.arc.dc.endpoint.list(this.azdataAdditionalEnvVars, session).then(result => {
|
||||||
newRegistrations.push(...result.result.map(r => {
|
this._endpoints = result.result;
|
||||||
return {
|
this.endpointsLastUpdated = new Date();
|
||||||
instanceName: r.name,
|
this._onEndpointsUpdated.fire(this._endpoints);
|
||||||
state: r.state,
|
}).catch(err => {
|
||||||
instanceType: ResourceType.sqlManagedInstances
|
// If an error occurs show a message so the user knows something failed but still
|
||||||
};
|
// fire the event so callers can know to update (e.g. so dashboards don't show the
|
||||||
}));
|
// loading icon forever)
|
||||||
|
if (showErrors) {
|
||||||
|
vscode.window.showErrorMessage(loc.fetchEndpointsFailed(this.info.name, err));
|
||||||
|
}
|
||||||
|
this._onEndpointsUpdated.fire(this._endpoints);
|
||||||
|
throw err;
|
||||||
|
}),
|
||||||
|
Promise.all([
|
||||||
|
this._azdataApi.azdata.arc.postgres.server.list(this.azdataAdditionalEnvVars, session).then(result => {
|
||||||
|
newRegistrations.push(...result.result.map(r => {
|
||||||
|
return {
|
||||||
|
instanceName: r.name,
|
||||||
|
state: r.state,
|
||||||
|
instanceType: ResourceType.postgresInstances
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}),
|
||||||
|
this._azdataApi.azdata.arc.sql.mi.list(this.azdataAdditionalEnvVars, session).then(result => {
|
||||||
|
newRegistrations.push(...result.result.map(r => {
|
||||||
|
return {
|
||||||
|
instanceName: r.name,
|
||||||
|
state: r.state,
|
||||||
|
instanceType: ResourceType.sqlManagedInstances
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
]).then(() => {
|
||||||
|
this._registrations = newRegistrations;
|
||||||
|
this.registrationsLastUpdated = new Date();
|
||||||
|
this._onRegistrationsUpdated.fire(this._registrations);
|
||||||
})
|
})
|
||||||
]).then(() => {
|
]);
|
||||||
this._registrations = newRegistrations;
|
} finally {
|
||||||
this.registrationsLastUpdated = new Date();
|
session.dispose();
|
||||||
this._onRegistrationsUpdated.fire(this._registrations);
|
ControllerModel._refreshInProgress.resolve();
|
||||||
})
|
ControllerModel._refreshInProgress = undefined;
|
||||||
]);
|
}
|
||||||
ControllerModel._refreshInProgress.resolve();
|
|
||||||
ControllerModel._refreshInProgress = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get endpoints(): azdataExt.DcEndpointListResult[] {
|
public get endpoints(): azdataExt.DcEndpointListResult[] {
|
||||||
|
|||||||
@@ -71,10 +71,11 @@ export class MiaaModel extends ResourceModel {
|
|||||||
return this._refreshPromise.promise;
|
return this._refreshPromise.promise;
|
||||||
}
|
}
|
||||||
this._refreshPromise = new Deferred();
|
this._refreshPromise = new Deferred();
|
||||||
|
let session: azdataExt.AzdataSession | undefined = undefined;
|
||||||
try {
|
try {
|
||||||
await this.controllerModel.azdataLogin();
|
session = await this.controllerModel.acquireAzdataSession();
|
||||||
try {
|
try {
|
||||||
const result = await this._azdataApi.azdata.arc.sql.mi.show(this.info.name);
|
const result = await this._azdataApi.azdata.arc.sql.mi.show(this.info.name, this.controllerModel.azdataAdditionalEnvVars, session);
|
||||||
this._config = result.result;
|
this._config = result.result;
|
||||||
this.configLastUpdated = new Date();
|
this.configLastUpdated = new Date();
|
||||||
this._onConfigUpdated.fire(this._config);
|
this._onConfigUpdated.fire(this._config);
|
||||||
@@ -114,6 +115,7 @@ export class MiaaModel extends ResourceModel {
|
|||||||
this._refreshPromise.reject(err);
|
this._refreshPromise.reject(err);
|
||||||
throw err;
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
|
session?.dispose();
|
||||||
this._refreshPromise = undefined;
|
this._refreshPromise = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,10 +107,10 @@ export class PostgresModel extends ResourceModel {
|
|||||||
return this._refreshPromise.promise;
|
return this._refreshPromise.promise;
|
||||||
}
|
}
|
||||||
this._refreshPromise = new Deferred();
|
this._refreshPromise = new Deferred();
|
||||||
|
let session: azdataExt.AzdataSession | undefined = undefined;
|
||||||
try {
|
try {
|
||||||
await this.controllerModel.azdataLogin();
|
session = await this.controllerModel.acquireAzdataSession();
|
||||||
this._config = (await this._azdataApi.azdata.arc.postgres.server.show(this.info.name)).result;
|
this._config = (await this._azdataApi.azdata.arc.postgres.server.show(this.info.name, this.controllerModel.azdataAdditionalEnvVars, session)).result;
|
||||||
this.configLastUpdated = new Date();
|
this.configLastUpdated = new Date();
|
||||||
this._onConfigUpdated.fire(this._config);
|
this._onConfigUpdated.fire(this._config);
|
||||||
this._refreshPromise.resolve();
|
this._refreshPromise.resolve();
|
||||||
@@ -118,6 +118,7 @@ export class PostgresModel extends ResourceModel {
|
|||||||
this._refreshPromise.reject(err);
|
this._refreshPromise.reject(err);
|
||||||
throw err;
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
|
session?.dispose();
|
||||||
this._refreshPromise = undefined;
|
this._refreshPromise = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,9 +75,12 @@ export class FakeAzdataApi implements azdataExt.IAzdataApi {
|
|||||||
getPath(): Promise<string> {
|
getPath(): Promise<string> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
login(_endpoint: string, _username: string, _password: string): Promise<azdataExt.AzdataOutput<any>> {
|
login(_endpoint: string, _username: string, _password: string): Promise<azdataExt.AzdataOutput<void>> {
|
||||||
return <any>undefined;
|
return <any>undefined;
|
||||||
}
|
}
|
||||||
|
acquireSession(_endpoint: string, _username: string, _password: string): Promise<azdataExt.AzdataSession> {
|
||||||
|
return Promise.resolve({ dispose: () => { } });
|
||||||
|
}
|
||||||
version(): Promise<azdataExt.AzdataOutput<string>> {
|
version(): Promise<azdataExt.AzdataOutput<string>> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ describe('ControllerModel', function (): void {
|
|||||||
// Returning an undefined model here indicates that the dialog closed without clicking "Ok" - usually through the user clicking "Cancel"
|
// Returning an undefined model here indicates that the dialog closed without clicking "Ok" - usually through the user clicking "Cancel"
|
||||||
sinon.stub(ConnectToControllerDialog.prototype, 'waitForClose').returns(Promise.resolve(undefined));
|
sinon.stub(ConnectToControllerDialog.prototype, 'waitForClose').returns(Promise.resolve(undefined));
|
||||||
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
||||||
await should(model.azdataLogin()).be.rejectedWith(new UserCancelledError(loc.userCancelledError));
|
await should(model.acquireAzdataSession()).be.rejectedWith(new UserCancelledError(loc.userCancelledError));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Reads password from cred store', async function (): Promise<void> {
|
it('Reads password from cred store', async function (): Promise<void> {
|
||||||
@@ -58,13 +58,13 @@ describe('ControllerModel', function (): void {
|
|||||||
|
|
||||||
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
||||||
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
||||||
azdataMock.setup(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
azdataMock.setup(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
||||||
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
||||||
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
||||||
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
||||||
|
|
||||||
await model.azdataLogin();
|
await model.acquireAzdataSession();
|
||||||
azdataMock.verify(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), password, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
azdataMock.verify(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), password, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Prompt for password when not in cred store', async function (): Promise<void> {
|
it('Prompt for password when not in cred store', async function (): Promise<void> {
|
||||||
@@ -79,7 +79,7 @@ describe('ControllerModel', function (): void {
|
|||||||
|
|
||||||
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
||||||
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
||||||
azdataMock.setup(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
azdataMock.setup(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
||||||
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
||||||
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
||||||
|
|
||||||
@@ -89,8 +89,8 @@ describe('ControllerModel', function (): void {
|
|||||||
|
|
||||||
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
||||||
|
|
||||||
await model.azdataLogin();
|
await model.acquireAzdataSession();
|
||||||
azdataMock.verify(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), password, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
azdataMock.verify(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), password, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Prompt for password when rememberPassword is true but prompt reconnect is true', async function (): Promise<void> {
|
it('Prompt for password when rememberPassword is true but prompt reconnect is true', async function (): Promise<void> {
|
||||||
@@ -104,7 +104,7 @@ describe('ControllerModel', function (): void {
|
|||||||
|
|
||||||
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
||||||
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
||||||
azdataMock.setup(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
azdataMock.setup(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
||||||
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
||||||
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
||||||
|
|
||||||
@@ -114,9 +114,9 @@ describe('ControllerModel', function (): void {
|
|||||||
|
|
||||||
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
||||||
|
|
||||||
await model.azdataLogin(true);
|
await model.acquireAzdataSession(true);
|
||||||
should(waitForCloseStub.called).be.true('waitForClose should have been called');
|
should(waitForCloseStub.called).be.true('waitForClose should have been called');
|
||||||
azdataMock.verify(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), password, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
azdataMock.verify(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), password, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Prompt for password when we already have a password but prompt reconnect is true', async function (): Promise<void> {
|
it('Prompt for password when we already have a password but prompt reconnect is true', async function (): Promise<void> {
|
||||||
@@ -130,7 +130,7 @@ describe('ControllerModel', function (): void {
|
|||||||
|
|
||||||
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
||||||
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
||||||
azdataMock.setup(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
azdataMock.setup(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
||||||
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
||||||
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
||||||
|
|
||||||
@@ -141,9 +141,9 @@ describe('ControllerModel', function (): void {
|
|||||||
// Set up original model with a password
|
// Set up original model with a password
|
||||||
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] }, 'originalPassword');
|
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', kubeConfigFilePath: '/path/to/.kube/config', kubeClusterContext: 'currentCluster', username: 'admin', name: 'arc', rememberPassword: true, resources: [] }, 'originalPassword');
|
||||||
|
|
||||||
await model.azdataLogin(true);
|
await model.acquireAzdataSession(true);
|
||||||
should(waitForCloseStub.called).be.true('waitForClose should have been called');
|
should(waitForCloseStub.called).be.true('waitForClose should have been called');
|
||||||
azdataMock.verify(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), password, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
azdataMock.verify(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), password, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Model values are updated correctly when modified during reconnect', async function (): Promise<void> {
|
it('Model values are updated correctly when modified during reconnect', async function (): Promise<void> {
|
||||||
@@ -158,7 +158,7 @@ describe('ControllerModel', function (): void {
|
|||||||
|
|
||||||
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
const azdataExtApiMock = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
||||||
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
const azdataMock = TypeMoq.Mock.ofType<azdataExt.IAzdataApi>();
|
||||||
azdataMock.setup(x => x.login(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
azdataMock.setup(x => x.acquireSession(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => <any>Promise.resolve(undefined));
|
||||||
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
azdataExtApiMock.setup(x => x.azdata).returns(() => azdataMock.object);
|
||||||
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
sinon.stub(vscode.extensions, 'getExtension').returns(<any>{ exports: azdataExtApiMock.object });
|
||||||
|
|
||||||
@@ -199,10 +199,11 @@ describe('ControllerModel', function (): void {
|
|||||||
const waitForCloseStub = sinon.stub(ConnectToControllerDialog.prototype, 'waitForClose').returns(Promise.resolve(
|
const waitForCloseStub = sinon.stub(ConnectToControllerDialog.prototype, 'waitForClose').returns(Promise.resolve(
|
||||||
{ controllerModel: newModel, password: newPassword }));
|
{ controllerModel: newModel, password: newPassword }));
|
||||||
|
|
||||||
await model.azdataLogin(true);
|
await model.acquireAzdataSession(true);
|
||||||
should(waitForCloseStub.called).be.true('waitForClose should have been called');
|
should(waitForCloseStub.called).be.true('waitForClose should have been called');
|
||||||
should((await treeDataProvider.getChildren()).length).equal(1, 'Tree Data provider should still only have 1 node');
|
should((await treeDataProvider.getChildren()).length).equal(1, 'Tree Data provider should still only have 1 node');
|
||||||
should(model.info).deepEqual(newInfo, 'Model info should have been updated');
|
should(model.info).deepEqual(newInfo, 'Model info should have been updated');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -129,13 +129,16 @@ export class MiaaComputeAndStoragePage extends DashboardPage {
|
|||||||
cancellable: false
|
cancellable: false
|
||||||
},
|
},
|
||||||
async (_progress, _token): Promise<void> => {
|
async (_progress, _token): Promise<void> => {
|
||||||
|
let session: azdataExt.AzdataSession | undefined = undefined;
|
||||||
try {
|
try {
|
||||||
await this._miaaModel.controllerModel.azdataLogin();
|
session = await this._miaaModel.controllerModel.acquireAzdataSession();
|
||||||
await this._azdataApi.azdata.arc.sql.mi.edit(
|
await this._azdataApi.azdata.arc.sql.mi.edit(
|
||||||
this._miaaModel.info.name, this.saveArgs);
|
this._miaaModel.info.name, this.saveArgs, this._miaaModel.controllerModel.azdataAdditionalEnvVars, session);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.saveButton!.enabled = true;
|
this.saveButton!.enabled = true;
|
||||||
throw err;
|
throw err;
|
||||||
|
} finally {
|
||||||
|
session?.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._miaaModel.refresh();
|
await this._miaaModel.refresh();
|
||||||
|
|||||||
@@ -206,8 +206,13 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
|
|||||||
cancellable: false
|
cancellable: false
|
||||||
},
|
},
|
||||||
async (_progress, _token) => {
|
async (_progress, _token) => {
|
||||||
await this._controllerModel.azdataLogin();
|
const session = await this._controllerModel.acquireAzdataSession();
|
||||||
return await this._azdataApi.azdata.arc.sql.mi.delete(this._miaaModel.info.name);
|
try {
|
||||||
|
return await this._azdataApi.azdata.arc.sql.mi.delete(this._miaaModel.info.name, this._controllerModel.azdataAdditionalEnvVars, session);
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
await this._controllerModel.refreshTreeNode();
|
await this._controllerModel.refreshTreeNode();
|
||||||
|
|||||||
@@ -155,18 +155,23 @@ export class PostgresComputeAndStoragePage extends DashboardPage {
|
|||||||
cancellable: false
|
cancellable: false
|
||||||
},
|
},
|
||||||
async (_progress, _token): Promise<void> => {
|
async (_progress, _token): Promise<void> => {
|
||||||
|
let session: azdataExt.AzdataSession | undefined = undefined;
|
||||||
try {
|
try {
|
||||||
await this._postgresModel.controllerModel.azdataLogin();
|
session = await this._postgresModel.controllerModel.acquireAzdataSession();
|
||||||
await this._azdataApi.azdata.arc.postgres.server.edit(
|
await this._azdataApi.azdata.arc.postgres.server.edit(
|
||||||
this._postgresModel.info.name,
|
this._postgresModel.info.name,
|
||||||
this.saveArgs,
|
this.saveArgs,
|
||||||
this._postgresModel.engineVersion
|
this._postgresModel.engineVersion,
|
||||||
|
this._postgresModel.controllerModel.azdataAdditionalEnvVars,
|
||||||
|
session
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// If an error occurs while editing the instance then re-enable the save button since
|
// If an error occurs while editing the instance then re-enable the save button since
|
||||||
// the edit wasn't successfully applied
|
// the edit wasn't successfully applied
|
||||||
this.saveButton!.enabled = true;
|
this.saveButton!.enabled = true;
|
||||||
throw err;
|
throw err;
|
||||||
|
} finally {
|
||||||
|
session?.dispose();
|
||||||
}
|
}
|
||||||
await this._postgresModel.refresh();
|
await this._postgresModel.refresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,16 +151,21 @@ export class PostgresOverviewPage extends DashboardPage {
|
|||||||
try {
|
try {
|
||||||
const password = await promptAndConfirmPassword(input => !input ? loc.enterANonEmptyPassword : '');
|
const password = await promptAndConfirmPassword(input => !input ? loc.enterANonEmptyPassword : '');
|
||||||
if (password) {
|
if (password) {
|
||||||
await this._postgresModel.controllerModel.azdataLogin();
|
const session = await this._postgresModel.controllerModel.acquireAzdataSession();
|
||||||
await this._azdataApi.azdata.arc.postgres.server.edit(
|
try {
|
||||||
this._postgresModel.info.name,
|
await this._azdataApi.azdata.arc.postgres.server.edit(
|
||||||
{
|
this._postgresModel.info.name,
|
||||||
adminPassword: true,
|
{
|
||||||
noWait: true
|
adminPassword: true,
|
||||||
},
|
noWait: true
|
||||||
this._postgresModel.engineVersion,
|
},
|
||||||
{ 'AZDATA_PASSWORD': password }
|
this._postgresModel.engineVersion,
|
||||||
);
|
Object.assign({ 'AZDATA_PASSWORD': password }, this._controllerModel.azdataAdditionalEnvVars),
|
||||||
|
session
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
vscode.window.showInformationMessage(loc.passwordReset);
|
vscode.window.showInformationMessage(loc.passwordReset);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -188,8 +193,13 @@ export class PostgresOverviewPage extends DashboardPage {
|
|||||||
cancellable: false
|
cancellable: false
|
||||||
},
|
},
|
||||||
async (_progress, _token) => {
|
async (_progress, _token) => {
|
||||||
await this._postgresModel.controllerModel.azdataLogin();
|
const session = await this._postgresModel.controllerModel.acquireAzdataSession();
|
||||||
return await this._azdataApi.azdata.arc.postgres.server.delete(this._postgresModel.info.name);
|
try {
|
||||||
|
return await this._azdataApi.azdata.arc.postgres.server.delete(this._postgresModel.info.name, this._controllerModel.azdataAdditionalEnvVars, session);
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
await this._controllerModel.refreshTreeNode();
|
await this._controllerModel.refreshTreeNode();
|
||||||
|
|||||||
@@ -172,8 +172,14 @@ export class PostgresParametersPage extends DashboardPage {
|
|||||||
this.engineSettingUpdates!.forEach((value: string) => {
|
this.engineSettingUpdates!.forEach((value: string) => {
|
||||||
this.engineSettings += value + ', ';
|
this.engineSettings += value + ', ';
|
||||||
});
|
});
|
||||||
await this._azdataApi.azdata.arc.postgres.server.edit(
|
const session = await this._postgresModel.controllerModel.acquireAzdataSession();
|
||||||
this._postgresModel.info.name, { engineSettings: this.engineSettings + `'` });
|
try {
|
||||||
|
await this._azdataApi.azdata.arc.postgres.server.edit(
|
||||||
|
this._postgresModel.info.name, { engineSettings: this.engineSettings + `'` });
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// If an error occurs while editing the instance then re-enable the save button since
|
// If an error occurs while editing the instance then re-enable the save button since
|
||||||
// the edit wasn't successfully applied
|
// the edit wasn't successfully applied
|
||||||
@@ -237,7 +243,9 @@ export class PostgresParametersPage extends DashboardPage {
|
|||||||
async (_progress, _token): Promise<void> => {
|
async (_progress, _token): Promise<void> => {
|
||||||
//all
|
//all
|
||||||
// azdata arc postgres server edit -n <server group name> -e '' -re
|
// azdata arc postgres server edit -n <server group name> -e '' -re
|
||||||
|
let session: azdataExt.AzdataSession | undefined = undefined;
|
||||||
try {
|
try {
|
||||||
|
session = await this._postgresModel.controllerModel.acquireAzdataSession();
|
||||||
await this._azdataApi.azdata.arc.postgres.server.edit(
|
await this._azdataApi.azdata.arc.postgres.server.edit(
|
||||||
this._postgresModel.info.name, { engineSettings: `'' -re` });
|
this._postgresModel.info.name, { engineSettings: `'' -re` });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -245,6 +253,8 @@ export class PostgresParametersPage extends DashboardPage {
|
|||||||
// the edit wasn't successfully applied
|
// the edit wasn't successfully applied
|
||||||
this.resetButton!.enabled = true;
|
this.resetButton!.enabled = true;
|
||||||
throw err;
|
throw err;
|
||||||
|
} finally {
|
||||||
|
session?.dispose();
|
||||||
}
|
}
|
||||||
await this._postgresModel.refresh();
|
await this._postgresModel.refresh();
|
||||||
}
|
}
|
||||||
@@ -463,9 +473,14 @@ export class PostgresParametersPage extends DashboardPage {
|
|||||||
title: loc.updatingInstance(this._postgresModel.info.name),
|
title: loc.updatingInstance(this._postgresModel.info.name),
|
||||||
cancellable: false
|
cancellable: false
|
||||||
},
|
},
|
||||||
(_progress, _token) => {
|
async (_progress, _token) => {
|
||||||
return this._azdataApi.azdata.arc.postgres.server.edit(
|
const session = await this._postgresModel.controllerModel.acquireAzdataSession();
|
||||||
this._postgresModel.info.name, { engineSettings: name + '=' });
|
try {
|
||||||
|
this._azdataApi.azdata.arc.postgres.server.edit(
|
||||||
|
this._postgresModel.info.name, { engineSettings: name + '=' });
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -45,47 +45,57 @@ export function getAzdataApi(localAzdataDiscovered: Promise<IAzdataTool | undefi
|
|||||||
return {
|
return {
|
||||||
arc: {
|
arc: {
|
||||||
dc: {
|
dc: {
|
||||||
create: async (namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string, additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
create: async (
|
||||||
|
namespace: string,
|
||||||
|
name: string,
|
||||||
|
connectivityMode: string,
|
||||||
|
resourceGroup: string,
|
||||||
|
location: string,
|
||||||
|
subscription: string,
|
||||||
|
profileName?: string,
|
||||||
|
storageClass?: string,
|
||||||
|
additionalEnvVars?: azdataExt.AdditionalEnvVars,
|
||||||
|
session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.dc.create(namespace, name, connectivityMode, resourceGroup, location, subscription, profileName, storageClass, additionalEnvVars);
|
return azdataToolService.localAzdata.arc.dc.create(namespace, name, connectivityMode, resourceGroup, location, subscription, profileName, storageClass, additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
endpoint: {
|
endpoint: {
|
||||||
list: async (additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
list: async (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.dc.endpoint.list(additionalEnvVars);
|
return azdataToolService.localAzdata.arc.dc.endpoint.list(additionalEnvVars, session);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
list: async (additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
list: async (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.dc.config.list(additionalEnvVars);
|
return azdataToolService.localAzdata.arc.dc.config.list(additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
show: async (additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
show: async (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.dc.config.show(additionalEnvVars);
|
return azdataToolService.localAzdata.arc.dc.config.show(additionalEnvVars, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
postgres: {
|
postgres: {
|
||||||
server: {
|
server: {
|
||||||
delete: async (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
delete: async (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.postgres.server.delete(name, additionalEnvVars);
|
return azdataToolService.localAzdata.arc.postgres.server.delete(name, additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
list: async (additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
list: async (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.postgres.server.list(additionalEnvVars);
|
return azdataToolService.localAzdata.arc.postgres.server.list(additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
show: async (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
show: async (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.postgres.server.show(name, additionalEnvVars);
|
return azdataToolService.localAzdata.arc.postgres.server.show(name, additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
edit: async (
|
edit: async (
|
||||||
name: string,
|
name: string,
|
||||||
@@ -103,29 +113,30 @@ export function getAzdataApi(localAzdataDiscovered: Promise<IAzdataTool | undefi
|
|||||||
workers?: number;
|
workers?: number;
|
||||||
},
|
},
|
||||||
engineVersion?: string,
|
engineVersion?: string,
|
||||||
additionalEnvVars?: { [key: string]: string; }) => {
|
additionalEnvVars?: azdataExt.AdditionalEnvVars,
|
||||||
|
session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.postgres.server.edit(name, args, engineVersion, additionalEnvVars);
|
return azdataToolService.localAzdata.arc.postgres.server.edit(name, args, engineVersion, additionalEnvVars, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sql: {
|
sql: {
|
||||||
mi: {
|
mi: {
|
||||||
delete: async (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
delete: async (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.sql.mi.delete(name, additionalEnvVars);
|
return azdataToolService.localAzdata.arc.sql.mi.delete(name, additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
list: async (additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
list: async (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.sql.mi.list(additionalEnvVars);
|
return azdataToolService.localAzdata.arc.sql.mi.list(additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
show: async (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars) => {
|
show: async (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.sql.mi.show(name, additionalEnvVars);
|
return azdataToolService.localAzdata.arc.sql.mi.show(name, additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
edit: async (
|
edit: async (
|
||||||
name: string,
|
name: string,
|
||||||
@@ -136,11 +147,12 @@ export function getAzdataApi(localAzdataDiscovered: Promise<IAzdataTool | undefi
|
|||||||
memoryRequest?: string;
|
memoryRequest?: string;
|
||||||
noWait?: boolean;
|
noWait?: boolean;
|
||||||
},
|
},
|
||||||
additionalEnvVars?: azdataExt.AdditionalEnvVars
|
additionalEnvVars?: azdataExt.AdditionalEnvVars,
|
||||||
|
session?: azdataExt.AzdataSession
|
||||||
) => {
|
) => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.arc.sql.mi.edit(name, args, additionalEnvVars);
|
return azdataToolService.localAzdata.arc.sql.mi.edit(name, args, additionalEnvVars, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,6 +166,10 @@ export function getAzdataApi(localAzdataDiscovered: Promise<IAzdataTool | undefi
|
|||||||
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
return azdataToolService.localAzdata.login(endpoint, username, password, additionalEnvVars);
|
return azdataToolService.localAzdata.login(endpoint, username, password, additionalEnvVars);
|
||||||
},
|
},
|
||||||
|
acquireSession: async (endpoint: string, username: string, password: string, additionEnvVars?: azdataExt.AdditionalEnvVars) => {
|
||||||
|
throwIfNoAzdataOrEulaNotAccepted(azdataToolService.localAzdata, isEulaAccepted(memento));
|
||||||
|
return azdataToolService.localAzdata?.acquireSession(endpoint, username, password, additionEnvVars);
|
||||||
|
},
|
||||||
getSemVersion: async () => {
|
getSemVersion: async () => {
|
||||||
await localAzdataDiscovered;
|
await localAzdataDiscovered;
|
||||||
throwIfNoAzdata(azdataToolService.localAzdata);
|
throwIfNoAzdata(azdataToolService.localAzdata);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { getPlatformDownloadLink, getPlatformReleaseVersion } from './azdataRele
|
|||||||
import { executeCommand, executeSudoCommand, ExitCodeError, ProcessOutput } from './common/childProcess';
|
import { executeCommand, executeSudoCommand, ExitCodeError, ProcessOutput } from './common/childProcess';
|
||||||
import { HttpClient } from './common/httpClient';
|
import { HttpClient } from './common/httpClient';
|
||||||
import Logger from './common/logger';
|
import Logger from './common/logger';
|
||||||
|
import { Deferred } from './common/promise';
|
||||||
import { getErrorMessage, NoAzdataError, searchForCmd } from './common/utils';
|
import { getErrorMessage, NoAzdataError, searchForCmd } from './common/utils';
|
||||||
import { azdataAcceptEulaKey, azdataConfigSection, azdataFound, azdataInstallKey, azdataUpdateKey, debugConfigKey, eulaAccepted, eulaUrl, microsoftPrivacyStatementUrl } from './constants';
|
import { azdataAcceptEulaKey, azdataConfigSection, azdataFound, azdataInstallKey, azdataUpdateKey, debugConfigKey, eulaAccepted, eulaUrl, microsoftPrivacyStatementUrl } from './constants';
|
||||||
import * as loc from './localizedConstants';
|
import * as loc from './localizedConstants';
|
||||||
@@ -34,12 +35,29 @@ export interface IAzdataTool extends azdataExt.IAzdataApi {
|
|||||||
executeCommand<R>(args: string[], additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<R>>
|
executeCommand<R>(args: string[], additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<R>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AzdataSession implements azdataExt.AzdataSession {
|
||||||
|
|
||||||
|
private _session = new Deferred<void>();
|
||||||
|
|
||||||
|
public sessionEnded(): Promise<void> {
|
||||||
|
return this._session.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
this._session.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object to interact with the azdata tool installed on the box.
|
* An object to interact with the azdata tool installed on the box.
|
||||||
*/
|
*/
|
||||||
export class AzdataTool implements azdataExt.IAzdataApi {
|
export class AzdataTool implements azdataExt.IAzdataApi {
|
||||||
|
|
||||||
private _semVersion: SemVer;
|
private _semVersion: SemVer;
|
||||||
|
private _currentSession: azdataExt.AzdataSession | undefined = undefined;
|
||||||
|
private _currentlyExecutingCommands: Deferred<void>[] = [];
|
||||||
|
private _queuedCommands: { deferred: Deferred<void>, session?: azdataExt.AzdataSession }[] = [];
|
||||||
|
|
||||||
constructor(private _path: string, version: string) {
|
constructor(private _path: string, version: string) {
|
||||||
this._semVersion = new SemVer(version);
|
this._semVersion = new SemVer(version);
|
||||||
}
|
}
|
||||||
@@ -62,7 +80,17 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
|||||||
|
|
||||||
public arc = {
|
public arc = {
|
||||||
dc: {
|
dc: {
|
||||||
create: (namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string, additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<void>> => {
|
create: (
|
||||||
|
namespace: string,
|
||||||
|
name: string,
|
||||||
|
connectivityMode: string,
|
||||||
|
resourceGroup: string,
|
||||||
|
location: string,
|
||||||
|
subscription: string,
|
||||||
|
profileName?: string,
|
||||||
|
storageClass?: string,
|
||||||
|
additionalEnvVars?: azdataExt.AdditionalEnvVars,
|
||||||
|
session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<void>> => {
|
||||||
const args = ['arc', 'dc', 'create',
|
const args = ['arc', 'dc', 'create',
|
||||||
'--namespace', namespace,
|
'--namespace', namespace,
|
||||||
'--name', name,
|
'--name', name,
|
||||||
@@ -76,32 +104,32 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
|||||||
if (storageClass) {
|
if (storageClass) {
|
||||||
args.push('--storage-class', storageClass);
|
args.push('--storage-class', storageClass);
|
||||||
}
|
}
|
||||||
return this.executeCommand<void>(args, additionalEnvVars);
|
return this.executeCommand<void>(args, additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
endpoint: {
|
endpoint: {
|
||||||
list: (additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<azdataExt.DcEndpointListResult[]>> => {
|
list: (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<azdataExt.DcEndpointListResult[]>> => {
|
||||||
return this.executeCommand<azdataExt.DcEndpointListResult[]>(['arc', 'dc', 'endpoint', 'list'], additionalEnvVars);
|
return this.executeCommand<azdataExt.DcEndpointListResult[]>(['arc', 'dc', 'endpoint', 'list'], additionalEnvVars, session);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
list: (additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<azdataExt.DcConfigListResult[]>> => {
|
list: (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<azdataExt.DcConfigListResult[]>> => {
|
||||||
return this.executeCommand<azdataExt.DcConfigListResult[]>(['arc', 'dc', 'config', 'list'], additionalEnvVars);
|
return this.executeCommand<azdataExt.DcConfigListResult[]>(['arc', 'dc', 'config', 'list'], additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
show: (additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<azdataExt.DcConfigShowResult>> => {
|
show: (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<azdataExt.DcConfigShowResult>> => {
|
||||||
return this.executeCommand<azdataExt.DcConfigShowResult>(['arc', 'dc', 'config', 'show'], additionalEnvVars);
|
return this.executeCommand<azdataExt.DcConfigShowResult>(['arc', 'dc', 'config', 'show'], additionalEnvVars, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
postgres: {
|
postgres: {
|
||||||
server: {
|
server: {
|
||||||
delete: (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<void>> => {
|
delete: (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<void>> => {
|
||||||
return this.executeCommand<void>(['arc', 'postgres', 'server', 'delete', '-n', name, '--force'], additionalEnvVars);
|
return this.executeCommand<void>(['arc', 'postgres', 'server', 'delete', '-n', name, '--force'], additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
list: (additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<azdataExt.PostgresServerListResult[]>> => {
|
list: (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<azdataExt.PostgresServerListResult[]>> => {
|
||||||
return this.executeCommand<azdataExt.PostgresServerListResult[]>(['arc', 'postgres', 'server', 'list'], additionalEnvVars);
|
return this.executeCommand<azdataExt.PostgresServerListResult[]>(['arc', 'postgres', 'server', 'list'], additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
show: (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<azdataExt.PostgresServerShowResult>> => {
|
show: (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<azdataExt.PostgresServerShowResult>> => {
|
||||||
return this.executeCommand<azdataExt.PostgresServerShowResult>(['arc', 'postgres', 'server', 'show', '-n', name], additionalEnvVars);
|
return this.executeCommand<azdataExt.PostgresServerShowResult>(['arc', 'postgres', 'server', 'show', '-n', name], additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
edit: (
|
edit: (
|
||||||
name: string,
|
name: string,
|
||||||
@@ -119,7 +147,8 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
|||||||
workers?: number
|
workers?: number
|
||||||
},
|
},
|
||||||
engineVersion?: string,
|
engineVersion?: string,
|
||||||
additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<void>> => {
|
additionalEnvVars?: azdataExt.AdditionalEnvVars,
|
||||||
|
session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<void>> => {
|
||||||
const argsArray = ['arc', 'postgres', 'server', 'edit', '-n', name];
|
const argsArray = ['arc', 'postgres', 'server', 'edit', '-n', name];
|
||||||
if (args.adminPassword) { argsArray.push('--admin-password'); }
|
if (args.adminPassword) { argsArray.push('--admin-password'); }
|
||||||
if (args.coresLimit) { argsArray.push('--cores-limit', args.coresLimit); }
|
if (args.coresLimit) { argsArray.push('--cores-limit', args.coresLimit); }
|
||||||
@@ -133,20 +162,20 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
|||||||
if (args.replaceEngineSettings) { argsArray.push('--replace-engine-settings'); }
|
if (args.replaceEngineSettings) { argsArray.push('--replace-engine-settings'); }
|
||||||
if (args.workers) { argsArray.push('--workers', args.workers.toString()); }
|
if (args.workers) { argsArray.push('--workers', args.workers.toString()); }
|
||||||
if (engineVersion) { argsArray.push('--engine-version', engineVersion); }
|
if (engineVersion) { argsArray.push('--engine-version', engineVersion); }
|
||||||
return this.executeCommand<void>(argsArray, additionalEnvVars);
|
return this.executeCommand<void>(argsArray, additionalEnvVars, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sql: {
|
sql: {
|
||||||
mi: {
|
mi: {
|
||||||
delete: (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<void>> => {
|
delete: (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<void>> => {
|
||||||
return this.executeCommand<void>(['arc', 'sql', 'mi', 'delete', '-n', name], additionalEnvVars);
|
return this.executeCommand<void>(['arc', 'sql', 'mi', 'delete', '-n', name], additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
list: (additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<azdataExt.SqlMiListResult[]>> => {
|
list: (additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<azdataExt.SqlMiListResult[]>> => {
|
||||||
return this.executeCommand<azdataExt.SqlMiListResult[]>(['arc', 'sql', 'mi', 'list'], additionalEnvVars);
|
return this.executeCommand<azdataExt.SqlMiListResult[]>(['arc', 'sql', 'mi', 'list'], additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
show: (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<azdataExt.SqlMiShowResult>> => {
|
show: (name: string, additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<azdataExt.SqlMiShowResult>> => {
|
||||||
return this.executeCommand<azdataExt.SqlMiShowResult>(['arc', 'sql', 'mi', 'show', '-n', name], additionalEnvVars);
|
return this.executeCommand<azdataExt.SqlMiShowResult>(['arc', 'sql', 'mi', 'show', '-n', name], additionalEnvVars, session);
|
||||||
},
|
},
|
||||||
edit: (
|
edit: (
|
||||||
name: string,
|
name: string,
|
||||||
@@ -157,7 +186,8 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
|||||||
memoryRequest?: string,
|
memoryRequest?: string,
|
||||||
noWait?: boolean,
|
noWait?: boolean,
|
||||||
},
|
},
|
||||||
additionalEnvVars?: azdataExt.AdditionalEnvVars
|
additionalEnvVars?: azdataExt.AdditionalEnvVars,
|
||||||
|
session?: azdataExt.AzdataSession
|
||||||
): Promise<azdataExt.AzdataOutput<void>> => {
|
): Promise<azdataExt.AzdataOutput<void>> => {
|
||||||
const argsArray = ['arc', 'sql', 'mi', 'edit', '-n', name];
|
const argsArray = ['arc', 'sql', 'mi', 'edit', '-n', name];
|
||||||
if (args.coresLimit) { argsArray.push('--cores-limit', args.coresLimit); }
|
if (args.coresLimit) { argsArray.push('--cores-limit', args.coresLimit); }
|
||||||
@@ -165,14 +195,59 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
|||||||
if (args.memoryLimit) { argsArray.push('--memory-limit', args.memoryLimit); }
|
if (args.memoryLimit) { argsArray.push('--memory-limit', args.memoryLimit); }
|
||||||
if (args.memoryRequest) { argsArray.push('--memory-request', args.memoryRequest); }
|
if (args.memoryRequest) { argsArray.push('--memory-request', args.memoryRequest); }
|
||||||
if (args.noWait) { argsArray.push('--no-wait'); }
|
if (args.noWait) { argsArray.push('--no-wait'); }
|
||||||
return this.executeCommand<void>(argsArray, additionalEnvVars);
|
return this.executeCommand<void>(argsArray, additionalEnvVars, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public login(endpoint: string, username: string, password: string, additionalEnvVars: azdataExt.AdditionalEnvVars = {}): Promise<azdataExt.AzdataOutput<void>> {
|
public async login(endpoint: string, username: string, password: string, additionalEnvVars: azdataExt.AdditionalEnvVars = {}): Promise<azdataExt.AzdataOutput<void>> {
|
||||||
return this.executeCommand<void>(['login', '-e', endpoint, '-u', username], Object.assign({}, additionalEnvVars, { 'AZDATA_PASSWORD': password }));
|
// Since login changes the context we want to wait until all currently executing commands are finished before this is executed
|
||||||
|
while (this._currentlyExecutingCommands.length > 0) {
|
||||||
|
await this._currentlyExecutingCommands[0];
|
||||||
|
}
|
||||||
|
// Logins need to be done outside the session aware logic so call impl directly
|
||||||
|
return this.executeCommandImpl<void>(['login', '-e', endpoint, '-u', username], Object.assign({}, additionalEnvVars, { 'AZDATA_PASSWORD': password }));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async acquireSession(endpoint: string, username: string, password: string, additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataSession> {
|
||||||
|
const session = new AzdataSession();
|
||||||
|
session.sessionEnded().then(async () => {
|
||||||
|
// Wait for all commands running for this session to end
|
||||||
|
while (this._currentlyExecutingCommands.length > 0) {
|
||||||
|
await this._currentlyExecutingCommands[0].promise;
|
||||||
|
}
|
||||||
|
this._currentSession = undefined;
|
||||||
|
// Start our next command now that we're all done with this session
|
||||||
|
// TODO: Should we check if the command has a session that hasn't started? That should never happen..
|
||||||
|
// TODO: Look into kicking off multiple commands
|
||||||
|
this._queuedCommands.shift()?.deferred.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
// We're not in a session or waiting on anything so just set the current session right now
|
||||||
|
if (!this._currentSession && this._queuedCommands.length === 0) {
|
||||||
|
this._currentSession = session;
|
||||||
|
} else {
|
||||||
|
// We're in a session or another command is executing so add this to the end of the queued commands and wait our turn
|
||||||
|
const deferred = new Deferred<void>();
|
||||||
|
deferred.promise.then(() => {
|
||||||
|
this._currentSession = session;
|
||||||
|
// We've started a new session so look at all our queued commands and start
|
||||||
|
// the ones for this session now.
|
||||||
|
this._queuedCommands = this._queuedCommands.filter(c => {
|
||||||
|
if (c.session === this._currentSession) {
|
||||||
|
c.deferred.resolve();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this._queuedCommands.push({ deferred, session: undefined });
|
||||||
|
await deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.login(endpoint, username, password, additionalEnvVars);
|
||||||
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,7 +265,33 @@ export class AzdataTool implements azdataExt.IAzdataApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async executeCommand<R>(args: string[], additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<R>> {
|
public async executeCommand<R>(args: string[], additionalEnvVars?: azdataExt.AdditionalEnvVars, session?: azdataExt.AzdataSession): Promise<azdataExt.AzdataOutput<R>> {
|
||||||
|
if (this._currentSession && this._currentSession !== session) {
|
||||||
|
const deferred = new Deferred<void>();
|
||||||
|
this._queuedCommands.push({ deferred, session: session });
|
||||||
|
await deferred.promise;
|
||||||
|
}
|
||||||
|
const executingDeferred = new Deferred<void>();
|
||||||
|
this._currentlyExecutingCommands.push(executingDeferred);
|
||||||
|
try {
|
||||||
|
return await this.executeCommandImpl<R>(args, additionalEnvVars);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
this._currentlyExecutingCommands = this._currentlyExecutingCommands.filter(c => c !== executingDeferred);
|
||||||
|
executingDeferred.resolve();
|
||||||
|
// If there isn't an active session and we still have queued commands then we have to manually kick off the next one
|
||||||
|
if (this._queuedCommands.length > 0 && !this._currentSession) {
|
||||||
|
this._queuedCommands.shift()?.deferred.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the specified azdata command. This is NOT session-aware so should only be used for calls that don't care about a session
|
||||||
|
* @param args The args to pass to azdata
|
||||||
|
* @param additionalEnvVars Additional environment variables to set for this execution
|
||||||
|
*/
|
||||||
|
private async executeCommandImpl<R>(args: string[], additionalEnvVars?: azdataExt.AdditionalEnvVars): Promise<azdataExt.AzdataOutput<R>> {
|
||||||
try {
|
try {
|
||||||
const output = JSON.parse((await executeAzdataCommand(`"${this._path}"`, args.concat(['--output', 'json']), additionalEnvVars)).stdout);
|
const output = JSON.parse((await executeAzdataCommand(`"${this._path}"`, args.concat(['--output', 'json']), additionalEnvVars)).stdout);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ describe('api', function (): void {
|
|||||||
await assertRejected(api.azdata.getPath(), 'getPath');
|
await assertRejected(api.azdata.getPath(), 'getPath');
|
||||||
await assertRejected(api.azdata.getSemVersion(), 'getSemVersion');
|
await assertRejected(api.azdata.getSemVersion(), 'getSemVersion');
|
||||||
await assertRejected(api.azdata.login('', '', ''), 'login');
|
await assertRejected(api.azdata.login('', '', ''), 'login');
|
||||||
|
await assertRejected(api.azdata.acquireSession('', '', ''), 'acquireSession');
|
||||||
await assertRejected(api.azdata.version(), 'version');
|
await assertRejected(api.azdata.version(), 'version');
|
||||||
|
|
||||||
await assertRejected(api.azdata.arc.dc.create('', '', '', '', '', ''), 'arc dc create');
|
await assertRejected(api.azdata.arc.dc.create('', '', '', '', '', ''), 'arc dc create');
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as azdataExt from 'azdata-ext';
|
||||||
import * as should from 'should';
|
import * as should from 'should';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
@@ -16,6 +17,7 @@ import * as fs from 'fs';
|
|||||||
import { AzdataReleaseInfo } from '../azdataReleaseInfo';
|
import { AzdataReleaseInfo } from '../azdataReleaseInfo';
|
||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
import { eulaAccepted } from '../constants';
|
import { eulaAccepted } from '../constants';
|
||||||
|
import { sleep } from './testUtils';
|
||||||
|
|
||||||
const oldAzdataMock = new azdata.AzdataTool('/path/to/azdata', '0.0.0');
|
const oldAzdataMock = new azdata.AzdataTool('/path/to/azdata', '0.0.0');
|
||||||
const currentAzdataMock = new azdata.AzdataTool('/path/to/azdata', '9999.999.999');
|
const currentAzdataMock = new azdata.AzdataTool('/path/to/azdata', '9999.999.999');
|
||||||
@@ -170,18 +172,6 @@ describe('azdata', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('login', async function (): Promise<void> {
|
|
||||||
const endpoint = 'myEndpoint';
|
|
||||||
const username = 'myUsername';
|
|
||||||
const password = 'myPassword';
|
|
||||||
await azdataTool.login(endpoint, username, password);
|
|
||||||
verifyExecuteCommandCalledWithArgs(['login', endpoint, username]);
|
|
||||||
});
|
|
||||||
it('version', async function (): Promise<void> {
|
|
||||||
executeCommandStub.resolves({ stdout: '1.0.0', stderr: '' });
|
|
||||||
await azdataTool.version();
|
|
||||||
verifyExecuteCommandCalledWithArgs(['--version']);
|
|
||||||
});
|
|
||||||
it('general error throws', async function (): Promise<void> {
|
it('general error throws', async function (): Promise<void> {
|
||||||
const err = new Error();
|
const err = new Error();
|
||||||
executeCommandStub.throws(err);
|
executeCommandStub.throws(err);
|
||||||
@@ -228,12 +218,136 @@ describe('azdata', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('login', async function (): Promise<void> {
|
||||||
|
const endpoint = 'myEndpoint';
|
||||||
|
const username = 'myUsername';
|
||||||
|
const password = 'myPassword';
|
||||||
|
await azdataTool.login(endpoint, username, password);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['login', endpoint, username]);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('acquireSession', function (): void {
|
||||||
|
it('calls login', async function (): Promise<void> {
|
||||||
|
const endpoint = 'myEndpoint';
|
||||||
|
const username = 'myUsername';
|
||||||
|
const password = 'myPassword';
|
||||||
|
const session = await azdataTool.acquireSession(endpoint, username, password);
|
||||||
|
session.dispose();
|
||||||
|
verifyExecuteCommandCalledWithArgs(['login', endpoint, username]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('command executed under current session completes', async function (): Promise<void> {
|
||||||
|
const session = await azdataTool.acquireSession('', '', '');
|
||||||
|
try {
|
||||||
|
await azdataTool.arc.dc.config.show(undefined, session);
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
|
verifyExecuteCommandCalledWithArgs(['login'], 0);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'dc', 'config', 'show'], 1);
|
||||||
|
});
|
||||||
|
it('multiple commands executed under current session completes', async function (): Promise<void> {
|
||||||
|
const session = await azdataTool.acquireSession('', '', '');
|
||||||
|
try {
|
||||||
|
// Kick off multiple commands at the same time and then ensure that they both complete
|
||||||
|
await Promise.all([
|
||||||
|
azdataTool.arc.dc.config.show(undefined, session),
|
||||||
|
azdataTool.arc.sql.mi.list(undefined, session)
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
|
verifyExecuteCommandCalledWithArgs(['login'], 0);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'dc', 'config', 'show'], 1);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'sql', 'mi', 'list'], 2);
|
||||||
|
});
|
||||||
|
it('command executed without session context is queued up until session is closed', async function (): Promise<void> {
|
||||||
|
const session = await azdataTool.acquireSession('', '', '');
|
||||||
|
let nonSessionCommand: Promise<any> | undefined = undefined;
|
||||||
|
try {
|
||||||
|
// Start one command in the current session
|
||||||
|
await azdataTool.arc.dc.config.show(undefined, session);
|
||||||
|
// Verify that the command isn't executed until after the session is disposed
|
||||||
|
let isFulfilled = false;
|
||||||
|
nonSessionCommand = azdataTool.arc.sql.mi.list().then(() => isFulfilled = true);
|
||||||
|
await sleep(2000);
|
||||||
|
should(isFulfilled).equal(false, 'The command should not be completed yet');
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
|
await nonSessionCommand;
|
||||||
|
verifyExecuteCommandCalledWithArgs(['login'], 0);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'dc', 'config', 'show'], 1);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'sql', 'mi', 'list'], 2);
|
||||||
|
});
|
||||||
|
it('multiple commands executed without session context are queued up until session is closed', async function (): Promise<void> {
|
||||||
|
const session = await azdataTool.acquireSession('', '', '');
|
||||||
|
let nonSessionCommand1: Promise<any> | undefined = undefined;
|
||||||
|
let nonSessionCommand2: Promise<any> | undefined = undefined;
|
||||||
|
try {
|
||||||
|
// Start one command in the current session
|
||||||
|
await azdataTool.arc.dc.config.show(undefined, session);
|
||||||
|
// Verify that neither command is completed until the session is closed
|
||||||
|
let isFulfilled = false;
|
||||||
|
nonSessionCommand1 = azdataTool.arc.sql.mi.list().then(() => isFulfilled = true);
|
||||||
|
nonSessionCommand2 = azdataTool.arc.postgres.server.list().then(() => isFulfilled = true);
|
||||||
|
await sleep(2000);
|
||||||
|
should(isFulfilled).equal(false, 'The commands should not be completed yet');
|
||||||
|
} finally {
|
||||||
|
session.dispose();
|
||||||
|
}
|
||||||
|
await Promise.all([nonSessionCommand1, nonSessionCommand2]);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['login'], 0);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'dc', 'config', 'show'], 1);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'sql', 'mi', 'list'], 2);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'postgres', 'server', 'list'], 3);
|
||||||
|
});
|
||||||
|
it('attempting to acquire a second session while a first is still active queues the second session', async function (): Promise<void> {
|
||||||
|
const firstSession = await azdataTool.acquireSession('', '', '');
|
||||||
|
let sessionPromise: Promise<azdataExt.AzdataSession> | undefined = undefined;
|
||||||
|
let secondSessionCommand: Promise<any> | undefined = undefined;
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
// Start one command in the current session
|
||||||
|
await azdataTool.arc.dc.config.show(undefined, firstSession);
|
||||||
|
// Verify that none of the commands for the second session are completed before the first is disposed
|
||||||
|
let isFulfilled = false;
|
||||||
|
sessionPromise = azdataTool.acquireSession('', '', '');
|
||||||
|
sessionPromise.then(session => {
|
||||||
|
isFulfilled = true;
|
||||||
|
secondSessionCommand = azdataTool.arc.sql.mi.list(undefined, session).then(() => isFulfilled = true);
|
||||||
|
});
|
||||||
|
await sleep(2000);
|
||||||
|
should(isFulfilled).equal(false, 'The commands should not be completed yet');
|
||||||
|
} finally {
|
||||||
|
firstSession.dispose();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
(await sessionPromise)?.dispose();
|
||||||
|
}
|
||||||
|
should(secondSessionCommand).not.equal(undefined, 'The second command should have been queued already');
|
||||||
|
await secondSessionCommand!;
|
||||||
|
|
||||||
|
|
||||||
|
verifyExecuteCommandCalledWithArgs(['login'], 0);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'dc', 'config', 'show'], 1);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['login'], 2);
|
||||||
|
verifyExecuteCommandCalledWithArgs(['arc', 'sql', 'mi', 'list'], 3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('version', async function (): Promise<void> {
|
||||||
|
executeCommandStub.resolves({ stdout: '1.0.0', stderr: '' });
|
||||||
|
await azdataTool.version();
|
||||||
|
verifyExecuteCommandCalledWithArgs(['--version']);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that the specified args were included in the call to executeCommand
|
* Verifies that the specified args were included in the call to executeCommand
|
||||||
* @param args The args to check were included in the execute command call
|
* @param args The args to check were included in the execute command call
|
||||||
*/
|
*/
|
||||||
function verifyExecuteCommandCalledWithArgs(args: string[]): void {
|
function verifyExecuteCommandCalledWithArgs(args: string[], callIndex = 0): void {
|
||||||
const commandArgs = executeCommandStub.args[0][1] as string[];
|
const commandArgs = executeCommandStub.args[callIndex][1] as string[];
|
||||||
args.forEach(arg => should(commandArgs).containEql(arg));
|
args.forEach(arg => should(commandArgs).containEql(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,8 +583,8 @@ describe('azdata', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('promptForEula', function(): void {
|
describe('promptForEula', function (): void {
|
||||||
it('skipped because of config', async function(): Promise<void> {
|
it('skipped because of config', async function (): Promise<void> {
|
||||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||||
@@ -479,7 +593,7 @@ describe('azdata', function () {
|
|||||||
should(result).be.false();
|
should(result).be.false();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('always prompt if user requested', async function(): Promise<void> {
|
it('always prompt if user requested', async function (): Promise<void> {
|
||||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||||
@@ -490,7 +604,7 @@ describe('azdata', function () {
|
|||||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('prompt if config set to do so', async function(): Promise<void> {
|
it('prompt if config set to do so', async function (): Promise<void> {
|
||||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||||
@@ -501,7 +615,7 @@ describe('azdata', function () {
|
|||||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('update config if user chooses not to prompt', async function(): Promise<void> {
|
it('update config if user chooses not to prompt', async function (): Promise<void> {
|
||||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||||
@@ -513,7 +627,7 @@ describe('azdata', function () {
|
|||||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('user accepted EULA', async function(): Promise<void> {
|
it('user accepted EULA', async function (): Promise<void> {
|
||||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||||
@@ -525,7 +639,7 @@ describe('azdata', function () {
|
|||||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('user accepted EULA - require user action', async function(): Promise<void> {
|
it('user accepted EULA - require user action', async function (): Promise<void> {
|
||||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||||
@@ -538,7 +652,7 @@ describe('azdata', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isEulaAccepted', function(): void {
|
describe('isEulaAccepted', function (): void {
|
||||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||||
mementoMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => true);
|
mementoMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => true);
|
||||||
should(azdata.isEulaAccepted(mementoMock.object)).be.true();
|
should(azdata.isEulaAccepted(mementoMock.object)).be.true();
|
||||||
|
|||||||
@@ -18,3 +18,7 @@ export async function assertRejected(promise: Promise<any>, message: string): Pr
|
|||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function sleep(ms: number): Promise<void> {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
40
extensions/azdata/src/typings/azdata-ext.d.ts
vendored
40
extensions/azdata/src/typings/azdata-ext.d.ts
vendored
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
declare module 'azdata-ext' {
|
declare module 'azdata-ext' {
|
||||||
import { SemVer } from 'semver';
|
import { SemVer } from 'semver';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Covers defining what the azdata extension exports to other extensions
|
* Covers defining what the azdata extension exports to other extensions
|
||||||
@@ -232,23 +233,25 @@ declare module 'azdata-ext' {
|
|||||||
code?: number
|
code?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AzdataSession extends vscode.Disposable { }
|
||||||
|
|
||||||
export interface IAzdataApi {
|
export interface IAzdataApi {
|
||||||
arc: {
|
arc: {
|
||||||
dc: {
|
dc: {
|
||||||
create(namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<void>>,
|
create(namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string, additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<void>>,
|
||||||
endpoint: {
|
endpoint: {
|
||||||
list(additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<DcEndpointListResult[]>>
|
list(additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<DcEndpointListResult[]>>
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
list(additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<DcConfigListResult[]>>,
|
list(additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<DcConfigListResult[]>>,
|
||||||
show(additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<DcConfigShowResult>>
|
show(additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<DcConfigShowResult>>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
postgres: {
|
postgres: {
|
||||||
server: {
|
server: {
|
||||||
delete(name: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<void>>,
|
delete(name: string, additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<void>>,
|
||||||
list(additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<PostgresServerListResult[]>>,
|
list(additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<PostgresServerListResult[]>>,
|
||||||
show(name: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<PostgresServerShowResult>>,
|
show(name: string, additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<PostgresServerShowResult>>,
|
||||||
edit(
|
edit(
|
||||||
name: string,
|
name: string,
|
||||||
args: {
|
args: {
|
||||||
@@ -265,15 +268,16 @@ declare module 'azdata-ext' {
|
|||||||
workers?: number
|
workers?: number
|
||||||
},
|
},
|
||||||
engineVersion?: string,
|
engineVersion?: string,
|
||||||
additionalEnvVars?: AdditionalEnvVars
|
additionalEnvVars?: AdditionalEnvVars,
|
||||||
|
session?: AzdataSession
|
||||||
): Promise<AzdataOutput<void>>
|
): Promise<AzdataOutput<void>>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sql: {
|
sql: {
|
||||||
mi: {
|
mi: {
|
||||||
delete(name: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<void>>,
|
delete(name: string, additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<void>>,
|
||||||
list(additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<SqlMiListResult[]>>,
|
list(additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<SqlMiListResult[]>>,
|
||||||
show(name: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<SqlMiShowResult>>,
|
show(name: string, additionalEnvVars?: AdditionalEnvVars, session?: AzdataSession): Promise<AzdataOutput<SqlMiShowResult>>,
|
||||||
edit(
|
edit(
|
||||||
name: string,
|
name: string,
|
||||||
args: {
|
args: {
|
||||||
@@ -283,13 +287,23 @@ declare module 'azdata-ext' {
|
|||||||
memoryRequest?: string,
|
memoryRequest?: string,
|
||||||
noWait?: boolean,
|
noWait?: boolean,
|
||||||
},
|
},
|
||||||
additionalEnvVars?: AdditionalEnvVars
|
additionalEnvVars?: AdditionalEnvVars,
|
||||||
|
session?: AzdataSession
|
||||||
): Promise<AzdataOutput<void>>
|
): Promise<AzdataOutput<void>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getPath(): Promise<string>,
|
getPath(): Promise<string>,
|
||||||
login(endpoint: string, username: string, password: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<any>>,
|
login(endpoint: string, username: string, password: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzdataOutput<void>>,
|
||||||
|
/**
|
||||||
|
* Acquires a session for the specified controller, which will log in to the specified controller and then block all other commands
|
||||||
|
* that are not part of the original session from executing until the session is released (disposed).
|
||||||
|
* @param endpoint
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
* @param additionalEnvVars
|
||||||
|
*/
|
||||||
|
acquireSession(endpoint: string, username: string, password: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzdataSession>,
|
||||||
/**
|
/**
|
||||||
* The semVersion corresponding to this installation of azdata. version() method should have been run
|
* The semVersion corresponding to this installation of azdata. version() method should have been run
|
||||||
* before fetching this value to ensure that correct value is returned. This is almost always correct unless
|
* before fetching this value to ensure that correct value is returned. This is almost always correct unless
|
||||||
|
|||||||
Reference in New Issue
Block a user