Skip to content

Commit c180e95

Browse files
committed
feat: Configure connectors with DNS Name.
1 parent ffbb4af commit c180e95

File tree

7 files changed

+477
-233
lines changed

7 files changed

+477
-233
lines changed

.github/workflows/tests.yml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,15 @@ jobs:
154154
MYSQL_DB:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_DB
155155
POSTGRES_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CONNECTION_NAME
156156
POSTGRES_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER
157-
POSTGRES_IAM_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER_IAM_NODE
157+
POSTGRES_USER_IAM_NODE:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER_IAM_NODE
158158
POSTGRES_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_PASS
159159
POSTGRES_DB:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_DB
160160
POSTGRES_CAS_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CAS_CONNECTION_NAME
161161
POSTGRES_CAS_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CAS_PASS
162162
POSTGRES_CUSTOMER_CAS_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_CONNECTION_NAME
163163
POSTGRES_CUSTOMER_CAS_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_PASS
164+
POSTGRES_CUSTOMER_CAS_DOMAIN_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_DOMAIN_NAME
165+
POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME
164166
SQLSERVER_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_CONNECTION_NAME
165167
SQLSERVER_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_USER
166168
SQLSERVER_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_PASS
@@ -181,13 +183,15 @@ jobs:
181183
MYSQL_DB: "${{ steps.secrets.outputs.MYSQL_DB }}"
182184
POSTGRES_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_CONNECTION_NAME }}"
183185
POSTGRES_USER: "${{ steps.secrets.outputs.POSTGRES_USER }}"
184-
POSTGRES_IAM_USER: "${{ steps.secrets.outputs.POSTGRES_IAM_USER }}"
186+
POSTGRES_USER_IAM_NODE: "${{ steps.secrets.outputs.POSTGRES_USER_IAM_NODE }}"
185187
POSTGRES_PASS: "${{ steps.secrets.outputs.POSTGRES_PASS }}"
186188
POSTGRES_DB: "${{ steps.secrets.outputs.POSTGRES_DB }}"
187189
POSTGRES_CAS_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_CAS_CONNECTION_NAME }}"
188190
POSTGRES_CAS_PASS: "${{ steps.secrets.outputs.POSTGRES_CAS_PASS }}"
189191
POSTGRES_CUSTOMER_CAS_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_CONNECTION_NAME }}"
190192
POSTGRES_CUSTOMER_CAS_PASS: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_PASS }}"
193+
POSTGRES_CUSTOMER_CAS_DOMAIN_NAME: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_DOMAIN_NAME }}"
194+
POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME }}"
191195
SQLSERVER_CONNECTION_NAME: "${{ steps.secrets.outputs.SQLSERVER_CONNECTION_NAME }}"
192196
SQLSERVER_USER: "${{ steps.secrets.outputs.SQLSERVER_USER }}"
193197
SQLSERVER_PASS: "${{ steps.secrets.outputs.SQLSERVER_PASS }}"
@@ -275,9 +279,15 @@ jobs:
275279
MYSQL_DB:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_DB
276280
POSTGRES_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CONNECTION_NAME
277281
POSTGRES_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER
278-
POSTGRES_IAM_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER_IAM_NODE
282+
POSTGRES_USER_IAM_NODE:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER_IAM_NODE
279283
POSTGRES_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_PASS
280284
POSTGRES_DB:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_DB
285+
POSTGRES_CAS_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CAS_CONNECTION_NAME
286+
POSTGRES_CAS_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CAS_PASS
287+
POSTGRES_CUSTOMER_CAS_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_CONNECTION_NAME
288+
POSTGRES_CUSTOMER_CAS_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_PASS
289+
POSTGRES_CUSTOMER_CAS_DOMAIN_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_DOMAIN_NAME
290+
POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME
281291
SQLSERVER_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_CONNECTION_NAME
282292
SQLSERVER_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_USER
283293
SQLSERVER_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_PASS
@@ -292,9 +302,15 @@ jobs:
292302
MYSQL_DB: "${{ steps.secrets.outputs.MYSQL_DB }}"
293303
POSTGRES_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_CONNECTION_NAME }}"
294304
POSTGRES_USER: "${{ steps.secrets.outputs.POSTGRES_USER }}"
295-
POSTGRES_IAM_USER: "${{ steps.secrets.outputs.POSTGRES_IAM_USER }}"
305+
POSTGRES_IAM_USER: "${{ steps.secrets.outputs.POSTGRES_USER_IAM_NODE }}"
296306
POSTGRES_PASS: "${{ steps.secrets.outputs.POSTGRES_PASS }}"
297307
POSTGRES_DB: "${{ steps.secrets.outputs.POSTGRES_DB }}"
308+
POSTGRES_CAS_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_CAS_CONNECTION_NAME }}"
309+
POSTGRES_CAS_PASS: "${{ steps.secrets.outputs.POSTGRES_CAS_PASS }}"
310+
POSTGRES_CUSTOMER_CAS_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_CONNECTION_NAME }}"
311+
POSTGRES_CUSTOMER_CAS_PASS: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_PASS }}"
312+
POSTGRES_CUSTOMER_CAS_DOMAIN_NAME: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_DOMAIN_NAME }}"
313+
POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME }}"
298314
SQLSERVER_CONNECTION_NAME: "${{ steps.secrets.outputs.SQLSERVER_CONNECTION_NAME }}"
299315
SQLSERVER_USER: "${{ steps.secrets.outputs.SQLSERVER_USER }}"
300316
SQLSERVER_PASS: "${{ steps.secrets.outputs.SQLSERVER_PASS }}"

