-
Notifications
You must be signed in to change notification settings - Fork 193
Add Impersonate Service Account argument #2015
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c3094eb
f3feefd
c65768d
85a0440
a5b4288
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import { GoogleAuth, Impersonated } from "google-auth-library"; | ||
| import Long from "long"; | ||
| import { PromisePoolExecutor } from "promise-pool-executor"; | ||
|
|
||
|
|
@@ -102,8 +103,8 @@ export class BigQueryDbAdapter implements IDbAdapter { | |
| try { | ||
| await this.pool | ||
| .addSingleTask({ | ||
| generator: () => | ||
| this.getClient().query({ | ||
| generator: async () => | ||
| (await this.getClient()).query({ | ||
| useLegacySql: false, | ||
| query, | ||
| dryRun: true | ||
|
|
@@ -128,7 +129,8 @@ export class BigQueryDbAdapter implements IDbAdapter { | |
| } | ||
|
|
||
| public async tables(): Promise<dataform.ITarget[]> { | ||
| const datasets = await this.getClient().getDatasets({ autoPaginate: true, maxResults: 1000 }); | ||
| const client = await this.getClient(); | ||
| const datasets = await client.getDatasets({ autoPaginate: true, maxResults: 1000 }); | ||
| const tables = await Promise.all( | ||
| datasets[0].map(dataset => dataset.getTables({ autoPaginate: true, maxResults: 1000 })) | ||
| ); | ||
|
|
@@ -218,7 +220,7 @@ export class BigQueryDbAdapter implements IDbAdapter { | |
| } | ||
|
|
||
| public async schemas(database: string): Promise<string[]> { | ||
| const data = await this.getClient(database).getDatasets(); | ||
| const data = await (await this.getClient(database)).getDatasets(); | ||
| return data[0].map(dataset => dataset.id); | ||
| } | ||
|
|
||
|
|
@@ -238,7 +240,7 @@ export class BigQueryDbAdapter implements IDbAdapter { | |
| metadata.schema.fields | ||
| ); | ||
|
|
||
| await this.getClient(target.database) | ||
| await (await this.getClient(target.database)) | ||
| .dataset(target.schema) | ||
| .table(target.name) | ||
| .setMetadata({ | ||
|
|
@@ -250,7 +252,7 @@ export class BigQueryDbAdapter implements IDbAdapter { | |
|
|
||
| private async getMetadata(target: dataform.ITarget): Promise<TableMetadata> { | ||
| try { | ||
| const table = await this.getClient(target.database) | ||
| const table = await (await this.getClient(target.database)) | ||
| .dataset(target.schema) | ||
| .table(target.name) | ||
| .getMetadata(); | ||
|
|
@@ -265,19 +267,36 @@ export class BigQueryDbAdapter implements IDbAdapter { | |
| } | ||
| } | ||
|
|
||
| private getClient(projectId?: string) { | ||
| private async getClient(projectId?: string) { | ||
| projectId = projectId || this.bigQueryCredentials.projectId; | ||
| if (!this.clients.has(projectId)) { | ||
| this.clients.set( | ||
| const clientConfig: any = { | ||
| projectId, | ||
| new BigQuery({ | ||
| scopes: EXTRA_GOOGLE_SCOPES, | ||
| location: this.bigQueryCredentials.location | ||
| }; | ||
|
|
||
| if (this.bigQueryCredentials.impersonateServiceAccount) { | ||
| // For impersonation, create an Impersonated credential directly | ||
| const sourceAuth = new GoogleAuth({ | ||
| projectId, | ||
| scopes: EXTRA_GOOGLE_SCOPES, | ||
| location: this.bigQueryCredentials.location, | ||
| credentials: | ||
| this.bigQueryCredentials.credentials && JSON.parse(this.bigQueryCredentials.credentials) | ||
| scopes: ['https://www.googleapis.com/auth/cloud-platform'], | ||
| credentials: this.bigQueryCredentials.credentials && JSON.parse(this.bigQueryCredentials.credentials), | ||
| }); | ||
|
|
||
| const authClient = await sourceAuth.getClient(); | ||
|
|
||
| clientConfig.authClient = new Impersonated({ | ||
| sourceClient: authClient, | ||
| targetPrincipal: this.bigQueryCredentials.impersonateServiceAccount, | ||
| targetScopes: ['https://www.googleapis.com/auth/cloud-platform'] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure what you would like done here?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean using |
||
| }) | ||
| ); | ||
| } else { | ||
| clientConfig.credentials = | ||
| this.bigQueryCredentials.credentials && JSON.parse(this.bigQueryCredentials.credentials); | ||
| } | ||
|
|
||
| this.clients.set(projectId, new BigQuery(clientConfig)); | ||
| } | ||
| return this.clients.get(projectId); | ||
| } | ||
|
|
@@ -289,12 +308,12 @@ export class BigQueryDbAdapter implements IDbAdapter { | |
| byteLimit?: number, | ||
| location?: string | ||
| ) { | ||
| const results = await new Promise<any[]>((resolve, reject) => { | ||
| const results = await new Promise<any[]>(async (resolve, reject) => { | ||
| const allRows = new LimitedResultSet({ | ||
| rowLimit, | ||
| byteLimit | ||
| }); | ||
| const stream = this.getClient().createQueryStream({ | ||
| const stream = (await this.getClient()).createQueryStream({ | ||
| query, | ||
| params, | ||
| location | ||
|
|
@@ -330,7 +349,8 @@ export class BigQueryDbAdapter implements IDbAdapter { | |
| return retry( | ||
| async () => { | ||
| try { | ||
| const job = await this.getClient().createQueryJob({ | ||
| const client = await this.getClient(); | ||
| const job = await client.createQueryJob({ | ||
| useLegacySql: false, | ||
| jobPrefix: "dataform-" + (jobPrefix ? `${jobPrefix}-` : ""), | ||
| query, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In #2001 @ashish10alex added support for impersonating a service account through ADC. Will it be enough for your use case or you need an explicit option as well?
If the latter, can you please validate manually that it works?