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

Add Scheduler config resource #157

Merged
merged 8 commits into from
Oct 30, 2020
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 nomad/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func Provider() terraform.ResourceProvider {
"nomad_quota_specification": resourceQuotaSpecification(),
"nomad_sentinel_policy": resourceSentinelPolicy(),
"nomad_volume": resourceVolume(),
"nomad_scheduler_config": resourceSchedulerConfig(),
},
}
}
Expand Down
135 changes: 135 additions & 0 deletions nomad/resource_scheduler_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package nomad

import (
"errors"
"fmt"
"log"

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

func resourceSchedulerConfig() *schema.Resource {
return &schema.Resource{
Create: resourceSchedulerConfigurationCreate,
Update: resourceSchedulerConfigurationCreate,
Delete: resourceSchedulerConfigurationDelete,
Read: resourceSchedulerConfigurationRead,

Schema: map[string]*schema.Schema{
"scheduler_algorithm": {
Description: "Specifies whether scheduler binpacks or spreads allocations on available nodes.",
Type: schema.TypeString,
Default: "binpack",
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{
"binpack",
"spread",
}, false),
},
},
// TODO(jrasell) once the Terraform SDK has been updated within
// this provider, we should add validation.MapKeyMatch to this
// schema entry using a regex such as:
// "("^[service,system,batch]_scheduler_enabled")".
"preemption_config": {
Description: "Options to enable preemption for various schedulers.",
Optional: true,
Type: schema.TypeMap,
Elem: &schema.Schema{
Type: schema.TypeBool,
},
},
},
}
}

func resourceSchedulerConfigurationCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(ProviderConfig).client
operator := client.Operator()

config := api.SchedulerConfiguration{
SchedulerAlgorithm: api.SchedulerAlgorithm(d.Get("scheduler_algorithm").(string)),
PreemptionConfig: api.PreemptionConfig{},
}

// Unpack the preemption block.
preempt, ok := d.GetOk("preemption_config")
if ok {
preemptMap, ok := preempt.(map[string]interface{})
if !ok {
return errors.New("failed to unpack preemption configuration block")
}

if val, ok := preemptMap["batch_scheduler_enabled"].(bool); ok {
config.PreemptionConfig.BatchSchedulerEnabled = val
}
if val, ok := preemptMap["service_scheduler_enabled"].(bool); ok {
config.PreemptionConfig.ServiceSchedulerEnabled = val
}
if val, ok := preemptMap["system_scheduler_enabled"].(bool); ok {
config.PreemptionConfig.SystemSchedulerEnabled = val
}
}

// Perform the config write.
log.Printf("[DEBUG] Upserting Scheduler configuration")
if _, _, err := operator.SchedulerSetConfiguration(&config, nil); err != nil {
return fmt.Errorf("error upserting scheduler configuration: %s", err.Error())
}
log.Printf("[DEBUG] Upserted scheduler configuration")

return resourceSchedulerConfigurationRead(d, meta)
}

// resourceSchedulerConfigurationDelete does not do anything:
//
// There is not a correct way to destroy this "resource" nor check it was
// destroyed.
//
// Consider the following:
// 1. an operator manually updates the Nomad scheduler config, or doesn't
// 2. they decide to move management over to Terraform
// 3. they get rid of Terraform management
//
// If the destroy reverts to the Nomad default configuration, we are over
// writing changes based on assumption. We cannot go back in time to the
// initial version as we do not have this information available, so we just
// have to leave it be.
func resourceSchedulerConfigurationDelete(_ *schema.ResourceData, _ interface{}) error { return nil }

func resourceSchedulerConfigurationRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(ProviderConfig).client
operator := client.Operator()

// The scheduler config doesn't have a UUID, so the resource uses the agent
// region. Grab this so we can set it later.
reg, err := client.Agent().Region()
if err != nil {
return fmt.Errorf("error getting region: %s", err.Error())
}
// retrieve the config
log.Printf("[DEBUG] Reading scheduler configuration")
config, _, err := operator.SchedulerGetConfiguration(nil)
if err != nil {
return fmt.Errorf("error reading scheduler configuration: %s", err.Error())
}
log.Printf("[DEBUG] Read scheduler configuration")

d.SetId(fmt.Sprintf("nomad-scheduler-configuration-%s", reg))

// Set the algorithm, handling any error when performing the set.
if err := d.Set("scheduler_algorithm", config.SchedulerConfig.SchedulerAlgorithm); err != nil {
return err
}

