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

data source/allocations: add new data source #358

Merged
merged 3 commits into from
Jul 27, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

* **New Resource**: `nomad_node_pool` manages node pools ([#340](https://github.com/hashicorp/terraform-provider-nomad/pull/340))
* **New Resource**: `nomad_variable` manages Nomad variables ([#325](https://github.com/hashicorp/terraform-provider-nomad/pull/325))
* **New Data Source**: `nomad_allocations` to retrieve a list of allocations ([#358](https://github.com/hashicorp/terraform-provider-nomad/pull/358))
* **New Data Source**: `nomad_node_pool` and `nomad_node_pools` to retrieves one or mode node pools ([#340](https://github.com/hashicorp/terraform-provider-nomad/pull/340))
* **New Data Source**: `nomad_variable` retrieves a Nomad variable ([#325](https://github.com/hashicorp/terraform-provider-nomad/pull/325))

Expand Down
163 changes: 163 additions & 0 deletions nomad/data_source_allocations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package nomad
lgfa29 marked this conversation as resolved.
Show resolved Hide resolved

import (
"fmt"
"log"
"strconv"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceAllocations() *schema.Resource {
return &schema.Resource{
Read: dataSourceAllocationsRead,

Schema: map[string]*schema.Schema{
"prefix": {
Description: "Specifies a string to filter node pools based on a name prefix.",
Type: schema.TypeString,
Optional: true,
},
"filter": {
Description: "Specifies the expression used to filter the results.",
Type: schema.TypeString,
Optional: true,
},
"allocations": {
Description: "List of node pools returned",
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
},
"eval_id": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"namespace": {
Type: schema.TypeString,
Computed: true,
},
"node_id": {
Type: schema.TypeString,
Computed: true,
},
"node_name": {
Type: schema.TypeString,
Computed: true,
},
"job_id": {
Type: schema.TypeString,
Computed: true,
},
"job_type": {
Type: schema.TypeString,
Computed: true,
},
"job_version": {
Type: schema.TypeInt,
Computed: true,
},
"task_group": {
Type: schema.TypeString,
Computed: true,
},
"desired_status": {
Type: schema.TypeString,
Computed: true,
},
"client_status": {
Type: schema.TypeString,
Computed: true,
},
"followup_eval_id": {
Type: schema.TypeString,
Computed: true,
},
"next_allocation": {
Type: schema.TypeString,
Computed: true,
},
"preempted_by_allocation": {
Type: schema.TypeString,
Computed: true,
},
"create_index": {
Type: schema.TypeInt,
Computed: true,
},
"modify_index": {
Type: schema.TypeInt,
Computed: true,
},
"create_time": {
Type: schema.TypeInt,
Computed: true,
},
"modify_time": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
}
}

func dataSourceAllocationsRead(d *schema.ResourceData, meta any) error {
client := meta.(ProviderConfig).client

prefix := d.Get("prefix").(string)
filter := d.Get("filter").(string)
id := strconv.Itoa(schema.HashString(prefix + filter))

log.Printf("[DEBUG] Reading allocation list")
resp, _, err := client.Allocations().List(&api.QueryOptions{
Prefix: prefix,
Filter: filter,
})
if err != nil {
return fmt.Errorf("error reading allocations: %w", err)
}

allocs := make([]map[string]any, len(resp))
for i, alloc := range resp {
allocs[i] = map[string]any{
"id": alloc.ID,
"eval_id": alloc.EvalID,
"name": alloc.Name,
"namespace": alloc.Namespace,
"node_id": alloc.NodeID,
"node_name": alloc.NodeName,
"job_id": alloc.JobID,
"job_type": alloc.JobType,
"job_version": alloc.JobVersion,
"task_group": alloc.TaskGroup,
"desired_status": alloc.DesiredStatus,
"client_status": alloc.ClientStatus,
"followup_eval_id": alloc.FollowupEvalID,
"next_allocation": alloc.NextAllocation,
"preempted_by_allocation": alloc.PreemptedByAllocation,
"create_index": alloc.CreateIndex,
"modify_index": alloc.ModifyIndex,
"create_time": alloc.CreateTime,
"modify_time": alloc.ModifyTime,
}
}
log.Printf("[DEBUG] Read allocations")

d.SetId(id)
return d.Set("allocations", allocs)
}
105 changes: 105 additions & 0 deletions nomad/data_source_allocations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package nomad

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestDataSourceAllocations_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tf-nomad-test")
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testDataSourceAllocations_basicConfig(name),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.nomad_allocations.all", "allocations.#"),
resource.TestCheckResourceAttr("data.nomad_allocations.by_job", "allocations.#", "3"),
func(s *terraform.State) error {
resourceName := "data.nomad_allocations.by_job"
for i := 0; i < 2; i++ {
keyPrefix := fmt.Sprintf("allocations.%d", i)
err := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(resourceName, fmt.Sprintf("%s.eval_id", keyPrefix)),
resource.TestMatchResourceAttr(resourceName, fmt.Sprintf("%s.name", keyPrefix),
regexp.MustCompile(fmt.Sprintf("%s\\.sleep\\[\\d+\\]", name))),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.namespace", keyPrefix), api.DefaultNamespace),
resource.TestCheckResourceAttrSet(resourceName, fmt.Sprintf("%s.node_id", keyPrefix)),
resource.TestCheckResourceAttrSet(resourceName, fmt.Sprintf("%s.node_name", keyPrefix)),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.job_id", keyPrefix), name),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.job_type", keyPrefix), "service"),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.job_version", keyPrefix), "0"),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.task_group", keyPrefix), "sleep"),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.desired_status", keyPrefix), api.AllocDesiredStatusRun),
resource.TestCheckResourceAttrSet(resourceName, fmt.Sprintf("%s.client_status", keyPrefix)),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.followup_eval_id", keyPrefix), ""),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.next_allocation", keyPrefix), ""),
resource.TestCheckResourceAttr(resourceName, fmt.Sprintf("%s.preempted_by_allocation", keyPrefix), ""),
resource.TestCheckResourceAttrSet(resourceName, fmt.Sprintf("%s.create_index", keyPrefix)),
resource.TestCheckResourceAttrSet(resourceName, fmt.Sprintf("%s.modify_index", keyPrefix)),
resource.TestCheckResourceAttrSet(resourceName, fmt.Sprintf("%s.create_time", keyPrefix)),
resource.TestCheckResourceAttrSet(resourceName, fmt.Sprintf("%s.modify_time", keyPrefix)),
)(s)
if err != nil {
return err
}
}
return nil
},
),
},
},
CheckDestroy: testResourceJob_checkDestroy(name),
})
}

