From 02c675c7967b4a64e0ea6bf096ee94caff6f4221 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 6 Feb 2023 17:27:43 -0800 Subject: [PATCH] more base layout and setup --- .gitignore | 3 ++ internal/provider/dir_resource.go | 36 ++++++++++++++++-------- internal/provider/file_resource.go | 44 ++++++++++++++++++++---------- internal/provider/helpers.go | 42 ++++++++++++++++++++++++++++ internal/provider/provider.go | 26 ++++++++++++------ system/system.go | 28 +++++++++++++++++++ 6 files changed, 144 insertions(+), 35 deletions(-) create mode 100644 .gitignore create mode 100644 internal/provider/helpers.go create mode 100644 system/system.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c95a5aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.test +.idea +.DS_Store diff --git a/internal/provider/dir_resource.go b/internal/provider/dir_resource.go index 0e938f2..99de8f1 100644 --- a/internal/provider/dir_resource.go +++ b/internal/provider/dir_resource.go @@ -3,13 +3,11 @@ package provider import ( "context" "fmt" - "net/http" - + "git.davepedu.com/dave/terraform-provider-system/system" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -24,7 +22,7 @@ func NewDirResource() resource.Resource { // DirResource defines the resource implementation. type DirResource struct { - client *http.Client + client *system.SystemManager } // DirResourceModel describes the resource data model. @@ -34,7 +32,7 @@ type DirResourceModel struct { } func (r *DirResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_example" + resp.TypeName = req.ProviderTypeName + "_dir" } func (r *DirResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { @@ -43,15 +41,29 @@ func (r *DirResource) Schema(ctx context.Context, req resource.SchemaRequest, re MarkdownDescription: "Example resource", Attributes: map[string]schema.Attribute{ - "configurable_attribute": schema.StringAttribute{ + "path": schema.StringAttribute{ + MarkdownDescription: "File path", + Required: true, + }, + "mode": schema.StringAttribute{ MarkdownDescription: "Example configurable attribute", Optional: true, - }, - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "Example identifier", PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), + StringDefaultValue(types.StringValue("0755")), + }, + }, + "owner": schema.StringAttribute{ + MarkdownDescription: "Example configurable attribute", + Optional: true, + PlanModifiers: []planmodifier.String{ + StringDefaultValue(types.StringValue("root")), // TODO we won't always run as root, default to current user + }, + }, + "group": schema.StringAttribute{ + MarkdownDescription: "Example configurable attribute", + Optional: true, + PlanModifiers: []planmodifier.String{ + StringDefaultValue(types.StringValue("root")), // TODO we won't always run as root, default to current user }, }, }, @@ -64,7 +76,7 @@ func (r *DirResource) Configure(ctx context.Context, req resource.ConfigureReque return } - client, ok := req.ProviderData.(*http.Client) + client, ok := req.ProviderData.(*system.SystemManager) if !ok { resp.Diagnostics.AddError( diff --git a/internal/provider/file_resource.go b/internal/provider/file_resource.go index 5d08d32..a0affbd 100644 --- a/internal/provider/file_resource.go +++ b/internal/provider/file_resource.go @@ -3,13 +3,11 @@ package provider import ( "context" "fmt" - "net/http" - + "git.davepedu.com/dave/terraform-provider-system/system" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -24,7 +22,7 @@ func NewFileResource() resource.Resource { // FileResource defines the resource implementation. type FileResource struct { - client *http.Client + client *system.SystemManager } // FileResourceModel describes the resource data model. @@ -34,26 +32,42 @@ type FileResourceModel struct { } func (r *FileResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_example" + resp.TypeName = req.ProviderTypeName + "_file" } func (r *FileResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "Example resource", - + MarkdownDescription: "File resource", Attributes: map[string]schema.Attribute{ - "configurable_attribute": schema.StringAttribute{ + "path": schema.StringAttribute{ + MarkdownDescription: "File path", + Required: true, + }, + "mode": schema.StringAttribute{ MarkdownDescription: "Example configurable attribute", Optional: true, - }, - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "Example identifier", PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), + StringDefaultValue(types.StringValue("0755")), }, }, + "owner": schema.StringAttribute{ + MarkdownDescription: "Example configurable attribute", + Optional: true, + PlanModifiers: []planmodifier.String{ + StringDefaultValue(types.StringValue("root")), // TODO we won't always run as root, default to current user + }, + }, + "group": schema.StringAttribute{ + MarkdownDescription: "Example configurable attribute", + Optional: true, + PlanModifiers: []planmodifier.String{ + StringDefaultValue(types.StringValue("root")), // TODO we won't always run as root, default to current user + }, + }, + "content": schema.StringAttribute{ + MarkdownDescription: "Example configurable attribute", + Required: true, + }, }, } } @@ -64,7 +78,7 @@ func (r *FileResource) Configure(ctx context.Context, req resource.ConfigureRequ return } - client, ok := req.ProviderData.(*http.Client) + client, ok := req.ProviderData.(*system.SystemManager) if !ok { resp.Diagnostics.AddError( diff --git a/internal/provider/helpers.go b/internal/provider/helpers.go new file mode 100644 index 0000000..225dc63 --- /dev/null +++ b/internal/provider/helpers.go @@ -0,0 +1,42 @@ +package provider + +import ( + "context" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Hashicorp, what the fuck are you making me write this shit for?. Give me back sdkv2 defaults. This is insane + +func StringDefaultValue(v types.String) *stringDefaultValue { + return &stringDefaultValue{v} +} + +type stringDefaultValue struct { + DefaultValue types.String +} + +var _ planmodifier.String = (*stringDefaultValue)(nil) + +func (s *stringDefaultValue) Description(ctx context.Context) string { + return "stringDefaultValue Description" +} + +func (s *stringDefaultValue) MarkdownDescription(ctx context.Context) string { + return "stringDefaultValue MarkdownDescription" +} + +func (s *stringDefaultValue) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, res *planmodifier.StringResponse) { + // If the attribute configuration is not null, we are done here + if !req.ConfigValue.IsNull() { + return + } + + // If the attribute plan is "known" and "not null", then a previous plan modifier in the sequence + // has already been applied, and we don't want to interfere. + if !req.PlanValue.IsUnknown() && !req.PlanValue.IsNull() { + return + } + + res.PlanValue = s.DefaultValue +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 7f5fb77..dae9d14 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -2,6 +2,8 @@ package provider import ( "context" + "fmt" + "git.davepedu.com/dave/terraform-provider-system/system" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider/schema" @@ -22,7 +24,7 @@ type SystemProvider struct { // SystemProviderModel describes the provider data model. type SystemProviderModel struct { - Endpoint types.String `tfsdk:"connection_string"` + ConnectionString types.String `tfsdk:"connection_string"` } func (p *SystemProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { @@ -35,7 +37,7 @@ func (p *SystemProvider) Schema(ctx context.Context, req provider.SchemaRequest, Attributes: map[string]schema.Attribute{ "connection_string": schema.StringAttribute{ MarkdownDescription: "SSH connection string", - Optional: false, + Required: true, }, }, } @@ -50,13 +52,21 @@ func (p *SystemProvider) Configure(ctx context.Context, req provider.ConfigureRe return } - // Configuration values are now available. - // if data.Endpoint.IsNull() { /* ... */ } - - // Example client configuration for data sources and resources - /*client := http.DefaultClient + client, err := system.NewSystemManagerFromUri(data.ConnectionString.String()) + if err != nil { + resp.Diagnostics.AddError( + "Unable to create System Manager API client", + fmt.Sprintf("%s", err), + ) + } + if err := client.Test(); err != nil { + resp.Diagnostics.AddError( + "System Manager API Client connection test failed", + fmt.Sprintf("%s", err), + ) + } resp.DataSourceData = client - resp.ResourceData = client*/ + resp.ResourceData = client } func (p *SystemProvider) Resources(ctx context.Context) []func() resource.Resource { diff --git a/system/system.go b/system/system.go new file mode 100644 index 0000000..f6dad50 --- /dev/null +++ b/system/system.go @@ -0,0 +1,28 @@ +package system + +// SystemManager providers the functionality to interrogate / interact with target systems +type SystemManager struct { + connection *SystemConnection +} + +func NewSystemManagerFromUri(uri string) (*SystemManager, error) { + conn, err := NewSystemConnectionFromUri(uri) + if err != nil { + return nil, err + } + return &SystemManager{ + connection: conn, + }, nil +} + +func (s *SystemManager) Test() error { + return nil +} + +// SystemConnection provides an unopinionated interface for interacting with remote systems on a low level +type SystemConnection struct { +} + +func NewSystemConnectionFromUri(uri string) (*SystemConnection, error) { + return nil, nil +}