src/cloud-sql-instance.ts

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import {IpAddressTypes, selectIpAddress} from './ip-addresses';
1616
import {InstanceConnectionInfo} from './instance-connection-info';
17-
import {parseInstanceConnectionName} from './parse-instance-connection-name';
17+
import {resolveInstanceName} from './parse-instance-connection-name';
1818
import {InstanceMetadata} from './sqladmin-fetcher';
1919
import {generateKeys} from './crypto';
2020
import {RSAKeys} from './rsa-keys';
@@ -54,7 +54,10 @@ export class CloudSQLInstance {
5454
static async getCloudSQLInstance(
5555
options: CloudSQLInstanceOptions
5656
): Promise<CloudSQLInstance> {
57-
const instance = new CloudSQLInstance(options);
57+
const instance = new CloudSQLInstance({
58+
options: options,
59+
instanceInfo: await resolveInstanceName(options.instanceConnectionName),
60+
});
5861
await instance.refresh();
5962
return instance;
6063
}
@@ -69,6 +72,8 @@ export class CloudSQLInstance {
6972
private scheduledRefreshID?: ReturnType<typeof setTimeout> | null = undefined;
7073
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
7174
private throttle?: any;
75+
private throttleSignal: AbortController;
76+
private closed = false;
7277
public readonly instanceInfo: InstanceConnectionInfo;
7378
public ephemeralCert?: SslCert;
7479
public host?: string;
@@ -79,17 +84,18 @@ export class CloudSQLInstance {
7984
public dnsName = '';
8085

8186
constructor({
82-
ipType,
83-
authType,
84-
instanceConnectionName,
85-
sqlAdminFetcher,
86-
limitRateInterval = 30 * 1000, // 30s default
87-
}: CloudSQLInstanceOptions) {
88-
this.authType = authType;
89-
this.instanceInfo = parseInstanceConnectionName(instanceConnectionName);
90-
this.ipType = ipType;
91-
this.limitRateInterval = limitRateInterval;
92-
this.sqlAdminFetcher = sqlAdminFetcher;
87+
options,
88+
instanceInfo,
89+
}: {
90+
options: CloudSQLInstanceOptions;
91+
instanceInfo: InstanceConnectionInfo;
92+
}) {
93+
this.instanceInfo = instanceInfo;
94+
this.authType = options.authType || AuthTypes.PASSWORD;
95+
this.ipType = options.ipType || IpAddressTypes.PUBLIC;
96+
this.limitRateInterval = options.limitRateInterval || 30 * 1000; // 30 seconds
97+
this.sqlAdminFetcher = options.sqlAdminFetcher;
98+
this.throttleSignal = new AbortController();
9399
}
94100

95101
// p-throttle library has to be initialized in an async scope in order to
@@ -103,20 +109,30 @@ export class CloudSQLInstance {
103109
limit: 1,
104110
interval: this.limitRateInterval,
105111
strict: true,
112+
signal: this.throttleSignal.signal,
106113
}) as ReturnType<typeof pThrottle>;
107114
}
108115

109-
forceRefresh(): Promise<RefreshResult> {
110-
// if a refresh is already ongoing, just await for its promise to fulfill
111-
// so that a new instance info is available before reconnecting
116+
forceRefresh() {
117+
// If the connector is closed, do nothing.
118+
if (this.closed) {
119+
return;
120+
}
121+
122+
// if a refresh is already ongoing, do nothing.
112123
if (this.next) {
113-
return this.next;
124+
return;
114125
}
126+
127+
// Cancel a pending refresh timeout and start a new refresh immediately.
115128
this.cancelRefresh();
116-
return this.refresh();
129+
this.scheduleRefresh(0);
117130
}
118131

119132
refresh(): Promise<RefreshResult> {
133+
if (this.closed) {
134+
return Promise.reject('closed');
135+
}
120136
const currentRefreshId = this.scheduledRefreshID;
121137

122138
// Since forceRefresh might be invoked during an ongoing refresh
@@ -246,8 +262,12 @@ export class CloudSQLInstance {
246262
private scheduleRefresh(delay: number): void {
247263
this.scheduledRefreshID = setTimeout(() => this.refresh(), delay);
248264
}
249-
265+
close() {
266+
this.closed = true;
267+
this.cancelRefresh();
268+
}
250269
cancelRefresh(): void {
270+
// If refresh has not yet started, then cancel the setTimeout
251271
if (this.scheduledRefreshID) {
252272
clearTimeout(this.scheduledRefreshID);
253273
}

src/connector.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,13 @@ export class Connector {
228228
privateKey,
229229
serverCaCert,
230230
serverCaMode,
231-
dnsName,
231+
dnsName: instanceInfo.domainName || dnsName, // use the configured domain name, or the instance dnsName.
232232
});
233-
tlsSocket.once('error', async () => {
234-
await cloudSqlInstance.forceRefresh();
233+
tlsSocket.once('error', () => {
234+
cloudSqlInstance.forceRefresh();
235+
// TODO: Commenting this out causes the tests to exit.
236+
// When this is uncommented, the tests never exit.
237+
// Somehow a refresh promise never resolves.
235238
});
236239
tlsSocket.once('secureConnect', async () => {
237240
cloudSqlInstance.setEstablishedConnection();
@@ -333,7 +336,7 @@ export class Connector {
333336
// Also clear up any local proxy servers and socket connections.
334337
close(): void {
335338
for (const instance of this.instances.values()) {
336-
instance.cancelRefresh();
339+
instance.close();
337340
}
338341
for (const server of this.localProxies) {
339342
server.close();

0 commit comments

Comments
 (0)