teamcity/global.go (274 lines of code) (raw):
package teamcity
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/types"
"terraform-provider-teamcity/client"
)
var (
_ resource.Resource = &globalResource{}
_ resource.ResourceWithConfigure = &globalResource{}
_ resource.ResourceWithImportState = &globalResource{}
)
func NewGlobalResource() resource.Resource {
return &globalResource{}
}
type globalResource struct {
client *client.Client
}
type globalResourceModel struct {
ArtifactDirectories types.String `tfsdk:"artifact_directories"`
RootUrl types.String `tfsdk:"root_url"`
MaxArtifactSize types.Int64 `tfsdk:"max_artifact_size"`
MaxArtifactNumber types.Int64 `tfsdk:"max_artifact_number"`
DefaultExecutionTimeout types.Int64 `tfsdk:"default_execution_timeout"`
DefaultVCSCheckInterval types.Int64 `tfsdk:"default_vcs_check_interval"`
EnforceDefaultVCSCheckInterval types.Bool `tfsdk:"enforce_default_vcs_check_interval"`
DefaultQuietPeriod types.Int64 `tfsdk:"default_quiet_period"`
Encryption *EncryptionModel `tfsdk:"encryption"`
ArtifactIsolation *ArtifactIsolationModel `tfsdk:"artifacts_domain_isolation"`
}
type EncryptionModel struct {
Key types.String `tfsdk:"key"`
}
type ArtifactIsolationModel struct {
Enabled types.Bool `tfsdk:"enabled"`
ArtifactsUrl types.String `tfsdk:"artifacts_url"`
}
func (r *globalResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
r.client = req.ProviderData.(*client.Client)
}
func (r *globalResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_global_settings"
}
func (r *globalResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "[General TeamCity configuration](https://www.jetbrains.com/help/teamcity/teamcity-configuration-and-maintenance.html#TeamCity+Configuration)",
Attributes: map[string]schema.Attribute{
"artifact_directories": schema.StringAttribute{
Optional: true,
Computed: true,
Default: stringdefault.StaticString("system/artifacts"),
},
"root_url": schema.StringAttribute{
Optional: true,
Computed: true,
Default: stringdefault.StaticString("http://localhost:8111"),
},
"max_artifact_size": schema.Int64Attribute{
Optional: true,
Computed: true,
Default: int64default.StaticInt64(314572800),
},
"max_artifact_number": schema.Int64Attribute{
Optional: true,
Computed: true,
Default: int64default.StaticInt64(1000),
},
"default_execution_timeout": schema.Int64Attribute{
Optional: true,
Computed: true,
Default: int64default.StaticInt64(0),
},
"default_vcs_check_interval": schema.Int64Attribute{
Optional: true,
Computed: true,
Default: int64default.StaticInt64(60),
},
"enforce_default_vcs_check_interval": schema.BoolAttribute{
Optional: true,
Computed: true,
Default: booldefault.StaticBool(false),
},
"default_quiet_period": schema.Int64Attribute{
Optional: true,
Computed: true,
Default: int64default.StaticInt64(60),
},
"encryption": schema.SingleNestedAttribute{
Optional: true,
Computed: true,
Attributes: map[string]schema.Attribute{
"key": schema.StringAttribute{
Required: true,
Sensitive: true,
},
},
Default: objectdefault.StaticValue(types.ObjectNull(
map[string]attr.Type{"key": types.StringType},
)),
},
"artifacts_domain_isolation": schema.SingleNestedAttribute{
Optional: true,
Computed: true,
Attributes: map[string]schema.Attribute{
"enabled": schema.BoolAttribute{
Optional: true,
Computed: true,
Default: booldefault.StaticBool(true),
Description: "Enabled by default, set false if it needs to be disabled",
},
"artifacts_url": schema.StringAttribute{
Optional: true,
Computed: true,
},
},
Default: objectdefault.StaticValue(types.ObjectValueMust(
map[string]attr.Type{
"enabled": types.BoolType,
"artifacts_url": types.StringType,
},
map[string]attr.Value{
"enabled": types.BoolValue(true),
"artifacts_url": types.StringValue(""),
},
)),
},
},
}
}
func (r *globalResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan globalResourceModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
newState, err := r.update(plan)
if err != nil {
resp.Diagnostics.AddError(
"Error setting global settings",
err.Error(),
)
return
}
if newState.Encryption != nil {
newState.Encryption.Key = plan.Encryption.Key
}
diags = resp.State.Set(ctx, newState)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
func (r *globalResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var oldState globalResourceModel
diags := req.State.Get(ctx, &oldState)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
result, err := r.client.GetGlobalSettings()
if err != nil {
resp.Diagnostics.AddError(
"Unable to read global settings",
err.Error(),
)
return
}
newState, err := r.readState(*result)
if err != nil {
resp.Diagnostics.AddError(
"Unable to read global settings",
err.Error(),
)
return
}
if newState.Encryption != nil {
newState.Encryption.Key = oldState.Encryption.Key
}
diags = resp.State.Set(ctx, newState)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
func (r *globalResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var plan globalResourceModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
newState, err := r.update(plan)
if err != nil {
resp.Diagnostics.AddError(
"Error setting global settings",
err.Error(),
)
return
}
if newState.Encryption != nil {
newState.Encryption.Key = plan.Encryption.Key
}
diags = resp.State.Set(ctx, newState)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
func (r *globalResource) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {
}
func (r *globalResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resp.State.Set(ctx, globalResourceModel{})
}
func (r *globalResource) update(plan globalResourceModel) (*globalResourceModel, error) {
var key string
if plan.Encryption != nil {
v := plan.Encryption.Key.ValueString()
key = v
}
enableArtifactsDomainIsolation := true
var artifactsURL string
if plan.ArtifactIsolation != nil {
enableArtifactsDomainIsolation = plan.ArtifactIsolation.Enabled.ValueBool()
artifactsURL = plan.ArtifactIsolation.ArtifactsUrl.ValueString()
}
settings := client.GlobalSettings{
ArtifactDirectories: plan.ArtifactDirectories.ValueString(),
RootUrl: plan.RootUrl.ValueString(),
MaxArtifactSize: plan.MaxArtifactSize.ValueInt64(),
MaxArtifactNumber: plan.MaxArtifactNumber.ValueInt64(),
DefaultExecutionTimeout: plan.DefaultExecutionTimeout.ValueInt64(),
DefaultVCSCheckInterval: plan.DefaultVCSCheckInterval.ValueInt64(),
EnforceDefaultVCSCheckInterval: plan.EnforceDefaultVCSCheckInterval.ValueBool(),
DefaultQuietPeriod: plan.DefaultQuietPeriod.ValueInt64(),
UseEncryption: plan.Encryption != nil,
EncryptionKey: key,
ArtifactsDomainIsolation: enableArtifactsDomainIsolation,
ArtifactsUrl: artifactsURL,
}
result, err := r.client.SetGlobalSettings(settings)
if err != nil {
return nil, err
}
return r.readState(*result)
}
func (r *globalResource) readState(result client.GlobalSettings) (*globalResourceModel, error) {
var state globalResourceModel
state.ArtifactDirectories = types.StringValue(result.ArtifactDirectories)
state.RootUrl = types.StringValue(result.RootUrl)
state.MaxArtifactSize = types.Int64Value(result.MaxArtifactSize)
state.MaxArtifactNumber = types.Int64Value(result.MaxArtifactNumber)
state.DefaultExecutionTimeout = types.Int64Value(result.DefaultExecutionTimeout)
state.DefaultVCSCheckInterval = types.Int64Value(result.DefaultVCSCheckInterval)
state.EnforceDefaultVCSCheckInterval = types.BoolValue(result.EnforceDefaultVCSCheckInterval)
state.DefaultQuietPeriod = types.Int64Value(result.DefaultQuietPeriod)
if result.UseEncryption {
state.Encryption = &EncryptionModel{}
}
state.ArtifactIsolation = &ArtifactIsolationModel{
Enabled: types.BoolValue(result.ArtifactsDomainIsolation),
ArtifactsUrl: types.StringValue(result.ArtifactsUrl),
}
return &state, nil
}