Skip to content
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

[AV-62009] Code Health - Pass in Success Codes to Client #80

Merged
merged 8 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions examples/user/create_user.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ resource "capella_user" "new_user" {
name = var.user_name
email = var.email

organization_roles = [
"organizationMember"
]
organization_roles = var.organization_roles

resources = [
{
Expand Down
5 changes: 5 additions & 0 deletions examples/user/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ variable "user_name" {
variable "email" {
description = "Capella Email Address"
}

variable "organization_roles" {
description = "Capella Organization Roles"
type = list(string)
}
28 changes: 24 additions & 4 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,27 @@ type Response struct {
Body []byte
}

// RequestCfg is used to encapsulate request details to endpoints
type EndpointCfg struct {
// Url is url of the endpoint to be contacted
Url string

// Method is the HTTP method to be requested.
Method string

// SuccessStatus represents the HTTP status code associated
// with a successful response from the endpoint.
SuccessStatus int
aniket-Kumar-c marked this conversation as resolved.
Show resolved Hide resolved
}

// Execute is used to construct and execute a HTTP request.
// It then returns the response.
func (c *Client) Execute(url string, method string, payload any, authToken string, headers map[string]string) (response *Response, err error) {
func (c *Client) Execute(
endpointCfg EndpointCfg,
payload any,
authToken string,
headers map[string]string,
) (response *Response, err error) {
var requestBody []byte
if payload != nil {
requestBody, err = json.Marshal(payload)
Expand All @@ -42,7 +60,7 @@ func (c *Client) Execute(url string, method string, payload any, authToken strin
}
}

req, err := http.NewRequest(method, url, bytes.NewReader(requestBody))
req, err := http.NewRequest(endpointCfg.Method, endpointCfg.Url, bytes.NewReader(requestBody))
if err != nil {
return nil, fmt.Errorf("%s: %v", errors.ErrConstructingRequest, err)
}
Expand All @@ -63,10 +81,12 @@ func (c *Client) Execute(url string, method string, payload any, authToken strin
return
}

if apiRes.StatusCode >= http.StatusBadRequest {
if apiRes.StatusCode != endpointCfg.SuccessStatus {
var apiError Error
if err := json.Unmarshal(responseBody, &apiError); err != nil {
return nil, fmt.Errorf("status: %d, body: %s", apiRes.StatusCode, responseBody)
return nil, fmt.Errorf(
"unexpected code: %d, expected: %d, body: %s",
apiRes.StatusCode, endpointCfg.SuccessStatus, responseBody)
}
return nil, apiError
}
Expand Down
10 changes: 5 additions & 5 deletions internal/api/pagination.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,14 @@ func GetPaginated[DataSchema ~[]T, T any](
ctx context.Context,
client *Client,
token string,
url string,
cfg EndpointCfg,
sortBy sortParameter,
) (DataSchema, error) {
var (
responses DataSchema
page = 1
perPage = 10
baseUrl = cfg.Url
)

type overlay struct {
Expand All @@ -81,12 +82,11 @@ func GetPaginated[DataSchema ~[]T, T any](
}

for {
// construct pagination parameters
pageParams := fmt.Sprintf("?page=%d&perPage=%d&sortBy=%s", page, perPage, string(sortBy))
cfg.Url = baseUrl + fmt.Sprintf("?page=%d&perPage=%d&sortBy=%s", page, perPage, string(sortBy))
cfg.Method = http.MethodGet

response, err := client.Execute(
url+pageParams,
http.MethodGet,
cfg,
nil,
token,
nil,
Expand Down
3 changes: 2 additions & 1 deletion internal/datasources/allowlists.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ func (d *AllowLists) listAllowLists(ctx context.Context, organizationId, project
clusterId,
)

return api.GetPaginated[[]api.GetAllowListResponse](ctx, d.Client, d.Token, url, api.SortById)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}
return api.GetPaginated[[]api.GetAllowListResponse](ctx, d.Client, d.Token, cfg, api.SortById)
}

// Configure adds the provider configured client to the allowlist data source.
Expand Down
5 changes: 4 additions & 1 deletion internal/datasources/apikeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package datasources
import (
"context"
"fmt"
"net/http"

"terraform-provider-capella/internal/api"
providerschema "terraform-provider-capella/internal/schema"
Expand Down Expand Up @@ -86,7 +87,9 @@ func (d *ApiKeys) Read(ctx context.Context, req datasource.ReadRequest, resp *da
}

url := fmt.Sprintf("%s/v4/organizations/%s/apikeys", d.HostURL, organizationId)
response, err := api.GetPaginated[[]api.GetApiKeyResponse](ctx, d.Client, d.Token, url, api.SortByName)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}

response, err := api.GetPaginated[[]api.GetApiKeyResponse](ctx, d.Client, d.Token, cfg, api.SortByName)
switch err := err.(type) {
case nil:
case api.Error:
Expand Down
26 changes: 6 additions & 20 deletions internal/datasources/appservices.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ package datasources

import (
"context"
"encoding/json"
"fmt"
"net/http"
"terraform-provider-capella/internal/api/appservice"
appservice "terraform-provider-capella/internal/api/appservice"

"terraform-provider-capella/internal/api"
"terraform-provider-capella/internal/errors"
Expand Down Expand Up @@ -62,13 +61,10 @@ func (d *AppServices) Read(ctx context.Context, req datasource.ReadRequest, resp
organizationId = state.OrganizationId.ValueString()
)

response, err := d.Client.Execute(
fmt.Sprintf("%s/v4/organizations/%s/appservices", d.HostURL, organizationId),
http.MethodGet,
nil,
d.Token,
nil,
)
url := fmt.Sprintf("%s/v4/organizations/%s/appservices", d.HostURL, organizationId)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}

response, err := api.GetPaginated[[]appservice.GetAppServiceResponse](ctx, d.Client, d.Token, cfg, api.SortById)
switch err := err.(type) {
case nil:
case api.Error:
Expand All @@ -85,17 +81,7 @@ func (d *AppServices) Read(ctx context.Context, req datasource.ReadRequest, resp
return
}

appServicesResp := appservice.GetAppServicesResponse{}
err = json.Unmarshal(response.Body, &appServicesResp)
if err != nil {
resp.Diagnostics.AddError(
"Error reading app services",
"Could not read app services, unexpected error: "+err.Error(),
)
return
}

for _, appService := range appServicesResp.Data {
for _, appService := range response {
audit := providerschema.NewCouchbaseAuditData(appService.Audit)

auditObj, diags := types.ObjectValueFrom(ctx, audit.AttributeTypes(), audit)
Expand Down
5 changes: 4 additions & 1 deletion internal/datasources/buckets.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package datasources
import (
"context"
"fmt"
"net/http"
"terraform-provider-capella/internal/api/bucket"

"terraform-provider-capella/internal/api"
Expand Down Expand Up @@ -146,7 +147,9 @@ func (d *Buckets) Read(ctx context.Context, req datasource.ReadRequest, resp *da
}

url := fmt.Sprintf("%s/v4/organizations/%s/projects/%s/clusters/%s/buckets", d.HostURL, organizationId, projectId, clusterId)
response, err := api.GetPaginated[[]bucket.GetBucketResponse](ctx, d.Client, d.Token, url, api.SortById)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}

response, err := api.GetPaginated[[]bucket.GetBucketResponse](ctx, d.Client, d.Token, cfg, api.SortById)
switch err := err.(type) {
case nil:
case api.Error:
Expand Down
5 changes: 3 additions & 2 deletions internal/datasources/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ func (c *Certificate) Read(ctx context.Context, req datasource.ReadRequest, resp
clusterId = state.ClusterId.ValueString()
)

url := fmt.Sprintf("%s/v4/organizations/%s/projects/%s/clusters/%s/certificates", c.HostURL, organizationId, projectId, clusterId)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}
response, err := c.Client.Execute(
fmt.Sprintf("%s/v4/organizations/%s/projects/%s/clusters/%s/certificates", c.HostURL, organizationId, projectId, clusterId),
http.MethodGet,
cfg,
nil,
c.Token,
nil,
Expand Down
13 changes: 8 additions & 5 deletions internal/datasources/clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package datasources
import (
"context"
"fmt"
"net/http"

"terraform-provider-capella/internal/api"
clusterapi "terraform-provider-capella/internal/api/cluster"
Expand Down Expand Up @@ -50,16 +51,16 @@ func (d *Clusters) Read(ctx context.Context, req datasource.ReadRequest, resp *d

if state.OrganizationId.IsNull() {
resp.Diagnostics.AddError(
"Error creating cluster",
"Could not create cluster, unexpected error: organization ID cannot be empty.",
"Error reading cluster",
"Could not read cluster, unexpected error: organization ID cannot be empty.",
)
return
}

if state.ProjectId.IsNull() {
resp.Diagnostics.AddError(
"Error creating cluster",
"Could not create cluster, unexpected error: project ID cannot be empty.",
"Error reading cluster",
"Could not read cluster, unexpected error: project ID cannot be empty.",
)
return
}
Expand All @@ -70,7 +71,9 @@ func (d *Clusters) Read(ctx context.Context, req datasource.ReadRequest, resp *d
)

url := fmt.Sprintf("%s/v4/organizations/%s/projects/%s/clusters", d.HostURL, organizationId, projectId)
response, err := api.GetPaginated[[]clusterapi.GetClusterResponse](ctx, d.Client, d.Token, url, api.SortById)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}

response, err := api.GetPaginated[[]clusterapi.GetClusterResponse](ctx, d.Client, d.Token, cfg, api.SortById)
switch err := err.(type) {
case nil:
case api.Error:
Expand Down
5 changes: 4 additions & 1 deletion internal/datasources/database_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package datasources
import (
"context"
"fmt"
"net/http"

"terraform-provider-capella/internal/api"
providerschema "terraform-provider-capella/internal/schema"
Expand Down Expand Up @@ -113,7 +114,9 @@ func (d *DatabaseCredentials) Read(ctx context.Context, req datasource.ReadReque
}

url := fmt.Sprintf("%s/v4/organizations/%s/projects/%s/clusters/%s/users", d.HostURL, organizationId, projectId, clusterId)
response, err := api.GetPaginated[[]api.GetDatabaseCredentialResponse](ctx, d.Client, d.Token, url, api.SortById)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}

response, err := api.GetPaginated[[]api.GetDatabaseCredentialResponse](ctx, d.Client, d.Token, cfg, api.SortById)
switch err := err.(type) {
case nil:
case api.Error:
Expand Down
5 changes: 3 additions & 2 deletions internal/datasources/organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ func (o *Organization) Read(ctx context.Context, req datasource.ReadRequest, res
var organizationId = state.OrganizationId.ValueString()

// Make request to get organization
url := fmt.Sprintf("%s/v4/organizations/%s", o.HostURL, organizationId)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}
response, err := o.Client.Execute(
fmt.Sprintf("%s/v4/organizations/%s", o.HostURL, organizationId),
http.MethodGet,
cfg,
nil,
o.Token,
nil,
Expand Down
5 changes: 4 additions & 1 deletion internal/datasources/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package datasources
import (
"context"
"fmt"
"net/http"

"terraform-provider-capella/internal/api"
providerschema "terraform-provider-capella/internal/schema"
Expand Down Expand Up @@ -76,7 +77,9 @@ func (d *Projects) Read(ctx context.Context, req datasource.ReadRequest, resp *d
var organizationId = state.OrganizationId.ValueString()

url := fmt.Sprintf("%s/v4/organizations/%s/projects", d.HostURL, organizationId)
response, err := api.GetPaginated[[]api.GetProjectResponse](ctx, d.Client, d.Token, url, api.SortById)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}

response, err := api.GetPaginated[[]api.GetProjectResponse](ctx, d.Client, d.Token, cfg, api.SortById)
switch err := err.(type) {
case nil:
case api.Error:
Expand Down
4 changes: 3 additions & 1 deletion internal/datasources/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ func (d *Users) Read(ctx context.Context, req datasource.ReadRequest, resp *data

// Make request to list Users
url := fmt.Sprintf("%s/v4/organizations/%s/users", d.HostURL, organizationId)
response, err := api.GetPaginated[[]api.GetUserResponse](ctx, d.Client, d.Token, url, api.SortById)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}

response, err := api.GetPaginated[[]api.GetUserResponse](ctx, d.Client, d.Token, cfg, api.SortById)
switch err := err.(type) {
case nil:
case api.Error:
Expand Down
55 changes: 29 additions & 26 deletions internal/resources/allowlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,16 @@ func (r *AllowList) Create(ctx context.Context, req resource.CreateRequest, resp
ExpiresAt: plan.ExpiresAt.ValueString(),
}

url := fmt.Sprintf(
"%s/v4/organizations/%s/projects/%s/clusters/%s/allowedcidrs",
r.HostURL,
plan.OrganizationId.ValueString(),
plan.ProjectId.ValueString(),
plan.ClusterId.ValueString(),
)
cfg := api.EndpointCfg{Url: url, Method: http.MethodPost, SuccessStatus: http.StatusCreated}
response, err := r.Client.Execute(
fmt.Sprintf(
"%s/v4/organizations/%s/projects/%s/clusters/%s/allowedcidrs",
r.HostURL,
plan.OrganizationId.ValueString(),
plan.ProjectId.ValueString(),
plan.ClusterId.ValueString(),
),
http.MethodPost,
cfg,
allowListRequest,
r.Token,
nil,
Expand Down Expand Up @@ -227,16 +228,17 @@ func (r *AllowList) Delete(ctx context.Context, req resource.DeleteRequest, resp
allowListID = IDs[providerschema.Id]
)
// Execute request to delete existing allowlist
url := fmt.Sprintf(
"%s/v4/organizations/%s/projects/%s/clusters/%s/allowedcidrs/%s",
r.HostURL,
organizationId,
projectId,
clusterId,
allowListID,
)
cfg := api.EndpointCfg{Url: url, Method: http.MethodDelete, SuccessStatus: http.StatusNoContent}
_, err = r.Client.Execute(
fmt.Sprintf(
"%s/v4/organizations/%s/projects/%s/clusters/%s/allowedcidrs/%s",
r.HostURL,
organizationId,
projectId,
clusterId,
allowListID,
),
http.MethodDelete,
cfg,
nil,
r.Token,
nil,
Expand Down Expand Up @@ -274,16 +276,17 @@ func (r *AllowList) ImportState(ctx context.Context, req resource.ImportStateReq

// getAllowList is used to retrieve an existing allow list
func (r *AllowList) getAllowList(ctx context.Context, organizationId, projectId, clusterId, allowListId string) (*api.GetAllowListResponse, error) {
url := fmt.Sprintf(
"%s/v4/organizations/%s/projects/%s/clusters/%s/allowedcidrs/%s",
r.HostURL,
organizationId,
projectId,
clusterId,
allowListId,
)
cfg := api.EndpointCfg{Url: url, Method: http.MethodGet, SuccessStatus: http.StatusOK}
response, err := r.Client.Execute(
fmt.Sprintf(
"%s/v4/organizations/%s/projects/%s/clusters/%s/allowedcidrs/%s",
r.HostURL,
organizationId,
projectId,
clusterId,
allowListId,
),
http.MethodGet,
cfg,
nil,
r.Token,
nil,
Expand Down
Loading