Skip to content
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

(feat): Add data sources for all resources, and add service account resource #6

Merged
merged 1 commit into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,15 @@ provider "pomerium" {
shared_secret_b64 = "9OkZR6hwfmVD3a7Sfmgq58lUbFJGGz4hl/R9xbHFCAg="
}

# resource "pomerium_namespace" "test_namespace" {
# name = "test-namespace"
# parent_id = "9d8dbd2c-8cce-4e66-9c1f-c490b4a07243"
# }

locals {
namespace_id = "9d8dbd2c-8cce-4e66-9c1f-c490b4a07243"
# Create resources
resource "pomerium_namespace" "test_namespace" {
name = "test-namespace"
parent_id = "9d8dbd2c-8cce-4e66-9c1f-c490b4a07243"
}

resource "pomerium_policy" "test_policy" {
name = "test-policy"
namespace_id = local.namespace_id
namespace_id = pomerium_namespace.test_namespace.id
ppl = <<EOF
- allow:
and:
Expand All @@ -35,8 +32,26 @@ EOF

resource "pomerium_route" "test_route" {
name = "test-route"
namespace_id = local.namespace_id
namespace_id = pomerium_namespace.test_namespace.id
from = "https://verify-tf.localhost.pomerium.io"
to = ["https://verify.pomerium.com"]
policies = [pomerium_policy.test_policy.id]
}

# Data source examples
data "pomerium_namespace" "existing_namespace" {
id = "9d8dbd2c-8cce-4e66-9c1f-c490b4a07243"
}

data "pomerium_route" "existing_route" {
id = pomerium_route.test_route.id
}

# Output examples
output "namespace_name" {
value = data.pomerium_namespace.existing_namespace.name
}

output "route_from" {
value = data.pomerium_route.existing_route.from
}
100 changes: 100 additions & 0 deletions internal/provider/namespace_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
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"

client "github.com/pomerium/enterprise-client-go"
"github.com/pomerium/enterprise-client-go/pb"
)

var _ datasource.DataSource = &NamespaceDataSource{}

func NewNamespaceDataSource() datasource.DataSource {
return &NamespaceDataSource{}
}

type NamespaceDataSource struct {
client *client.Client
}

type NamespaceDataSourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
ParentID types.String `tfsdk:"parent_id"`
}

func (d *NamespaceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_namespace"
}

func (d *NamespaceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Namespace data source",

Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Required: true,
Description: "Unique identifier for the namespace.",
},
"name": schema.StringAttribute{
Computed: true,
Description: "Name of the namespace.",
},
"parent_id": schema.StringAttribute{
Computed: true,
Description: "ID of the parent namespace.",
},
},
}
}

func (d *NamespaceDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T.", req.ProviderData),
)
return
}

d.client = client
}

func (d *NamespaceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data NamespaceDataSourceModel

resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

namespaceResp, err := d.client.NamespaceService.GetNamespace(ctx, &pb.GetNamespaceRequest{
Id: data.ID.ValueString(),
})
if err != nil {
resp.Diagnostics.AddError("Error reading namespace", err.Error())
return
}

diags := ConvertNamespaceFromPB(&NamespaceResourceModel{
ID: data.ID,
Name: data.Name,
ParentID: data.ParentID,
}, namespaceResp.Namespace)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
106 changes: 106 additions & 0 deletions internal/provider/policy_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
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"

client "github.com/pomerium/enterprise-client-go"
"github.com/pomerium/enterprise-client-go/pb"
)

var _ datasource.DataSource = &PolicyDataSource{}

func NewPolicyDataSource() datasource.DataSource {
return &PolicyDataSource{}
}

type PolicyDataSource struct {
client *client.Client
}

type PolicyDataSourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
NamespaceID types.String `tfsdk:"namespace_id"`
PPL types.String `tfsdk:"ppl"`
}

func (d *PolicyDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_policy"
}

func (d *PolicyDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Policy data source",

Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Required: true,
Description: "Unique identifier for the policy.",
},
"name": schema.StringAttribute{
Computed: true,
Description: "Name of the policy.",
},
"namespace_id": schema.StringAttribute{
Computed: true,
Description: "ID of the namespace the policy belongs to.",
},
"ppl": schema.StringAttribute{
Computed: true,
Description: "Policy Policy Language (PPL) string.",
},
},
}
}

func (d *PolicyDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T.", req.ProviderData),
)
return
}

d.client = client
}

func (d *PolicyDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data PolicyDataSourceModel

resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

policyResp, err := d.client.PolicyService.GetPolicy(ctx, &pb.GetPolicyRequest{
Id: data.ID.ValueString(),
})
if err != nil {
resp.Diagnostics.AddError("Error reading policy", err.Error())
return
}

diags := ConvertPolicyFromPB(&PolicyResourceModel{
ID: data.ID,
Name: data.Name,
NamespaceID: data.NamespaceID,
PPL: data.PPL,
}, policyResp.Policy)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
8 changes: 7 additions & 1 deletion internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,17 @@ func (p *PomeriumProvider) Resources(_ context.Context) []func() resource.Resour
NewNamespaceResource,
NewRouteResource,
NewPolicyResource,
NewServiceAccountResource,
}
}

func (p *PomeriumProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{}
return []func() datasource.DataSource{
NewServiceAccountDataSource,
NewRouteDataSource,
NewNamespaceDataSource,
NewPolicyDataSource,
}
}

func (p *PomeriumProvider) Functions(_ context.Context) []func() function.Function {
Expand Down
120 changes: 120 additions & 0 deletions internal/provider/route_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
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"

client "github.com/pomerium/enterprise-client-go"
"github.com/pomerium/enterprise-client-go/pb"
)

var _ datasource.DataSource = &RouteDataSource{}

func NewRouteDataSource() datasource.DataSource {
return &RouteDataSource{}
}

type RouteDataSource struct {
client *client.Client
}

type RouteDataSourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
From types.String `tfsdk:"from"`
To types.List `tfsdk:"to"`
NamespaceID types.String `tfsdk:"namespace_id"`
Policies types.List `tfsdk:"policies"`
}

func (d *RouteDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_route"
}

func (d *RouteDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Route data source",

Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Required: true,
Description: "Unique identifier for the route.",
},
"name": schema.StringAttribute{
Computed: true,
Description: "Name of the route.",
},
"from": schema.StringAttribute{
Computed: true,
Description: "From URL.",
},
"to": schema.ListAttribute{
Computed: true,
ElementType: types.StringType,
Description: "To URLs.",
},
"namespace_id": schema.StringAttribute{
Computed: true,
Description: "ID of the namespace the route belongs to.",
},
"policies": schema.ListAttribute{
Computed: true,
ElementType: types.StringType,
Description: "List of policy IDs associated with the route.",
},
},
}
}

func (d *RouteDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T.", req.ProviderData),
)
return
}

d.client = client
}

func (d *RouteDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data RouteDataSourceModel

resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

routeResp, err := d.client.RouteService.GetRoute(ctx, &pb.GetRouteRequest{
Id: data.ID.ValueString(),
})
if err != nil {
resp.Diagnostics.AddError("Error reading route", err.Error())
return
}

diags := ConvertRouteFromPB(&RouteResourceModel{
ID: data.ID,
Name: data.Name,
From: data.From,
To: data.To,
NamespaceID: data.NamespaceID,
Policies: data.Policies,
}, routeResp.Route)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
Loading
Loading