func testDataSourceAllocations_basicConfig(prefix string) string {
return fmt.Sprintf(`
resource "nomad_job" "test" {
jobspec = <<EOT
job "%[1]s" {
group "sleep" {
count = 3

task "sleep" {
driver = "raw_exec"

config {
command = "/bin/sleep"
args = ["10"]
}

resources {
cpu = 10
memory = 10
}

logs {
max_files = 1
max_file_size = 1
}
}
}
}
EOT
}

data "nomad_allocations" "all" {
depends_on = [nomad_job.test]
}

data "nomad_allocations" "by_job" {
filter = "JobID == \"${nomad_job.test.id}\""
}
`, prefix)
}
1 change: 1 addition & 0 deletions nomad/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ func Provider() *schema.Provider {
"nomad_acl_roles": dataSourceACLRoles(),
"nomad_acl_token": dataSourceACLToken(),
"nomad_acl_tokens": dataSourceACLTokens(),
"nomad_allocations": dataSourceAllocations(),
"nomad_datacenters": dataSourceDatacenters(),
"nomad_deployments": dataSourceDeployments(),
"nomad_job": dataSourceJob(),
Expand Down
56 changes: 56 additions & 0 deletions website/docs/d/allocations.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
layout: "nomad"
page_title: "Nomad: nomad_allocations"
sidebar_current: "docs-nomad-datasource-allocations"
description: |-
Retrieve a list of allocations from Nomad.
---

# nomad_allocations

Retrieve a list of allocations from Nomad.

## Example Usage

```hcl
data "nomad_allocations" "example" {
filter = "JobID == \"example\""
}
```

## Argument Reference

The following arguments are supported:

- `prefix` `(string: <optional>)` - Specifies a string to filter allocations
based on an ID prefix.
- `filter` `(string: <optional>)` - Specifies the
[expression][nomad_api_filter] used to filter the results.

## Attribute Reference

The following attributes are exported:

- `allocations` `(list of allocations)` - A list of allocations matching the
search criteria.
- `id` `(string)` - The ID of the allocation.
- `eval_id` `(string)` - The ID of the evaluation that generated the allocation.
- `name` `(string)` - The name of the allocation.
- `namespace` `(string)` - The namespace the allocation belongs to.
- `node_id` `(string)` - The ID of the node to which the allocation was scheduled.
- `node_name` `(string)` - The ID of the node to which the allocation was scheduled.
- `job_id` `(string)` - The ID of the job related to the allocation.
- `job_type` `(string)` - The type of the job related to the allocation.
- `job_version` `(int)` - The version of the job that generated the allocation.
- `task_group` `(string)` - The job task group related to the allocation.
- `desired_status` `(string)` - The current desired status of the allocation.
- `client_status` `(string)` - The current client status of the allocation.
- `followup_eval_id` `(string)` - The ID of the evaluation that succeeds the allocation evaluation.
- `next_allocation` `(string)` - The ID of the allocation that succeeds the allocation.
- `preempted_by_allocation` `(string)` - The ID of the allocation that preempted the allocation.
- `create_index` `(int)` - The Raft index in which the allocation was created.
- `modify_index` `(int)` - The Raft index in which the allocation was last modified.
- `create_time` `(int)` - The timestamp of when the allocation was created.
- `modify_time` `(int)` - The timestamp of when the allocation was last modified.

[nomad_api_filter]: https://developer.hashicorp.com/nomad/api-docs/v1.6.x#filtering
Loading