-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from aidy/apps
Add application and certificate template resources
- Loading branch information
Showing
8 changed files
with
1,076 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "tlspc_ca_product Data Source - tlspc" | ||
subcategory: "" | ||
description: |- | ||
--- | ||
|
||
# tlspc_ca_product (Data Source) | ||
|
||
|
||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `ca_name` (String) | ||
- `product_option` (String) | ||
- `type` (String) | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "tlspc_application Resource - tlspc" | ||
subcategory: "" | ||
description: |- | ||
--- | ||
|
||
# tlspc_application (Resource) | ||
|
||
|
||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `ca_template_aliases` (Map of String) | ||
- `name` (String) | ||
- `owners` (Set of Map of String) | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "tlspc_certificate_template Resource - tlspc" | ||
subcategory: "" | ||
description: |- | ||
--- | ||
|
||
# tlspc_certificate_template (Resource) | ||
|
||
|
||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `ca_product_id` (String) | ||
- `ca_type` (String) | ||
- `key_reuse` (Boolean) | ||
- `name` (String) | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,286 @@ | ||
// Copyright (c) Venafi, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package provider | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"terraform-provider-tlspc/internal/tlspc" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/attr" | ||
"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/types" | ||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes" | ||
) | ||
|
||
var ( | ||
_ resource.Resource = &applicationResource{} | ||
_ resource.ResourceWithConfigure = &applicationResource{} | ||
_ resource.ResourceWithImportState = &applicationResource{} | ||
) | ||
|
||
type applicationResource struct { | ||
client *tlspc.Client | ||
} | ||
|
||
func NewApplicationResource() resource.Resource { | ||
return &applicationResource{} | ||
} | ||
|
||
func (r *applicationResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { | ||
resp.TypeName = req.ProviderTypeName + "_application" | ||
} | ||
|
||
func (r *applicationResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { | ||
resp.Schema = schema.Schema{ | ||
Attributes: map[string]schema.Attribute{ | ||
"id": schema.StringAttribute{ | ||
Computed: true, | ||
}, | ||
"name": schema.StringAttribute{ | ||
Required: true, | ||
}, | ||
"owners": schema.SetAttribute{ | ||
Required: true, | ||
ElementType: basetypes.MapType{ | ||
ElemType: types.StringType, | ||
}, | ||
}, | ||
"ca_template_aliases": schema.MapAttribute{ | ||
Required: true, | ||
ElementType: types.StringType, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func (r *applicationResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { | ||
if req.ProviderData == nil { | ||
return | ||
} | ||
|
||
client, ok := req.ProviderData.(*tlspc.Client) | ||
|
||
if !ok { | ||
resp.Diagnostics.AddError( | ||
"Unexpected Data Source Configure Type", | ||
fmt.Sprintf("Expected *tlspc.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), | ||
) | ||
|
||
return | ||
} | ||
|
||
r.client = client | ||
} | ||
|
||
type applicationResourceModel struct { | ||
ID types.String `tfsdk:"id"` | ||
Name types.String `tfsdk:"name"` | ||
Owners []types.Map `tfsdk:"owners"` | ||
CATemplateAliases types.Map `tfsdk:"ca_template_aliases"` | ||
} | ||
|
||
func (r *applicationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { | ||
var plan applicationResourceModel | ||
diags := req.Plan.Get(ctx, &plan) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
owners := []tlspc.OwnerAndType{} | ||
for _, v := range plan.Owners { | ||
m := v.Elements() | ||
// TODO: Work out how you're supposed to get an unquoted string out | ||
kind := strings.Trim(m["type"].String(), `"`) | ||
ownerId := strings.Trim(m["owner"].String(), `"`) | ||
if kind != "USER" && kind != "TEAM" { | ||
resp.Diagnostics.AddError( | ||
"Error creating application", | ||
"Could not create application, unsupported owner type: "+kind, | ||
) | ||
return | ||
} | ||
if ownerId == "" { | ||
resp.Diagnostics.AddError( | ||
"Error creating application", | ||
"Could not create application, undefined owner", | ||
) | ||
return | ||
} | ||
owner := tlspc.OwnerAndType{ | ||
ID: ownerId, | ||
Type: kind, | ||
} | ||
owners = append(owners, owner) | ||
} | ||
|
||
aliases := map[string]string{} | ||
for k, v := range plan.CATemplateAliases.Elements() { | ||
aliases[k] = strings.Trim(v.String(), `"`) | ||
} | ||
|
||
application := tlspc.Application{ | ||
Name: plan.Name.ValueString(), | ||
Owners: owners, | ||
CertificateTemplates: aliases, | ||
} | ||
created, err := r.client.CreateApplication(application) | ||
if err != nil { | ||
resp.Diagnostics.AddError( | ||
"Error creating application", | ||
"Could not create application, unexpected error: "+err.Error(), | ||
) | ||
return | ||
} | ||
plan.ID = types.StringValue(created.ID) | ||
diags = resp.State.Set(ctx, plan) | ||
resp.Diagnostics.Append(diags...) | ||
} | ||
|
||
func (r *applicationResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { | ||
var state applicationResourceModel | ||
|
||
diags := req.State.Get(ctx, &state) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
app, err := r.client.GetApplication(state.ID.ValueString()) | ||
if err != nil { | ||
resp.Diagnostics.AddError( | ||
"Error Reading Application", | ||
"Could not read application ID "+state.ID.ValueString()+": "+err.Error(), | ||
) | ||
return | ||
} | ||
|
||
state.ID = types.StringValue(app.ID) | ||
state.Name = types.StringValue(app.Name) | ||
|
||
owners := []types.Map{} | ||
for _, v := range app.Owners { | ||
owner := map[string]attr.Value{ | ||
"type": types.StringValue(v.Type), | ||
"owner": types.StringValue(v.ID), | ||
} | ||
ownermap, diags := types.MapValue(types.StringType, owner) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
owners = append(owners, ownermap) | ||
} | ||
state.Owners = owners | ||
|
||
aliases := map[string]attr.Value{} | ||
for k, v := range app.CertificateTemplates { | ||
aliases[k] = types.StringValue(v) | ||
} | ||
|
||
aliasmap, diags := types.MapValue(types.StringType, aliases) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
state.CATemplateAliases = aliasmap | ||
|
||
diags = resp.State.Set(ctx, state) | ||
resp.Diagnostics.Append(diags...) | ||
} | ||
|
||
func (r *applicationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { | ||
var plan, state applicationResourceModel | ||
|
||
diags := req.State.Get(ctx, &state) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
diags = req.Plan.Get(ctx, &plan) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
owners := []tlspc.OwnerAndType{} | ||
for _, v := range plan.Owners { | ||
m := v.Elements() | ||
// TODO: Work out how you're supposed to get an unquoted string out | ||
kind := strings.Trim(m["type"].String(), `"`) | ||
ownerId := strings.Trim(m["owner"].String(), `"`) | ||
if kind != "USER" && kind != "TEAM" { | ||
resp.Diagnostics.AddError( | ||
"Error creating application", | ||
"Could not create application, unsupported owner type: "+kind, | ||
) | ||
return | ||
} | ||
if ownerId == "" { | ||
resp.Diagnostics.AddError( | ||
"Error creating application", | ||
"Could not create application, undefined owner", | ||
) | ||
return | ||
} | ||
owner := tlspc.OwnerAndType{ | ||
ID: ownerId, | ||
Type: kind, | ||
} | ||
owners = append(owners, owner) | ||
} | ||
|
||
aliases := map[string]string{} | ||
for k, v := range plan.CATemplateAliases.Elements() { | ||
aliases[k] = strings.Trim(v.String(), `"`) | ||
} | ||
|
||
application := tlspc.Application{ | ||
ID: state.ID.ValueString(), | ||
Name: plan.Name.ValueString(), | ||
Owners: owners, | ||
CertificateTemplates: aliases, | ||
} | ||
|
||
updated, err := r.client.UpdateApplication(application) | ||
if err != nil { | ||
resp.Diagnostics.AddError( | ||
"Error updating application", | ||
"Could not update application, unexpected error: "+err.Error(), | ||
) | ||
return | ||
} | ||
plan.ID = types.StringValue(updated.ID) | ||
diags = resp.State.Set(ctx, plan) | ||
resp.Diagnostics.Append(diags...) | ||
} | ||
|
||
func (r *applicationResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { | ||
var state applicationResourceModel | ||
|
||
diags := req.State.Get(ctx, &state) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
err := r.client.DeleteApplication(state.ID.ValueString()) | ||
if err != nil { | ||
resp.Diagnostics.AddError( | ||
"Error Deleting Application", | ||
"Could not delete Application ID "+state.ID.ValueString()+": "+err.Error(), | ||
) | ||
return | ||
} | ||
} | ||
|
||
func (r *applicationResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { | ||
// Retrieve import ID and save to id attribute | ||
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) | ||
} |
Oops, something went wrong.