-
Notifications
You must be signed in to change notification settings - Fork 408
fix(Spanner.Data): Specify credential type when loading from file. #15565
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
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 |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ | |
| // limitations under the License. | ||
|
|
||
| using Google.Api.Gax.Grpc.Gcp; | ||
| using Google.Apis.Auth.OAuth2; | ||
| using Google.Cloud.Spanner.Admin.Database.V1; | ||
| using Google.Cloud.Spanner.V1; | ||
| using System; | ||
|
|
@@ -32,16 +33,17 @@ internal sealed class SpannerClientCreationOptions : IEquatable<SpannerClientCre | |
|
|
||
| internal bool UsesEmulator { get; } | ||
|
|
||
| private readonly string _credentialFile; | ||
| private readonly string _credentialType; | ||
| private readonly Lazy<GoogleCredential> _effectiveGoogleCredential; | ||
|
|
||
| internal SpannerClientCreationOptions(SpannerConnectionStringBuilder builder) | ||
| { | ||
| var clientBuilder = new SpannerClientBuilder | ||
| { | ||
| EmulatorDetection = builder.EmulatorDetection, | ||
| EnvironmentVariableProvider = builder.EnvironmentVariableProvider, | ||
| Endpoint = builder.ContainsKey(nameof(builder.Host)) || builder.ContainsKey(nameof(builder.Port)) ? builder.EndPoint : null, | ||
| #pragma warning disable CS0618 // Temporarily disable warnings for obsolete methods. See b/453009677 for more details. | ||
| CredentialsPath = builder.CredentialFile == "" ? null: builder.CredentialFile, | ||
| #pragma warning restore CS0618 | ||
| ChannelCredentials = builder.CredentialOverride, | ||
| GoogleCredential = builder.GoogleCredential, | ||
|
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. Should you call here
Contributor
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. Yeah good point, I was keeping the original google credential override around for equality considerations, but we can just add a reference field for that. Removed. |
||
| AffinityChannelPoolConfiguration = new ChannelPoolConfig | ||
|
|
@@ -59,6 +61,11 @@ internal SpannerClientCreationOptions(SpannerConnectionStringBuilder builder) | |
|
|
||
| UsesEmulator = emulatorBuilder is not null; | ||
| ClientBuilder = emulatorBuilder ?? clientBuilder; | ||
| _credentialFile = builder.CredentialFile; | ||
| _credentialType = builder.CredentialType; | ||
| // Use Lazy to avoid throwing in the constructor if the credential file is missing. | ||
| _effectiveGoogleCredential = new Lazy<GoogleCredential>(() => | ||
| ClientBuilder.GoogleCredential ?? (string.IsNullOrEmpty(_credentialFile) ? null : CredentialFactory.FromFile(_credentialFile, _credentialType))); | ||
| } | ||
|
|
||
| internal Task<SpannerClient> CreateSpannerClientAsync(SpannerSettings settings) => | ||
|
|
@@ -68,11 +75,8 @@ internal Task<SpannerClient> CreateSpannerClientAsync(SpannerSettings settings) | |
| // Note we don't copy emulator detection properties because we already took care | ||
| // of emulator detection on the constructor. | ||
| Endpoint = ClientBuilder.Endpoint, | ||
| #pragma warning disable CS0618 // Temporarily disable warnings for obsolete methods. See b/453009677 for more details. | ||
| CredentialsPath = ClientBuilder.CredentialsPath, | ||
| #pragma warning disable CS0618 | ||
| ChannelCredentials = ClientBuilder.ChannelCredentials, | ||
| GoogleCredential = ClientBuilder.GoogleCredential, | ||
| GoogleCredential = _effectiveGoogleCredential.Value, | ||
| AffinityChannelPoolConfiguration = ClientBuilder.AffinityChannelPoolConfiguration, | ||
| LeaderRoutingEnabled = ClientBuilder.LeaderRoutingEnabled, | ||
| DirectedReadOptions = ClientBuilder.DirectedReadOptions, | ||
|
|
@@ -88,11 +92,8 @@ internal DatabaseAdminClientBuilder CreateDatabaseAdminClientBuilder() | |
| // Note we don't copy emulator detection properties because we already took care | ||
| // of emulator detection on the constructor. | ||
| Endpoint = ClientBuilder.Endpoint, | ||
| #pragma warning disable CS0618 // Temporarily disable warnings for obsolete methods. See b/453009677 for more details. | ||
| CredentialsPath = ClientBuilder.CredentialsPath, | ||
| #pragma warning restore CS0618 | ||
| ChannelCredentials = ClientBuilder.ChannelCredentials, | ||
| GoogleCredential = ClientBuilder.GoogleCredential, | ||
| GoogleCredential = _effectiveGoogleCredential.Value, | ||
| // If we ever have settings of our own, we need to merge those with these. | ||
| Settings = CreateDatabaseAdminSettings(), | ||
| UniverseDomain = ClientBuilder.UniverseDomain, | ||
|
|
@@ -113,11 +114,10 @@ other is not null && | |
| UsesEmulator == other.UsesEmulator && | ||
| // TODO: Consider overriding ClientBuilderBase and SpannerClientBuilder Equals, etc. | ||
| Equals(ClientBuilder.Endpoint, other.ClientBuilder.Endpoint) && | ||
| #pragma warning disable CS0618 // Temporarily disable warnings for obsolete methods. See b/453009677 for more details. | ||
| Equals(ClientBuilder.CredentialsPath, other.ClientBuilder.CredentialsPath) && | ||
| #pragma warning restore CS0618 | ||
| Equals(ClientBuilder.ChannelCredentials, other.ClientBuilder.ChannelCredentials) && | ||
| Equals(ClientBuilder.GoogleCredential, other.ClientBuilder.GoogleCredential) && | ||
| _credentialFile == other._credentialFile && | ||
| _credentialType == other._credentialType && | ||
| Equals(ClientBuilder.AffinityChannelPoolConfiguration, other.ClientBuilder.AffinityChannelPoolConfiguration) && | ||
| ClientBuilder.LeaderRoutingEnabled == other.ClientBuilder.LeaderRoutingEnabled && | ||
| Equals(ClientBuilder.DirectedReadOptions, other.ClientBuilder.DirectedReadOptions) && | ||
|
|
@@ -129,11 +129,10 @@ public override int GetHashCode() | |
| { | ||
| int hash = 31; | ||
| hash = hash * 23 + (ClientBuilder.Endpoint?.GetHashCode() ?? 0); | ||
| #pragma warning disable CS0618 // Temporarily disable warnings for obsolete methods. See b/453009677 for more details. | ||
| hash = hash * 23 + (ClientBuilder.CredentialsPath?.GetHashCode() ?? 0); | ||
| #pragma warning restore CS0618 | ||
| hash = hash * 23 + (ClientBuilder.ChannelCredentials?.GetHashCode() ?? 0); | ||
| hash = hash * 23 + (ClientBuilder.GoogleCredential?.GetHashCode() ?? 0); | ||
| hash = hash * 23 + (_credentialFile?.GetHashCode() ?? 0); | ||
| hash = hash * 23 + (_credentialType?.GetHashCode() ?? 0); | ||
| hash = hash * 23 + UsesEmulator.GetHashCode(); | ||
| hash = hash * 23 + (ClientBuilder.AffinityChannelPoolConfiguration?.GetHashCode() ?? 0); | ||
| hash = hash * 23 + (ClientBuilder.LeaderRoutingEnabled.GetHashCode()); | ||
|
|
@@ -150,12 +149,14 @@ public override int GetHashCode() | |
| public override string ToString() | ||
| { | ||
| var builder = new StringBuilder($"EndPoint: {ClientBuilder.Endpoint ?? "Default"}"); | ||
| #pragma warning disable CS0618 // Temporarily disable warnings for obsolete methods. See b/453009677 for more details. | ||
| if (!string.IsNullOrEmpty(ClientBuilder.CredentialsPath)) | ||
| if (!string.IsNullOrEmpty(_credentialFile)) | ||
| { | ||
| builder.Append($"; CredentialsFile: {_credentialFile}"); | ||
| } | ||
| if (!string.IsNullOrEmpty(_credentialType)) | ||
| { | ||
| builder.Append($"; CredentialsFile: {ClientBuilder.CredentialsPath}"); | ||
| builder.Append($"; CredentialType: {_credentialType}"); | ||
| } | ||
|
robertvoinescu-work marked this conversation as resolved.
|
||
| #pragma warning restore CS0618 | ||
| if (ClientBuilder.ChannelCredentials is not null) | ||
| { | ||
| builder.Append($"; CredentialsOverride: True"); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,6 +51,7 @@ public sealed class SpannerConnectionStringBuilder : DbConnectionStringBuilder | |
| internal const int DefaultMaxConcurrentStreamsLowWatermark = 20; | ||
|
|
||
| private const string CredentialFileKeyword = "CredentialFile"; | ||
| private const string CredentialTypeKeyword = "CredentialType"; | ||
| private const string DataSourceKeyword = "Data Source"; | ||
| private const string UseClrDefaultForNullKeyword = "UseClrDefaultForNull"; | ||
| private const string EnableGetSchemaTableKeyword = "EnableGetSchemaTable"; | ||
|
|
@@ -94,6 +95,17 @@ public string CredentialFile | |
| set => this[CredentialFileKeyword] = value; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The expected type of the credential provided via <see cref="CredentialFile"/>. | ||
| /// Accepted values can be found in <see cref="JsonCredentialParameters"/>. | ||
| /// Defaults to <see cref="JsonCredentialParameters.ServiceAccountCredentialType"/>. | ||
|
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. Leave a note also saying that the rest of accepted values are the ones defined in
Contributor
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. Done |
||
| /// </summary> | ||
| public string CredentialType | ||
| { | ||
| get => GetValueOrDefault(CredentialTypeKeyword, JsonCredentialParameters.ServiceAccountCredentialType); | ||
| set => this[CredentialTypeKeyword] = value; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Option to change between the default handling of null database values (return <see cref="DBNull.Value">DBNull.Value</see>) or | ||
| /// the non-standard handling (return the default value for whatever type is requested). | ||
|
|
||
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.
According to the general rules, when asserting that an exception is thrown in a test, the exception message should also be asserted to ensure the correct exception is being propagated.
References