Skip to content

Commit 78fd272

Browse files
authored
streaming auth improvements (#369)
The Astra Pulsar admin API now allows authentication directly with an Astra token, so it's no longer necessary to retrieve a Pulsar token before performing admin operations.
1 parent 92893ba commit 78fd272

File tree

4 files changed

+15
-155
lines changed

4 files changed

+15
-155
lines changed

internal/provider/provider_framework.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ func (p *astraProvider) Configure(ctx context.Context, req provider.ConfigureReq
125125
return
126126
}
127127

128-
token := firstNonEmptyString(config.Token.ValueString(), os.Getenv("ASTRA_API_TOKEN"))
129-
if token == "" {
128+
astraToken := firstNonEmptyString(config.Token.ValueString(), os.Getenv("ASTRA_API_TOKEN"))
129+
if astraToken == "" {
130130
resp.Diagnostics.AddError("missing required Astra API token",
131131
"missing required Astra API token. Please set the ASTRA_API_TOKEN environment variable or provide a token in the provider configuration")
132132
return
@@ -171,9 +171,9 @@ func (p *astraProvider) Configure(ctx context.Context, req provider.ConfigureReq
171171
}
172172

173173
// TODO: can we get this version at compile time?
174-
pluginFrameworkVersion := "1.2.0"
174+
pluginFrameworkVersion := "1.5.0"
175175
userAgent := p.UserAgent(req.TerraformVersion, pluginFrameworkVersion)
176-
authorization := fmt.Sprintf("Bearer %s", token)
176+
authorization := fmt.Sprintf("Bearer %s", astraToken)
177177
clientVersion := fmt.Sprintf("go/%s", astra.Version)
178178
astraClient, err := astra.NewClientWithResponses(astraAPIServerURL, func(c *astra.Client) error {
179179
c.Client = retryClient.StandardClient()
@@ -210,6 +210,7 @@ func (p *astraProvider) Configure(ctx context.Context, req provider.ConfigureReq
210210
// The streaming API server can handle Pulsar admin requests under the '/admin/v2' path, and these are passed through to a backend Pulsar cluster
211211
pulsarAdminClient, err := pulsaradmin.NewClientWithResponses(streamingAPIServerURLPulsarAdmin, func(c *pulsaradmin.Client) error {
212212
c.RequestEditors = append(c.RequestEditors, func(ctx context.Context, req *http.Request) error {
213+
req.Header.Set("Authorization", authorization)
213214
req.Header.Set("User-Agent", userAgent)
214215
req.Header.Set("X-Astra-Provider-Version", p.Version)
215216
req.Header.Set("X-Astra-Client-Version", clientVersion)
@@ -228,7 +229,7 @@ func (p *astraProvider) Configure(ctx context.Context, req provider.ConfigureReq
228229
astraClient: astraClient,
229230
astraStreamingClient: streamingClient,
230231
pulsarAdminClient: pulsarAdminClient,
231-
token: token,
232+
token: astraToken,
232233
stargateClientCache: clientCache,
233234
providerVersion: p.Version,
234235
userAgent: userAgent,

internal/provider/resource_streaming_namespace.go

Lines changed: 5 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -104,25 +104,7 @@ func (r *StreamingNamespaceResource) Create(ctx context.Context, req resource.Cr
104104
// Manually set the ID because this is not directly managed by the user or the server when creating a new namespace
105105
plan.ID = types.StringValue(fmt.Sprintf("%s/%s/%s", plan.Cluster.ValueString(), plan.Tenant.ValueString(), plan.Namespace.ValueString()))
106106

107-
orgID, err := getCurrentOrgID(ctx, r.clients.astraClient)
108-
if err != nil {
109-
resp.Diagnostics.AddError(
110-
"Error creating namespace",
111-
"Could not get current organization: "+err.Error(),
112-
)
113-
return
114-
}
115-
116-
pulsarToken, err := getLatestPulsarToken(ctx, r.clients.astraStreamingClient, r.clients.token, orgID, plan.Cluster.ValueString(), plan.Tenant.ValueString())
117-
if err != nil {
118-
resp.Diagnostics.AddError(
119-
"Error creating namespace",
120-
"Could not get pulsar token: "+err.Error(),
121-
)
122-
return
123-
}
124-
125-
pulsarRequestEditor := setPulsarClusterHeaders("", plan.Cluster.ValueString(), pulsarToken)
107+
pulsarRequestEditor := setPulsarClusterHeaders(plan.Cluster.ValueString())
126108

127109
// We have to create the namespace with an empty policy because the Astra Streaming control plane will override any
128110
// policy that we send. Then later we adjust any policy fields that have been set by the user.
@@ -160,29 +142,9 @@ func (r *StreamingNamespaceResource) Read(ctx context.Context, req resource.Read
160142
return
161143
}
162144

163-
astraClient := r.clients.astraClient
164-
streamingClient := r.clients.astraStreamingClient
165145
pulsarClient := r.clients.pulsarAdminClient
166146

167-
orgID, err := getCurrentOrgID(ctx, astraClient)
168-
if err != nil {
169-
resp.Diagnostics.AddError(
170-
fmt.Sprintf("Error reading streaming namespace '%s/%s'", state.Tenant.ValueString(), state.Namespace.ValueString()),
171-
"Failed to get current organization: "+err.Error(),
172-
)
173-
return
174-
}
175-
176-
pulsarToken, err := getLatestPulsarToken(ctx, streamingClient, r.clients.token, orgID, state.Cluster.ValueString(), state.Tenant.ValueString())
177-
if err != nil {
178-
resp.Diagnostics.AddError(
179-
fmt.Sprintf("Error reading streaming namespace '%s/%s'", state.Tenant.ValueString(), state.Namespace.ValueString()),
180-
"Failed to get valid Pulsar token: "+err.Error(),
181-
)
182-
return
183-
}
184-
185-
pulsarRequestEditor := setPulsarClusterHeaders(orgID, state.Cluster.ValueString(), pulsarToken)
147+
pulsarRequestEditor := setPulsarClusterHeaders(state.Cluster.ValueString())
186148
policiesFromServer, diags := getPulsarNamespacePolicies(ctx, pulsarClient, state, pulsarRequestEditor)
187149
resp.Diagnostics.Append(diags...)
188150
if resp.Diagnostics.HasError() {
@@ -204,25 +166,7 @@ func (r *StreamingNamespaceResource) Update(ctx context.Context, req resource.Up
204166
// Manually set the ID because this is not directly managed by the user or the server when creating a new namespace
205167
plan.ID = types.StringValue(fmt.Sprintf("%s/%s/%s", plan.Cluster.ValueString(), plan.Tenant.ValueString(), plan.Namespace.ValueString()))
206168

207-
orgID, err := getCurrentOrgID(ctx, r.clients.astraClient)
208-
if err != nil {
209-
resp.Diagnostics.AddError(
210-
fmt.Sprintf("Error reading streaming namespace '%s/%s'", plan.Tenant.ValueString(), plan.Namespace.ValueString()),
211-
"Failed to get current organization: "+err.Error(),
212-
)
213-
return
214-
}
215-
216-
pulsarToken, err := getLatestPulsarToken(ctx, r.clients.astraStreamingClient, r.clients.token, orgID, plan.Cluster.ValueString(), plan.Tenant.ValueString())
217-
if err != nil {
218-
resp.Diagnostics.AddError(
219-
fmt.Sprintf("Error reading streaming namespace '%s/%s'", plan.Tenant.ValueString(), plan.Namespace.ValueString()),
220-
"Failed to get valid Pulsar token: "+err.Error(),
221-
)
222-
return
223-
}
224-
225-
pulsarRequestEditor := setPulsarClusterHeaders("", plan.Cluster.ValueString(), pulsarToken)
169+
pulsarRequestEditor := setPulsarClusterHeaders(plan.Cluster.ValueString())
226170
resp.Diagnostics.Append(setNamespacePolicies(ctx, r.clients.pulsarAdminClient, plan, pulsarRequestEditor)...)
227171
if resp.Diagnostics.HasError() {
228172
return
@@ -250,30 +194,11 @@ func (r *StreamingNamespaceResource) Delete(ctx context.Context, req resource.De
250194
return
251195
}
252196

253-
astraClient := r.clients.astraClient
254197
streamingClient := r.clients.astraStreamingClient
255198

256-
orgID, err := getCurrentOrgID(ctx, astraClient)
257-
if err != nil {
258-
resp.Diagnostics.AddError(
259-
fmt.Sprintf("Error deleting streaming namespace '%s/%s'", state.Tenant.ValueString(), state.Namespace.ValueString()),
260-
"Failed to get current organization: "+err.Error(),
261-
)
262-
return
263-
}
264-
265-
pulsarToken, err := getLatestPulsarToken(ctx, streamingClient, r.clients.token, orgID, state.Cluster.ValueString(), state.Tenant.ValueString())
266-
if err != nil {
267-
resp.Diagnostics.AddError(
268-
fmt.Sprintf("Error deleting streaming namespace '%s/%s'", state.Tenant.ValueString(), state.Namespace.ValueString()),
269-
"Failed to get valid Pulsar token: "+err.Error(),
270-
)
271-
return
272-
}
273-
274-
pulsarRequestEditor := setPulsarClusterHeaders("", state.Cluster.ValueString(), pulsarToken)
199+
pulsarRequestEditor := setPulsarClusterHeaders(state.Cluster.ValueString())
275200
params := astrastreaming.DeleteNamespaceParams{}
276-
_, err = streamingClient.DeleteNamespace(ctx, state.Tenant.ValueString(), state.Namespace.ValueString(), &params, pulsarRequestEditor)
201+
_, err := streamingClient.DeleteNamespace(ctx, state.Tenant.ValueString(), state.Namespace.ValueString(), &params, pulsarRequestEditor)
277202
if err != nil {
278203
resp.Diagnostics.AddError(
279204
fmt.Sprintf("Error deleting streaming namespace '%s/%s'", state.Tenant.ValueString(), state.Namespace.ValueString()),

internal/provider/resource_streaming_topic.go

Lines changed: 3 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -265,25 +265,7 @@ func (r *StreamingTopicResource) Create(ctx context.Context, req resource.Create
265265

266266
pulsarClient := r.clients.pulsarAdminClient
267267

268-
astraOrgID, err := getCurrentOrgID(ctx, r.clients.astraClient)
269-
if err != nil {
270-
resp.Diagnostics.AddError(
271-
"Error creating topic",
272-
"Could not get current Astra organization: "+err.Error(),
273-
)
274-
return
275-
}
276-
277-
pulsarToken, err := getLatestPulsarToken(ctx, r.clients.astraStreamingClient, r.clients.token, astraOrgID, cluster, tenant)
278-
if err != nil {
279-
resp.Diagnostics.AddError(
280-
"Error creating topic",
281-
"Could not get pulsar token: "+err.Error(),
282-
)
283-
return
284-
}
285-
286-
streamingRequestHeaders := setPulsarClusterHeaders("", cluster, pulsarToken)
268+
streamingRequestHeaders := setPulsarClusterHeaders(cluster)
287269

288270
if plan.Persistent.ValueBool() {
289271
if plan.Partitioned.ValueBool() {
@@ -350,24 +332,6 @@ func (r *StreamingTopicResource) Read(ctx context.Context, req resource.ReadRequ
350332

351333
pulsarClient := r.clients.pulsarAdminClient
352334

353-
astraOrgID, err := getCurrentOrgID(ctx, r.clients.astraClient)
354-
if err != nil {
355-
resp.Diagnostics.AddError(
356-
"Error reading topic",
357-
"Could not get current Astra organization: "+err.Error(),
358-
)
359-
return
360-
}
361-
362-
pulsarToken, err := getLatestPulsarToken(ctx, r.clients.astraStreamingClient, r.clients.token, astraOrgID, cluster, tenant)
363-
if err != nil {
364-
resp.Diagnostics.AddError(
365-
"Error reading topic",
366-
"Could not get pulsar token: "+err.Error(),
367-
)
368-
return
369-
}
370-
371335
// Default to persistent true and partitioned false for compatibility with older provider versions
372336
if state.Persistent.IsNull() {
373337
state.Persistent = types.BoolValue(true)
@@ -376,7 +340,7 @@ func (r *StreamingTopicResource) Read(ctx context.Context, req resource.ReadRequ
376340
state.Partitioned = types.BoolValue(false)
377341
}
378342

379-
streamingRequestHeaders := setPulsarClusterHeaders("", cluster, pulsarToken)
343+
streamingRequestHeaders := setPulsarClusterHeaders(cluster)
380344

381345
if state.Persistent.ValueBool() {
382346
if state.Partitioned.ValueBool() {
@@ -500,25 +464,7 @@ func (r *StreamingTopicResource) Delete(ctx context.Context, req resource.Delete
500464

501465
pulsarClient := r.clients.pulsarAdminClient
502466

503-
astraOrgID, err := getCurrentOrgID(ctx, r.clients.astraClient)
504-
if err != nil {
505-
resp.Diagnostics.AddError(
506-
"Error deleting topic",
507-
"Could not get current Astra organization: "+err.Error(),
508-
)
509-
return
510-
}
511-
512-
pulsarToken, err := getLatestPulsarToken(ctx, r.clients.astraStreamingClient, r.clients.token, astraOrgID, cluster, tenant)
513-
if err != nil {
514-
resp.Diagnostics.AddError(
515-
"Error deleting topic",
516-
"Could not get pulsar token: "+err.Error(),
517-
)
518-
return
519-
}
520-
521-
pulsarRequestEditor := setPulsarClusterHeaders("", cluster, pulsarToken)
467+
pulsarRequestEditor := setPulsarClusterHeaders(cluster)
522468

523469
if state.Persistent.ValueBool() {
524470
if state.Partitioned.ValueBool() {

internal/provider/util_streaming.go

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,9 @@ const (
2020
)
2121

2222
// setPulsarClusterHeaders returns a function that can be used to set the request headers for a Pulsar admin API requests.
23-
// This overrides the provider Authorization header because the Pulsar admin API requires a Pulsar token instead of the AstraCS
24-
// token required by the Astra API.
25-
func setPulsarClusterHeaders(organizationID, cluster, pulsarToken string) func(ctx context.Context, req *http.Request) error {
23+
func setPulsarClusterHeaders(cluster string) func(ctx context.Context, req *http.Request) error {
2624
return func(ctx context.Context, req *http.Request) error {
27-
if pulsarToken == "" {
28-
return fmt.Errorf("missing required pulsar token")
29-
}
30-
req.Header.Set(authHeader, fmt.Sprintf("Bearer %s", pulsarToken))
31-
if cluster == "" {
32-
return fmt.Errorf("missing required pulsar cluster name")
33-
}
3425
req.Header.Set(pulsarClusterHeader, cluster)
35-
if organizationID != "" {
36-
req.Header.Set(organizationHeader, organizationID)
37-
}
3826
return nil
3927
}
4028
}

0 commit comments

Comments
 (0)