Skip to content

Commit

Permalink
Intial implementation for #11807
Browse files Browse the repository at this point in the history
  • Loading branch information
apollo13 committed Jan 10, 2022
1 parent e9032c1 commit 84ce0f7
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 8 deletions.
10 changes: 8 additions & 2 deletions api/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,14 @@ type Namespace struct {
Name string
Description string
Quota string
CreateIndex uint64
ModifyIndex uint64
// TODO: how to encode properly?
Capabilities *NamespaceCapabilities
CreateIndex uint64
ModifyIndex uint64
}

type NamespaceCapabilities struct {
EnabledTaskDrivers []string
}

// NamespaceIndexSort is a wrapper to sort Namespaces by CreateIndex. We
Expand Down
17 changes: 14 additions & 3 deletions command/namespace_apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,19 @@ Apply Options:
-description
An optional description for the namespace.
-enabled-task-drivers
A comma separated list of allowed task drivers.
`
return strings.TrimSpace(helpText)
}

func (c *NamespaceApplyCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
"-description": complete.PredictAnything,
"-quota": QuotaPredictor(c.Meta.Client),
"-description": complete.PredictAnything,
"-quota": QuotaPredictor(c.Meta.Client),
"-enabled-task-drivers": complete.PredictAnything,
})
}

Expand All @@ -56,7 +60,7 @@ func (c *NamespaceApplyCommand) Synopsis() string {
func (c *NamespaceApplyCommand) Name() string { return "namespace apply" }

func (c *NamespaceApplyCommand) Run(args []string) int {
var description, quota *string
var description, quota, enabledTaskDrivers *string

flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
Expand All @@ -68,6 +72,10 @@ func (c *NamespaceApplyCommand) Run(args []string) int {
quota = &s
return nil
}), "quota", "")
flags.Var((flaghelper.FuncVar)(func(s string) error {
enabledTaskDrivers = &s
return nil
}), "enabled-task-drivers", "")

if err := flags.Parse(args); err != nil {
return 1
Expand Down Expand Up @@ -116,6 +124,9 @@ func (c *NamespaceApplyCommand) Run(args []string) int {
if quota != nil {
ns.Quota = *quota
}
if enabledTaskDrivers != nil {
ns.Capabilities = &api.NamespaceCapabilities{EnabledTaskDrivers: strings.Split(*enabledTaskDrivers, ",")}
}

_, err = client.Namespaces().Register(ns, nil)
if err != nil {
Expand Down
11 changes: 8 additions & 3 deletions command/namespace_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,16 @@ func formatNamespaces(namespaces []*api.Namespace) string {
sort.Slice(namespaces, func(i, j int) bool { return namespaces[i].Name < namespaces[j].Name })

rows := make([]string, len(namespaces)+1)
rows[0] = "Name|Description"
rows[0] = "Name|Description|Drivers"
for i, ns := range namespaces {
rows[i+1] = fmt.Sprintf("%s|%s",
drivers := "*"
if ns.Capabilities != nil && len(ns.Capabilities.EnabledTaskDrivers) != 0 {
drivers = strings.Join(ns.Capabilities.EnabledTaskDrivers, ",")
}
rows[i+1] = fmt.Sprintf("%s|%s|%s",
ns.Name,
ns.Description)
ns.Description,
drivers)
}
return formatList(rows)
}
5 changes: 5 additions & 0 deletions command/namespace_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,15 @@ func (c *NamespaceStatusCommand) Run(args []string) int {

// formatNamespaceBasics formats the basic information of the namespace
func formatNamespaceBasics(ns *api.Namespace) string {
drivers := "*"
if ns.Capabilities != nil && len(ns.Capabilities.EnabledTaskDrivers) != 0 {
drivers = strings.Join(ns.Capabilities.EnabledTaskDrivers, ",")
}
basic := []string{
fmt.Sprintf("Name|%s", ns.Name),
fmt.Sprintf("Description|%s", ns.Description),
fmt.Sprintf("Quota|%s", ns.Quota),
fmt.Sprintf("Drivers|%s", drivers),
}

return formatKV(basic)
Expand Down
1 change: 1 addition & 0 deletions nomad/job_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func NewJobEndpoints(s *Server) *Job {
validators: []jobValidator{
jobConnectHook{},
jobExposeCheckHook{},
jobNamespaceConstraintCheckHook{srv: s},
jobValidate{},
&memoryOversubscriptionValidate{srv: s},
},
Expand Down
45 changes: 45 additions & 0 deletions nomad/job_endpoint_validators.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package nomad

import (
"github.com/hashicorp/nomad/nomad/structs"
"github.com/pkg/errors"
)

type jobNamespaceConstraintCheckHook struct {
srv *Server
}

func (jobNamespaceConstraintCheckHook) Name() string {
return "namespace-constraint-check"
}

func (c jobNamespaceConstraintCheckHook) Validate(job *structs.Job) (warnings []error, err error) {
// This was validated before and matches the WriteRequest namespace
ns, err := c.srv.State().NamespaceByName(nil, job.Namespace)
if err != nil {
return nil, err
}

for _, tg := range job.TaskGroups {
for _, t := range tg.Tasks {
if !taskValidateDriver(t, ns) {
return nil, errors.Errorf(
"used task driver '%s' in %s[%s] is not allowed in namespace %s",
t.Driver, tg.Name, t.Name, ns.Name)
}
}
}
return nil, nil
}

func taskValidateDriver(task *structs.Task, ns *structs.Namespace) bool {
if ns.Capabilities == nil || len(ns.Capabilities.EnabledTaskDrivers) == 0 {
return true
}
for _, d := range ns.Capabilities.EnabledTaskDrivers {
if task.Driver == d {
return true
}
}
return false
}
15 changes: 15 additions & 0 deletions nomad/job_endpoint_validators_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package nomad

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestJobNamespaceConstraintCheckHook_Name(t *testing.T) {
t.Parallel()

require.Equal(t, "namespace-constraint-check", new(jobNamespaceConstraintCheckHook).Name())
}

// TODO: More tests
9 changes: 9 additions & 0 deletions nomad/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4945,6 +4945,9 @@ type Namespace struct {
// against.
Quota string

// Capabilities is the set of capabilities allowed for this namespace
Capabilities *NamespaceCapabilities

// Hash is the hash of the namespace which is used to efficiently replicate
// cross-regions.
Hash []byte
Expand All @@ -4954,6 +4957,12 @@ type Namespace struct {
ModifyIndex uint64
}

// NamespaceCapabilities represents a set of capabilities allowed for this
// namespace, to be checked at job submission time.
type NamespaceCapabilities struct {
EnabledTaskDrivers []string
}

func (n *Namespace) Validate() error {
var mErr multierror.Error

Expand Down

0 comments on commit 84ce0f7

Please sign in to comment.