Skip to content

Commit

Permalink
Added buildpacks datasource
Browse files Browse the repository at this point in the history
  • Loading branch information
Dray56 authored and debTheRay committed Nov 6, 2024
1 parent af605c9 commit 3dc929a
Show file tree
Hide file tree
Showing 11 changed files with 844 additions and 2 deletions.
58 changes: 58 additions & 0 deletions docs/data-sources/buildpacks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
page_title: "cloudfoundry_buildpacks Data Source - terraform-provider-cloudfoundry"
subcategory: ""
description: |-
Gets information of Cloud Foundry buildpacks present.
---

# cloudfoundry_buildpacks (Data Source)

Gets information of Cloud Foundry buildpacks present.

## Example Usage

```terraform
data "cloudfoundry_buildpacks" "buildpack" {
name = "java_buildpack"
}
output "buildpack" {
value = data.cloudfoundry_buildpacks.buildpack
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- `name` (String) Name of the buildpack to filter by
- `stack` (String) The name of the stack to filter by

### Read-Only

- `buildpacks` (Attributes List) The list of buildpacks (see [below for nested schema](#nestedatt--buildpacks))

<a id="nestedatt--buildpacks"></a>
### Nested Schema for `buildpacks`

Required:

- `name` (String) Name of the buildpack

Optional:

- `annotations` (Map of String) The annotations associated with Cloud Foundry resources. Add as described [here](https://docs.cloudfoundry.org/adminguide/metadata.html#-view-metadata-for-an-object).
- `enabled` (Boolean) Whether or not the buildpack can be used for staging
- `labels` (Map of String) The labels associated with Cloud Foundry resources. Add as described [here](https://docs.cloudfoundry.org/adminguide/metadata.html#-view-metadata-for-an-object).
- `locked` (Boolean) Whether or not the buildpack is locked to prevent updating the bits
- `position` (Number) The order in which the buildpacks are checked during buildpack auto-detection
- `stack` (String) The name of the stack that the buildpack will use

Read-Only:

- `created_at` (String) The date and time when the resource was created in [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) format.
- `filename` (String) The filename of the buildpack
- `id` (String) The GUID of the object.
- `state` (String) The state of the buildpack
- `updated_at` (String) The date and time when the resource was updated in [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) format.
7 changes: 7 additions & 0 deletions examples/data-sources/cloudfoundry_buildpacks/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
data "cloudfoundry_buildpacks" "buildpack" {
name = "java_buildpack"
}

output "buildpack" {
value = data.cloudfoundry_buildpacks.buildpack
}
154 changes: 154 additions & 0 deletions internal/provider/datasource_buildpacks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package provider

import (
"context"
"fmt"

cfv3client "github.com/cloudfoundry/go-cfclient/v3/client"
"github.com/cloudfoundry/terraform-provider-cloudfoundry/internal/provider/managers"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

var _ datasource.DataSource = &buildpacksDataSource{}
var _ datasource.DataSourceWithConfigure = &buildpacksDataSource{}

func NewBuildpacksDataSource() datasource.DataSource {
return &buildpacksDataSource{}
}

type buildpacksDataSource struct {
cfClient *cfv3client.Client
}

func (d *buildpacksDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_buildpacks"
}

func (d *buildpacksDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
session, ok := req.ProviderData.(*managers.Session)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *managers.Session, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}
d.cfClient = session.CFClient
}

func (d *buildpacksDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Gets information of Cloud Foundry buildpacks present.",
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
MarkdownDescription: "Name of the buildpack to filter by",
Optional: true,
},
"stack": schema.StringAttribute{
MarkdownDescription: "The name of the stack to filter by",
Optional: true,
},
"buildpacks": schema.ListNestedAttribute{
MarkdownDescription: "The list of buildpacks",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
MarkdownDescription: "Name of the buildpack",
Required: true,
},
"stack": schema.StringAttribute{
MarkdownDescription: "The name of the stack that the buildpack will use",
Optional: true,
},
"position": schema.Int64Attribute{
MarkdownDescription: "The order in which the buildpacks are checked during buildpack auto-detection",
Optional: true,
Computed: true,
},
"enabled": schema.BoolAttribute{
MarkdownDescription: "Whether or not the buildpack can be used for staging",
Optional: true,
Computed: true,
},
"locked": schema.BoolAttribute{
MarkdownDescription: "Whether or not the buildpack is locked to prevent updating the bits",
Optional: true,
Computed: true,
},
"state": schema.StringAttribute{
MarkdownDescription: "The state of the buildpack",
Computed: true,
},
"filename": schema.StringAttribute{
MarkdownDescription: "The filename of the buildpack",
Computed: true,
},
labelsKey: resourceLabelsSchema(),
annotationsKey: resourceAnnotationsSchema(),
createdAtKey: createdAtSchema(),
updatedAtKey: updatedAtSchema(),
idKey: guidSchema(),
},
},
},
},
}
}

func (d *buildpacksDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {

var data datasourceBuildpacksType

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

blo := cfv3client.NewBuildpackListOptions()

if !data.Name.IsNull() {
blo.Names = cfv3client.Filter{
Values: []string{
data.Name.ValueString(),
},
}
}
if !data.Stack.IsNull() {
blo.Stacks = cfv3client.Filter{
Values: []string{
data.Stack.ValueString(),
},
}
}

buildpacks, err := d.cfClient.Buildpacks.ListAll(ctx, blo)
if err != nil {
resp.Diagnostics.AddError(
"API Error Fetching Buildpacks",
"Response failed with %s"+err.Error(),
)
return
}

if len(buildpacks) == 0 {
resp.Diagnostics.AddError(
"Unable to find any buildpack in the list",
"No buildpack present with mentioned criteria",
)
return
}

data.Buildpacks, diags = mapBuildpacksValuesToType(ctx, buildpacks)
resp.Diagnostics.Append(diags...)

tflog.Trace(ctx, "read the buildpacks data source")
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
105 changes: 105 additions & 0 deletions internal/provider/datasource_buildpacks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package provider

import (
"bytes"
"regexp"
"testing"
"text/template"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

type BuildpacksModelPtr struct {
HclType string
HclObjectName string
Name *string
Stack *string
Buildpacks *string
}

func hclBuildpacks(ddsmp *BuildpacksModelPtr) string {
if ddsmp != nil {
s := `
{{.HclType}} "cloudfoundry_buildpacks" "{{.HclObjectName}}" {
{{- if .Name}}
name = "{{.Name}}"
{{- end -}}
{{if .Stack}}
stack = "{{.Stack}}"
{{- end }}
{{if .Buildpacks}}
buildpacks = {{.Buildpacks}}
{{- end }}
}`
tmpl, err := template.New("buildpacks").Parse(s)
if err != nil {
panic(err)
}
buf := new(bytes.Buffer)
err = tmpl.Execute(buf, ddsmp)
if err != nil {
panic(err)
}
return buf.String()
}
return ddsmp.HclType + ` cloudfoundry_Buildpacks" ` + ddsmp.HclObjectName + ` {}`
}
func TestBuildpacksDataSource_Configure(t *testing.T) {
resourceName := "data.cloudfoundry_buildpacks.ds"
buildpackName := "java_buildpack"
stackName := "cflinuxfs4"
t.Parallel()
t.Run("error path - get buildpacks", func(t *testing.T) {
cfg := getCFHomeConf()
rec := cfg.SetupVCR(t, "fixtures/datasource_buildpacks_invalid")
defer stopQuietly(rec)

resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProtoV6ProviderFactories: getProviders(rec.GetDefaultClient()),
Steps: []resource.TestStep{
{
Config: hclProvider(nil) + hclBuildpacks(&BuildpacksModelPtr{
HclType: hclObjectDataSource,
HclObjectName: "ds",
Name: &invalidOrgGUID,
}),
ExpectError: regexp.MustCompile(`Unable to find any buildpack in the list`),
},
},
})
})
t.Run("happy path - get buildpacks", func(t *testing.T) {
cfg := getCFHomeConf()

rec := cfg.SetupVCR(t, "fixtures/datasource_buildpacks")
defer stopQuietly(rec)

resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProtoV6ProviderFactories: getProviders(rec.GetDefaultClient()),
Steps: []resource.TestStep{
{
Config: hclProvider(nil) + hclBuildpacks(&BuildpacksModelPtr{
HclType: hclObjectDataSource,
HclObjectName: "ds",
Name: &buildpackName,
}),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "buildpacks.#", "2"),
),
},
{
Config: hclProvider(nil) + hclBuildpacks(&BuildpacksModelPtr{
HclType: hclObjectDataSource,
HclObjectName: "ds",
Stack: &stackName,
}),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "buildpacks.#", "8"),
),
},
},
})
})
}
4 changes: 2 additions & 2 deletions internal/provider/datasource_domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ func (d *DomainsDataSource) Read(ctx context.Context, req datasource.ReadRequest
if err != nil {
resp.Diagnostics.AddError(
"API Error Fetching Domains",
"Could not get domains for organization "+data.Org.ValueString()+" : "+err.Error(),
"Could not get domains : "+err.Error(),
)
return
}

if len(domains) == 0 {
resp.Diagnostics.AddError(
"Unable to find any domain in the list",
fmt.Sprintf("No domain present under org %s with mentioned criteria", data.Org.ValueString()),
"No domain present with mentioned criteria",
)
return
}
Expand Down
Loading

0 comments on commit 3dc929a

Please sign in to comment.