Skip to content

Support HCLv2 for Nomad jobs #9142

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

Merged
merged 9 commits into from
Oct 22, 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
6 changes: 3 additions & 3 deletions api/constraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ const (

// Constraint is used to serialize a job placement constraint.
type Constraint struct {
LTarget string
RTarget string
Operand string
LTarget string `hcl:"attribute,optional"`
RTarget string `hcl:"value,optional"`
Operand string `hcl:"operator,optional"`
}

// NewConstraint generates a new job placement constraint.
Expand Down
8 changes: 4 additions & 4 deletions api/csi.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ const (
)

type CSIMountOptions struct {
FSType string `hcl:"fs_type"`
MountFlags []string `hcl:"mount_flags"`
ExtraKeysHCL []string `hcl:",unusedKeys" json:"-"` // report unexpected keys
FSType string `hcl:"fs_type,optional"`
MountFlags []string `hcl:"mount_flags,optional"`
ExtraKeysHCL []string `hcl1:",unusedKeys" json:"-"` // report unexpected keys
}

type CSISecrets map[string]string
Expand Down Expand Up @@ -133,7 +133,7 @@ type CSIVolume struct {
ModifyIndex uint64

// ExtraKeysHCL is used by the hcl parser to report unexpected keys
ExtraKeysHCL []string `hcl:",unusedKeys" json:"-"`
ExtraKeysHCL []string `hcl1:",unusedKeys" json:"-"`
}

// allocs is called after we query the volume (creating this CSIVolume struct) to collapse
Expand Down
98 changes: 53 additions & 45 deletions api/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ type JobsParseRequest struct {
// JobHCL is an hcl jobspec
JobHCL string

// HCLv1 indicates whether the JobHCL should be parsed with the hcl v1 parser
HCLv1 bool `json:"hclv1,omitempty"`

// Canonicalize is a flag as to if the server should return default values
// for unset fields
Canonicalize bool
Expand Down Expand Up @@ -439,15 +442,15 @@ type periodicForceResponse struct {

// UpdateStrategy defines a task groups update strategy.
type UpdateStrategy struct {
Stagger *time.Duration `mapstructure:"stagger"`
MaxParallel *int `mapstructure:"max_parallel"`
HealthCheck *string `mapstructure:"health_check"`
MinHealthyTime *time.Duration `mapstructure:"min_healthy_time"`
HealthyDeadline *time.Duration `mapstructure:"healthy_deadline"`
ProgressDeadline *time.Duration `mapstructure:"progress_deadline"`
Canary *int `mapstructure:"canary"`
AutoRevert *bool `mapstructure:"auto_revert"`
AutoPromote *bool `mapstructure:"auto_promote"`
Stagger *time.Duration `mapstructure:"stagger" hcl:"stagger,optional"`
MaxParallel *int `mapstructure:"max_parallel" hcl:"max_parallel,optional"`
HealthCheck *string `mapstructure:"health_check" hcl:"health_check,optional"`
MinHealthyTime *time.Duration `mapstructure:"min_healthy_time" hcl:"min_healthy_time,optional"`
HealthyDeadline *time.Duration `mapstructure:"healthy_deadline" hcl:"healthy_deadline,optional"`
ProgressDeadline *time.Duration `mapstructure:"progress_deadline" hcl:"progress_deadline,optional"`
Canary *int `mapstructure:"canary" hcl:"canary,optional"`
AutoRevert *bool `mapstructure:"auto_revert" hcl:"auto_revert,optional"`
AutoPromote *bool `mapstructure:"auto_promote" hcl:"auto_promote,optional"`
}

// DefaultUpdateStrategy provides a baseline that can be used to upgrade
Expand Down Expand Up @@ -640,8 +643,8 @@ func (u *UpdateStrategy) Empty() bool {
}

type Multiregion struct {
Strategy *MultiregionStrategy
Regions []*MultiregionRegion
Strategy *MultiregionStrategy `hcl:"strategy,block"`
Regions []*MultiregionRegion `hcl:"region,block"`
}

func (m *Multiregion) Canonicalize() {
Expand Down Expand Up @@ -700,24 +703,24 @@ func (m *Multiregion) Copy() *Multiregion {
}

type MultiregionStrategy struct {
MaxParallel *int `mapstructure:"max_parallel"`
OnFailure *string `mapstructure:"on_failure"`
MaxParallel *int `mapstructure:"max_parallel" hcl:"max_parallel,optional"`
OnFailure *string `mapstructure:"on_failure" hcl:"on_failure,optional"`
}

type MultiregionRegion struct {
Name string
Count *int
Datacenters []string
Meta map[string]string
Name string `hcl:",label"`
Count *int `hcl:"count,optional"`
Datacenters []string `hcl:"datacenters,optional"`
Meta map[string]string `hcl:"meta,block"`
}

// PeriodicConfig is for serializing periodic config for a job.
type PeriodicConfig struct {
Enabled *bool
Spec *string
Enabled *bool `hcl:"enabled,optional"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting: we parse this in HCLv1 but it's not documented in the jobspec. Another one to follow up later on I think.

Spec *string `hcl:"cron,optional"`
SpecType *string
ProhibitOverlap *bool `mapstructure:"prohibit_overlap"`
TimeZone *string `mapstructure:"time_zone"`
ProhibitOverlap *bool `mapstructure:"prohibit_overlap" hcl:"prohibit_overlap,optional"`
TimeZone *string `mapstructure:"time_zone" hcl:"time_zone,optional"`
}

func (p *PeriodicConfig) Canonicalize() {
Expand Down Expand Up @@ -779,38 +782,43 @@ func (p *PeriodicConfig) GetLocation() (*time.Location, error) {

// ParameterizedJobConfig is used to configure the parameterized job.
type ParameterizedJobConfig struct {
Payload string
MetaRequired []string `mapstructure:"meta_required"`
MetaOptional []string `mapstructure:"meta_optional"`
Payload string `hcl:"payload,optional"`
MetaRequired []string `mapstructure:"meta_required" hcl:"meta_required,optional"`
MetaOptional []string `mapstructure:"meta_optional" hcl:"meta_optional,optional"`
}

// Job is used to serialize a job.
type Job struct {
/* Fields parsed from HCL config */

Region *string `hcl:"region,optional"`
Namespace *string `hcl:"namespace,optional"`
ID *string `hcl:"id,optional"`
Name *string `hcl:"name,optional"`
Type *string `hcl:"type,optional"`
Priority *int `hcl:"priority,optional"`
AllAtOnce *bool `mapstructure:"all_at_once" hcl:"all_at_once,optional"`
Datacenters []string `hcl:"datacenters,optional"`
Constraints []*Constraint `hcl:"constraint,block"`
Affinities []*Affinity `hcl:"affinity,block"`
TaskGroups []*TaskGroup `hcl:"group,block"`
Update *UpdateStrategy `hcl:"update,block"`
Multiregion *Multiregion `hcl:"multiregion,block"`
Spreads []*Spread `hcl:"spread,block"`
Periodic *PeriodicConfig `hcl:"periodic,block"`
ParameterizedJob *ParameterizedJobConfig `hcl:"parameterized,block"`
Reschedule *ReschedulePolicy `hcl:"reschedule,block"`
Migrate *MigrateStrategy `hcl:"migrate,block"`
Meta map[string]string `hcl:"meta,block"`
ConsulToken *string `mapstructure:"consul_token" hcl:"consul_token,optional"`
VaultToken *string `mapstructure:"vault_token" hcl:"vault_token,optional"`

/* Fields set by server, not sourced from job config file */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Good comment: this is definitely the sort of thing people would wander by and not remember why. 😀


Stop *bool
Region *string
Namespace *string
ID *string
ParentID *string
Name *string
Type *string
Priority *int
AllAtOnce *bool `mapstructure:"all_at_once"`
Datacenters []string
Constraints []*Constraint
Affinities []*Affinity
TaskGroups []*TaskGroup
Update *UpdateStrategy
Multiregion *Multiregion
Spreads []*Spread
Periodic *PeriodicConfig
ParameterizedJob *ParameterizedJobConfig
Dispatched bool
Payload []byte
Reschedule *ReschedulePolicy
Migrate *MigrateStrategy
Meta map[string]string
ConsulToken *string `mapstructure:"consul_token"`
VaultToken *string `mapstructure:"vault_token"`
VaultNamespace *string `mapstructure:"vault_namespace"`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May require follow up for VaultNamespace. I'm a little surprised that vault_namespace field isn't a valid config option. I checked the field is rejected emperically, and confirmed it's not listed as a valid key in the hclv1 parser: https://github.com/hashicorp/nomad/blob/1d6997942992e92a0eccaec1d87cb0c1d43eeb0b/jobspec/parse_job.go#L79-L82.

NomadTokenID *string `mapstructure:"nomad_token_id"`
Status *string
Expand Down
50 changes: 25 additions & 25 deletions api/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import (
// Resources encapsulates the required resources of
// a given task or task group.
type Resources struct {
CPU *int
MemoryMB *int `mapstructure:"memory"`
DiskMB *int `mapstructure:"disk"`
Networks []*NetworkResource
Devices []*RequestedDevice
CPU *int `hcl:"cpu,optional"`
MemoryMB *int `mapstructure:"memory" hcl:"memory,optional"`
DiskMB *int `mapstructure:"disk" hcl:"disk,optional"`
Networks []*NetworkResource `hcl:"network,block"`
Devices []*RequestedDevice `hcl:"device,block"`

// COMPAT(0.10)
// XXX Deprecated. Please do not use. The field will be removed in Nomad
// 0.10 and is only being kept to allow any references to be removed before
// then.
IOPS *int
IOPS *int `hcl:"iops,optional"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another item to follow-up on later: we probably should take advantage of 1.0 to remove this entirely.

}

// Canonicalize will supply missing values in the cases
Expand Down Expand Up @@ -84,29 +84,29 @@ func (r *Resources) Merge(other *Resources) {
}

type Port struct {
Label string
Value int `mapstructure:"static"`
To int `mapstructure:"to"`
HostNetwork string `mapstructure:"host_network"`
Label string `hcl:",label"`
Value int `mapstructure:"static" hcl:"static,optional"`
To int `mapstructure:"to" hcl:"to,optional"`
HostNetwork string `mapstructure:"host_network" hcl:"host_network,optional"`
}

type DNSConfig struct {
Servers []string `mapstructure:"servers"`
Searches []string `mapstructure:"searches"`
Options []string `mapstructure:"options"`
Servers []string `mapstructure:"servers" hcl:"servers,optional"`
Searches []string `mapstructure:"searches" hcl:"searches,optional"`
Options []string `mapstructure:"options" hcl:"options,optional"`
}

// NetworkResource is used to describe required network
// resources of a given task.
type NetworkResource struct {
Mode string
Device string
CIDR string
IP string
MBits *int
DNS *DNSConfig
ReservedPorts []Port
DynamicPorts []Port
Mode string `hcl:"mode,optional"`
Device string `hcl:"device,optional"`
CIDR string `hcl:"cidr,optional"`
IP string `hcl:"ip,optional"`
MBits *int `hcl:"mbits,optional"`
DNS *DNSConfig `hcl:"dns,block"`
ReservedPorts []Port `hcl:"reserved_ports,block"`
DynamicPorts []Port `hcl:"port,block"`
}

func (n *NetworkResource) Canonicalize() {
Expand Down Expand Up @@ -226,18 +226,18 @@ type RequestedDevice struct {
// * "gpu"
// * "nvidia/gpu"
// * "nvidia/gpu/GTX2080Ti"
Name string
Name string `hcl:",label"`

// Count is the number of requested devices
Count *uint64
Count *uint64 `hcl:"count,optional"`

// Constraints are a set of constraints to apply when selecting the device
// to use.
Constraints []*Constraint
Constraints []*Constraint `hcl:"constraint,block"`

// Affinities are a set of affinites to apply when selecting the device
// to use.
Affinities []*Affinity
Affinities []*Affinity `hcl:"affinity,block"`
}

func (d *RequestedDevice) Canonicalize() {
Expand Down
13 changes: 9 additions & 4 deletions api/scaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,19 @@ type ScalingRequest struct {

// ScalingPolicy is the user-specified API object for an autoscaling policy
type ScalingPolicy struct {
/* fields set by user in HCL config */

Min *int64 `hcl:"min,optional"`
Max *int64 `hcl:"max,optional"`
Policy map[string]interface{} `hcl:"policy,block"`
Enabled *bool `hcl:"enabled,optional"`

/* fields set by server */

ID string
Namespace string
Type string
Target map[string]string
Min *int64
Max *int64
Policy map[string]interface{}
Enabled *bool
CreateIndex uint64
ModifyIndex uint64
}
Expand Down
Loading