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 new tctl bots update command #36496

Merged
merged 18 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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
54 changes: 52 additions & 2 deletions docs/pages/reference/cli/tctl.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,15 @@ $ tctl bots add <name> [<flags>]
| `--logins` | none | Comma-separated list of allowed SSH logins to set Bot's login trait to. | Optional. Specifies the values that should be configured as the Bot's logins trait for the purpose of role templating. |
| `--token` | none | String name of an existing join token. | Optional. Specifies an existing join token to be used rather than creating one as part of the Bot creation. |
| `--ttl` | 15m | Duration. | Optional. Overrides the TTL of the token that will be created if `--token` is not specified. |
| `--format` | `text` | `text`, `json` | If set to `json`, return new bot information as a machine-readable JSON string. |

### Examples

Create a new bot named `example` that may assume the `access` role and log in as `root`:

```code
$ tctl bots add example --roles=access --logins=root
```

### Global flags

Expand Down Expand Up @@ -441,6 +450,49 @@ $ tctl bots rm <name> [<flags>]
These flags are available for all commands: `--debug, --config`. Run
`tctl help <subcommand>` or see the [Global Flags section](#tctl-global-flags).

## tctl bots update

Update a Machine ID bot:

```code
$ tctl bots update <bot> [<flags>]
```

### Arguments

- `<name>` - The name of the bot to update

### Flags

| Name | Default Value(s) | Allowed Value(s) | Description |
| - | - | - | - |
| `--add-roles` | none | Comma-separated list of roles the bot may assume | Appends the given roles to the existing roles the bot may assume. |
| `--set-roles` | none | Comma-separated list of roles the bot may assume | Replaces the bots's current roles with the list provided. |
| `--add-logins` | none | Comma-separated list of allowed Unix logins | Appends the given logins to the bot's current allowed logins. |
| `--set-logins` | none | Comma-separated list of allowed Unix logins | Replaces the bot's current allowed logins with the given list. |

### Examples

Replace the bot `example` roles and add a new allowed Unix login:

```code
$ tctl bots update example --add-logins root --set-roles=access
timothyb89 marked this conversation as resolved.
Show resolved Hide resolved
```

Remove all implicitly allowed Unix logins from a bot named `example` by passing
an empty list:

```code
$ tctl bots update example --set-logins=,
```

Note that the bot may still be granted additional logins via roles.

### Global flags

These flags are available for all commands: `--debug, --config`. Run
`tctl help <subcommand>` or see the [Global Flags section](#tctl-global-flags).

## tctl create

Create or update a Teleport resource from a YAML file.
Expand Down Expand Up @@ -1492,5 +1544,3 @@ Print the version of your `tctl` binary:
```code
tctl version
```


76 changes: 76 additions & 0 deletions lib/utils/set/set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package set

import "golang.org/x/exp/maps"
timothyb89 marked this conversation as resolved.
Show resolved Hide resolved

// Set represents a set data structure, using the map type with an empty value.
type Set[T comparable] map[T]struct{}
timothyb89 marked this conversation as resolved.
Show resolved Hide resolved
codingllama marked this conversation as resolved.
Show resolved Hide resolved

// Empty returns a new, empty set.
func Empty[T comparable]() Set[T] {
return make(map[T]struct{})
}

// Union returns a new Set that is the union of one or more other sets. A single
// argument effectively clones the set.
func Union[T comparable](sets ...Set[T]) Set[T] {
ret := make(map[T]struct{})
for _, set := range sets {
for key := range set {
ret[key] = struct{}{}
}
}

return ret
}

// New returns a new Set from the given array of entries. Duplicate entries will
// be removed.
func New[T comparable](entries ...T) Set[T] {
ret := make(map[T]struct{})

for _, entry := range entries {
ret[entry] = struct{}{}
}

return ret
}

// Union returns a new Set that is the union of this set and one or more other
// sets.
func (s Set[T]) Union(sets ...Set[T]) Set[T] {
args := append([]Set[T]{s}, sets...)
return Union(args...)
}

// Clone returns a clone of this set.
func (s Set[T]) Clone() Set[T] {
return Union(s)
}

// ToArray converts a set to an array. Note that the output order is undefined.
func (s Set[T]) ToArray() []T {
return maps.Keys(s)
}

// Equal determines if this set contains the same keys as another set.
func (s Set[T]) Equals(other Set[T]) bool {
return maps.Equal(s, other)
}
101 changes: 101 additions & 0 deletions lib/utils/set/set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package set

import (
"testing"

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

func TestSetsEqual(t *testing.T) {
tests := []struct {
name string
a Set[string]
b Set[string]
assert require.BoolAssertionFunc
}{
{
name: "out of order true",
a: New("a", "b", "c", "d"),
b: New("d", "b", "c", "a"),
assert: require.True,
},
{
name: "length mismatch",
a: New("a", "b", "c"),
b: New("d", "b", "c", "a"),
assert: require.False,
},
{
name: "simple false",
a: New("a", "b", "c", "d"),
b: New("d", "b", "c", "e"),
assert: require.False,
},
{
name: "duplicates ignored",
a: New("a", "b", "c", "d"),
b: New("d", "b", "c", "a", "a", "b", "c"),
assert: require.True,
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

tt.assert(t, tt.a.Equals(tt.b))
})
}
}

func TestArrayToSetRoundtrip(t *testing.T) {
a := []string{"a", "b", "c", "d"}
require.ElementsMatch(t, a, New(a...).ToArray())

// It should also remove duplicates
require.ElementsMatch(t, New(append(a, a...)...).ToArray(), a)
}

func TestSetUnion(t *testing.T) {
a := []string{"a", "b", "c", "d"}
b := []string{"c", "d", "e", "f"}

// Self union clones
require.ElementsMatch(
t,
Union(New(a...), New(a...), New(a...)).ToArray(),
a,
)

// Clone also clones (and is a union)
require.ElementsMatch(
t,
New(a...).Clone().ToArray(),
a,
)

require.ElementsMatch(
t,
New(a...).Union(New(b...)).ToArray(),
[]string{"a", "b", "c", "d", "e", "f"},
)
}
Loading
Loading