premptMap := map[string]bool{
"batch_scheduler_enabled": config.SchedulerConfig.PreemptionConfig.BatchSchedulerEnabled,
"service_scheduler_enabled": config.SchedulerConfig.PreemptionConfig.ServiceSchedulerEnabled,
"system_scheduler_enabled": config.SchedulerConfig.PreemptionConfig.SystemSchedulerEnabled,
}
return d.Set("preemption_config", premptMap)
}
94 changes: 94 additions & 0 deletions nomad/resource_scheduler_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package nomad

import (
"testing"

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

func TestSchedulerConfig_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testProviders,
CheckDestroy: testFinalConfiguration,
Steps: []resource.TestStep{
{
Config: testAccNomadSchedulerConfigSpread,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"nomad_scheduler_config.config",
"scheduler_algorithm",
"spread",
),
resource.TestCheckResourceAttr(
"nomad_scheduler_config.config",
"preemption_config.batch_scheduler_enabled",
"true",
),
resource.TestCheckResourceAttr(
"nomad_scheduler_config.config",
"preemption_config.service_scheduler_enabled",
"true",
),
resource.TestCheckResourceAttr(
"nomad_scheduler_config.config",
"preemption_config.system_scheduler_enabled",
"true",
),
),
},
{
Config: testAccNomadSchedulerConfigBinpack,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"nomad_scheduler_config.config",
"scheduler_algorithm",
"binpack",
),
resource.TestCheckResourceAttr(
"nomad_scheduler_config.config",
"preemption_config.batch_scheduler_enabled",
"false",
),
resource.TestCheckResourceAttr(
"nomad_scheduler_config.config",
"preemption_config.service_scheduler_enabled",
"true",
),
resource.TestCheckResourceAttr(
"nomad_scheduler_config.config",
"preemption_config.system_scheduler_enabled",
"false",
),
),
},
},
})
}

const testAccNomadSchedulerConfigSpread = `
resource "nomad_scheduler_config" "config" {
scheduler_algorithm = "spread"
preemption_config = {
system_scheduler_enabled = true
batch_scheduler_enabled = true
service_scheduler_enabled = true
}
}
`

const testAccNomadSchedulerConfigBinpack = `
resource "nomad_scheduler_config" "config" {
scheduler_algorithm = "binpack"
preemption_config = {
system_scheduler_enabled = false
batch_scheduler_enabled = false
service_scheduler_enabled = true
}
}
`

// for details on why this is the way it is, checkout the comments on
// resourceSchedulerConfigurationDelete.
func testFinalConfiguration(_ *terraform.State) error { return nil }
41 changes: 41 additions & 0 deletions website/docs/r/scheduler_config.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
layout: "nomad"
page_title: "Nomad: nomad_scheduler_config"
sidebar_current: "docs-nomad-scheduler-config"
description: |-
Manages scheduler configuration on the Nomad server.
---

# nomad_scheduler_config

Manages scheduler configuration of the Nomad cluster.

~> **Warning:** destroying this resource will not have any effect in the
cluster configuration, since there's no clear definition of what a destroy
action should do. The cluster will be left as-is and only the state reference
will be removed.

## Example Usage

Set cluster scheduler configuration:

```hcl
resource "nomad_scheduler_config" "config" {
scheduler_algorithm = "spread"
preemption_config = {
system_scheduler_enabled = true
batch_scheduler_enabled = true
service_scheduler_enabled = true
}
}
```

## Argument Reference

The following arguments are supported:

- `algorithm` `(string: "binpack")` - Specifies whether scheduler binpacks or spreads allocations on available nodes. Possible values are `binpack` and `spread`.
- `preemption_config` `(map[string]bool)` - Options to enable preemption for various schedulers.
- `system_scheduler_enabled` `(bool: true)` - Specifies whether preemption for system jobs is enabled. Note that if this is set to true, then system jobs can preempt any other jobs.
- `batch_scheduler_enabled` `(bool: false")` - Specifies whether preemption for batch jobs is enabled. Note that if this is set to true, then batch jobs can preempt any other jobs.
- `service_scheduler_enabled` `(bool: false)` - Specifies whether preemption for service jobs is enabled. Note that if this is set to true, then service jobs can preempt any other jobs.
3 changes: 3 additions & 0 deletions website/nomad.erb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
<li<%= sidebar_current("docs-nomad-resource-sentinel-policy") %>>
<a href="/docs/providers/nomad/r/sentinel_policy.html">nomad_sentinel_policy</a>
</li>
<li<%= sidebar_current("docs-nomad-resource-scheduler-config") %>>
<a href="/docs/providers/nomad/r/scheduler_config.html">nomad_scheduler_config</a>
</li>
<li<%= sidebar_current("docs-nomad-resource-volume-policy") %>>
<a href="/docs/providers/nomad/r/volume.html">nomad_volume</a>
</li>
Expand Down