feat: add YAML support to server (#6934)

This commit is contained in:
Ammar Bandukwala 2023-04-07 17:58:21 -05:00 committed by GitHub
parent a3c6cb1768
commit 4b99e2d07e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1605 additions and 468 deletions

View File

@ -194,6 +194,7 @@ issues:
linters:
# We use assertions rather than explicitly checking errors in tests
- errcheck
- forcetypeassert
fix: true
max-issues-per-linter: 0

View File

@ -518,7 +518,7 @@ update-golden-files: cli/testdata/.gen-golden helm/tests/testdata/.gen-golden sc
.PHONY: update-golden-files
cli/testdata/.gen-golden: $(wildcard cli/testdata/*.golden) $(wildcard cli/*.tpl) $(GO_SRC_FILES)
go test ./cli -run=TestCommandHelp -update
go test ./cli -run="Test(CommandHelp|ServerYAML)" -update
touch "$@"
helm/tests/testdata/.gen-golden: $(wildcard helm/tests/testdata/*.golden) $(GO_SRC_FILES)

View File

@ -14,15 +14,10 @@ import (
// Group describes a hierarchy of groups that an option or command belongs to.
type Group struct {
Parent *Group `json:"parent,omitempty"`
Name string `json:"name,omitempty"`
Children []Group `json:"children,omitempty"`
Description string `json:"description,omitempty"`
}
func (g *Group) AddChild(child Group) {
child.Parent = g
g.Children = append(g.Children, child)
Parent *Group `json:"parent,omitempty"`
Name string `json:"name,omitempty"`
YAML string `json:"yaml,omitempty"`
Description string `json:"description,omitempty"`
}
// Ancestry returns the group and all of its parents, in order.

View File

@ -13,6 +13,7 @@ import (
"github.com/spf13/pflag"
"golang.org/x/exp/slices"
"golang.org/x/xerrors"
"gopkg.in/yaml.v3"
)
// Cmd describes an executable command.
@ -76,10 +77,8 @@ func (c *Cmd) PrepareAll() error {
}
var merr error
slices.SortFunc(c.Options, func(a, b Option) bool {
return a.Flag < b.Flag
})
for _, opt := range c.Options {
for i := range c.Options {
opt := &c.Options[i]
if opt.Name == "" {
switch {
case opt.Flag != "":
@ -102,6 +101,10 @@ func (c *Cmd) PrepareAll() error {
}
}
}
slices.SortFunc(c.Options, func(a, b Option) bool {
return a.Name < b.Name
})
slices.SortFunc(c.Children, func(a, b *Cmd) bool {
return a.Name() < b.Name()
})
@ -262,17 +265,38 @@ func (inv *Invocation) run(state *runState) error {
parsedArgs = inv.parsedFlags.Args()
}
// Set defaults for flags that weren't set by the user.
skipDefaults := make(map[int]struct{}, len(inv.Command.Options))
// Set value sources for flags.
for i, opt := range inv.Command.Options {
if fl := inv.parsedFlags.Lookup(opt.Flag); fl != nil && fl.Changed {
skipDefaults[i] = struct{}{}
}
if opt.envChanged {
skipDefaults[i] = struct{}{}
inv.Command.Options[i].ValueSource = ValueSourceFlag
}
}
err = inv.Command.Options.SetDefaults(skipDefaults)
// Read YAML configs, if any.
for _, opt := range inv.Command.Options {
path, ok := opt.Value.(*YAMLConfigPath)
if !ok || path.String() == "" {
continue
}
byt, err := os.ReadFile(path.String())
if err != nil {
return xerrors.Errorf("reading yaml: %w", err)
}
var n yaml.Node
err = yaml.Unmarshal(byt, &n)
if err != nil {
return xerrors.Errorf("decoding yaml: %w", err)
}
err = inv.Command.Options.UnmarshalYAML(&n)
if err != nil {
return xerrors.Errorf("applying yaml: %w", err)
}
}
err = inv.Command.Options.SetDefaults()
if err != nil {
return xerrors.Errorf("setting defaults: %w", err)
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"os"
"strings"
"testing"
@ -555,42 +556,80 @@ func TestCommand_EmptySlice(t *testing.T) {
func TestCommand_DefaultsOverride(t *testing.T) {
t.Parallel()
var got string
cmd := &clibase.Cmd{
Options: clibase.OptionSet{
{
Name: "url",
Flag: "url",
Default: "def.com",
Env: "URL",
Value: clibase.StringOf(&got),
},
},
Handler: (func(i *clibase.Invocation) error {
_, _ = fmt.Fprintf(i.Stdout, "%s", got)
return nil
}),
test := func(name string, want string, fn func(t *testing.T, inv *clibase.Invocation)) {
t.Run(name, func(t *testing.T) {
t.Parallel()
var (
got string
config clibase.YAMLConfigPath
)
cmd := &clibase.Cmd{
Options: clibase.OptionSet{
{
Name: "url",
Flag: "url",
Default: "def.com",
Env: "URL",
Value: clibase.StringOf(&got),
YAML: "url",
},
{
Name: "config",
Flag: "config",
Default: "",
Value: &config,
},
},
Handler: (func(i *clibase.Invocation) error {
_, _ = fmt.Fprintf(i.Stdout, "%s", got)
return nil
}),
}
inv := cmd.Invoke()
stdio := fakeIO(inv)
fn(t, inv)
err := inv.Run()
require.NoError(t, err)
require.Equal(t, want, stdio.Stdout.String())
})
}
// Base case
inv := cmd.Invoke()
stdio := fakeIO(inv)
err := inv.Run()
require.NoError(t, err)
require.Equal(t, "def.com", stdio.Stdout.String())
test("DefaultOverNothing", "def.com", func(t *testing.T, inv *clibase.Invocation) {})
// Flag overrides
inv = cmd.Invoke("--url", "good.com")
stdio = fakeIO(inv)
err = inv.Run()
require.NoError(t, err)
require.Equal(t, "good.com", stdio.Stdout.String())
test("FlagOverDefault", "good.com", func(t *testing.T, inv *clibase.Invocation) {
inv.Args = []string{"--url", "good.com"}
})
// Env overrides
inv = cmd.Invoke()
inv.Environ.Set("URL", "good.com")
stdio = fakeIO(inv)
err = inv.Run()
require.NoError(t, err)
require.Equal(t, "good.com", stdio.Stdout.String())
test("EnvOverDefault", "good.com", func(t *testing.T, inv *clibase.Invocation) {
inv.Environ.Set("URL", "good.com")
})
test("FlagOverEnv", "good.com", func(t *testing.T, inv *clibase.Invocation) {
inv.Environ.Set("URL", "bad.com")
inv.Args = []string{"--url", "good.com"}
})
test("FlagOverYAML", "good.com", func(t *testing.T, inv *clibase.Invocation) {
fi, err := os.CreateTemp(t.TempDir(), "config.yaml")
require.NoError(t, err)
defer fi.Close()
_, err = fi.WriteString("url: bad.com")
require.NoError(t, err)
inv.Args = []string{"--config", fi.Name(), "--url", "good.com"}
})
test("YAMLOverDefault", "good.com", func(t *testing.T, inv *clibase.Invocation) {
fi, err := os.CreateTemp(t.TempDir(), "config.yaml")
require.NoError(t, err)
defer fi.Close()
_, err = fi.WriteString("url: good.com")
require.NoError(t, err)
inv.Args = []string{"--config", fi.Name()}
})
}

View File

@ -2,12 +2,23 @@ package clibase
import (
"os"
"strings"
"github.com/hashicorp/go-multierror"
"github.com/spf13/pflag"
"golang.org/x/xerrors"
)
type ValueSource string
const (
ValueSourceNone ValueSource = ""
ValueSourceFlag ValueSource = "flag"
ValueSourceEnv ValueSource = "env"
ValueSourceYAML ValueSource = "yaml"
ValueSourceDefault ValueSource = "default"
)
// Option is a configuration option for a CLI application.
type Option struct {
Name string `json:"name,omitempty"`
@ -47,7 +58,18 @@ type Option struct {
Hidden bool `json:"hidden,omitempty"`
envChanged bool
ValueSource ValueSource `json:"value_source,omitempty"`
}
func (o Option) YAMLPath() string {
if o.YAML == "" {
return ""
}
var gs []string
for _, g := range o.Group.Ancestry() {
gs = append(gs, g.YAML)
}
return strings.Join(append(gs, o.YAML), ".")
}
// OptionSet is a group of options that can be applied to a command.
@ -135,8 +157,7 @@ func (s *OptionSet) ParseEnv(vs []EnvVar) error {
continue
}
opt.envChanged = true
(*s)[i] = opt
(*s)[i].ValueSource = ValueSourceEnv
if err := opt.Value.Set(envVal); err != nil {
merr = multierror.Append(
merr, xerrors.Errorf("parse %q: %w", opt.Name, err),
@ -148,8 +169,8 @@ func (s *OptionSet) ParseEnv(vs []EnvVar) error {
}
// SetDefaults sets the default values for each Option, skipping values
// that have already been set as indicated by the skip map.
func (s *OptionSet) SetDefaults(skip map[int]struct{}) error {
// that already have a value source.
func (s *OptionSet) SetDefaults() error {
if s == nil {
return nil
}
@ -158,10 +179,8 @@ func (s *OptionSet) SetDefaults(skip map[int]struct{}) error {
for i, opt := range *s {
// Skip values that may have already been set by the user.
if len(skip) > 0 {
if _, ok := skip[i]; ok {
continue
}
if opt.ValueSource != ValueSourceNone {
continue
}
if opt.Default == "" {
@ -178,6 +197,7 @@ func (s *OptionSet) SetDefaults(skip map[int]struct{}) error {
)
continue
}
(*s)[i].ValueSource = ValueSourceDefault
if err := opt.Value.Set(opt.Default); err != nil {
merr = multierror.Append(
merr, xerrors.Errorf("parse %q: %w", opt.Name, err),
@ -186,3 +206,15 @@ func (s *OptionSet) SetDefaults(skip map[int]struct{}) error {
}
return merr.ErrorOrNil()
}
// ByName returns the Option with the given name, or nil if no such option
// exists.
func (s *OptionSet) ByName(name string) *Option {
for i := range *s {
opt := &(*s)[i]
if opt.Name == name {
return opt
}
}
return nil
}

View File

@ -49,7 +49,7 @@ func TestOptionSet_ParseFlags(t *testing.T) {
},
}
err := os.SetDefaults(nil)
err := os.SetDefaults()
require.NoError(t, err)
err = os.FlagSet().Parse([]string{"--name", "foo", "--name", "bar"})
@ -111,7 +111,7 @@ func TestOptionSet_ParseEnv(t *testing.T) {
},
}
err := os.SetDefaults(nil)
err := os.SetDefaults()
require.NoError(t, err)
err = os.ParseEnv(clibase.ParseEnviron([]string{"CODER_WORKSPACE_NAME="}, "CODER_"))
@ -133,7 +133,7 @@ func TestOptionSet_ParseEnv(t *testing.T) {
},
}
err := os.SetDefaults(nil)
err := os.SetDefaults()
require.NoError(t, err)
err = os.ParseEnv([]clibase.EnvVar{
@ -157,7 +157,7 @@ func TestOptionSet_ParseEnv(t *testing.T) {
},
}
err := os.SetDefaults(nil)
err := os.SetDefaults()
require.NoError(t, err)
err = os.ParseEnv([]clibase.EnvVar{

View File

@ -6,6 +6,7 @@ import (
"fmt"
"net"
"net/url"
"reflect"
"strconv"
"strings"
"time"
@ -194,6 +195,17 @@ func (Duration) Type() string {
return "duration"
}
func (d *Duration) MarshalYAML() (interface{}, error) {
return yaml.Node{
Kind: yaml.ScalarNode,
Value: d.String(),
}, nil
}
func (d *Duration) UnmarshalYAML(n *yaml.Node) error {
return d.Set(n.Value)
}
type URL url.URL
func URLOf(u *url.URL) *URL {
@ -214,6 +226,17 @@ func (u *URL) String() string {
return uu.String()
}
func (u *URL) MarshalYAML() (interface{}, error) {
return yaml.Node{
Kind: yaml.ScalarNode,
Value: u.String(),
}, nil
}
func (u *URL) UnmarshalYAML(n *yaml.Node) error {
return u.Set(n.Value)
}
func (u *URL) MarshalJSON() ([]byte, error) {
return json.Marshal(u.String())
}
@ -277,6 +300,17 @@ func (hp *HostPort) UnmarshalJSON(b []byte) error {
return hp.Set(s)
}
func (hp *HostPort) MarshalYAML() (interface{}, error) {
return yaml.Node{
Kind: yaml.ScalarNode,
Value: hp.String(),
}, nil
}
func (hp *HostPort) UnmarshalYAML(n *yaml.Node) error {
return hp.Set(n.Value)
}
func (*HostPort) Type() string {
return "host:port"
}
@ -317,6 +351,13 @@ func (s *Struct[T]) MarshalYAML() (interface{}, error) {
}
func (s *Struct[T]) UnmarshalYAML(n *yaml.Node) error {
// HACK: for compatibility with flags, we use nil slices instead of empty
// slices. In most cases, nil slices and empty slices are treated
// the same, so this behavior may be removed at some point.
if typ := reflect.TypeOf(s.Value); typ.Kind() == reflect.Slice && len(n.Content) == 0 {
reflect.ValueOf(&s.Value).Elem().Set(reflect.Zero(typ))
return nil
}
return n.Decode(&s.Value)
}
@ -382,3 +423,22 @@ func (e *Enum) Type() string {
func (e *Enum) String() string {
return *e.Value
}
var _ pflag.Value = (*YAMLConfigPath)(nil)
// YAMLConfigPath is a special value type that encodes a path to a YAML
// configuration file where options are read from.
type YAMLConfigPath string
func (p *YAMLConfigPath) Set(v string) error {
*p = YAMLConfigPath(v)
return nil
}
func (p *YAMLConfigPath) String() string {
return string(*p)
}
func (*YAMLConfigPath) Type() string {
return "yaml-config-path"
}

View File

@ -1,12 +1,20 @@
package clibase
import (
"github.com/iancoleman/strcase"
"errors"
"fmt"
"strings"
"github.com/mitchellh/go-wordwrap"
"golang.org/x/xerrors"
"gopkg.in/yaml.v3"
)
var (
_ yaml.Marshaler = new(OptionSet)
_ yaml.Unmarshaler = new(OptionSet)
)
// deepMapNode returns the mapping node at the given path,
// creating it if it doesn't exist.
func deepMapNode(n *yaml.Node, path []string, headComment string) *yaml.Node {
@ -36,27 +44,43 @@ func deepMapNode(n *yaml.Node, path []string, headComment string) *yaml.Node {
return deepMapNode(&valueNode, path[1:], headComment)
}
// ToYAML converts the option set to a YAML node, that can be
// MarshalYAML converts the option set to a YAML node, that can be
// converted into bytes via yaml.Marshal.
//
// The node is returned to enable post-processing higher up in
// the stack.
func (s OptionSet) ToYAML() (*yaml.Node, error) {
//
// It is isomorphic with FromYAML.
func (s *OptionSet) MarshalYAML() (any, error) {
root := yaml.Node{
Kind: yaml.MappingNode,
}
for _, opt := range s {
for _, opt := range *s {
if opt.YAML == "" {
continue
}
defValue := opt.Default
if defValue == "" {
defValue = "<unset>"
}
comment := wordwrap.WrapString(
fmt.Sprintf("%s\n(default: %s, type: %s)", opt.Description, defValue, opt.Value.Type()),
80,
)
nameNode := yaml.Node{
Kind: yaml.ScalarNode,
Value: opt.YAML,
HeadComment: wordwrap.WrapString(opt.Description, 80),
HeadComment: comment,
}
var valueNode yaml.Node
if m, ok := opt.Value.(yaml.Marshaler); ok {
if opt.Value == nil {
valueNode = yaml.Node{
Kind: yaml.ScalarNode,
Value: "null",
}
} else if m, ok := opt.Value.(yaml.Marshaler); ok {
v, err := m.MarshalYAML()
if err != nil {
return nil, xerrors.Errorf(
@ -71,21 +95,43 @@ func (s OptionSet) ToYAML() (*yaml.Node, error) {
)
}
} else {
valueNode = yaml.Node{
Kind: yaml.ScalarNode,
Value: opt.Value.String(),
// The all-other types case.
//
// A bit of a hack, we marshal and then unmarshal to get
// the underlying node.
byt, err := yaml.Marshal(opt.Value)
if err != nil {
return nil, xerrors.Errorf(
"marshal %q: %w", opt.Name, err,
)
}
var docNode yaml.Node
err = yaml.Unmarshal(byt, &docNode)
if err != nil {
return nil, xerrors.Errorf(
"unmarshal %q: %w", opt.Name, err,
)
}
if len(docNode.Content) != 1 {
return nil, xerrors.Errorf(
"unmarshal %q: expected one node, got %d",
opt.Name, len(docNode.Content),
)
}
valueNode = *docNode.Content[0]
}
var group []string
for _, g := range opt.Group.Ancestry() {
if g.Name == "" {
if g.YAML == "" {
return nil, xerrors.Errorf(
"group name is empty for %q, groups: %+v",
"group yaml name is empty for %q, groups: %+v",
opt.Name,
opt.Group,
)
}
group = append(group, strcase.ToLowerCamel(g.Name))
group = append(group, g.YAML)
}
var groupDesc string
if opt.Group != nil {
@ -103,3 +149,147 @@ func (s OptionSet) ToYAML() (*yaml.Node, error) {
}
return &root, nil
}
// mapYAMLNodes converts parent into a map with keys of form "group.subgroup.option"
// and values as the corresponding YAML nodes.
func mapYAMLNodes(parent *yaml.Node) (map[string]*yaml.Node, error) {
if parent.Kind != yaml.MappingNode {
return nil, xerrors.Errorf("expected mapping node, got type %v", parent.Kind)
}
if len(parent.Content)%2 != 0 {
return nil, xerrors.Errorf("expected an even number of k/v pairs, got %d", len(parent.Content))
}
var (
key string
m = make(map[string]*yaml.Node, len(parent.Content)/2)
merr error
)
for i, child := range parent.Content {
if i%2 == 0 {
if child.Kind != yaml.ScalarNode {
// We immediately because the rest of the code is bound to fail
// if we don't know to expect a key or a value.
return nil, xerrors.Errorf("expected scalar node for key, got type %v", child.Kind)
}
key = child.Value
continue
}
// We don't know if this is a grouped simple option or complex option,
// so we store both "key" and "group.key". Since we're storing pointers,
// the additional memory is of little concern.
m[key] = child
if child.Kind != yaml.MappingNode {
continue
}
sub, err := mapYAMLNodes(child)
if err != nil {
merr = errors.Join(merr, xerrors.Errorf("mapping node %q: %w", key, err))
continue
}
for k, v := range sub {
m[key+"."+k] = v
}
}
return m, nil
}
func (o *Option) setFromYAMLNode(n *yaml.Node) error {
o.ValueSource = ValueSourceYAML
if um, ok := o.Value.(yaml.Unmarshaler); ok {
return um.UnmarshalYAML(n)
}
switch n.Kind {
case yaml.ScalarNode:
return o.Value.Set(n.Value)
case yaml.SequenceNode:
// We treat empty values as nil for consistency with other option
// mechanisms.
if len(n.Content) == 0 {
o.Value = nil
return nil
}
return n.Decode(o.Value)
case yaml.MappingNode:
return xerrors.Errorf("mapping nodes must implement yaml.Unmarshaler")
default:
return xerrors.Errorf("unexpected node kind %v", n.Kind)
}
}
// UnmarshalYAML converts the given YAML node into the option set.
// It is isomorphic with ToYAML.
func (s *OptionSet) UnmarshalYAML(rootNode *yaml.Node) error {
// The rootNode will be a DocumentNode if it's read from a file. We do
// not support multiple documents in a single file.
if rootNode.Kind == yaml.DocumentNode {
if len(rootNode.Content) != 1 {
return xerrors.Errorf("expected one node in document, got %d", len(rootNode.Content))
}
rootNode = rootNode.Content[0]
}
yamlNodes, err := mapYAMLNodes(rootNode)
if err != nil {
return xerrors.Errorf("mapping nodes: %w", err)
}
matchedNodes := make(map[string]*yaml.Node, len(yamlNodes))
var merr error
for i := range *s {
opt := &(*s)[i]
if opt.YAML == "" {
continue
}
var group []string
for _, g := range opt.Group.Ancestry() {
if g.YAML == "" {
return xerrors.Errorf(
"group yaml name is empty for %q, groups: %+v",
opt.Name,
opt.Group,
)
}
group = append(group, g.YAML)
delete(yamlNodes, strings.Join(group, "."))
}
key := strings.Join(append(group, opt.YAML), ".")
node, ok := yamlNodes[key]
if !ok {
continue
}
matchedNodes[key] = node
if opt.ValueSource != ValueSourceNone {
continue
}
if err := opt.setFromYAMLNode(node); err != nil {
merr = errors.Join(merr, xerrors.Errorf("setting %q: %w", opt.YAML, err))
}
}
// Remove all matched nodes and their descendants from yamlNodes so we
// can accurately report unknown options.
for k := range yamlNodes {
var key string
for _, part := range strings.Split(k, ".") {
if key != "" {
key += "."
}
key += part
if _, ok := matchedNodes[key]; ok {
delete(yamlNodes, k)
}
}
}
for k := range yamlNodes {
merr = errors.Join(merr, xerrors.Errorf("unknown option %q", k))
}
return merr
}

View File

@ -3,13 +3,15 @@ package clibase_test
import (
"testing"
"github.com/spf13/pflag"
"github.com/stretchr/testify/require"
"golang.org/x/exp/slices"
"gopkg.in/yaml.v3"
"github.com/coder/coder/cli/clibase"
)
func TestOption_ToYAML(t *testing.T) {
func TestOptionSet_YAML(t *testing.T) {
t.Parallel()
t.Run("RequireKey", func(t *testing.T) {
@ -23,9 +25,9 @@ func TestOption_ToYAML(t *testing.T) {
},
}
node, err := os.ToYAML()
node, err := os.MarshalYAML()
require.NoError(t, err)
require.Len(t, node.Content, 0)
require.Len(t, node.(*yaml.Node).Content, 0)
})
t.Run("SimpleString", func(t *testing.T) {
@ -39,15 +41,15 @@ func TestOption_ToYAML(t *testing.T) {
Value: &workspaceName,
Default: "billie",
Description: "The workspace's name.",
Group: &clibase.Group{Name: "Names"},
Group: &clibase.Group{YAML: "names"},
YAML: "workspaceName",
},
}
err := os.SetDefaults(nil)
err := os.SetDefaults()
require.NoError(t, err)
n, err := os.ToYAML()
n, err := os.MarshalYAML()
require.NoError(t, err)
// Visually inspect for now.
byt, err := yaml.Marshal(n)
@ -55,3 +57,146 @@ func TestOption_ToYAML(t *testing.T) {
t.Logf("Raw YAML:\n%s", string(byt))
})
}
func TestOptionSet_YAMLUnknownOptions(t *testing.T) {
t.Parallel()
os := clibase.OptionSet{
{
Name: "Workspace Name",
Default: "billie",
Description: "The workspace's name.",
YAML: "workspaceName",
Value: new(clibase.String),
},
}
const yamlDoc = `something: else`
err := yaml.Unmarshal([]byte(yamlDoc), &os)
require.Error(t, err)
require.Empty(t, os[0].Value.String())
os[0].YAML = "something"
err = yaml.Unmarshal([]byte(yamlDoc), &os)
require.NoError(t, err)
require.Equal(t, "else", os[0].Value.String())
}
// TestOptionSet_YAMLIsomorphism tests that the YAML representations of an
// OptionSet converts to the same OptionSet when read back in.
func TestOptionSet_YAMLIsomorphism(t *testing.T) {
t.Parallel()
// This is used to form a generic.
//nolint:unused
type kid struct {
Name string `yaml:"name"`
Age int `yaml:"age"`
}
for _, tc := range []struct {
name string
os clibase.OptionSet
zeroValue func() pflag.Value
}{
{
name: "SimpleString",
os: clibase.OptionSet{
{
Name: "Workspace Name",
Default: "billie",
Description: "The workspace's name.",
Group: &clibase.Group{YAML: "names"},
YAML: "workspaceName",
},
},
zeroValue: func() pflag.Value {
return clibase.StringOf(new(string))
},
},
{
name: "Array",
os: clibase.OptionSet{
{
YAML: "names",
Default: "jill,jack,joan",
},
},
zeroValue: func() pflag.Value {
return clibase.StringArrayOf(&[]string{})
},
},
{
name: "ComplexObject",
os: clibase.OptionSet{
{
YAML: "kids",
Default: `- name: jill
age: 12
- name: jack
age: 13`,
},
},
zeroValue: func() pflag.Value {
return &clibase.Struct[[]kid]{}
},
},
{
name: "DeepGroup",
os: clibase.OptionSet{
{
YAML: "names",
Default: "jill,jack,joan",
Group: &clibase.Group{YAML: "kids", Parent: &clibase.Group{YAML: "family"}},
},
},
zeroValue: func() pflag.Value {
return clibase.StringArrayOf(&[]string{})
},
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// Set initial values.
for i := range tc.os {
tc.os[i].Value = tc.zeroValue()
}
err := tc.os.SetDefaults()
require.NoError(t, err)
y, err := tc.os.MarshalYAML()
require.NoError(t, err)
toByt, err := yaml.Marshal(y)
require.NoError(t, err)
t.Logf("Raw YAML:\n%s", string(toByt))
var y2 yaml.Node
err = yaml.Unmarshal(toByt, &y2)
require.NoError(t, err)
os2 := slices.Clone(tc.os)
for i := range os2 {
os2[i].Value = tc.zeroValue()
os2[i].ValueSource = clibase.ValueSourceNone
}
// os2 values should be zeroed whereas tc.os should be
// set to defaults.
// This check makes sure we aren't mixing pointers.
require.NotEqual(t, tc.os, os2)
err = os2.UnmarshalYAML(&y2)
require.NoError(t, err)
want := tc.os
for i := range want {
want[i].ValueSource = clibase.ValueSourceYAML
}
require.Equal(t, tc.os, os2)
})
}
}

View File

@ -226,6 +226,8 @@ func StartWithWaiter(t *testing.T, inv *clibase.Invocation) *ErrorWaiter {
// down Postgres.
t.Logf("command %q timed out during test cleanup", inv.Command.FullName())
}
// Whether or not this fails the test is left to the caller.
t.Logf("command %q exited with error: %v", inv.Command.FullName(), err)
errCh <- err
}()

View File

@ -16,6 +16,7 @@ import (
"runtime"
"strings"
"syscall"
"text/tabwriter"
"time"
"golang.org/x/exp/slices"
@ -250,6 +251,26 @@ func (r *RootCmd) Command(subcommands []*clibase.Cmd) (*clibase.Cmd, error) {
return nil, merr
}
var debugOptions bool
// Add a wrapper to every command to enable debugging options.
cmd.Walk(func(cmd *clibase.Cmd) {
h := cmd.Handler
cmd.Handler = func(i *clibase.Invocation) error {
if !debugOptions {
return h(i)
}
tw := tabwriter.NewWriter(i.Stdout, 0, 0, 4, ' ', 0)
_, _ = fmt.Fprintf(tw, "Option\tValue Source\n")
for _, opt := range cmd.Options {
_, _ = fmt.Fprintf(tw, "%q\t%v\n", opt.Name, opt.ValueSource)
}
tw.Flush()
return nil
}
})
if r.agentURL == nil {
r.agentURL = new(url.URL)
}
@ -269,6 +290,12 @@ func (r *RootCmd) Command(subcommands []*clibase.Cmd) (*clibase.Cmd, error) {
Value: clibase.URLOf(r.clientURL),
Group: globalGroup,
},
{
Flag: "debug-options",
Description: "Print all options, how they're set, then exit.",
Value: clibase.BoolOf(&debugOptions),
Group: globalGroup,
},
{
Flag: varToken,
Env: envSessionToken,

View File

@ -107,20 +107,7 @@ ExtractCommandPathsLoop:
actual = bytes.ReplaceAll(actual, []byte(k), []byte(v))
}
// Replace any timestamps with a placeholder.
actual = timestampRegex.ReplaceAll(actual, []byte("[timestamp]"))
homeDir, err := os.UserHomeDir()
require.NoError(t, err)
configDir := config.DefaultDir()
actual = bytes.ReplaceAll(actual, []byte(configDir), []byte("~/.config/coderv2"))
actual = bytes.ReplaceAll(actual, []byte(codersdk.DefaultCacheDir()), []byte("[cache dir]"))
// The home directory changes depending on the test environment.
actual = bytes.ReplaceAll(actual, []byte(homeDir), []byte("~"))
actual = normalizeGoldenFile(t, actual)
goldenPath := filepath.Join("testdata", strings.Replace(tt.name, " ", "_", -1)+".golden")
if *updateGoldenFiles {
t.Logf("update golden file for: %q: %s", tt.name, goldenPath)
@ -131,19 +118,7 @@ ExtractCommandPathsLoop:
expected, err := os.ReadFile(goldenPath)
require.NoError(t, err, "read golden file, run \"make update-golden-files\" and commit the changes")
// Normalize files to tolerate different operating systems.
for _, r := range []struct {
old string
new string
}{
{"\r\n", "\n"},
{`~\.cache\coder`, "~/.cache/coder"},
{`C:\Users\RUNNER~1\AppData\Local\Temp`, "/tmp"},
{os.TempDir(), "/tmp"},
} {
expected = bytes.ReplaceAll(expected, []byte(r.old), []byte(r.new))
actual = bytes.ReplaceAll(actual, []byte(r.old), []byte(r.new))
}
expected = normalizeGoldenFile(t, expected)
require.Equal(
t, string(expected), string(actual),
"golden file mismatch: %s, run \"make update-golden-files\", verify and commit the changes",
@ -153,6 +128,37 @@ ExtractCommandPathsLoop:
}
}
// normalizeGoldenFiles replaces any strings that are system or timing dependent
// with a placeholder so that the golden files can be compared with a simple
// equality check.
func normalizeGoldenFile(t *testing.T, byt []byte) []byte {
// Replace any timestamps with a placeholder.
byt = timestampRegex.ReplaceAll(byt, []byte("[timestamp]"))
homeDir, err := os.UserHomeDir()
require.NoError(t, err)
configDir := config.DefaultDir()
byt = bytes.ReplaceAll(byt, []byte(configDir), []byte("~/.config/coderv2"))
byt = bytes.ReplaceAll(byt, []byte(codersdk.DefaultCacheDir()), []byte("[cache dir]"))
// The home directory changes depending on the test environment.
byt = bytes.ReplaceAll(byt, []byte(homeDir), []byte("~"))
for _, r := range []struct {
old string
new string
}{
{"\r\n", "\n"},
{`~\.cache\coder`, "~/.cache/coder"},
{`C:\Users\RUNNER~1\AppData\Local\Temp`, "/tmp"},
{os.TempDir(), "/tmp"},
} {
byt = bytes.ReplaceAll(byt, []byte(r.old), []byte(r.new))
}
return byt
}
func extractVisibleCommandPaths(cmdPath []string, cmds []*clibase.Cmd) [][]string {
var cmdPaths [][]string
for _, c := range cmds {

View File

@ -176,12 +176,12 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
defer cancel()
if cfg.WriteConfig {
// TODO: this should output to a file.
n, err := opts.ToYAML()
n, err := opts.MarshalYAML()
if err != nil {
return xerrors.Errorf("generate yaml: %w", err)
}
enc := yaml.NewEncoder(inv.Stderr)
enc := yaml.NewEncoder(inv.Stdout)
enc.SetIndent(2)
err = enc.Encode(n)
if err != nil {
return xerrors.Errorf("encode yaml: %w", err)
@ -193,6 +193,10 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
return nil
}
if cfg.Config != "" {
cliui.Warnf(inv.Stderr, "YAML support is experimental and offers no compatibility guarantees.")
}
// Print deprecation warnings.
for _, opt := range opts {
if opt.UseInstead == nil {

View File

@ -2,6 +2,7 @@ package cli_test
import (
"bufio"
"bytes"
"context"
"crypto/ecdsa"
"crypto/elliptic"
@ -12,12 +13,14 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"io"
"math/big"
"net"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
@ -29,6 +32,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"gopkg.in/yaml.v3"
"github.com/coder/coder/cli"
"github.com/coder/coder/cli/clitest"
@ -1411,6 +1415,80 @@ func TestServer(t *testing.T) {
waitFile(t, fi3, testutil.WaitSuperLong)
})
})
t.Run("YAML", func(t *testing.T) {
t.Parallel()
t.Run("WriteThenReadConfig", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
args := []string{
"server",
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
"--log-human", filepath.Join(t.TempDir(), "coder-logging-test-human"),
// We use ecdsa here because it's the fastest alternative algorithm.
"--ssh-keygen-algorithm", "ecdsa",
"--cache-dir", t.TempDir(),
}
// First, we get the base config as set via flags (like users before
// migrating).
inv, cfg := clitest.New(t,
args...,
)
ptytest.New(t).Attach(inv)
inv = inv.WithContext(ctx)
w := clitest.StartWithWaiter(t, inv)
gotURL := waitAccessURL(t, cfg)
client := codersdk.New(gotURL)
_ = coderdtest.CreateFirstUser(t, client)
wantConfig, err := client.DeploymentConfig(ctx)
require.NoError(t, err)
cancel()
w.RequireSuccess()
// Next, we instruct the same server to display the YAML config
// and then save it.
inv = inv.WithContext(testutil.Context(t, testutil.WaitMedium))
inv.Args = append(args, "--write-config")
fi, err := os.OpenFile(testutil.TempFile(t, "", "coder-config-test-*"), os.O_WRONLY|os.O_CREATE, 0o600)
require.NoError(t, err)
defer fi.Close()
var conf bytes.Buffer
inv.Stdout = io.MultiWriter(fi, &conf)
t.Logf("%+v", inv.Args)
err = inv.Run()
require.NoError(t, err)
// Reset the context.
ctx = testutil.Context(t, testutil.WaitMedium)
// Finally, we restart the server with just the config and no flags
// and ensure that the live configuration is equivalent.
inv, cfg = clitest.New(t, "server", "--config="+fi.Name())
w = clitest.StartWithWaiter(t, inv)
client = codersdk.New(waitAccessURL(t, cfg))
_ = coderdtest.CreateFirstUser(t, client)
gotConfig, err := client.DeploymentConfig(ctx)
require.NoError(t, err, "config:\n%s\nargs: %+v", conf.String(), inv.Args)
gotConfig.Options.ByName("Config Path").Value.Set("")
// We check the options individually for better error messages.
for i := range wantConfig.Options {
assert.Equal(
t, wantConfig.Options[i],
gotConfig.Options[i],
"option %q",
wantConfig.Options[i].Name,
)
}
w.RequireSuccess()
})
})
}
func generateTLSCertificate(t testing.TB, commonName ...string) (certPath, keyPath string) {
@ -1470,3 +1548,42 @@ func waitAccessURL(t *testing.T, cfg config.Root) *url.URL {
return accessURL
}
func TestServerYAMLConfig(t *testing.T) {
t.Parallel()
var deployValues codersdk.DeploymentValues
opts := deployValues.Options()
err := opts.SetDefaults()
require.NoError(t, err)
n, err := opts.MarshalYAML()
require.NoError(t, err)
// Sanity-check that we can read the config back in.
err = opts.UnmarshalYAML(n.(*yaml.Node))
require.NoError(t, err)
var wantBuf bytes.Buffer
enc := yaml.NewEncoder(&wantBuf)
enc.SetIndent(2)
err = enc.Encode(n)
require.NoError(t, err)
wantByt := wantBuf.Bytes()
goldenPath := filepath.Join("testdata", "server-config.yaml.golden")
wantByt = normalizeGoldenFile(t, wantByt)
if *updateGoldenFiles {
require.NoError(t, os.WriteFile(goldenPath, wantByt, 0o600))
return
}
got, err := os.ReadFile(goldenPath)
require.NoError(t, err)
got = normalizeGoldenFile(t, got)
require.Equal(t, string(wantByt), string(got))
}

View File

@ -47,6 +47,9 @@ Coder v0.0.0-devel — A tool for provisioning self-hosted development environme
Global options are applied to all commands. They can be set using environment
variables or flags.
--debug-options bool
Print all options, how they're set, then exit.
--global-config string, $CODER_CONFIG_DIR (default: ~/.config/coderv2)
Path to the global `coder` config directory.

View File

@ -57,6 +57,16 @@ Clients include the coder cli, vs code extension, and the web UI.
--ssh-hostname-prefix string, $CODER_SSH_HOSTNAME_PREFIX (default: coder.)
The SSH deployment prefix is used in the Host of the ssh config.
Config Options
Use a YAML configuration file when your server launch become unwieldy.
-c, --config yaml-config-path, $CODER_CONFIG_PATH
Specify a YAML file to load configuration from.
--write-config bool
Write out the current server config as YAML to stdout.
Introspection / Logging Options
--log-human string, $CODER_LOGGING_HUMAN (default: /dev/stderr)
Output human-readable logs to a given file.

336
cli/testdata/server-config.yaml.golden vendored Normal file
View File

@ -0,0 +1,336 @@
networking:
# The URL that users will use to access the Coder deployment.
# (default: <unset>, type: url)
accessURL:
# Specifies the wildcard hostname to use for workspace applications in the form
# "*.example.com".
# (default: <unset>, type: url)
wildcardAccessURL:
# Specifies whether to redirect requests that do not match the access URL host.
# (default: <unset>, type: bool)
redirectToAccessURL: false
http:
# HTTP bind address of the server. Unset to disable the HTTP endpoint.
# (default: 127.0.0.1:3000, type: string)
httpAddress: 127.0.0.1:3000
# The maximum lifetime duration users can specify when creating an API token.
# (default: 876600h0m0s, type: duration)
maxTokenLifetime: 876600h0m0s
# The token expiry duration for browser sessions. Sessions may last longer if they
# are actively making requests, but this functionality can be disabled via
# --disable-session-expiry-refresh.
# (default: 24h0m0s, type: duration)
sessionDuration: 24h0m0s
# Disable automatic session expiry bumping due to activity. This forces all
# sessions to become invalid after the session expiry duration has been reached.
# (default: <unset>, type: bool)
disableSessionExpiryRefresh: false
# Disable password authentication. This is recommended for security purposes in
# production deployments that rely on an identity provider. Any user with the
# owner role will be able to sign in with their password regardless of this
# setting to avoid potential lock out. If you are locked out of your account, you
# can use the `coder server create-admin` command to create a new admin user
# directly in the database.
# (default: <unset>, type: bool)
disablePasswordAuth: false
# Configure TLS / HTTPS for your Coder deployment. If you're running
# Coder behind a TLS-terminating reverse proxy or are accessing Coder over a
# secure link, you can safely ignore these settings.
tls:
# HTTPS bind address of the server.
# (default: 127.0.0.1:3443, type: host:port)
address: 127.0.0.1:3443
# Whether TLS will be enabled.
# (default: <unset>, type: bool)
enable: false
# Whether HTTP requests will be redirected to the access URL (if it's a https URL
# and TLS is enabled). Requests to local IP addresses are never redirected
# regardless of this setting.
# (default: true, type: bool)
redirectHTTP: true
# Path to each certificate for TLS. It requires a PEM-encoded file. To configure
# the listener to use a CA certificate, concatenate the primary certificate and
# the CA certificate together. The primary certificate should appear first in the
# combined file.
# (default: <unset>, type: string-array)
certFiles: []
# PEM-encoded Certificate Authority file used for checking the authenticity of
# client.
# (default: <unset>, type: string)
clientCAFile: ""
# Policy the server will follow for TLS Client Authentication. Accepted values are
# "none", "request", "require-any", "verify-if-given", or "require-and-verify".
# (default: none, type: string)
clientAuth: none
# Paths to the private keys for each of the certificates. It requires a
# PEM-encoded file.
# (default: <unset>, type: string-array)
keyFiles: []
# Minimum supported version of TLS. Accepted values are "tls10", "tls11", "tls12"
# or "tls13".
# (default: tls12, type: string)
minVersion: tls12
# Path to certificate for client TLS authentication. It requires a PEM-encoded
# file.
# (default: <unset>, type: string)
clientCertFile: ""
# Path to key for client TLS authentication. It requires a PEM-encoded file.
# (default: <unset>, type: string)
clientKeyFile: ""
# Controls if the 'Strict-Transport-Security' header is set on all static file
# responses. This header should only be set if the server is accessed via HTTPS.
# This value is the MaxAge in seconds of the header.
# (default: 0, type: int)
strictTransportSecurity: 0
# Two optional fields can be set in the Strict-Transport-Security header;
# 'includeSubDomains' and 'preload'. The 'strict-transport-security' flag must be
# set to a non-zero value for these options to be used.
# (default: <unset>, type: string-array)
strictTransportSecurityOptions: []
# Most Coder deployments never have to think about DERP because all connections
# between workspaces and users are peer-to-peer. However, when Coder cannot
# establish
# a peer to peer connection, Coder uses a distributed relay network backed by
# Tailscale and WireGuard.
derp:
# Whether to enable or disable the embedded DERP relay server.
# (default: true, type: bool)
enable: true
# Region ID to use for the embedded DERP server.
# (default: 999, type: int)
regionID: 999
# Region code to use for the embedded DERP server.
# (default: coder, type: string)
regionCode: coder
# Region name that for the embedded DERP server.
# (default: Coder Embedded Relay, type: string)
regionName: Coder Embedded Relay
# Addresses for STUN servers to establish P2P connections. Set empty to disable
# P2P connections.
# (default: stun.l.google.com:19302, type: string-array)
stunAddresses:
- stun.l.google.com:19302
# An HTTP URL that is accessible by other replicas to relay DERP traffic. Required
# for high availability.
# (default: <unset>, type: url)
relayURL:
# URL to fetch a DERP mapping on startup. See:
# https://tailscale.com/kb/1118/custom-derp-servers/.
# (default: <unset>, type: string)
url: ""
# Path to read a DERP mapping from. See:
# https://tailscale.com/kb/1118/custom-derp-servers/.
# (default: <unset>, type: string)
configPath: ""
# Headers to trust for forwarding IP addresses. e.g. Cf-Connecting-Ip,
# True-Client-Ip, X-Forwarded-For.
# (default: <unset>, type: string-array)
proxyTrustedHeaders: []
# Origin addresses to respect "proxy-trusted-headers". e.g. 192.168.1.0/24.
# (default: <unset>, type: string-array)
proxyTrustedOrigins: []
# Controls if the 'Secure' property is set on browser session cookies.
# (default: <unset>, type: bool)
secureAuthCookie: false
# Whether Coder only allows connections to workspaces via the browser.
# (default: <unset>, type: bool)
browserOnly: false
# Interval to poll for scheduled workspace builds.
# (default: 1m0s, type: duration)
autobuildPollInterval: 1m0s
introspection:
prometheus:
# Serve prometheus metrics on the address defined by prometheus address.
# (default: <unset>, type: bool)
enable: false
# The bind address to serve prometheus metrics.
# (default: 127.0.0.1:2112, type: host:port)
address: 127.0.0.1:2112
pprof:
# Serve pprof metrics on the address defined by pprof address.
# (default: <unset>, type: bool)
enable: false
# The bind address to serve pprof.
# (default: 127.0.0.1:6060, type: host:port)
address: 127.0.0.1:6060
tracing:
# Whether application tracing data is collected. It exports to a backend
# configured by environment variables. See:
# https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md.
# (default: <unset>, type: bool)
enable: false
# Enables capturing of logs as events in traces. This is useful for debugging, but
# may result in a very large amount of events being sent to the tracing backend
# which may incur significant costs. If the verbose flag was supplied, debug-level
# logs will be included.
# (default: <unset>, type: bool)
captureLogs: false
logging:
# Output debug-level logs.
# (default: <unset>, type: bool)
verbose: false
# Output human-readable logs to a given file.
# (default: /dev/stderr, type: string)
humanPath: /dev/stderr
# Output JSON logs to a given file.
# (default: <unset>, type: string)
jsonPath: ""
# Output Stackdriver compatible logs to a given file.
# (default: <unset>, type: string)
stackdriverPath: ""
oauth2:
github:
# Client ID for Login with GitHub.
# (default: <unset>, type: string)
clientID: ""
# Organizations the user must be a member of to Login with GitHub.
# (default: <unset>, type: string-array)
allowedOrgs: []
# Teams inside organizations the user must be a member of to Login with GitHub.
# Structured as: <organization-name>/<team-slug>.
# (default: <unset>, type: string-array)
allowedTeams: []
# Whether new users can sign up with GitHub.
# (default: <unset>, type: bool)
allowSignups: false
# Allow all logins, setting this option means allowed orgs and teams must be
# empty.
# (default: <unset>, type: bool)
allowEveryone: false
# Base URL of a GitHub Enterprise deployment to use for Login with GitHub.
# (default: <unset>, type: string)
enterpriseBaseURL: ""
oidc:
# Whether new users can sign up with OIDC.
# (default: true, type: bool)
allowSignups: true
# Client ID to use for Login with OIDC.
# (default: <unset>, type: string)
clientID: ""
# Email domains that clients logging in with OIDC must match.
# (default: <unset>, type: string-array)
emailDomain: []
# Issuer URL to use for Login with OIDC.
# (default: <unset>, type: string)
issuerURL: ""
# Scopes to grant when authenticating with OIDC.
# (default: openid,profile,email, type: string-array)
scopes:
- openid
- profile
- email
# Ignore the email_verified claim from the upstream provider.
# (default: <unset>, type: bool)
ignoreEmailVerified: false
# OIDC claim field to use as the username.
# (default: preferred_username, type: string)
usernameField: preferred_username
# OIDC claim field to use as the email.
# (default: email, type: string)
emailField: email
# OIDC auth URL parameters to pass to the upstream provider.
# (default: {"access_type": "offline"}, type: struct[map[string]string])
authURLParams:
access_type: offline
# Ignore the userinfo endpoint and only use the ID token for user information.
# (default: false, type: bool)
ignoreUserInfo: false
# Change the OIDC default 'groups' claim field. By default, will be 'groups' if
# present in the oidc scopes argument.
# (default: <unset>, type: string)
groupField: ""
# A map of OIDC group IDs and the group in Coder it should map to. This is useful
# for when OIDC providers only return group IDs.
# (default: {}, type: struct[map[string]string])
groupMapping: {}
# The text to show on the OpenID Connect sign in button.
# (default: OpenID Connect, type: string)
signInText: OpenID Connect
# URL pointing to the icon to use on the OepnID Connect login button.
# (default: <unset>, type: url)
iconURL:
# Telemetry is critical to our ability to improve Coder. We strip all personal
# information before sending data to our servers. Please only disable telemetry
# when required by your organization's security policy.
telemetry:
# Whether telemetry is enabled or not. Coder collects anonymized usage data to
# help improve our product.
# (default: false, type: bool)
enable: false
# Whether Opentelemetry traces are sent to Coder. Coder collects anonymized
# application tracing to help improve our product. Disabling telemetry also
# disables this option.
# (default: false, type: bool)
trace: false
# URL to send telemetry.
# (default: https://telemetry.coder.com, type: url)
url: https://telemetry.coder.com
# Tune the behavior of the provisioner, which is responsible for creating,
# updating, and deleting workspace resources.
provisioning:
# Number of provisioner daemons to create on start. If builds are stuck in queued
# state for a long time, consider increasing this.
# (default: 3, type: int)
daemons: 3
# Time to wait before polling for a new job.
# (default: 1s, type: duration)
daemonPollInterval: 1s
# Random jitter added to the poll interval.
# (default: 100ms, type: duration)
daemonPollJitter: 100ms
# Time to force cancel provisioning tasks that are stuck.
# (default: 10m0s, type: duration)
forceCancelInterval: 10m0s
# Enable one or more experiments. These are not ready for production. Separate
# multiple experiments with commas, or enter '*' to opt-in to all available
# experiments.
# (default: <unset>, type: string-array)
experiments: []
# Periodically check for new releases of Coder and inform the owner. The check is
# performed once per day.
# (default: false, type: bool)
updateCheck: false
# Expose the swagger endpoint via /swagger.
# (default: <unset>, type: bool)
enableSwagger: false
# The directory to cache temporary files. If unspecified and $CACHE_DIRECTORY is
# set, it will be used for compatibility with systemd.
# (default: [cache dir], type: string)
cacheDir: [cache dir]
# Controls whether data will be stored in an in-memory database.
# (default: <unset>, type: bool)
inMemoryDatabase: false
# The algorithm to use for generating ssh keys. Accepted values are "ed25519",
# "ecdsa", or "rsa4096".
# (default: ed25519, type: string)
sshKeygenAlgorithm: ed25519
# URL to use for agent troubleshooting when not set in the template.
# (default:
# https://coder.com/docs/coder-oss/latest/templates#troubleshooting-templates,
# type: url)
agentFallbackTroubleshootingURL: https://coder.com/docs/coder-oss/latest/templates#troubleshooting-templates
# Disable workspace apps that are not served from subdomains. Path-based apps can
# make requests to the Coder API and pose a security risk when the workspace
# serves malicious JavaScript. This is recommended for security purposes if a
# --wildcard-access-url is configured.
# (default: <unset>, type: bool)
disablePathApps: false
# These options change the behavior of how clients interact with the Coder.
# Clients include the coder cli, vs code extension, and the web UI.
client:
# The SSH deployment prefix is used in the Host of the ssh config.
# (default: coder., type: string)
sshHostnamePrefix: coder.
# These SSH config options will override the default SSH config options. Provide
# options in "key=value" or "key value" format separated by commas.Using this
# incorrectly can break SSH to your deployment, use cautiously.
# (default: <unset>, type: string-array)
sshConfigOptions: []
# Support links to display in the top right drop down menu.
# (default: <unset>, type: struct[[]codersdk.LinkConfig])
supportLinks: []
# Hostname of HTTPS server that runs https://github.com/coder/wgtunnel. By
# default, this will pick the best available wgtunnel server hosted by Coder. e.g.
# "tunnel.example.com".
# (default: <unset>, type: string)
wgtunnelHost: ""

29
coderd/apidoc/docs.go generated
View File

@ -5721,12 +5721,6 @@ const docTemplate = `{
"clibase.Group": {
"type": "object",
"properties": {
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/clibase.Group"
}
},
"description": {
"type": "string"
},
@ -5735,6 +5729,9 @@ const docTemplate = `{
},
"parent": {
"$ref": "#/definitions/clibase.Group"
},
"yaml": {
"type": "string"
}
}
},
@ -5803,6 +5800,9 @@ const docTemplate = `{
"value": {
"description": "Value includes the types listed in values.go."
},
"value_source": {
"$ref": "#/definitions/clibase.ValueSource"
},
"yaml": {
"description": "YAML is the YAML key used to configure this option. If unset, YAML\nconfiguring is disabled.",
"type": "string"
@ -5883,6 +5883,23 @@ const docTemplate = `{
}
}
},
"clibase.ValueSource": {
"type": "string",
"enum": [
"",
"flag",
"env",
"yaml",
"default"
],
"x-enum-varnames": [
"ValueSourceNone",
"ValueSourceFlag",
"ValueSourceEnv",
"ValueSourceYAML",
"ValueSourceDefault"
]
},
"coderd.SCIMUser": {
"type": "object",
"properties": {

View File

@ -5066,12 +5066,6 @@
"clibase.Group": {
"type": "object",
"properties": {
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/clibase.Group"
}
},
"description": {
"type": "string"
},
@ -5080,6 +5074,9 @@
},
"parent": {
"$ref": "#/definitions/clibase.Group"
},
"yaml": {
"type": "string"
}
}
},
@ -5148,6 +5145,9 @@
"value": {
"description": "Value includes the types listed in values.go."
},
"value_source": {
"$ref": "#/definitions/clibase.ValueSource"
},
"yaml": {
"description": "YAML is the YAML key used to configure this option. If unset, YAML\nconfiguring is disabled.",
"type": "string"
@ -5228,6 +5228,17 @@
}
}
},
"clibase.ValueSource": {
"type": "string",
"enum": ["", "flag", "env", "yaml", "default"],
"x-enum-varnames": [
"ValueSourceNone",
"ValueSourceFlag",
"ValueSourceEnv",
"ValueSourceYAML",
"ValueSourceDefault"
]
},
"coderd.SCIMUser": {
"type": "object",
"properties": {

View File

@ -1108,7 +1108,7 @@ QastnN77KfUwdj3SJt44U/uh1jAIv4oSLBr8HYUkbnI8
func DeploymentValues(t *testing.T) *codersdk.DeploymentValues {
var cfg codersdk.DeploymentValues
opts := cfg.Options()
err := opts.SetDefaults(nil)
err := opts.SetDefaults()
require.NoError(t, err)
return &cfg
}

View File

@ -2,6 +2,8 @@ package rbac
import (
"errors"
"flag"
"fmt"
"github.com/open-policy-agent/opa/rego"
)
@ -10,7 +12,7 @@ const (
// errUnauthorized is the error message that should be returned to
// clients when an action is forbidden. It is intentionally vague to prevent
// disclosing information that a client should not have access to.
errUnauthorized = "forbidden"
errUnauthorized = "rbac: forbidden"
)
// UnauthorizedError is the error type for authorization errors
@ -51,8 +53,18 @@ func (e UnauthorizedError) Unwrap() error {
return e.internal
}
func (e *UnauthorizedError) longError() string {
return fmt.Sprintf(
"%s: (subject: %v), (action: %v), (object: %v), (output: %v)",
errUnauthorized, e.subject, e.action, e.object, e.output,
)
}
// Error implements the error interface.
func (UnauthorizedError) Error() string {
func (e UnauthorizedError) Error() string {
if flag.Lookup("test.v") != nil {
return e.longError()
}
return errUnauthorized
}

View File

@ -163,8 +163,8 @@ type DeploymentValues struct {
SSHConfig SSHConfig `json:"config_ssh,omitempty" typescript:",notnull"`
WgtunnelHost clibase.String `json:"wgtunnel_host,omitempty" typescript:",notnull"`
Config clibase.String `json:"config,omitempty" typescript:",notnull"`
WriteConfig clibase.Bool `json:"write_config,omitempty" typescript:",notnull"`
Config clibase.YAMLConfigPath `json:"config,omitempty" typescript:",notnull"`
WriteConfig clibase.Bool `json:"write_config,omitempty" typescript:",notnull"`
// DEPRECATED: Use HTTPAddress or TLS.Address instead.
Address clibase.HostPort `json:"address,omitempty" typescript:",notnull"`
@ -368,6 +368,7 @@ func (c *DeploymentValues) Options() clibase.OptionSet {
var (
deploymentGroupNetworking = clibase.Group{
Name: "Networking",
YAML: "networking",
}
deploymentGroupNetworkingTLS = clibase.Group{
Parent: &deploymentGroupNetworking,
@ -375,10 +376,12 @@ func (c *DeploymentValues) Options() clibase.OptionSet {
Description: `Configure TLS / HTTPS for your Coder deployment. If you're running
Coder behind a TLS-terminating reverse proxy or are accessing Coder over a
secure link, you can safely ignore these settings.`,
YAML: "tls",
}
deploymentGroupNetworkingHTTP = clibase.Group{
Parent: &deploymentGroupNetworking,
Name: "HTTP",
YAML: "http",
}
deploymentGroupNetworkingDERP = clibase.Group{
Parent: &deploymentGroupNetworking,
@ -387,40 +390,50 @@ func (c *DeploymentValues) Options() clibase.OptionSet {
between workspaces and users are peer-to-peer. However, when Coder cannot establish
a peer to peer connection, Coder uses a distributed relay network backed by
Tailscale and WireGuard.`,
YAML: "derp",
}
deploymentGroupIntrospection = clibase.Group{
Name: "Introspection",
Description: `Configure logging, tracing, and metrics exporting.`,
YAML: "introspection",
}
deploymentGroupIntrospectionPPROF = clibase.Group{
Parent: &deploymentGroupIntrospection,
Name: "pprof",
YAML: "pprof",
}
deploymentGroupIntrospectionPrometheus = clibase.Group{
Parent: &deploymentGroupIntrospection,
Name: "Prometheus",
YAML: "prometheus",
}
deploymentGroupIntrospectionTracing = clibase.Group{
Parent: &deploymentGroupIntrospection,
Name: "Tracing",
YAML: "tracing",
}
deploymentGroupIntrospectionLogging = clibase.Group{
Parent: &deploymentGroupIntrospection,
Name: "Logging",
YAML: "logging",
}
deploymentGroupOAuth2 = clibase.Group{
Name: "OAuth2",
Description: `Configure login and user-provisioning with GitHub via oAuth2.`,
YAML: "oauth2",
}
deploymentGroupOAuth2GitHub = clibase.Group{
Parent: &deploymentGroupOAuth2,
Name: "GitHub",
YAML: "github",
}
deploymentGroupOIDC = clibase.Group{
Name: "OIDC",
YAML: "oidc",
}
deploymentGroupTelemetry = clibase.Group{
Name: "Telemetry",
YAML: "telemetry",
Description: `Telemetry is critical to our ability to improve Coder. We strip all personal
information before sending data to our servers. Please only disable telemetry
when required by your organization's security policy.`,
@ -428,14 +441,17 @@ when required by your organization's security policy.`,
deploymentGroupProvisioning = clibase.Group{
Name: "Provisioning",
Description: `Tune the behavior of the provisioner, which is responsible for creating, updating, and deleting workspace resources.`,
YAML: "provisioning",
}
deploymentGroupDangerous = clibase.Group{
Name: "⚠️ Dangerous",
YAML: "dangerous",
}
deploymentGroupClient = clibase.Group{
Name: "Client",
Description: "These options change the behavior of how clients interact with the Coder. " +
"Clients include the coder cli, vs code extension, and the web UI.",
YAML: "client",
}
deploymentGroupConfig = clibase.Group{
Name: "Config",
@ -1340,11 +1356,9 @@ when required by your organization's security policy.`,
Flag: "config",
Env: "CODER_CONFIG_PATH",
FlagShorthand: "c",
// The config parameters are hidden until they are tested and
// documented.
Hidden: true,
Group: &deploymentGroupConfig,
Value: &c.Config,
Hidden: false,
Group: &deploymentGroupConfig,
Value: &c.Config,
},
{
Name: "SSH Host Prefix",
@ -1372,11 +1386,10 @@ when required by your organization's security policy.`,
{
Name: "Write Config",
Description: `
Write out the current server configuration to the path specified by --config.`,
Write out the current server config as YAML to stdout.`,
Flag: "write-config",
Env: "CODER_WRITE_CONFIG",
Group: &deploymentGroupConfig,
Hidden: true,
Hidden: false,
Value: &c.WriteConfig,
},
{
@ -1392,9 +1405,11 @@ Write out the current server configuration to the path specified by --config.`,
// Env handling is done in cli.ReadGitAuthFromEnvironment
Name: "Git Auth Providers",
Description: "Git Authentication providers.",
YAML: "gitAuthProviders",
Value: &c.GitAuthProviders,
Hidden: true,
// We need extra scrutiny to ensure this works, is documented, and
// tested before enabling.
// YAML: "gitAuthProviders",
Value: &c.GitAuthProviders,
Hidden: true,
},
{
Name: "Custom wgtunnel Host",

View File

@ -30,6 +30,7 @@ func TestDeploymentValues_HighlyConfigurable(t *testing.T) {
},
"Write Config": {
yaml: true,
env: true,
},
// Dangerous values? Not sure we should help users
// persistent their configuration.

View File

@ -371,27 +371,21 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
"flag": "string",
"flag_shorthand": "string",
"group": {
"children": [
{
"children": [],
"description": "string",
"name": "string",
"parent": {}
}
],
"description": "string",
"name": "string",
"parent": {
"children": [{}],
"description": "string",
"name": "string",
"parent": {}
}
"parent": {},
"yaml": "string"
},
"yaml": "string"
},
"hidden": true,
"name": "string",
"use_instead": [{}],
"value": null,
"value_source": "",
"yaml": "string"
}
]

View File

@ -384,33 +384,26 @@
```json
{
"children": [
{
"children": [],
"description": "string",
"name": "string",
"parent": {}
}
],
"description": "string",
"name": "string",
"parent": {
"children": [{}],
"description": "string",
"name": "string",
"parent": {}
}
"parent": {},
"yaml": "string"
},
"yaml": "string"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
| ------------- | --------------------------------------- | -------- | ------------ | ----------- |
| `children` | array of [clibase.Group](#clibasegroup) | false | | |
| `description` | string | false | | |
| `name` | string | false | | |
| `parent` | [clibase.Group](#clibasegroup) | false | | |
| Name | Type | Required | Restrictions | Description |
| ------------- | ------------------------------ | -------- | ------------ | ----------- |
| `description` | string | false | | |
| `name` | string | false | | |
| `parent` | [clibase.Group](#clibasegroup) | false | | |
| `yaml` | string | false | | |
## clibase.HostPort
@ -442,22 +435,15 @@
"flag": "string",
"flag_shorthand": "string",
"group": {
"children": [
{
"children": [],
"description": "string",
"name": "string",
"parent": {}
}
],
"description": "string",
"name": "string",
"parent": {
"children": [{}],
"description": "string",
"name": "string",
"parent": {}
}
"parent": {},
"yaml": "string"
},
"yaml": "string"
},
"hidden": true,
"name": "string",
@ -473,31 +459,26 @@
"flag": "string",
"flag_shorthand": "string",
"group": {
"children": [
{
"children": [],
"description": "string",
"name": "string",
"parent": {}
}
],
"description": "string",
"name": "string",
"parent": {
"children": [{}],
"description": "string",
"name": "string",
"parent": {}
}
"parent": {},
"yaml": "string"
},
"yaml": "string"
},
"hidden": true,
"name": "string",
"use_instead": [],
"value": null,
"value_source": "",
"yaml": "string"
}
],
"value": null,
"value_source": "",
"yaml": "string"
}
```
@ -517,6 +498,7 @@
| `name` | string | false | | |
| `use_instead` | array of [clibase.Option](#clibaseoption) | false | | Use instead is a list of options that should be used instead of this one. The field is used to generate a deprecation warning. |
| `value` | any | false | | Value includes the types listed in values.go. |
| `value_source` | [clibase.ValueSource](#clibasevaluesource) | false | | |
| `yaml` | string | false | | Yaml is the YAML key used to configure this option. If unset, YAML configuring is disabled. |
## clibase.Struct-array_codersdk_GitAuthConfig
@ -599,6 +581,24 @@
| `scheme` | string | false | | |
| `user` | [url.Userinfo](#urluserinfo) | false | | username and password information |
## clibase.ValueSource
```json
""
```
### Properties
#### Enumerated Values
| Value |
| --------- |
| `` |
| `flag` |
| `env` |
| `yaml` |
| `default` |
## coderd.SCIMUser
```json
@ -1997,27 +1997,21 @@ CreateParameterRequest is a structure used to create a new parameter value for a
"flag": "string",
"flag_shorthand": "string",
"group": {
"children": [
{
"children": [],
"description": "string",
"name": "string",
"parent": {}
}
],
"description": "string",
"name": "string",
"parent": {
"children": [{}],
"description": "string",
"name": "string",
"parent": {}
}
"parent": {},
"yaml": "string"
},
"yaml": "string"
},
"hidden": true,
"name": "string",
"use_instead": [{}],
"value": null,
"value_source": "",
"yaml": "string"
}
]

View File

@ -59,6 +59,14 @@ Coder — A tool for provisioning self-hosted development environments with Terr
## Options
### --debug-options
| | |
| ---- | ----------------- |
| Type | <code>bool</code> |
Print all options, how they're set, then exit.
### --global-config
| | |

View File

@ -22,19 +22,21 @@ coder server [flags]
### --access-url
| | |
| ----------- | ------------------------------ |
| Type | <code>url</code> |
| Environment | <code>$CODER_ACCESS_URL</code> |
| | |
| ----------- | --------------------------------- |
| Type | <code>url</code> |
| Environment | <code>$CODER_ACCESS_URL</code> |
| YAML | <code>networking.accessURL</code> |
The URL that users will use to access the Coder deployment.
### --browser-only
| | |
| ----------- | -------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_BROWSER_ONLY</code> |
| | |
| ----------- | ----------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_BROWSER_ONLY</code> |
| YAML | <code>networking.browserOnly</code> |
Whether Coder only allows connections to workspaces via the browser.
@ -44,10 +46,30 @@ Whether Coder only allows connections to workspaces via the browser.
| ----------- | ----------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_CACHE_DIRECTORY</code> |
| YAML | <code>cacheDir</code> |
| Default | <code>~/.cache/coder</code> |
The directory to cache temporary files. If unspecified and $CACHE_DIRECTORY is set, it will be used for compatibility with systemd.
### --trace-logs
| | |
| ----------- | ---------------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_TRACE_LOGS</code> |
| YAML | <code>introspection.tracing.captureLogs</code> |
Enables capturing of logs as events in traces. This is useful for debugging, but may result in a very large amount of events being sent to the tracing backend which may incur significant costs. If the verbose flag was supplied, debug-level logs will be included.
### -c, --config
| | |
| ----------- | ------------------------------- |
| Type | <code>yaml-config-path</code> |
| Environment | <code>$CODER_CONFIG_PATH</code> |
Specify a YAML file to load configuration from.
### --dangerous-allow-path-app-sharing
| | |
@ -68,10 +90,11 @@ Allow site-owners to access workspace apps from workspaces they do not own. Owne
### --derp-config-path
| | |
| ----------- | ------------------------------------ |
| Type | <code>string</code> |
| Environment | <code>$CODER_DERP_CONFIG_PATH</code> |
| | |
| ----------- | --------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_DERP_CONFIG_PATH</code> |
| YAML | <code>networking.derp.configPath</code> |
Path to read a DERP mapping from. See: https://tailscale.com/kb/1118/custom-derp-servers/.
@ -81,6 +104,7 @@ Path to read a DERP mapping from. See: https://tailscale.com/kb/1118/custom-derp
| ----------- | ----------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_DERP_CONFIG_URL</code> |
| YAML | <code>networking.derp.url</code> |
URL to fetch a DERP mapping on startup. See: https://tailscale.com/kb/1118/custom-derp-servers/.
@ -90,6 +114,7 @@ URL to fetch a DERP mapping on startup. See: https://tailscale.com/kb/1118/custo
| ----------- | -------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_DERP_SERVER_ENABLE</code> |
| YAML | <code>networking.derp.enable</code> |
| Default | <code>true</code> |
Whether to enable or disable the embedded DERP relay server.
@ -100,6 +125,7 @@ Whether to enable or disable the embedded DERP relay server.
| ----------- | ------------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_DERP_SERVER_REGION_CODE</code> |
| YAML | <code>networking.derp.regionCode</code> |
| Default | <code>coder</code> |
Region code to use for the embedded DERP server.
@ -110,6 +136,7 @@ Region code to use for the embedded DERP server.
| ----------- | ----------------------------------------- |
| Type | <code>int</code> |
| Environment | <code>$CODER_DERP_SERVER_REGION_ID</code> |
| YAML | <code>networking.derp.regionID</code> |
| Default | <code>999</code> |
Region ID to use for the embedded DERP server.
@ -120,6 +147,7 @@ Region ID to use for the embedded DERP server.
| ----------- | ------------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_DERP_SERVER_REGION_NAME</code> |
| YAML | <code>networking.derp.regionName</code> |
| Default | <code>Coder Embedded Relay</code> |
Region name that for the embedded DERP server.
@ -130,6 +158,7 @@ Region name that for the embedded DERP server.
| ----------- | ----------------------------------------- |
| Type | <code>url</code> |
| Environment | <code>$CODER_DERP_SERVER_RELAY_URL</code> |
| YAML | <code>networking.derp.relayURL</code> |
An HTTP URL that is accessible by other replicas to relay DERP traffic. Required for high availability.
@ -139,16 +168,18 @@ An HTTP URL that is accessible by other replicas to relay DERP traffic. Required
| ----------- | ---------------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_DERP_SERVER_STUN_ADDRESSES</code> |
| YAML | <code>networking.derp.stunAddresses</code> |
| Default | <code>stun.l.google.com:19302</code> |
Addresses for STUN servers to establish P2P connections. Set empty to disable P2P connections.
### --disable-password-auth
| | |
| ----------- | ----------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_DISABLE_PASSWORD_AUTH</code> |
| | |
| ----------- | ------------------------------------------------ |
| Type | <code>bool</code> |
| Environment | <code>$CODER_DISABLE_PASSWORD_AUTH</code> |
| YAML | <code>networking.http.disablePasswordAuth</code> |
Disable password authentication. This is recommended for security purposes in production deployments that rely on an identity provider. Any user with the owner role will be able to sign in with their password regardless of this setting to avoid potential lock out. If you are locked out of your account, you can use the `coder server create-admin` command to create a new admin user directly in the database.
@ -158,72 +189,91 @@ Disable password authentication. This is recommended for security purposes in pr
| ----------- | ------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_DISABLE_PATH_APPS</code> |
| YAML | <code>disablePathApps</code> |
Disable workspace apps that are not served from subdomains. Path-based apps can make requests to the Coder API and pose a security risk when the workspace serves malicious JavaScript. This is recommended for security purposes if a --wildcard-access-url is configured.
### --disable-session-expiry-refresh
| | |
| ----------- | -------------------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_DISABLE_SESSION_EXPIRY_REFRESH</code> |
| | |
| ----------- | -------------------------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_DISABLE_SESSION_EXPIRY_REFRESH</code> |
| YAML | <code>networking.http.disableSessionExpiryRefresh</code> |
Disable automatic session expiry bumping due to activity. This forces all sessions to become invalid after the session expiry duration has been reached.
### --swagger-enable
| | |
| ----------- | ---------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_SWAGGER_ENABLE</code> |
| YAML | <code>enableSwagger</code> |
Expose the swagger endpoint via /swagger.
### --experiments
| | |
| ----------- | ------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_EXPERIMENTS</code> |
| YAML | <code>experiments</code> |
Enable one or more experiments. These are not ready for production. Separate multiple experiments with commas, or enter '\*' to opt-in to all available experiments.
### --provisioner-force-cancel-interval
| | |
| ----------- | ----------------------------------------------------- |
| Type | <code>duration</code> |
| Environment | <code>$CODER_PROVISIONER_FORCE_CANCEL_INTERVAL</code> |
| YAML | <code>provisioning.forceCancelInterval</code> |
| Default | <code>10m0s</code> |
Time to force cancel provisioning tasks that are stuck.
### --http-address
| | |
| ----------- | -------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_HTTP_ADDRESS</code> |
| Default | <code>127.0.0.1:3000</code> |
| | |
| ----------- | ---------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_HTTP_ADDRESS</code> |
| YAML | <code>networking.http.httpAddress</code> |
| Default | <code>127.0.0.1:3000</code> |
HTTP bind address of the server. Unset to disable the HTTP endpoint.
### --log-human
| | |
| ----------- | --------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_LOGGING_HUMAN</code> |
| Default | <code>/dev/stderr</code> |
| | |
| ----------- | -------------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_LOGGING_HUMAN</code> |
| YAML | <code>introspection.logging.humanPath</code> |
| Default | <code>/dev/stderr</code> |
Output human-readable logs to a given file.
### --log-json
| | |
| ----------- | -------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_LOGGING_JSON</code> |
| | |
| ----------- | ------------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_LOGGING_JSON</code> |
| YAML | <code>introspection.logging.jsonPath</code> |
Output JSON logs to a given file.
### --log-stackdriver
| | |
| ----------- | --------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_LOGGING_STACKDRIVER</code> |
Output Stackdriver compatible logs to a given file.
### --max-token-lifetime
| | |
| ----------- | -------------------------------------- |
| Type | <code>duration</code> |
| Environment | <code>$CODER_MAX_TOKEN_LIFETIME</code> |
| Default | <code>876600h0m0s</code> |
| | |
| ----------- | --------------------------------------------- |
| Type | <code>duration</code> |
| Environment | <code>$CODER_MAX_TOKEN_LIFETIME</code> |
| YAML | <code>networking.http.maxTokenLifetime</code> |
| Default | <code>876600h0m0s</code> |
The maximum lifetime duration users can specify when creating an API token.
@ -233,6 +283,7 @@ The maximum lifetime duration users can specify when creating an API token.
| ----------- | ------------------------------------------------ |
| Type | <code>bool</code> |
| Environment | <code>$CODER_OAUTH2_GITHUB_ALLOW_EVERYONE</code> |
| YAML | <code>oauth2.github.allowEveryone</code> |
Allow all logins, setting this option means allowed orgs and teams must be empty.
@ -242,6 +293,7 @@ Allow all logins, setting this option means allowed orgs and teams must be empty
| ----------- | ----------------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS</code> |
| YAML | <code>oauth2.github.allowSignups</code> |
Whether new users can sign up with GitHub.
@ -251,6 +303,7 @@ Whether new users can sign up with GitHub.
| ----------- | ---------------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_OAUTH2_GITHUB_ALLOWED_ORGS</code> |
| YAML | <code>oauth2.github.allowedOrgs</code> |
Organizations the user must be a member of to Login with GitHub.
@ -260,6 +313,7 @@ Organizations the user must be a member of to Login with GitHub.
| ----------- | ----------------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_OAUTH2_GITHUB_ALLOWED_TEAMS</code> |
| YAML | <code>oauth2.github.allowedTeams</code> |
Teams inside organizations the user must be a member of to Login with GitHub. Structured as: <organization-name>/<team-slug>.
@ -269,6 +323,7 @@ Teams inside organizations the user must be a member of to Login with GitHub. St
| ----------- | ------------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_OAUTH2_GITHUB_CLIENT_ID</code> |
| YAML | <code>oauth2.github.clientID</code> |
Client ID for Login with GitHub.
@ -287,6 +342,7 @@ Client secret for Login with GitHub.
| ----------- | ----------------------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_OAUTH2_GITHUB_ENTERPRISE_BASE_URL</code> |
| YAML | <code>oauth2.github.enterpriseBaseURL</code> |
Base URL of a GitHub Enterprise deployment to use for Login with GitHub.
@ -296,6 +352,7 @@ Base URL of a GitHub Enterprise deployment to use for Login with GitHub.
| ----------- | -------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_OIDC_ALLOW_SIGNUPS</code> |
| YAML | <code>oidc.allowSignups</code> |
| Default | <code>true</code> |
Whether new users can sign up with OIDC.
@ -306,6 +363,7 @@ Whether new users can sign up with OIDC.
| ----------- | ---------------------------------------- |
| Type | <code>struct[map[string]string]</code> |
| Environment | <code>$CODER_OIDC_AUTH_URL_PARAMS</code> |
| YAML | <code>oidc.authURLParams</code> |
| Default | <code>{"access_type": "offline"}</code> |
OIDC auth URL parameters to pass to the upstream provider.
@ -316,6 +374,7 @@ OIDC auth URL parameters to pass to the upstream provider.
| ----------- | ---------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_OIDC_CLIENT_ID</code> |
| YAML | <code>oidc.clientID</code> |
Client ID to use for Login with OIDC.
@ -334,6 +393,7 @@ Client secret to use for Login with OIDC.
| ----------- | ------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_OIDC_EMAIL_DOMAIN</code> |
| YAML | <code>oidc.emailDomain</code> |
Email domains that clients logging in with OIDC must match.
@ -343,6 +403,7 @@ Email domains that clients logging in with OIDC must match.
| ----------- | ------------------------------------ |
| Type | <code>string</code> |
| Environment | <code>$CODER_OIDC_EMAIL_FIELD</code> |
| YAML | <code>oidc.emailField</code> |
| Default | <code>email</code> |
OIDC claim field to use as the email.
@ -353,6 +414,7 @@ OIDC claim field to use as the email.
| ----------- | ------------------------------------ |
| Type | <code>string</code> |
| Environment | <code>$CODER_OIDC_GROUP_FIELD</code> |
| YAML | <code>oidc.groupField</code> |
Change the OIDC default 'groups' claim field. By default, will be 'groups' if present in the oidc scopes argument.
@ -362,25 +424,18 @@ Change the OIDC default 'groups' claim field. By default, will be 'groups' if pr
| ----------- | -------------------------------------- |
| Type | <code>struct[map[string]string]</code> |
| Environment | <code>$CODER_OIDC_GROUP_MAPPING</code> |
| YAML | <code>oidc.groupMapping</code> |
| Default | <code>{}</code> |
A map of OIDC group IDs and the group in Coder it should map to. This is useful for when OIDC providers only return group IDs.
### --oidc-icon-url
| | |
| ----------- | --------------------------------- |
| Type | <code>url</code> |
| Environment | <code>$CODER_OIDC_ICON_URL</code> |
URL pointing to the icon to use on the OepnID Connect login button.
### --oidc-ignore-email-verified
| | |
| ----------- | ---------------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_OIDC_IGNORE_EMAIL_VERIFIED</code> |
| YAML | <code>oidc.ignoreEmailVerified</code> |
Ignore the email_verified claim from the upstream provider.
@ -390,6 +445,7 @@ Ignore the email_verified claim from the upstream provider.
| ----------- | ---------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_OIDC_IGNORE_USERINFO</code> |
| YAML | <code>oidc.ignoreUserInfo</code> |
| Default | <code>false</code> |
Ignore the userinfo endpoint and only use the ID token for user information.
@ -400,6 +456,7 @@ Ignore the userinfo endpoint and only use the ID token for user information.
| ----------- | ----------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_OIDC_ISSUER_URL</code> |
| YAML | <code>oidc.issuerURL</code> |
Issuer URL to use for Login with OIDC.
@ -409,76 +466,42 @@ Issuer URL to use for Login with OIDC.
| ----------- | --------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_OIDC_SCOPES</code> |
| YAML | <code>oidc.scopes</code> |
| Default | <code>openid,profile,email</code> |
Scopes to grant when authenticating with OIDC.
### --oidc-sign-in-text
| | |
| ----------- | ------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_OIDC_SIGN_IN_TEXT</code> |
| Default | <code>OpenID Connect</code> |
The text to show on the OpenID Connect sign in button.
### --oidc-username-field
| | |
| ----------- | --------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_OIDC_USERNAME_FIELD</code> |
| YAML | <code>oidc.usernameField</code> |
| Default | <code>preferred_username</code> |
OIDC claim field to use as the username.
### --postgres-url
### --oidc-sign-in-text
| | |
| ----------- | ------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_PG_CONNECTION_URL</code> |
| Environment | <code>$CODER_OIDC_SIGN_IN_TEXT</code> |
| YAML | <code>oidc.signInText</code> |
| Default | <code>OpenID Connect</code> |
URL of a PostgreSQL database. If empty, PostgreSQL binaries will be downloaded from Maven (https://repo1.maven.org/maven2) and store all data in the config root. Access the built-in database with "coder server postgres-builtin-url".
The text to show on the OpenID Connect sign in button.
### --pprof-address
### --oidc-icon-url
| | |
| ----------- | --------------------------------- |
| Type | <code>host:port</code> |
| Environment | <code>$CODER_PPROF_ADDRESS</code> |
| Default | <code>127.0.0.1:6060</code> |
| Type | <code>url</code> |
| Environment | <code>$CODER_OIDC_ICON_URL</code> |
| YAML | <code>oidc.iconURL</code> |
The bind address to serve pprof.
### --pprof-enable
| | |
| ----------- | -------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_PPROF_ENABLE</code> |
Serve pprof metrics on the address defined by pprof address.
### --prometheus-address
| | |
| ----------- | -------------------------------------- |
| Type | <code>host:port</code> |
| Environment | <code>$CODER_PROMETHEUS_ADDRESS</code> |
| Default | <code>127.0.0.1:2112</code> |
The bind address to serve prometheus metrics.
### --prometheus-enable
| | |
| ----------- | ------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_PROMETHEUS_ENABLE</code> |
Serve prometheus metrics on the address defined by prometheus address.
URL pointing to the icon to use on the OepnID Connect login button.
### --provisioner-daemon-poll-interval
@ -486,6 +509,7 @@ Serve prometheus metrics on the address defined by prometheus address.
| ----------- | ---------------------------------------------------- |
| Type | <code>duration</code> |
| Environment | <code>$CODER_PROVISIONER_DAEMON_POLL_INTERVAL</code> |
| YAML | <code>provisioning.daemonPollInterval</code> |
| Default | <code>1s</code> |
Time to wait before polling for a new job.
@ -496,54 +520,79 @@ Time to wait before polling for a new job.
| ----------- | -------------------------------------------------- |
| Type | <code>duration</code> |
| Environment | <code>$CODER_PROVISIONER_DAEMON_POLL_JITTER</code> |
| YAML | <code>provisioning.daemonPollJitter</code> |
| Default | <code>100ms</code> |
Random jitter added to the poll interval.
### --postgres-url
| | |
| ----------- | ------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_PG_CONNECTION_URL</code> |
URL of a PostgreSQL database. If empty, PostgreSQL binaries will be downloaded from Maven (https://repo1.maven.org/maven2) and store all data in the config root. Access the built-in database with "coder server postgres-builtin-url".
### --prometheus-address
| | |
| ----------- | --------------------------------------------- |
| Type | <code>host:port</code> |
| Environment | <code>$CODER_PROMETHEUS_ADDRESS</code> |
| YAML | <code>introspection.prometheus.address</code> |
| Default | <code>127.0.0.1:2112</code> |
The bind address to serve prometheus metrics.
### --prometheus-enable
| | |
| ----------- | -------------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_PROMETHEUS_ENABLE</code> |
| YAML | <code>introspection.prometheus.enable</code> |
Serve prometheus metrics on the address defined by prometheus address.
### --provisioner-daemons
| | |
| ----------- | --------------------------------------- |
| Type | <code>int</code> |
| Environment | <code>$CODER_PROVISIONER_DAEMONS</code> |
| YAML | <code>provisioning.daemons</code> |
| Default | <code>3</code> |
Number of provisioner daemons to create on start. If builds are stuck in queued state for a long time, consider increasing this.
### --provisioner-force-cancel-interval
| | |
| ----------- | ----------------------------------------------------- |
| Type | <code>duration</code> |
| Environment | <code>$CODER_PROVISIONER_FORCE_CANCEL_INTERVAL</code> |
| Default | <code>10m0s</code> |
Time to force cancel provisioning tasks that are stuck.
### --proxy-trusted-headers
| | |
| ----------- | ----------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_PROXY_TRUSTED_HEADERS</code> |
| | |
| ----------- | ------------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_PROXY_TRUSTED_HEADERS</code> |
| YAML | <code>networking.proxyTrustedHeaders</code> |
Headers to trust for forwarding IP addresses. e.g. Cf-Connecting-Ip, True-Client-Ip, X-Forwarded-For.
### --proxy-trusted-origins
| | |
| ----------- | ----------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_PROXY_TRUSTED_ORIGINS</code> |
| | |
| ----------- | ------------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_PROXY_TRUSTED_ORIGINS</code> |
| YAML | <code>networking.proxyTrustedOrigins</code> |
Origin addresses to respect "proxy-trusted-headers". e.g. 192.168.1.0/24.
### --redirect-to-access-url
| | |
| ----------- | ------------------------------------------ |
| Type | <code>bool</code> |
| Environment | <code>$CODER_REDIRECT_TO_ACCESS_URL</code> |
| | |
| ----------- | ------------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_REDIRECT_TO_ACCESS_URL</code> |
| YAML | <code>networking.redirectToAccessURL</code> |
Specifies whether to redirect requests that do not match the access URL host.
@ -556,31 +605,13 @@ Specifies whether to redirect requests that do not match the access URL host.
Enables SCIM and sets the authentication header for the built-in SCIM server. New users are automatically created with OIDC authentication.
### --secure-auth-cookie
| | |
| ----------- | -------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_SECURE_AUTH_COOKIE</code> |
Controls if the 'Secure' property is set on browser session cookies.
### --session-duration
| | |
| ----------- | ------------------------------------ |
| Type | <code>duration</code> |
| Environment | <code>$CODER_SESSION_DURATION</code> |
| Default | <code>24h0m0s</code> |
The token expiry duration for browser sessions. Sessions may last longer if they are actively making requests, but this functionality can be disabled via --disable-session-expiry-refresh.
### --ssh-config-options
| | |
| ----------- | -------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_SSH_CONFIG_OPTIONS</code> |
| YAML | <code>client.sshConfigOptions</code> |
These SSH config options will override the default SSH config options. Provide options in "key=value" or "key value" format separated by commas.Using this incorrectly can break SSH to your deployment, use cautiously.
@ -590,6 +621,7 @@ These SSH config options will override the default SSH config options. Provide o
| ----------- | --------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_SSH_HOSTNAME_PREFIX</code> |
| YAML | <code>client.sshHostnamePrefix</code> |
| Default | <code>coder.</code> |
The SSH deployment prefix is used in the Host of the ssh config.
@ -600,37 +632,155 @@ The SSH deployment prefix is used in the Host of the ssh config.
| ----------- | ---------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_SSH_KEYGEN_ALGORITHM</code> |
| YAML | <code>sshKeygenAlgorithm</code> |
| Default | <code>ed25519</code> |
The algorithm to use for generating ssh keys. Accepted values are "ed25519", "ecdsa", or "rsa4096".
### --secure-auth-cookie
| | |
| ----------- | ---------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_SECURE_AUTH_COOKIE</code> |
| YAML | <code>networking.secureAuthCookie</code> |
Controls if the 'Secure' property is set on browser session cookies.
### --session-duration
| | |
| ----------- | -------------------------------------------- |
| Type | <code>duration</code> |
| Environment | <code>$CODER_SESSION_DURATION</code> |
| YAML | <code>networking.http.sessionDuration</code> |
| Default | <code>24h0m0s</code> |
The token expiry duration for browser sessions. Sessions may last longer if they are actively making requests, but this functionality can be disabled via --disable-session-expiry-refresh.
### --log-stackdriver
| | |
| ----------- | -------------------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_LOGGING_STACKDRIVER</code> |
| YAML | <code>introspection.logging.stackdriverPath</code> |
Output Stackdriver compatible logs to a given file.
### --strict-transport-security
| | |
| ----------- | --------------------------------------------- |
| Type | <code>int</code> |
| Environment | <code>$CODER_STRICT_TRANSPORT_SECURITY</code> |
| Default | <code>0</code> |
| | |
| ----------- | --------------------------------------------------- |
| Type | <code>int</code> |
| Environment | <code>$CODER_STRICT_TRANSPORT_SECURITY</code> |
| YAML | <code>networking.tls.strictTransportSecurity</code> |
| Default | <code>0</code> |
Controls if the 'Strict-Transport-Security' header is set on all static file responses. This header should only be set if the server is accessed via HTTPS. This value is the MaxAge in seconds of the header.
### --strict-transport-security-options
| | |
| ----------- | ----------------------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_STRICT_TRANSPORT_SECURITY_OPTIONS</code> |
| | |
| ----------- | ---------------------------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_STRICT_TRANSPORT_SECURITY_OPTIONS</code> |
| YAML | <code>networking.tls.strictTransportSecurityOptions</code> |
Two optional fields can be set in the Strict-Transport-Security header; 'includeSubDomains' and 'preload'. The 'strict-transport-security' flag must be set to a non-zero value for these options to be used.
### --swagger-enable
### --tls-address
| | |
| ----------- | ----------------------------------- |
| Type | <code>host:port</code> |
| Environment | <code>$CODER_TLS_ADDRESS</code> |
| YAML | <code>networking.tls.address</code> |
| Default | <code>127.0.0.1:3443</code> |
HTTPS bind address of the server.
### --tls-cert-file
| | |
| ----------- | ------------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_TLS_CERT_FILE</code> |
| YAML | <code>networking.tls.certFiles</code> |
Path to each certificate for TLS. It requires a PEM-encoded file. To configure the listener to use a CA certificate, concatenate the primary certificate and the CA certificate together. The primary certificate should appear first in the combined file.
### --tls-client-auth
| | |
| ----------- | -------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_CLIENT_AUTH</code> |
| YAML | <code>networking.tls.clientAuth</code> |
| Default | <code>none</code> |
Policy the server will follow for TLS Client Authentication. Accepted values are "none", "request", "require-any", "verify-if-given", or "require-and-verify".
### --tls-client-ca-file
| | |
| ----------- | ---------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_CLIENT_CA_FILE</code> |
| YAML | <code>networking.tls.clientCAFile</code> |
PEM-encoded Certificate Authority file used for checking the authenticity of client.
### --tls-client-cert-file
| | |
| ----------- | ------------------------------------------ |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_CLIENT_CERT_FILE</code> |
| YAML | <code>networking.tls.clientCertFile</code> |
Path to certificate for client TLS authentication. It requires a PEM-encoded file.
### --tls-client-key-file
| | |
| ----------- | ----------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_CLIENT_KEY_FILE</code> |
| YAML | <code>networking.tls.clientKeyFile</code> |
Path to key for client TLS authentication. It requires a PEM-encoded file.
### --tls-enable
| | |
| ----------- | ---------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_SWAGGER_ENABLE</code> |
| Environment | <code>$CODER_TLS_ENABLE</code> |
| YAML | <code>networking.tls.enable</code> |
Expose the swagger endpoint via /swagger.
Whether TLS will be enabled.
### --tls-key-file
| | |
| ----------- | ------------------------------------ |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_TLS_KEY_FILE</code> |
| YAML | <code>networking.tls.keyFiles</code> |
Paths to the private keys for each of the certificates. It requires a PEM-encoded file.
### --tls-min-version
| | |
| ----------- | -------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_MIN_VERSION</code> |
| YAML | <code>networking.tls.minVersion</code> |
| Default | <code>tls12</code> |
Minimum supported version of TLS. Accepted values are "tls10", "tls11", "tls12" or "tls13".
### --telemetry
@ -638,6 +788,7 @@ Expose the swagger endpoint via /swagger.
| ----------- | ------------------------------------ |
| Type | <code>bool</code> |
| Environment | <code>$CODER_TELEMETRY_ENABLE</code> |
| YAML | <code>telemetry.enable</code> |
| Default | <code>true</code> |
Whether telemetry is enabled or not. Coder collects anonymized usage data to help improve our product.
@ -648,100 +799,18 @@ Whether telemetry is enabled or not. Coder collects anonymized usage data to hel
| ----------- | ----------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_TELEMETRY_TRACE</code> |
| YAML | <code>telemetry.trace</code> |
| Default | <code>true</code> |
Whether Opentelemetry traces are sent to Coder. Coder collects anonymized application tracing to help improve our product. Disabling telemetry also disables this option.
### --tls-address
| | |
| ----------- | ------------------------------- |
| Type | <code>host:port</code> |
| Environment | <code>$CODER_TLS_ADDRESS</code> |
| Default | <code>127.0.0.1:3443</code> |
HTTPS bind address of the server.
### --tls-cert-file
| | |
| ----------- | --------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_TLS_CERT_FILE</code> |
Path to each certificate for TLS. It requires a PEM-encoded file. To configure the listener to use a CA certificate, concatenate the primary certificate and the CA certificate together. The primary certificate should appear first in the combined file.
### --tls-client-auth
| | |
| ----------- | ----------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_CLIENT_AUTH</code> |
| Default | <code>none</code> |
Policy the server will follow for TLS Client Authentication. Accepted values are "none", "request", "require-any", "verify-if-given", or "require-and-verify".
### --tls-client-ca-file
| | |
| ----------- | -------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_CLIENT_CA_FILE</code> |
PEM-encoded Certificate Authority file used for checking the authenticity of client.
### --tls-client-cert-file
| | |
| ----------- | ---------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_CLIENT_CERT_FILE</code> |
Path to certificate for client TLS authentication. It requires a PEM-encoded file.
### --tls-client-key-file
| | |
| ----------- | --------------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_CLIENT_KEY_FILE</code> |
Path to key for client TLS authentication. It requires a PEM-encoded file.
### --tls-enable
| | |
| ----------- | ------------------------------ |
| Type | <code>bool</code> |
| Environment | <code>$CODER_TLS_ENABLE</code> |
Whether TLS will be enabled.
### --tls-key-file
| | |
| ----------- | -------------------------------- |
| Type | <code>string-array</code> |
| Environment | <code>$CODER_TLS_KEY_FILE</code> |
Paths to the private keys for each of the certificates. It requires a PEM-encoded file.
### --tls-min-version
| | |
| ----------- | ----------------------------------- |
| Type | <code>string</code> |
| Environment | <code>$CODER_TLS_MIN_VERSION</code> |
| Default | <code>tls12</code> |
Minimum supported version of TLS. Accepted values are "tls10", "tls11", "tls12" or "tls13".
### --trace
| | |
| ----------- | -------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_TRACE_ENABLE</code> |
| | |
| ----------- | ----------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_TRACE_ENABLE</code> |
| YAML | <code>introspection.tracing.enable</code> |
Whether application tracing data is collected. It exports to a backend configured by environment variables. See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md.
@ -754,39 +823,62 @@ Whether application tracing data is collected. It exports to a backend configure
Enables trace exporting to Honeycomb.io using the provided API Key.
### --trace-logs
| | |
| ----------- | ------------------------------ |
| Type | <code>bool</code> |
| Environment | <code>$CODER_TRACE_LOGS</code> |
Enables capturing of logs as events in traces. This is useful for debugging, but may result in a very large amount of events being sent to the tracing backend which may incur significant costs. If the verbose flag was supplied, debug-level logs will be included.
### --update-check
| | |
| ----------- | -------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_UPDATE_CHECK</code> |
| YAML | <code>updateCheck</code> |
| Default | <code>false</code> |
Periodically check for new releases of Coder and inform the owner. The check is performed once per day.
### -v, --verbose
| | |
| ----------- | --------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_VERBOSE</code> |
| | |
| ----------- | ------------------------------------------ |
| Type | <code>bool</code> |
| Environment | <code>$CODER_VERBOSE</code> |
| YAML | <code>introspection.logging.verbose</code> |
Output debug-level logs.
### --wildcard-access-url
| | |
| ----------- | --------------------------------------- |
| Type | <code>url</code> |
| Environment | <code>$CODER_WILDCARD_ACCESS_URL</code> |
| | |
| ----------- | ----------------------------------------- |
| Type | <code>url</code> |
| Environment | <code>$CODER_WILDCARD_ACCESS_URL</code> |
| YAML | <code>networking.wildcardAccessURL</code> |
Specifies the wildcard hostname to use for workspace applications in the form "\*.example.com".
### --write-config
| | |
| ---- | ----------------- |
| Type | <code>bool</code> |
<br/>Write out the current server config as YAML to stdout.
### --pprof-address
| | |
| ----------- | ---------------------------------------- |
| Type | <code>host:port</code> |
| Environment | <code>$CODER_PPROF_ADDRESS</code> |
| YAML | <code>introspection.pprof.address</code> |
| Default | <code>127.0.0.1:6060</code> |
The bind address to serve pprof.
### --pprof-enable
| | |
| ----------- | --------------------------------------- |
| Type | <code>bool</code> |
| Environment | <code>$CODER_PPROF_ENABLE</code> |
| YAML | <code>introspection.pprof.enable</code> |
Serve pprof metrics on the address defined by pprof address.

1
go.mod
View File

@ -108,7 +108,6 @@ require (
github.com/hashicorp/terraform-config-inspect v0.0.0-20211115214459-90acf1ca460f
github.com/hashicorp/terraform-json v0.14.0
github.com/hashicorp/yamux v0.0.0-20220718163420-dd80a7ee44ce
github.com/iancoleman/strcase v0.2.0
github.com/imulab/go-scim/pkg/v2 v2.2.0
github.com/jedib0t/go-pretty/v6 v6.4.0
github.com/jmoiron/sqlx v1.3.5

1
go.sum
View File

@ -1095,7 +1095,6 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=

View File

@ -47,6 +47,9 @@ Aliases:
{{- with $opt.Env }}
| Environment | {{ (print "$" .) | wrapCode }} |
{{- end }}
{{- with $opt.YAMLPath }}
| YAML | {{ . | wrapCode }} |
{{- end }}
{{- with $opt.Default }}
| Default | {{- . | wrapCode }} |
{{ "" }}

View File

@ -379,6 +379,7 @@ export interface DeploymentValues {
readonly git_auth?: any
readonly config_ssh?: SSHConfig
readonly wgtunnel_host?: string
// This is likely an enum in an external package ("github.com/coder/coder/cli/clibase.YAMLConfigPath")
readonly config?: string
readonly write_config?: boolean
// Named type "github.com/coder/coder/cli/clibase.HostPort" unknown, using "any"