Skip to content

Commit

Permalink
Merge pull request #1172 from stgraber/cluster
Browse files Browse the repository at this point in the history
Better handle cluster group validation
  • Loading branch information
hallyn authored Sep 2, 2024
2 parents 665db31 + e8271a2 commit 450ed7e
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 1 deletion.
35 changes: 34 additions & 1 deletion cmd/incusd/api_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -1469,7 +1469,40 @@ func projectValidateConfig(s *state.State, config map[string]string) error {
// ---
// type: string
// shortdesc: Cluster groups that can be targeted
"restricted.cluster.groups": validate.Optional(validate.IsListOf(validate.IsAny)),
"restricted.cluster.groups": validate.Optional(func(value string) error {
// Basic format validation.
err := validate.IsListOf(validate.IsAny)(value)
if err != nil {
return err
}

// Get all valid groups.
groupNames := []string{}
err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
clusterGroups, err := cluster.GetClusterGroups(ctx, tx.Tx())
if err != nil {
return err
}

for _, group := range clusterGroups {
groupNames = append(groupNames, group.Name)
}

return nil
})
if err != nil {
return err
}

// Confirm that the group names exist.
for _, name := range util.SplitNTrimSpace(value, ",", -1, true) {
if !slices.Contains(groupNames, name) {
return fmt.Errorf("Cluster group %q doesn't exist", name)
}
}

return nil
}),

// gendoc:generate(entity=project, group=restricted, key=restricted.cluster.target)
// Possible values are `allow` or `block`.
Expand Down
10 changes: 10 additions & 0 deletions doc/howto/cluster_groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,13 @@ To launch an instance on a member of a cluster group, follow the instructions in
For example:

incus launch images:ubuntu/22.04 c1 --target=@gpu

## Use with restricted projects

A project can be configured to only have access to servers that are part of specific cluster groups.

This is done by setting both `restricted=true` and `restricted.cluster.groups` to a comma separated list of group names.

```{note}
If the cluster group is renamed, the project restrictions will need to be updated for the new group name.
```
16 changes: 16 additions & 0 deletions internal/server/db/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -1085,8 +1085,24 @@ func (c *ClusterTx) GetCandidateMembers(ctx context.Context, allMembers []NodeIn

// Skip if working with a restricted set of cluster groups and member isn't part of any.
if allowedClusterGroups != nil {
// Load the list of cluster groups.
groupNames := []string{}
clusterGroups, err := cluster.GetClusterGroups(ctx, c.Tx())
if err != nil {
return nil, err
}

for _, group := range clusterGroups {
groupNames = append(groupNames, group.Name)
}

// Filter based on groups.
found := false
for _, allowedClusterGroup := range allowedClusterGroups {
if !slices.Contains(groupNames, allowedClusterGroup) {
return nil, fmt.Errorf("Cluster group %q doesn't exist", allowedClusterGroup)
}

if slices.Contains(member.Groups, allowedClusterGroup) {
found = true
break
Expand Down

0 comments on commit 450ed7e

Please sign in to comment.