-
Notifications
You must be signed in to change notification settings - Fork 0
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
fix: Init system resource #5
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
oapi-codegen -config openapi.client.yaml https://raw.githubusercontent.com/ctrlplanedev/ctrlplane/refs/heads/main/openapi.v1.json | ||
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,3 +1,17 @@ | ||||||||||||||||||||||||||||||||
provider "scaffolding" { | ||||||||||||||||||||||||||||||||
# example configuration here | ||||||||||||||||||||||||||||||||
terraform { | ||||||||||||||||||||||||||||||||
required_providers { | ||||||||||||||||||||||||||||||||
ctrlplane = { | ||||||||||||||||||||||||||||||||
source = "ctrlplane/ctrlplane" | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
Comment on lines
+1
to
+7
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. 🛠️ Refactor suggestion Add version constraints for required provider. The Apply this diff: terraform {
required_providers {
ctrlplane = {
source = "ctrlplane/ctrlplane"
+ version = "~> 1.0"
}
}
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||
provider "ctrlplane" { | ||||||||||||||||||||||||||||||||
base_url = "http://localhost:3000" | ||||||||||||||||||||||||||||||||
workspace = "ctrlplane" | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
resource "ctrlplane_system" "example" { | ||||||||||||||||||||||||||||||||
name = "tf_test_official" | ||||||||||||||||||||||||||||||||
slug = "tf_test_official" | ||||||||||||||||||||||||||||||||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package provider | ||
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. Add the required file headers. The pipeline indicates this file is missing required file headers. Please add the necessary headers at the top of the file to comply with project standards and pass the checks. 🧰 Tools🪛 GitHub Actions: Tests[warning] File is missing required headers |
||
|
||
import ( | ||
"terraform-provider-ctrlplane/client" | ||
|
||
"github.com/google/uuid" | ||
) | ||
|
||
type DataSourceModel struct { | ||
Workspace uuid.UUID `tfsdk:"workspace"` | ||
Client *client.ClientWithResponses `tfsdk:"client"` | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -5,11 +5,14 @@ package provider | |||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||||
"context" | ||||||||||||||||||||||||||||
"errors" | ||||||||||||||||||||||||||||
"net/http" | ||||||||||||||||||||||||||||
"os" | ||||||||||||||||||||||||||||
"strings" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
"terraform-provider-ctrlplane/client" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
"github.com/google/uuid" | ||||||||||||||||||||||||||||
"github.com/hashicorp/terraform-plugin-framework/datasource" | ||||||||||||||||||||||||||||
"github.com/hashicorp/terraform-plugin-framework/function" | ||||||||||||||||||||||||||||
"github.com/hashicorp/terraform-plugin-framework/provider" | ||||||||||||||||||||||||||||
|
@@ -34,6 +37,7 @@ type CtrlplaneProvider struct { | |||||||||||||||||||||||||||
type CtrlplaneProviderModel struct { | ||||||||||||||||||||||||||||
BaseURL types.String `tfsdk:"base_url"` | ||||||||||||||||||||||||||||
Token types.String `tfsdk:"token"` | ||||||||||||||||||||||||||||
Workspace types.String `tfsdk:"workspace"` | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func (p *CtrlplaneProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { | ||||||||||||||||||||||||||||
|
@@ -52,6 +56,10 @@ func (p *CtrlplaneProvider) Schema(ctx context.Context, req provider.SchemaReque | |||||||||||||||||||||||||||
MarkdownDescription: "The token to use for authentication", | ||||||||||||||||||||||||||||
Optional: true, | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
"workspace": schema.StringAttribute{ | ||||||||||||||||||||||||||||
MarkdownDescription: "The workspace to use", | ||||||||||||||||||||||||||||
Optional: true, | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
@@ -63,6 +71,51 @@ func addAPIKey(apiKey string) client.RequestEditorFn { | |||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func getWorkspaceById(ctx context.Context, workspaceID uuid.UUID, client *client.ClientWithResponses) (uuid.UUID, error) { | ||||||||||||||||||||||||||||
validatedWorkspace, err := client.GetWorkspaceWithResponse(ctx, workspaceID) | ||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||
return uuid.Nil, err | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if validatedWorkspace.JSON200 != nil { | ||||||||||||||||||||||||||||
return validatedWorkspace.JSON200.Id, nil | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if validatedWorkspace.JSON404 != nil { | ||||||||||||||||||||||||||||
return uuid.Nil, errors.New("workspace not found") | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
return uuid.Nil, errors.New("failed to get workspace") | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+74
to
+89
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. 🛠️ Refactor suggestion Add context timeout handling for API calls. The workspace retrieval functions should handle context timeouts to ensure they don't hang indefinitely on slow API responses. +import "time"
func getWorkspaceById(ctx context.Context, workspaceID uuid.UUID, client *client.ClientWithResponses) (uuid.UUID, error) {
+ ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
+ defer cancel()
validatedWorkspace, err := client.GetWorkspaceWithResponse(ctx, workspaceID)
// ... rest of the function
}
func getWorkspaceBySlug(ctx context.Context, slug string, client *client.ClientWithResponses) (uuid.UUID, error) {
+ ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
+ defer cancel()
validatedWorkspace, err := client.GetWorkspaceBySlugWithResponse(ctx, slug)
// ... rest of the function
} Also applies to: 91-117 |
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func getWorkspaceBySlug(ctx context.Context, slug string, client *client.ClientWithResponses) (uuid.UUID, error) { | ||||||||||||||||||||||||||||
validatedWorkspace, err := client.GetWorkspaceBySlugWithResponse(ctx, slug) | ||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||
return uuid.Nil, err | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if validatedWorkspace.JSON200 != nil { | ||||||||||||||||||||||||||||
return getWorkspaceById(ctx, validatedWorkspace.JSON200.Id, client) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if validatedWorkspace.JSON404 != nil { | ||||||||||||||||||||||||||||
return uuid.Nil, errors.New("workspace not found") | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
return uuid.Nil, errors.New("failed to get workspace") | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func getWorkspace(ctx context.Context, workspace string, client *client.ClientWithResponses) (uuid.UUID, error) { | ||||||||||||||||||||||||||||
if workspace == "" { | ||||||||||||||||||||||||||||
return uuid.Nil, errors.New("workspace is required") | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if workspaceID, err := uuid.Parse(workspace); err == nil { | ||||||||||||||||||||||||||||
return getWorkspaceById(ctx, workspaceID, client) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
return getWorkspaceBySlug(ctx, workspace, client) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func (p *CtrlplaneProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { | ||||||||||||||||||||||||||||
var data CtrlplaneProviderModel | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
@@ -72,7 +125,7 @@ func (p *CtrlplaneProvider) Configure(ctx context.Context, req provider.Configur | |||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if data.BaseURL.IsNull() { | ||||||||||||||||||||||||||||
if data.BaseURL.IsNull() { | ||||||||||||||||||||||||||||
envBaseURL := os.Getenv("CTRLPLANE_BASE_URL") | ||||||||||||||||||||||||||||
if envBaseURL != "" { | ||||||||||||||||||||||||||||
data.BaseURL = types.StringValue(envBaseURL) | ||||||||||||||||||||||||||||
|
@@ -90,22 +143,39 @@ func (p *CtrlplaneProvider) Configure(ctx context.Context, req provider.Configur | |||||||||||||||||||||||||||
data.Token = types.StringValue(envToken) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
client, err := client.NewClient( | ||||||||||||||||||||||||||||
data.BaseURL.ValueString(), | ||||||||||||||||||||||||||||
server := data.BaseURL.ValueString() | ||||||||||||||||||||||||||||
server = strings.TrimSuffix(server, "/") | ||||||||||||||||||||||||||||
server = strings.TrimSuffix(server, "/api") | ||||||||||||||||||||||||||||
server = server + "/api" | ||||||||||||||||||||||||||||
Comment on lines
+146
to
+149
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. 🛠️ Refactor suggestion Improve URL manipulation robustness. The current URL manipulation logic could be made more robust by using proper URL parsing. +import "net/url"
- server := data.BaseURL.ValueString()
- server = strings.TrimSuffix(server, "/")
- server = strings.TrimSuffix(server, "/api")
- server = server + "/api"
+ baseURL, err := url.Parse(data.BaseURL.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("Invalid base URL", err.Error())
+ return
+ }
+ baseURL.Path = strings.TrimSuffix(baseURL.Path, "/")
+ baseURL.Path = strings.TrimSuffix(baseURL.Path, "/api")
+ baseURL.Path = baseURL.Path + "/api"
+ server := baseURL.String() 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
client, err := client.NewClientWithResponses( | ||||||||||||||||||||||||||||
server, | ||||||||||||||||||||||||||||
client.WithRequestEditorFn(addAPIKey(data.Token.ValueString())), | ||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||
resp.Diagnostics.AddError("Failed to create client", err.Error()) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
resp.DataSourceData = client | ||||||||||||||||||||||||||||
resp.ResourceData = client | ||||||||||||||||||||||||||||
configuredWorkspace := data.Workspace.ValueString() | ||||||||||||||||||||||||||||
workspaceID, err := getWorkspace(ctx, configuredWorkspace, client) | ||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||
resp.Diagnostics.AddError("Failed to get workspace", err.Error()) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
dataSourceModel := &DataSourceModel{ | ||||||||||||||||||||||||||||
Workspace: workspaceID, | ||||||||||||||||||||||||||||
Client: client, | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
resp.DataSourceData = dataSourceModel | ||||||||||||||||||||||||||||
resp.ResourceData = dataSourceModel | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func (p *CtrlplaneProvider) Resources(ctx context.Context) []func() resource.Resource { | ||||||||||||||||||||||||||||
return []func() resource.Resource{ | ||||||||||||||||||||||||||||
NewTargetResource, | ||||||||||||||||||||||||||||
NewSystemResource, | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
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.
Add required shell script headers and error handling.
The script is missing essential components:
Apply this diff to improve the script:
📝 Committable suggestion
🧰 Tools
🪛 Shellcheck (0.10.0)
[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
(SC2148)
🪛 GitHub Actions: Tests
[warning] File is missing required headers