diff --git a/docs/data-sources/systemsoftware.md b/docs/data-sources/systemsoftware.md new file mode 100644 index 0000000..41117c7 --- /dev/null +++ b/docs/data-sources/systemsoftware.md @@ -0,0 +1,30 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "mittwald_systemsoftware Data Source - terraform-provider-mittwald" +subcategory: "" +description: |- + A data source that selects versions of system components, such as PHP, MySQL, etc. +--- + +# mittwald_systemsoftware (Data Source) + +A data source that selects versions of system components, such as PHP, MySQL, etc. + + + + +## Schema + +### Required + +- `name` (String) The system software name + +### Optional + +- `recommended` (Boolean) Set this to just select the recommended version +- `selector` (String) A version selector, such as `>= 7.4` + +### Read-Only + +- `version` (String) The selected version +- `version_id` (String) The selected version ID diff --git a/docs/resources/project.md b/docs/resources/project.md index 9c6f7ea..ea7ca2f 100644 --- a/docs/resources/project.md +++ b/docs/resources/project.md @@ -36,5 +36,6 @@ resource "mittwald_project" "foobar" { ### Read-Only +- `default_ips` (List of String) Contains a list of default IP addresses for the project - `directories` (Map of String) Contains a map of data directories within the project - `id` (String) The generated project ID diff --git a/examples/resources/mittwald_app/resource.tf b/examples/resources/mittwald_app/resource.tf index 74e6c29..60b4d8a 100644 --- a/examples/resources/mittwald_app/resource.tf +++ b/examples/resources/mittwald_app/resource.tf @@ -4,6 +4,21 @@ variable "admin_password" { sensitive = true } +data "mittwald_systemsoftware" "php" { + name = "php" + selector = "^8.2" +} + +data "mittwald_systemsoftware" "composer" { + name = "composer" + recommended = true +} + +data "mittwald_systemsoftware" "mysql" { + name = "composer" + recommended = true +} + resource "mittwald_app" "wordpress" { project_id = mittwald_project.foobar.id @@ -33,17 +48,17 @@ resource "mittwald_app" "custom_php" { update_policy = "none" dependencies = { - "php" = { - version = "8.2.8" + (data.mittwald_systemsoftware.php.name) = { + version = data.mittwald_systemsoftware.php.version update_policy = "patchLevel" } - "composer" = { + (data.mittwald_systemsoftware.composer.name) = { + version = data.mittwald_systemsoftware.composer.version update_policy = "patchLevel" - version = "2.3.10" }, - "mysql" = { + (data.mittwald_systemsoftware.mysql.name) = { + version = data.mittwald_systemsoftware.mysql.version update_policy = "patchLevel" - version = "8.0.28" }, } } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index b1a3259..e46fe2d 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -93,6 +93,7 @@ func (p *MittwaldProvider) Resources(ctx context.Context) []func() resource.Reso func (p *MittwaldProvider) DataSources(ctx context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ NewProjectByShortIdDataSource, + NewSystemSoftwareDataSource, NewAppDataSource, } } diff --git a/internal/provider/systemsoftware_data_source.go b/internal/provider/systemsoftware_data_source.go new file mode 100644 index 0000000..efaf1d2 --- /dev/null +++ b/internal/provider/systemsoftware_data_source.go @@ -0,0 +1,136 @@ +package provider + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/mittwald/terraform-provider-mittwald/api/mittwaldv2" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ datasource.DataSource = &SystemSoftwareDataSource{} + +func NewSystemSoftwareDataSource() datasource.DataSource { + return &SystemSoftwareDataSource{} +} + +// ProjectByShortIdDataSource defines the data source implementation. +type SystemSoftwareDataSource struct { + client mittwaldv2.ClientBuilder +} + +// SystemSoftwareDataSourceModel describes the data source data model. +type SystemSoftwareDataSourceModel struct { + Name types.String `tfsdk:"name"` + Recommended types.Bool `tfsdk:"recommended"` + Selector types.String `tfsdk:"selector"` + + Version types.String `tfsdk:"version"` + VersionID types.String `tfsdk:"version_id"` +} + +func (m *SystemSoftwareDataSourceModel) SelectorOrDefault() string { + if m.Selector.IsNull() { + return "*" + } + return m.Selector.ValueString() +} + +func (d *SystemSoftwareDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_systemsoftware" +} + +func (d *SystemSoftwareDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "A data source that selects versions of system components, such as PHP, MySQL, etc.", + + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + MarkdownDescription: "The system software name", + Required: true, + }, + "recommended": schema.BoolAttribute{ + MarkdownDescription: "Set this to just select the recommended version", + Optional: true, + }, + "selector": schema.StringAttribute{ + MarkdownDescription: "A version selector, such as `>= 7.4`", + Optional: true, + }, + "version": schema.StringAttribute{ + MarkdownDescription: "The selected version", + Computed: true, + }, + "version_id": schema.StringAttribute{ + MarkdownDescription: "The selected version ID", + Computed: true, + }, + }, + } +} + +func (d *SystemSoftwareDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(mittwaldv2.ClientBuilder) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *SystemSoftwareDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data SystemSoftwareDataSourceModel + + // Read Terraform configuration data into the model + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + systemSoftware, ok, err := d.client.App().GetSystemSoftwareByName(ctx, data.Name.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Failed to get system software", err.Error()) + return + } else if !ok { + resp.Diagnostics.AddError("System software not found", fmt.Sprintf("System software '%s' not found", data.Name.ValueString())) + return + } + + versions, err := d.client.App().SelectSystemSoftwareVersion(ctx, systemSoftware.Id, data.SelectorOrDefault()) + if err != nil { + resp.Diagnostics.AddError("Failed to get recommended system software version", err.Error()) + return + } + + if data.Recommended.ValueBool() { + recommended, ok := versions.Recommended() + if !ok { + resp.Diagnostics.AddError("No recommended system software version found", fmt.Sprintf("No recommended version found for '%s'", data.Name.ValueString())) + return + } + + data.Version = types.StringValue(recommended.InternalVersion) + data.VersionID = types.StringValue(recommended.Id.String()) + } else { + data.Version = types.StringValue(versions[len(versions)-1].InternalVersion) + data.VersionID = types.StringValue(versions[len(versions)-1].Id.String()) + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +}