mirror of https://github.com/coder/coder.git
feat: Support config files with viper (#4696)
This commit is contained in:
parent
adc5c1a131
commit
7bc5b89f7a
|
@ -6,6 +6,10 @@ import (
|
|||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
FlagName = "global-config"
|
||||
)
|
||||
|
||||
// Root represents the configuration directory.
|
||||
type Root string
|
||||
|
||||
|
@ -42,6 +46,10 @@ func (r Root) PostgresPort() File {
|
|||
return File(filepath.Join(r.PostgresPath(), "port"))
|
||||
}
|
||||
|
||||
func (r Root) DeploymentConfigPath() string {
|
||||
return filepath.Join(string(r), "server.yaml")
|
||||
}
|
||||
|
||||
// File provides convenience methods for interacting with *os.File.
|
||||
type File string
|
||||
|
||||
|
|
|
@ -0,0 +1,450 @@
|
|||
package deployment
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/cli/cliui"
|
||||
"github.com/coder/coder/cli/config"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
func newConfig() codersdk.DeploymentConfig {
|
||||
return codersdk.DeploymentConfig{
|
||||
AccessURL: codersdk.DeploymentConfigField[string]{
|
||||
Key: "access_url",
|
||||
Usage: "External URL to access your deployment. This must be accessible by all provisioned workspaces.",
|
||||
Flag: "access-url",
|
||||
},
|
||||
WildcardAccessURL: codersdk.DeploymentConfigField[string]{
|
||||
Key: "wildcard_access_url",
|
||||
Usage: "Specifies the wildcard hostname to use for workspace applications in the form \"*.example.com\".",
|
||||
Flag: "wildcard-access-url",
|
||||
},
|
||||
Address: codersdk.DeploymentConfigField[string]{
|
||||
Key: "address",
|
||||
Usage: "Bind address of the server.",
|
||||
Flag: "address",
|
||||
Shorthand: "a",
|
||||
Value: "127.0.0.1:3000",
|
||||
},
|
||||
AutobuildPollInterval: codersdk.DeploymentConfigField[time.Duration]{
|
||||
Key: "autobuild_poll_interval",
|
||||
Usage: "Interval to poll for scheduled workspace builds.",
|
||||
Flag: "autobuild-poll-interval",
|
||||
Hidden: true,
|
||||
Value: time.Minute,
|
||||
},
|
||||
DERPServerEnable: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "derp.server.enable",
|
||||
Usage: "Whether to enable or disable the embedded DERP relay server.",
|
||||
Flag: "derp-server-enable",
|
||||
Value: true,
|
||||
},
|
||||
DERPServerRegionID: codersdk.DeploymentConfigField[int]{
|
||||
Key: "derp.server.region_id",
|
||||
Usage: "Region ID to use for the embedded DERP server.",
|
||||
Flag: "derp-server-region-id",
|
||||
Value: 999,
|
||||
},
|
||||
DERPServerRegionCode: codersdk.DeploymentConfigField[string]{
|
||||
Key: "derp.server.region_code",
|
||||
Usage: "Region code to use for the embedded DERP server.",
|
||||
Flag: "derp-server-region-code",
|
||||
Value: "coder",
|
||||
},
|
||||
DERPServerRegionName: codersdk.DeploymentConfigField[string]{
|
||||
Key: "derp.server.region_name",
|
||||
Usage: "Region name that for the embedded DERP server.",
|
||||
Flag: "derp-server-region-name",
|
||||
Value: "Coder Embedded Relay",
|
||||
},
|
||||
DERPServerSTUNAddresses: codersdk.DeploymentConfigField[[]string]{
|
||||
Key: "derp.server.stun_addresses",
|
||||
Usage: "Addresses for STUN servers to establish P2P connections. Set empty to disable P2P connections.",
|
||||
Flag: "derp-server-stun-addresses",
|
||||
Value: []string{"stun.l.google.com:19302"},
|
||||
},
|
||||
DERPServerRelayURL: codersdk.DeploymentConfigField[string]{
|
||||
Key: "derp.server.relay_url",
|
||||
Usage: "An HTTP URL that is accessible by other replicas to relay DERP traffic. Required for high availability.",
|
||||
Flag: "derp-server-relay-url",
|
||||
Enterprise: true,
|
||||
},
|
||||
DERPConfigURL: codersdk.DeploymentConfigField[string]{
|
||||
Key: "derp.config.url",
|
||||
Usage: "URL to fetch a DERP mapping on startup. See: https://tailscale.com/kb/1118/custom-derp-servers/",
|
||||
Flag: "derp-config-url",
|
||||
},
|
||||
DERPConfigPath: codersdk.DeploymentConfigField[string]{
|
||||
Key: "derp.config.path",
|
||||
Usage: "Path to read a DERP mapping from. See: https://tailscale.com/kb/1118/custom-derp-servers/",
|
||||
Flag: "derp-config-path",
|
||||
},
|
||||
PrometheusEnable: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "prometheus.enable",
|
||||
Usage: "Serve prometheus metrics on the address defined by prometheus address.",
|
||||
Flag: "prometheus-enable",
|
||||
},
|
||||
PrometheusAddress: codersdk.DeploymentConfigField[string]{
|
||||
Key: "prometheus.address",
|
||||
Usage: "The bind address to serve prometheus metrics.",
|
||||
Flag: "prometheus-address",
|
||||
Value: "127.0.0.1:2112",
|
||||
},
|
||||
PprofEnable: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "pprof.enable",
|
||||
Usage: "Serve pprof metrics on the address defined by pprof address.",
|
||||
Flag: "pprof-enable",
|
||||
},
|
||||
PprofAddress: codersdk.DeploymentConfigField[string]{
|
||||
Key: "pprof.address",
|
||||
Usage: "The bind address to serve pprof.",
|
||||
Flag: "pprof-address",
|
||||
Value: "127.0.0.1:6060",
|
||||
},
|
||||
CacheDirectory: codersdk.DeploymentConfigField[string]{
|
||||
Key: "cache_directory",
|
||||
Usage: "The directory to cache temporary files. If unspecified and $CACHE_DIRECTORY is set, it will be used for compatibility with systemd.",
|
||||
Flag: "cache-dir",
|
||||
Value: defaultCacheDir(),
|
||||
},
|
||||
InMemoryDatabase: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "in_memory_database",
|
||||
Usage: "Controls whether data will be stored in an in-memory database.",
|
||||
Flag: "in-memory",
|
||||
Hidden: true,
|
||||
},
|
||||
ProvisionerDaemons: codersdk.DeploymentConfigField[int]{
|
||||
Key: "provisioner.daemons",
|
||||
Usage: "Number of provisioner daemons to create on start. If builds are stuck in queued state for a long time, consider increasing this.",
|
||||
Flag: "provisioner-daemons",
|
||||
Value: 3,
|
||||
},
|
||||
PostgresURL: codersdk.DeploymentConfigField[string]{
|
||||
Key: "pg_connection_url",
|
||||
Usage: "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\".",
|
||||
Flag: "postgres-url",
|
||||
},
|
||||
OAuth2GithubClientID: codersdk.DeploymentConfigField[string]{
|
||||
Key: "oauth2.github.client_id",
|
||||
Usage: "Client ID for Login with GitHub.",
|
||||
Flag: "oauth2-github-client-id",
|
||||
},
|
||||
OAuth2GithubClientSecret: codersdk.DeploymentConfigField[string]{
|
||||
Key: "oauth2.github.client_secret",
|
||||
Usage: "Client secret for Login with GitHub.",
|
||||
Flag: "oauth2-github-client-secret",
|
||||
},
|
||||
OAuth2GithubAllowedOrgs: codersdk.DeploymentConfigField[[]string]{
|
||||
Key: "oauth2.github.allowed_orgs",
|
||||
Usage: "Organizations the user must be a member of to Login with GitHub.",
|
||||
Flag: "oauth2-github-allowed-orgs",
|
||||
},
|
||||
OAuth2GithubAllowedTeams: codersdk.DeploymentConfigField[[]string]{
|
||||
Key: "oauth2.github.allowed_teams",
|
||||
Usage: "Teams inside organizations the user must be a member of to Login with GitHub. Structured as: <organization-name>/<team-slug>.",
|
||||
Flag: "oauth2-github-allowed-teams",
|
||||
},
|
||||
OAuth2GithubAllowSignups: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "oauth2.github.allow_signups",
|
||||
Usage: "Whether new users can sign up with GitHub.",
|
||||
Flag: "oauth2-github-allow-signups",
|
||||
},
|
||||
OAuth2GithubEnterpriseBaseURL: codersdk.DeploymentConfigField[string]{
|
||||
Key: "oauth2.github.enterprise_base_url",
|
||||
Usage: "Base URL of a GitHub Enterprise deployment to use for Login with GitHub.",
|
||||
Flag: "oauth2-github-enterprise-base-url",
|
||||
},
|
||||
OIDCAllowSignups: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "oidc.allow_signups",
|
||||
Usage: "Whether new users can sign up with OIDC.",
|
||||
Flag: "oidc-allow-signups",
|
||||
Value: true,
|
||||
},
|
||||
OIDCClientID: codersdk.DeploymentConfigField[string]{
|
||||
Key: "oidc.client_id",
|
||||
Usage: "Client ID to use for Login with OIDC.",
|
||||
Flag: "oidc-client-id",
|
||||
},
|
||||
OIDCClientSecret: codersdk.DeploymentConfigField[string]{
|
||||
Key: "oidc.client_secret",
|
||||
Usage: "Client secret to use for Login with OIDC.",
|
||||
Flag: "oidc-client-secret",
|
||||
},
|
||||
OIDCEmailDomain: codersdk.DeploymentConfigField[string]{
|
||||
Key: "oidc.email_domain",
|
||||
Usage: "Email domain that clients logging in with OIDC must match.",
|
||||
Flag: "oidc-email-domain",
|
||||
},
|
||||
OIDCIssuerURL: codersdk.DeploymentConfigField[string]{
|
||||
Key: "oidc.issuer_url",
|
||||
Usage: "Issuer URL to use for Login with OIDC.",
|
||||
Flag: "oidc-issuer-url",
|
||||
},
|
||||
OIDCScopes: codersdk.DeploymentConfigField[[]string]{
|
||||
Key: "oidc.scopes",
|
||||
Usage: "Scopes to grant when authenticating with OIDC.",
|
||||
Flag: "oidc-scopes",
|
||||
Value: []string{oidc.ScopeOpenID, "profile", "email"},
|
||||
},
|
||||
TelemetryEnable: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "telemetry.enable",
|
||||
Usage: "Whether telemetry is enabled or not. Coder collects anonymized usage data to help improve our product.",
|
||||
Flag: "telemetry",
|
||||
Value: flag.Lookup("test.v") == nil,
|
||||
},
|
||||
TelemetryTrace: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "telemetry.trace",
|
||||
Usage: "Whether Opentelemetry traces are sent to Coder. Coder collects anonymized application tracing to help improve our product. Disabling telemetry also disables this option.",
|
||||
Flag: "telemetry-trace",
|
||||
Value: flag.Lookup("test.v") == nil,
|
||||
},
|
||||
TelemetryURL: codersdk.DeploymentConfigField[string]{
|
||||
Key: "telemetry.url",
|
||||
Usage: "URL to send telemetry.",
|
||||
Flag: "telemetry-url",
|
||||
Hidden: true,
|
||||
Value: "https://telemetry.coder.com",
|
||||
},
|
||||
TLSEnable: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "tls.enable",
|
||||
Usage: "Whether TLS will be enabled.",
|
||||
Flag: "tls-enable",
|
||||
},
|
||||
TLSCertFiles: codersdk.DeploymentConfigField[[]string]{
|
||||
Key: "tls.cert_file",
|
||||
Usage: "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.",
|
||||
Flag: "tls-cert-file",
|
||||
},
|
||||
TLSClientCAFile: codersdk.DeploymentConfigField[string]{
|
||||
Key: "tls.client_ca_file",
|
||||
Usage: "PEM-encoded Certificate Authority file used for checking the authenticity of client",
|
||||
Flag: "tls-client-ca-file",
|
||||
},
|
||||
TLSClientAuth: codersdk.DeploymentConfigField[string]{
|
||||
Key: "tls.client_auth",
|
||||
Usage: "Policy the server will follow for TLS Client Authentication. Accepted values are \"none\", \"request\", \"require-any\", \"verify-if-given\", or \"require-and-verify\".",
|
||||
Flag: "tls-client-auth",
|
||||
Value: "request",
|
||||
},
|
||||
TLSKeyFiles: codersdk.DeploymentConfigField[[]string]{
|
||||
Key: "tls.key_file",
|
||||
Usage: "Paths to the private keys for each of the certificates. It requires a PEM-encoded file.",
|
||||
Flag: "tls-key-file",
|
||||
},
|
||||
TLSMinVersion: codersdk.DeploymentConfigField[string]{
|
||||
Key: "tls.min_version",
|
||||
Usage: "Minimum supported version of TLS. Accepted values are \"tls10\", \"tls11\", \"tls12\" or \"tls13\"",
|
||||
Flag: "tls-min-version",
|
||||
Value: "tls12",
|
||||
},
|
||||
TraceEnable: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "trace",
|
||||
Usage: "Whether application tracing data is collected.",
|
||||
Flag: "trace",
|
||||
},
|
||||
SecureAuthCookie: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "secure_auth_cookie",
|
||||
Usage: "Controls if the 'Secure' property is set on browser session cookies.",
|
||||
Flag: "secure-auth-cookie",
|
||||
},
|
||||
SSHKeygenAlgorithm: codersdk.DeploymentConfigField[string]{
|
||||
Key: "ssh_keygen_algorithm",
|
||||
Usage: "The algorithm to use for generating ssh keys. Accepted values are \"ed25519\", \"ecdsa\", or \"rsa4096\".",
|
||||
Flag: "ssh-keygen-algorithm",
|
||||
Value: "ed25519",
|
||||
},
|
||||
AutoImportTemplates: codersdk.DeploymentConfigField[[]string]{
|
||||
Key: "auto_import_templates",
|
||||
Usage: "Templates to auto-import. Available auto-importable templates are: kubernetes",
|
||||
Flag: "auto-import-template",
|
||||
Hidden: true,
|
||||
},
|
||||
MetricsCacheRefreshInterval: codersdk.DeploymentConfigField[time.Duration]{
|
||||
Key: "metrics_cache_refresh_interval",
|
||||
Usage: "How frequently metrics are refreshed",
|
||||
Flag: "metrics-cache-refresh-interval",
|
||||
Hidden: true,
|
||||
Value: time.Hour,
|
||||
},
|
||||
AgentStatRefreshInterval: codersdk.DeploymentConfigField[time.Duration]{
|
||||
Key: "agent_stat_refresh_interval",
|
||||
Usage: "How frequently agent stats are recorded",
|
||||
Flag: "agent-stats-refresh-interval",
|
||||
Hidden: true,
|
||||
Value: 10 * time.Minute,
|
||||
},
|
||||
AuditLogging: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "audit_logging",
|
||||
Usage: "Specifies whether audit logging is enabled.",
|
||||
Flag: "audit-logging",
|
||||
Value: true,
|
||||
Enterprise: true,
|
||||
},
|
||||
BrowserOnly: codersdk.DeploymentConfigField[bool]{
|
||||
Key: "browser_only",
|
||||
Usage: "Whether Coder only allows connections to workspaces via the browser.",
|
||||
Flag: "browser-only",
|
||||
Enterprise: true,
|
||||
},
|
||||
SCIMAPIKey: codersdk.DeploymentConfigField[string]{
|
||||
Key: "scim_api_key",
|
||||
Usage: "Enables SCIM and sets the authentication header for the built-in SCIM server. New users are automatically created with OIDC authentication.",
|
||||
Flag: "scim-auth-header",
|
||||
Enterprise: true,
|
||||
},
|
||||
UserWorkspaceQuota: codersdk.DeploymentConfigField[int]{
|
||||
Key: "user_workspace_quota",
|
||||
Usage: "Enables and sets a limit on how many workspaces each user can create.",
|
||||
Flag: "user-workspace-quota",
|
||||
Enterprise: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:revive
|
||||
func Config(flagset *pflag.FlagSet, vip *viper.Viper) (codersdk.DeploymentConfig, error) {
|
||||
dc := newConfig()
|
||||
flg, err := flagset.GetString(config.FlagName)
|
||||
if err != nil {
|
||||
return dc, xerrors.Errorf("get global config from flag: %w", err)
|
||||
}
|
||||
vip.SetEnvPrefix("coder")
|
||||
vip.AutomaticEnv()
|
||||
|
||||
if flg != "" {
|
||||
vip.SetConfigFile(flg + "/server.yaml")
|
||||
err = vip.ReadInConfig()
|
||||
if err != nil && !xerrors.Is(err, os.ErrNotExist) {
|
||||
return dc, xerrors.Errorf("reading deployment config: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
dcv := reflect.ValueOf(&dc).Elem()
|
||||
t := dcv.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fve := dcv.Field(i)
|
||||
key := fve.FieldByName("Key").String()
|
||||
value := fve.FieldByName("Value").Interface()
|
||||
|
||||
switch value.(type) {
|
||||
case string:
|
||||
fve.FieldByName("Value").SetString(vip.GetString(key))
|
||||
case bool:
|
||||
fve.FieldByName("Value").SetBool(vip.GetBool(key))
|
||||
case int:
|
||||
fve.FieldByName("Value").SetInt(int64(vip.GetInt(key)))
|
||||
case time.Duration:
|
||||
fve.FieldByName("Value").SetInt(int64(vip.GetDuration(key)))
|
||||
case []string:
|
||||
// As of October 21st, 2022 we supported delimiting a string
|
||||
// with a comma, but Viper only supports with a space. This
|
||||
// is a small hack around it!
|
||||
rawSlice := reflect.ValueOf(vip.GetStringSlice(key)).Interface()
|
||||
slice, ok := rawSlice.([]string)
|
||||
if !ok {
|
||||
return dc, xerrors.Errorf("string slice is of type %T", rawSlice)
|
||||
}
|
||||
value := make([]string, 0, len(slice))
|
||||
for _, entry := range slice {
|
||||
value = append(value, strings.Split(entry, ",")...)
|
||||
}
|
||||
fve.FieldByName("Value").Set(reflect.ValueOf(value))
|
||||
default:
|
||||
return dc, xerrors.Errorf("unsupported type %T", value)
|
||||
}
|
||||
}
|
||||
|
||||
return dc, nil
|
||||
}
|
||||
|
||||
func NewViper() *viper.Viper {
|
||||
dc := newConfig()
|
||||
v := viper.New()
|
||||
v.SetEnvPrefix("coder")
|
||||
v.AutomaticEnv()
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_"))
|
||||
|
||||
dcv := reflect.ValueOf(dc)
|
||||
t := dcv.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fv := dcv.Field(i)
|
||||
key := fv.FieldByName("Key").String()
|
||||
value := fv.FieldByName("Value").Interface()
|
||||
v.SetDefault(key, value)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
//nolint:revive
|
||||
func AttachFlags(flagset *pflag.FlagSet, vip *viper.Viper, enterprise bool) {
|
||||
dc := newConfig()
|
||||
dcv := reflect.ValueOf(dc)
|
||||
t := dcv.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fv := dcv.Field(i)
|
||||
isEnt := fv.FieldByName("Enterprise").Bool()
|
||||
if enterprise != isEnt {
|
||||
continue
|
||||
}
|
||||
key := fv.FieldByName("Key").String()
|
||||
flg := fv.FieldByName("Flag").String()
|
||||
if flg == "" {
|
||||
continue
|
||||
}
|
||||
usage := fv.FieldByName("Usage").String()
|
||||
usage = fmt.Sprintf("%s\n%s", usage, cliui.Styles.Placeholder.Render("Consumes $"+formatEnv(key)))
|
||||
shorthand := fv.FieldByName("Shorthand").String()
|
||||
hidden := fv.FieldByName("Hidden").Bool()
|
||||
value := fv.FieldByName("Value").Interface()
|
||||
|
||||
switch value.(type) {
|
||||
case string:
|
||||
_ = flagset.StringP(flg, shorthand, vip.GetString(key), usage)
|
||||
case bool:
|
||||
_ = flagset.BoolP(flg, shorthand, vip.GetBool(key), usage)
|
||||
case int:
|
||||
_ = flagset.IntP(flg, shorthand, vip.GetInt(key), usage)
|
||||
case time.Duration:
|
||||
_ = flagset.DurationP(flg, shorthand, vip.GetDuration(key), usage)
|
||||
case []string:
|
||||
_ = flagset.StringSliceP(flg, shorthand, vip.GetStringSlice(key), usage)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
_ = vip.BindPFlag(key, flagset.Lookup(flg))
|
||||
if hidden {
|
||||
_ = flagset.MarkHidden(flg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func formatEnv(key string) string {
|
||||
return "CODER_" + strings.ToUpper(strings.NewReplacer("-", "_", ".", "_").Replace(key))
|
||||
}
|
||||
|
||||
func defaultCacheDir() string {
|
||||
defaultCacheDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
defaultCacheDir = os.TempDir()
|
||||
}
|
||||
if dir := os.Getenv("CACHE_DIRECTORY"); dir != "" {
|
||||
// For compatibility with systemd.
|
||||
defaultCacheDir = dir
|
||||
}
|
||||
|
||||
return filepath.Join(defaultCacheDir, "coder")
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package deployment_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/cli/config"
|
||||
"github.com/coder/coder/cli/deployment"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
// nolint:paralleltest
|
||||
func TestConfig(t *testing.T) {
|
||||
viper := deployment.NewViper()
|
||||
flagSet := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||
flagSet.String(config.FlagName, "", "")
|
||||
deployment.AttachFlags(flagSet, viper, true)
|
||||
|
||||
for _, tc := range []struct {
|
||||
Name string
|
||||
Env map[string]string
|
||||
Valid func(config codersdk.DeploymentConfig)
|
||||
}{{
|
||||
Name: "Deployment",
|
||||
Env: map[string]string{
|
||||
"CODER_ADDRESS": "0.0.0.0:8443",
|
||||
"CODER_ACCESS_URL": "https://dev.coder.com",
|
||||
"CODER_PG_CONNECTION_URL": "some-url",
|
||||
"CODER_PPROF_ADDRESS": "something",
|
||||
"CODER_PPROF_ENABLE": "true",
|
||||
"CODER_PROMETHEUS_ADDRESS": "hello-world",
|
||||
"CODER_PROMETHEUS_ENABLE": "true",
|
||||
"CODER_PROVISIONER_DAEMONS": "5",
|
||||
"CODER_SECURE_AUTH_COOKIE": "true",
|
||||
"CODER_SSH_KEYGEN_ALGORITHM": "potato",
|
||||
"CODER_TELEMETRY": "false",
|
||||
"CODER_TELEMETRY_TRACE": "false",
|
||||
"CODER_WILDCARD_ACCESS_URL": "something-wildcard.com",
|
||||
},
|
||||
Valid: func(config codersdk.DeploymentConfig) {
|
||||
require.Equal(t, config.Address.Value, "0.0.0.0:8443")
|
||||
require.Equal(t, config.AccessURL.Value, "https://dev.coder.com")
|
||||
require.Equal(t, config.PostgresURL.Value, "some-url")
|
||||
require.Equal(t, config.PprofAddress.Value, "something")
|
||||
require.Equal(t, config.PprofEnable.Value, true)
|
||||
require.Equal(t, config.PrometheusAddress.Value, "hello-world")
|
||||
require.Equal(t, config.PrometheusEnable.Value, true)
|
||||
require.Equal(t, config.ProvisionerDaemons.Value, 5)
|
||||
require.Equal(t, config.SecureAuthCookie.Value, true)
|
||||
require.Equal(t, config.SSHKeygenAlgorithm.Value, "potato")
|
||||
require.Equal(t, config.TelemetryEnable.Value, false)
|
||||
require.Equal(t, config.TelemetryTrace.Value, false)
|
||||
require.Equal(t, config.WildcardAccessURL.Value, "something-wildcard.com")
|
||||
},
|
||||
}, {
|
||||
Name: "DERP",
|
||||
Env: map[string]string{
|
||||
"CODER_DERP_CONFIG_PATH": "/example/path",
|
||||
"CODER_DERP_CONFIG_URL": "https://google.com",
|
||||
"CODER_DERP_SERVER_ENABLE": "false",
|
||||
"CODER_DERP_SERVER_REGION_CODE": "something",
|
||||
"CODER_DERP_SERVER_REGION_ID": "123",
|
||||
"CODER_DERP_SERVER_REGION_NAME": "Code-Land",
|
||||
"CODER_DERP_SERVER_RELAY_URL": "1.1.1.1",
|
||||
"CODER_DERP_SERVER_STUN_ADDRESSES": "google.org",
|
||||
},
|
||||
Valid: func(config codersdk.DeploymentConfig) {
|
||||
require.Equal(t, config.DERPConfigPath.Value, "/example/path")
|
||||
require.Equal(t, config.DERPConfigURL.Value, "https://google.com")
|
||||
require.Equal(t, config.DERPServerEnable.Value, false)
|
||||
require.Equal(t, config.DERPServerRegionCode.Value, "something")
|
||||
require.Equal(t, config.DERPServerRegionID.Value, 123)
|
||||
require.Equal(t, config.DERPServerRegionName.Value, "Code-Land")
|
||||
require.Equal(t, config.DERPServerRelayURL.Value, "1.1.1.1")
|
||||
require.Equal(t, config.DERPServerSTUNAddresses.Value, []string{"google.org"})
|
||||
},
|
||||
}, {
|
||||
Name: "Enterprise",
|
||||
Env: map[string]string{
|
||||
"CODER_AUDIT_LOGGING": "false",
|
||||
"CODER_BROWSER_ONLY": "true",
|
||||
"CODER_SCIM_API_KEY": "some-key",
|
||||
"CODER_USER_WORKSPACE_QUOTA": "10",
|
||||
},
|
||||
Valid: func(config codersdk.DeploymentConfig) {
|
||||
require.Equal(t, config.AuditLogging.Value, false)
|
||||
require.Equal(t, config.BrowserOnly.Value, true)
|
||||
require.Equal(t, config.SCIMAPIKey.Value, "some-key")
|
||||
require.Equal(t, config.UserWorkspaceQuota.Value, 10)
|
||||
},
|
||||
}, {
|
||||
Name: "TLS",
|
||||
Env: map[string]string{
|
||||
"CODER_TLS_CERT_FILE": "/etc/acme-sh/dev.coder.com,/etc/acme-sh/*.dev.coder.com",
|
||||
"CODER_TLS_KEY_FILE": "/etc/acme-sh/dev.coder.com,/etc/acme-sh/*.dev.coder.com",
|
||||
"CODER_TLS_CLIENT_AUTH": "/some/path",
|
||||
"CODER_TLS_CLIENT_CA_FILE": "/some/path",
|
||||
"CODER_TLS_ENABLE": "true",
|
||||
"CODER_TLS_MIN_VERSION": "tls10",
|
||||
},
|
||||
Valid: func(config codersdk.DeploymentConfig) {
|
||||
require.Len(t, config.TLSCertFiles.Value, 2)
|
||||
require.Equal(t, config.TLSCertFiles.Value[0], "/etc/acme-sh/dev.coder.com")
|
||||
require.Equal(t, config.TLSCertFiles.Value[1], "/etc/acme-sh/*.dev.coder.com")
|
||||
|
||||
require.Len(t, config.TLSKeyFiles.Value, 2)
|
||||
require.Equal(t, config.TLSKeyFiles.Value[0], "/etc/acme-sh/dev.coder.com")
|
||||
require.Equal(t, config.TLSKeyFiles.Value[1], "/etc/acme-sh/*.dev.coder.com")
|
||||
|
||||
require.Equal(t, config.TLSClientAuth.Value, "/some/path")
|
||||
require.Equal(t, config.TLSClientCAFile.Value, "/some/path")
|
||||
require.Equal(t, config.TLSEnable.Value, true)
|
||||
require.Equal(t, config.TLSMinVersion.Value, "tls10")
|
||||
},
|
||||
}, {
|
||||
Name: "OIDC",
|
||||
Env: map[string]string{
|
||||
"CODER_OIDC_ISSUER_URL": "https://accounts.google.com",
|
||||
"CODER_OIDC_EMAIL_DOMAIN": "coder.com",
|
||||
"CODER_OIDC_CLIENT_ID": "client",
|
||||
"CODER_OIDC_CLIENT_SECRET": "secret",
|
||||
"CODER_OIDC_ALLOW_SIGNUPS": "false",
|
||||
"CODER_OIDC_SCOPES": "something,here",
|
||||
},
|
||||
Valid: func(config codersdk.DeploymentConfig) {
|
||||
require.Equal(t, config.OIDCIssuerURL.Value, "https://accounts.google.com")
|
||||
require.Equal(t, config.OIDCEmailDomain.Value, "coder.com")
|
||||
require.Equal(t, config.OIDCClientID.Value, "client")
|
||||
require.Equal(t, config.OIDCClientSecret.Value, "secret")
|
||||
require.Equal(t, config.OIDCAllowSignups.Value, false)
|
||||
require.Equal(t, config.OIDCScopes.Value, []string{"something", "here"})
|
||||
},
|
||||
}, {
|
||||
Name: "GitHub",
|
||||
Env: map[string]string{
|
||||
"CODER_OAUTH2_GITHUB_CLIENT_ID": "client",
|
||||
"CODER_OAUTH2_GITHUB_CLIENT_SECRET": "secret",
|
||||
"CODER_OAUTH2_GITHUB_ALLOWED_ORGS": "coder",
|
||||
"CODER_OAUTH2_GITHUB_ALLOWED_TEAMS": "coder",
|
||||
"CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS": "true",
|
||||
},
|
||||
Valid: func(config codersdk.DeploymentConfig) {
|
||||
require.Equal(t, config.OAuth2GithubClientID.Value, "client")
|
||||
require.Equal(t, config.OAuth2GithubClientSecret.Value, "secret")
|
||||
require.Equal(t, []string{"coder"}, config.OAuth2GithubAllowedOrgs.Value)
|
||||
require.Equal(t, []string{"coder"}, config.OAuth2GithubAllowedTeams.Value)
|
||||
require.Equal(t, config.OAuth2GithubAllowSignups.Value, true)
|
||||
},
|
||||
}} {
|
||||
tc := tc
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
for key, value := range tc.Env {
|
||||
t.Setenv(key, value)
|
||||
}
|
||||
config, err := deployment.Config(flagSet, viper)
|
||||
require.NoError(t, err)
|
||||
tc.Valid(config)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,511 +0,0 @@
|
|||
package deployment
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/coder/coder/cli/cliflag"
|
||||
"github.com/coder/coder/cli/cliui"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
const (
|
||||
secretValue = "********"
|
||||
)
|
||||
|
||||
func Flags() *codersdk.DeploymentFlags {
|
||||
return &codersdk.DeploymentFlags{
|
||||
AccessURL: &codersdk.StringFlag{
|
||||
Name: "Access URL",
|
||||
Flag: "access-url",
|
||||
EnvVar: "CODER_ACCESS_URL",
|
||||
Description: "External URL to access your deployment. This must be accessible by all provisioned workspaces.",
|
||||
},
|
||||
WildcardAccessURL: &codersdk.StringFlag{
|
||||
Name: "Wildcard Address URL",
|
||||
Flag: "wildcard-access-url",
|
||||
EnvVar: "CODER_WILDCARD_ACCESS_URL",
|
||||
Description: `Specifies the wildcard hostname to use for workspace applications in the form "*.example.com" or "*-suffix.example.com". Ports or schemes should not be included. The scheme will be copied from the access URL.`,
|
||||
},
|
||||
Address: &codersdk.StringFlag{
|
||||
Name: "Bind Address",
|
||||
Flag: "address",
|
||||
EnvVar: "CODER_ADDRESS",
|
||||
Shorthand: "a",
|
||||
Description: "Bind address of the server.",
|
||||
Default: "127.0.0.1:3000",
|
||||
},
|
||||
AutobuildPollInterval: &codersdk.DurationFlag{
|
||||
Name: "Autobuild Poll Interval",
|
||||
Flag: "autobuild-poll-interval",
|
||||
EnvVar: "CODER_AUTOBUILD_POLL_INTERVAL",
|
||||
Description: "Interval to poll for scheduled workspace builds.",
|
||||
Hidden: true,
|
||||
Default: time.Minute,
|
||||
},
|
||||
DerpServerEnable: &codersdk.BoolFlag{
|
||||
Name: "DERP Server Enabled",
|
||||
Flag: "derp-server-enable",
|
||||
EnvVar: "CODER_DERP_SERVER_ENABLE",
|
||||
Description: "Whether to enable or disable the embedded DERP relay server.",
|
||||
Default: true,
|
||||
},
|
||||
DerpServerRegionID: &codersdk.IntFlag{
|
||||
Name: "DERP Server Region ID",
|
||||
Flag: "derp-server-region-id",
|
||||
EnvVar: "CODER_DERP_SERVER_REGION_ID",
|
||||
Description: "Region ID to use for the embedded DERP server.",
|
||||
Default: 999,
|
||||
},
|
||||
DerpServerRegionCode: &codersdk.StringFlag{
|
||||
Name: "DERP Server Region Code",
|
||||
Flag: "derp-server-region-code",
|
||||
EnvVar: "CODER_DERP_SERVER_REGION_CODE",
|
||||
Description: "Region code to use for the embedded DERP server.",
|
||||
Default: "coder",
|
||||
},
|
||||
DerpServerRegionName: &codersdk.StringFlag{
|
||||
Name: "DERP Server Region Name",
|
||||
Flag: "derp-server-region-name",
|
||||
EnvVar: "CODER_DERP_SERVER_REGION_NAME",
|
||||
Description: "Region name that for the embedded DERP server.",
|
||||
Default: "Coder Embedded Relay",
|
||||
},
|
||||
DerpServerSTUNAddresses: &codersdk.StringArrayFlag{
|
||||
Name: "DERP Server STUN Addresses",
|
||||
Flag: "derp-server-stun-addresses",
|
||||
EnvVar: "CODER_DERP_SERVER_STUN_ADDRESSES",
|
||||
Description: "Addresses for STUN servers to establish P2P connections. Set empty to disable P2P connections.",
|
||||
Default: []string{"stun.l.google.com:19302"},
|
||||
},
|
||||
DerpServerRelayAddress: &codersdk.StringFlag{
|
||||
Name: "DERP Server Relay Address",
|
||||
Flag: "derp-server-relay-address",
|
||||
EnvVar: "CODER_DERP_SERVER_RELAY_URL",
|
||||
Description: "An HTTP address that is accessible by other replicas to relay DERP traffic. Required for high availability.",
|
||||
Enterprise: true,
|
||||
},
|
||||
DerpConfigURL: &codersdk.StringFlag{
|
||||
Name: "DERP Config URL",
|
||||
Flag: "derp-config-url",
|
||||
EnvVar: "CODER_DERP_CONFIG_URL",
|
||||
Description: "URL to fetch a DERP mapping on startup. See: https://tailscale.com/kb/1118/custom-derp-servers/",
|
||||
},
|
||||
DerpConfigPath: &codersdk.StringFlag{
|
||||
Name: "DERP Config Path",
|
||||
Flag: "derp-config-path",
|
||||
EnvVar: "CODER_DERP_CONFIG_PATH",
|
||||
Description: "Path to read a DERP mapping from. See: https://tailscale.com/kb/1118/custom-derp-servers/",
|
||||
},
|
||||
PromEnabled: &codersdk.BoolFlag{
|
||||
Name: "Prometheus Enabled",
|
||||
Flag: "prometheus-enable",
|
||||
EnvVar: "CODER_PROMETHEUS_ENABLE",
|
||||
Description: "Serve prometheus metrics on the address defined by `prometheus-address`.",
|
||||
},
|
||||
PromAddress: &codersdk.StringFlag{
|
||||
Name: "Prometheus Address",
|
||||
Flag: "prometheus-address",
|
||||
EnvVar: "CODER_PROMETHEUS_ADDRESS",
|
||||
Description: "The bind address to serve prometheus metrics.",
|
||||
Default: "127.0.0.1:2112",
|
||||
},
|
||||
PprofEnabled: &codersdk.BoolFlag{
|
||||
Name: "pprof Enabled",
|
||||
Flag: "pprof-enable",
|
||||
EnvVar: "CODER_PPROF_ENABLE",
|
||||
Description: "Serve pprof metrics on the address defined by `pprof-address`.",
|
||||
},
|
||||
PprofAddress: &codersdk.StringFlag{
|
||||
Name: "pprof Address",
|
||||
Flag: "pprof-address",
|
||||
EnvVar: "CODER_PPROF_ADDRESS",
|
||||
Description: "The bind address to serve pprof.",
|
||||
Default: "127.0.0.1:6060",
|
||||
},
|
||||
CacheDir: &codersdk.StringFlag{
|
||||
Name: "Cache Directory",
|
||||
Flag: "cache-dir",
|
||||
EnvVar: "CODER_CACHE_DIRECTORY",
|
||||
Description: "The directory to cache temporary files. If unspecified and $CACHE_DIRECTORY is set, it will be used for compatibility with systemd.",
|
||||
Default: defaultCacheDir(),
|
||||
},
|
||||
InMemoryDatabase: &codersdk.BoolFlag{
|
||||
Name: "In-Memory Database",
|
||||
Flag: "in-memory",
|
||||
EnvVar: "CODER_INMEMORY",
|
||||
Description: "Controls whether data will be stored in an in-memory database.",
|
||||
Hidden: true,
|
||||
},
|
||||
ProvisionerDaemonCount: &codersdk.IntFlag{
|
||||
Name: "Provisioner Daemons",
|
||||
Flag: "provisioner-daemons",
|
||||
EnvVar: "CODER_PROVISIONER_DAEMONS",
|
||||
Description: "Number of provisioner daemons to create on start. If builds are stuck in queued state for a long time, consider increasing this.",
|
||||
Default: 3,
|
||||
},
|
||||
PostgresURL: &codersdk.StringFlag{
|
||||
Name: "Postgres URL",
|
||||
Flag: "postgres-url",
|
||||
EnvVar: "CODER_PG_CONNECTION_URL",
|
||||
Description: "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\"",
|
||||
Secret: true,
|
||||
},
|
||||
OAuth2GithubClientID: &codersdk.StringFlag{
|
||||
Name: "Oauth2 Github Client ID",
|
||||
Flag: "oauth2-github-client-id",
|
||||
EnvVar: "CODER_OAUTH2_GITHUB_CLIENT_ID",
|
||||
Description: "Client ID for Login with GitHub.",
|
||||
},
|
||||
OAuth2GithubClientSecret: &codersdk.StringFlag{
|
||||
Name: "Oauth2 Github Client Secret",
|
||||
Flag: "oauth2-github-client-secret",
|
||||
EnvVar: "CODER_OAUTH2_GITHUB_CLIENT_SECRET",
|
||||
Description: "Client secret for Login with GitHub.",
|
||||
Secret: true,
|
||||
},
|
||||
OAuth2GithubAllowedOrganizations: &codersdk.StringArrayFlag{
|
||||
Name: "Oauth2 Github Allowed Organizations",
|
||||
Flag: "oauth2-github-allowed-orgs",
|
||||
EnvVar: "CODER_OAUTH2_GITHUB_ALLOWED_ORGS",
|
||||
Description: "Organizations the user must be a member of to Login with GitHub.",
|
||||
Default: []string{},
|
||||
},
|
||||
OAuth2GithubAllowedTeams: &codersdk.StringArrayFlag{
|
||||
Name: "Oauth2 Github Allowed Teams",
|
||||
Flag: "oauth2-github-allowed-teams",
|
||||
EnvVar: "CODER_OAUTH2_GITHUB_ALLOWED_TEAMS",
|
||||
Description: "Teams inside organizations the user must be a member of to Login with GitHub. Structured as: <organization-name>/<team-slug>.",
|
||||
Default: []string{},
|
||||
},
|
||||
OAuth2GithubAllowSignups: &codersdk.BoolFlag{
|
||||
Name: "Oauth2 Github Allow Signups",
|
||||
Flag: "oauth2-github-allow-signups",
|
||||
EnvVar: "CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS",
|
||||
Description: "Whether new users can sign up with GitHub.",
|
||||
},
|
||||
OAuth2GithubEnterpriseBaseURL: &codersdk.StringFlag{
|
||||
Name: "Oauth2 Github Enterprise Base URL",
|
||||
Flag: "oauth2-github-enterprise-base-url",
|
||||
EnvVar: "CODER_OAUTH2_GITHUB_ENTERPRISE_BASE_URL",
|
||||
Description: "Base URL of a GitHub Enterprise deployment to use for Login with GitHub.",
|
||||
},
|
||||
OIDCAllowSignups: &codersdk.BoolFlag{
|
||||
Name: "OIDC Allow Signups",
|
||||
Flag: "oidc-allow-signups",
|
||||
EnvVar: "CODER_OIDC_ALLOW_SIGNUPS",
|
||||
Description: "Whether new users can sign up with OIDC.",
|
||||
Default: true,
|
||||
},
|
||||
OIDCClientID: &codersdk.StringFlag{
|
||||
Name: "OIDC Client ID",
|
||||
Flag: "oidc-client-id",
|
||||
EnvVar: "CODER_OIDC_CLIENT_ID",
|
||||
Description: "Client ID to use for Login with OIDC.",
|
||||
},
|
||||
OIDCClientSecret: &codersdk.StringFlag{
|
||||
Name: "OIDC Client Secret",
|
||||
Flag: "oidc-client-secret",
|
||||
EnvVar: "CODER_OIDC_CLIENT_SECRET",
|
||||
Description: "Client secret to use for Login with OIDC.",
|
||||
Secret: true,
|
||||
},
|
||||
OIDCEmailDomain: &codersdk.StringFlag{
|
||||
Name: "OIDC Email Domain",
|
||||
Flag: "oidc-email-domain",
|
||||
EnvVar: "CODER_OIDC_EMAIL_DOMAIN",
|
||||
Description: "Email domain that clients logging in with OIDC must match.",
|
||||
},
|
||||
OIDCIssuerURL: &codersdk.StringFlag{
|
||||
Name: "OIDC Issuer URL",
|
||||
Flag: "oidc-issuer-url",
|
||||
EnvVar: "CODER_OIDC_ISSUER_URL",
|
||||
Description: "Issuer URL to use for Login with OIDC.",
|
||||
},
|
||||
OIDCScopes: &codersdk.StringArrayFlag{
|
||||
Name: "OIDC Scopes",
|
||||
Flag: "oidc-scopes",
|
||||
EnvVar: "CODER_OIDC_SCOPES",
|
||||
Description: "Scopes to grant when authenticating with OIDC.",
|
||||
Default: []string{oidc.ScopeOpenID, "profile", "email"},
|
||||
},
|
||||
TelemetryEnable: &codersdk.BoolFlag{
|
||||
Name: "Telemetry Enabled",
|
||||
Flag: "telemetry",
|
||||
EnvVar: "CODER_TELEMETRY",
|
||||
Description: "Whether telemetry is enabled or not. Coder collects anonymized usage data to help improve our product.",
|
||||
Default: flag.Lookup("test.v") == nil,
|
||||
},
|
||||
TelemetryTraceEnable: &codersdk.BoolFlag{
|
||||
Name: "Trace Telemetry Enabled",
|
||||
Flag: "telemetry-trace",
|
||||
EnvVar: "CODER_TELEMETRY_TRACE",
|
||||
Shorthand: "",
|
||||
Description: "Whether Opentelemetry traces are sent to Coder. Coder collects anonymized application tracing to help improve our product. Disabling telemetry also disables this option.",
|
||||
Default: flag.Lookup("test.v") == nil,
|
||||
},
|
||||
TelemetryURL: &codersdk.StringFlag{
|
||||
Name: "Telemetry URL",
|
||||
Flag: "telemetry-url",
|
||||
EnvVar: "CODER_TELEMETRY_URL",
|
||||
Description: "URL to send telemetry.",
|
||||
Hidden: true,
|
||||
Default: "https://telemetry.coder.com",
|
||||
},
|
||||
TLSEnable: &codersdk.BoolFlag{
|
||||
Name: "TLS Enabled",
|
||||
Flag: "tls-enable",
|
||||
EnvVar: "CODER_TLS_ENABLE",
|
||||
Description: "Whether TLS will be enabled.",
|
||||
},
|
||||
TLSCertFiles: &codersdk.StringArrayFlag{
|
||||
Name: "TLS Cert Files",
|
||||
Flag: "tls-cert-file",
|
||||
EnvVar: "CODER_TLS_CERT_FILE",
|
||||
Description: "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: []string{},
|
||||
},
|
||||
TLSClientCAFile: &codersdk.StringFlag{
|
||||
Name: "TLS Client CA File",
|
||||
Flag: "tls-client-ca-file",
|
||||
EnvVar: "CODER_TLS_CLIENT_CA_FILE",
|
||||
Description: "PEM-encoded Certificate Authority file used for checking the authenticity of client",
|
||||
},
|
||||
TLSClientAuth: &codersdk.StringFlag{
|
||||
Name: "TLS Client Auth",
|
||||
Flag: "tls-client-auth",
|
||||
EnvVar: "CODER_TLS_CLIENT_AUTH",
|
||||
Description: `Policy the server will follow for TLS Client Authentication. ` +
|
||||
`Accepted values are "none", "request", "require-any", "verify-if-given", or "require-and-verify"`,
|
||||
Default: "request",
|
||||
},
|
||||
TLSKeyFiles: &codersdk.StringArrayFlag{
|
||||
Name: "TLS Key Files",
|
||||
Flag: "tls-key-file",
|
||||
EnvVar: "CODER_TLS_KEY_FILE",
|
||||
Description: "Paths to the private keys for each of the certificates. It requires a PEM-encoded file",
|
||||
Default: []string{},
|
||||
},
|
||||
TLSMinVersion: &codersdk.StringFlag{
|
||||
Name: "TLS Min Version",
|
||||
Flag: "tls-min-version",
|
||||
EnvVar: "CODER_TLS_MIN_VERSION",
|
||||
Description: `Minimum supported version of TLS. Accepted values are "tls10", "tls11", "tls12" or "tls13"`,
|
||||
Default: "tls12",
|
||||
},
|
||||
TraceEnable: &codersdk.BoolFlag{
|
||||
Name: "Trace Enabled",
|
||||
Flag: "trace",
|
||||
EnvVar: "CODER_TRACE",
|
||||
Description: "Whether application tracing data is collected.",
|
||||
},
|
||||
SecureAuthCookie: &codersdk.BoolFlag{
|
||||
Name: "Secure Auth Cookie",
|
||||
Flag: "secure-auth-cookie",
|
||||
EnvVar: "CODER_SECURE_AUTH_COOKIE",
|
||||
Description: "Controls if the 'Secure' property is set on browser session cookies",
|
||||
},
|
||||
SSHKeygenAlgorithm: &codersdk.StringFlag{
|
||||
Name: "SSH Keygen Algorithm",
|
||||
Flag: "ssh-keygen-algorithm",
|
||||
EnvVar: "CODER_SSH_KEYGEN_ALGORITHM",
|
||||
Description: "The algorithm to use for generating ssh keys. " +
|
||||
`Accepted values are "ed25519", "ecdsa", or "rsa4096"`,
|
||||
Default: "ed25519",
|
||||
},
|
||||
AutoImportTemplates: &codersdk.StringArrayFlag{
|
||||
Name: "Auto Import Templates",
|
||||
Flag: "auto-import-template",
|
||||
EnvVar: "CODER_TEMPLATE_AUTOIMPORT",
|
||||
Description: "Templates to auto-import. Available auto-importable templates are: kubernetes",
|
||||
Hidden: true,
|
||||
Default: []string{},
|
||||
},
|
||||
MetricsCacheRefreshInterval: &codersdk.DurationFlag{
|
||||
Name: "Metrics Cache Refresh Interval",
|
||||
Flag: "metrics-cache-refresh-interval",
|
||||
EnvVar: "CODER_METRICS_CACHE_REFRESH_INTERVAL",
|
||||
Description: "How frequently metrics are refreshed",
|
||||
Hidden: true,
|
||||
Default: time.Hour,
|
||||
},
|
||||
AgentStatRefreshInterval: &codersdk.DurationFlag{
|
||||
Name: "Agent Stats Refresh Interval",
|
||||
Flag: "agent-stats-refresh-interval",
|
||||
EnvVar: "CODER_AGENT_STATS_REFRESH_INTERVAL",
|
||||
Description: "How frequently agent stats are recorded",
|
||||
Hidden: true,
|
||||
Default: 10 * time.Minute,
|
||||
},
|
||||
Verbose: &codersdk.BoolFlag{
|
||||
Name: "Verbose Logging",
|
||||
Flag: "verbose",
|
||||
EnvVar: "CODER_VERBOSE",
|
||||
Shorthand: "v",
|
||||
Description: "Enables verbose logging.",
|
||||
},
|
||||
AuditLogging: &codersdk.BoolFlag{
|
||||
Name: "Audit Logging",
|
||||
Flag: "audit-logging",
|
||||
EnvVar: "CODER_AUDIT_LOGGING",
|
||||
Description: "Specifies whether audit logging is enabled.",
|
||||
Default: true,
|
||||
Enterprise: true,
|
||||
},
|
||||
BrowserOnly: &codersdk.BoolFlag{
|
||||
Name: "Browser Only",
|
||||
Flag: "browser-only",
|
||||
EnvVar: "CODER_BROWSER_ONLY",
|
||||
Description: "Whether Coder only allows connections to workspaces via the browser.",
|
||||
Enterprise: true,
|
||||
},
|
||||
SCIMAuthHeader: &codersdk.StringFlag{
|
||||
Name: "SCIM Authentication Header",
|
||||
Flag: "scim-auth-header",
|
||||
EnvVar: "CODER_SCIM_API_KEY",
|
||||
Description: "Enables SCIM and sets the authentication header for the built-in SCIM server. New users are automatically created with OIDC authentication.",
|
||||
Secret: true,
|
||||
Enterprise: true,
|
||||
},
|
||||
UserWorkspaceQuota: &codersdk.IntFlag{
|
||||
Name: "User Workspace Quota",
|
||||
Flag: "user-workspace-quota",
|
||||
EnvVar: "CODER_USER_WORKSPACE_QUOTA",
|
||||
Description: "Enables and sets a limit on how many workspaces each user can create.",
|
||||
Default: 0,
|
||||
Enterprise: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveSensitiveValues(df codersdk.DeploymentFlags) codersdk.DeploymentFlags {
|
||||
v := reflect.ValueOf(&df).Elem()
|
||||
t := v.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fv := v.Field(i)
|
||||
if vp, ok := fv.Interface().(*codersdk.StringFlag); ok {
|
||||
if vp.Secret && vp.Value != "" {
|
||||
// Make a copy and remove the value.
|
||||
v := *vp
|
||||
v.Value = secretValue
|
||||
fv.Set(reflect.ValueOf(&v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return df
|
||||
}
|
||||
|
||||
//nolint:revive
|
||||
func AttachFlags(flagset *pflag.FlagSet, df *codersdk.DeploymentFlags, enterprise bool) {
|
||||
v := reflect.ValueOf(df).Elem()
|
||||
t := v.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fv := v.Field(i)
|
||||
fve := fv.Elem()
|
||||
e := fve.FieldByName("Enterprise").Bool()
|
||||
if e != enterprise {
|
||||
continue
|
||||
}
|
||||
if e {
|
||||
d := fve.FieldByName("Description").String()
|
||||
d += cliui.Styles.Keyword.Render(" This is an Enterprise feature. Contact sales@coder.com for licensing")
|
||||
fve.FieldByName("Description").SetString(d)
|
||||
}
|
||||
|
||||
switch v := fv.Interface().(type) {
|
||||
case *codersdk.StringFlag:
|
||||
StringFlag(flagset, v)
|
||||
case *codersdk.StringArrayFlag:
|
||||
StringArrayFlag(flagset, v)
|
||||
case *codersdk.IntFlag:
|
||||
IntFlag(flagset, v)
|
||||
case *codersdk.BoolFlag:
|
||||
BoolFlag(flagset, v)
|
||||
case *codersdk.DurationFlag:
|
||||
DurationFlag(flagset, v)
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown flag type: %T", v))
|
||||
}
|
||||
if fve.FieldByName("Hidden").Bool() {
|
||||
_ = flagset.MarkHidden(fve.FieldByName("Flag").String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StringFlag(flagset *pflag.FlagSet, fl *codersdk.StringFlag) {
|
||||
cliflag.StringVarP(flagset,
|
||||
&fl.Value,
|
||||
fl.Flag,
|
||||
fl.Shorthand,
|
||||
fl.EnvVar,
|
||||
fl.Default,
|
||||
fl.Description,
|
||||
)
|
||||
}
|
||||
|
||||
func BoolFlag(flagset *pflag.FlagSet, fl *codersdk.BoolFlag) {
|
||||
cliflag.BoolVarP(flagset,
|
||||
&fl.Value,
|
||||
fl.Flag,
|
||||
fl.Shorthand,
|
||||
fl.EnvVar,
|
||||
fl.Default,
|
||||
fl.Description,
|
||||
)
|
||||
}
|
||||
|
||||
func IntFlag(flagset *pflag.FlagSet, fl *codersdk.IntFlag) {
|
||||
cliflag.IntVarP(flagset,
|
||||
&fl.Value,
|
||||
fl.Flag,
|
||||
fl.Shorthand,
|
||||
fl.EnvVar,
|
||||
fl.Default,
|
||||
fl.Description,
|
||||
)
|
||||
}
|
||||
|
||||
func DurationFlag(flagset *pflag.FlagSet, fl *codersdk.DurationFlag) {
|
||||
cliflag.DurationVarP(flagset,
|
||||
&fl.Value,
|
||||
fl.Flag,
|
||||
fl.Shorthand,
|
||||
fl.EnvVar,
|
||||
fl.Default,
|
||||
fl.Description,
|
||||
)
|
||||
}
|
||||
|
||||
func StringArrayFlag(flagset *pflag.FlagSet, fl *codersdk.StringArrayFlag) {
|
||||
cliflag.StringArrayVarP(flagset,
|
||||
&fl.Value,
|
||||
fl.Flag,
|
||||
fl.Shorthand,
|
||||
fl.EnvVar,
|
||||
fl.Default,
|
||||
fl.Description,
|
||||
)
|
||||
}
|
||||
|
||||
func defaultCacheDir() string {
|
||||
defaultCacheDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
defaultCacheDir = os.TempDir()
|
||||
}
|
||||
if dir := os.Getenv("CACHE_DIRECTORY"); dir != "" {
|
||||
// For compatibility with systemd.
|
||||
defaultCacheDir = dir
|
||||
}
|
||||
|
||||
return filepath.Join(defaultCacheDir, "coder")
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package deployment_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/cli/deployment"
|
||||
)
|
||||
|
||||
func TestFlags(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
df := deployment.Flags()
|
||||
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
deployment.AttachFlags(fs, df, false)
|
||||
|
||||
require.NotNil(t, fs.Lookup("access-url"))
|
||||
require.False(t, fs.Lookup("access-url").Hidden)
|
||||
require.True(t, fs.Lookup("telemetry-url").Hidden)
|
||||
require.NotEmpty(t, fs.Lookup("telemetry-url").DefValue)
|
||||
require.Nil(t, fs.Lookup("audit-logging"))
|
||||
|
||||
df = deployment.Flags()
|
||||
fs = pflag.NewFlagSet("test-enterprise", pflag.ContinueOnError)
|
||||
deployment.AttachFlags(fs, df, true)
|
||||
|
||||
require.Nil(t, fs.Lookup("access-url"))
|
||||
require.NotNil(t, fs.Lookup("audit-logging"))
|
||||
require.Contains(t, fs.Lookup("audit-logging").Usage, "This is an Enterprise feature")
|
||||
}
|
|
@ -43,7 +43,6 @@ const (
|
|||
varToken = "token"
|
||||
varAgentToken = "agent-token"
|
||||
varAgentURL = "agent-url"
|
||||
varGlobalConfig = "global-config"
|
||||
varHeader = "header"
|
||||
varNoOpen = "no-open"
|
||||
varNoVersionCheck = "no-version-warning"
|
||||
|
@ -101,7 +100,7 @@ func Core() []*cobra.Command {
|
|||
}
|
||||
|
||||
func AGPL() []*cobra.Command {
|
||||
all := append(Core(), Server(deployment.Flags(), func(_ context.Context, o *coderd.Options) (*coderd.API, io.Closer, error) {
|
||||
all := append(Core(), Server(deployment.NewViper(), func(_ context.Context, o *coderd.Options) (*coderd.API, io.Closer, error) {
|
||||
api := coderd.New(o)
|
||||
return api, api, nil
|
||||
}))
|
||||
|
@ -184,7 +183,7 @@ func Root(subcommands []*cobra.Command) *cobra.Command {
|
|||
_ = cmd.PersistentFlags().MarkHidden(varAgentToken)
|
||||
cliflag.String(cmd.PersistentFlags(), varAgentURL, "", "CODER_AGENT_URL", "", "URL for an agent to access your deployment.")
|
||||
_ = cmd.PersistentFlags().MarkHidden(varAgentURL)
|
||||
cliflag.String(cmd.PersistentFlags(), varGlobalConfig, "", "CODER_CONFIG_DIR", configdir.LocalConfig("coderv2"), "Path to the global `coder` config directory.")
|
||||
cliflag.String(cmd.PersistentFlags(), config.FlagName, "", "CODER_CONFIG_DIR", configdir.LocalConfig("coderv2"), "Path to the global `coder` config directory.")
|
||||
cliflag.StringArray(cmd.PersistentFlags(), varHeader, "", "CODER_HEADER", []string{}, "HTTP headers added to all requests. Provide as \"Key=Value\"")
|
||||
cmd.PersistentFlags().Bool(varForceTty, false, "Force the `coder` command to run as if connected to a TTY.")
|
||||
_ = cmd.PersistentFlags().MarkHidden(varForceTty)
|
||||
|
@ -362,7 +361,7 @@ func namedWorkspace(cmd *cobra.Command, client *codersdk.Client, identifier stri
|
|||
|
||||
// createConfig consumes the global configuration flag to produce a config root.
|
||||
func createConfig(cmd *cobra.Command) config.Root {
|
||||
globalRoot, err := cmd.Flags().GetString(varGlobalConfig)
|
||||
globalRoot, err := cmd.Flags().GetString(config.FlagName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
168
cli/server.go
168
cli/server.go
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/mod/semver"
|
||||
"golang.org/x/oauth2"
|
||||
|
@ -70,14 +71,18 @@ import (
|
|||
)
|
||||
|
||||
// nolint:gocyclo
|
||||
func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *cobra.Command {
|
||||
func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *cobra.Command {
|
||||
root := &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "Start a Coder server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := deployment.Config(cmd.Flags(), vip)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting deployment config: %w", err)
|
||||
}
|
||||
printLogo(cmd)
|
||||
logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr()))
|
||||
if dflags.Verbose.Value {
|
||||
if ok, _ := cmd.Flags().GetBool(varVerbose); ok {
|
||||
logger = logger.Leveled(slog.LevelDebug)
|
||||
}
|
||||
|
||||
|
@ -106,22 +111,21 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
|
||||
var (
|
||||
tracerProvider trace.TracerProvider
|
||||
err error
|
||||
sqlDriver = "postgres"
|
||||
)
|
||||
|
||||
// Coder tracing should be disabled if telemetry is disabled unless
|
||||
// --telemetry-trace was explicitly provided.
|
||||
shouldCoderTrace := dflags.TelemetryEnable.Value && !isTest()
|
||||
shouldCoderTrace := cfg.TelemetryEnable.Value && !isTest()
|
||||
// Only override if telemetryTraceEnable was specifically set.
|
||||
// By default we want it to be controlled by telemetryEnable.
|
||||
if cmd.Flags().Changed("telemetry-trace") {
|
||||
shouldCoderTrace = dflags.TelemetryTraceEnable.Value
|
||||
shouldCoderTrace = cfg.TelemetryTrace.Value
|
||||
}
|
||||
|
||||
if dflags.TraceEnable.Value || shouldCoderTrace {
|
||||
if cfg.TraceEnable.Value || shouldCoderTrace {
|
||||
sdkTracerProvider, closeTracing, err := tracing.TracerProvider(ctx, "coderd", tracing.TracerOpts{
|
||||
Default: dflags.TraceEnable.Value,
|
||||
Default: cfg.TraceEnable.Value,
|
||||
Coder: shouldCoderTrace,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -146,10 +150,10 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
config := createConfig(cmd)
|
||||
builtinPostgres := false
|
||||
// Only use built-in if PostgreSQL URL isn't specified!
|
||||
if !dflags.InMemoryDatabase.Value && dflags.PostgresURL.Value == "" {
|
||||
if !cfg.InMemoryDatabase.Value && cfg.PostgresURL.Value == "" {
|
||||
var closeFunc func() error
|
||||
cmd.Printf("Using built-in PostgreSQL (%s)\n", config.PostgresPath())
|
||||
dflags.PostgresURL.Value, closeFunc, err = startBuiltinPostgres(ctx, config, logger)
|
||||
cfg.PostgresURL.Value, closeFunc, err = startBuiltinPostgres(ctx, config, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -162,20 +166,20 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
}()
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", dflags.Address.Value)
|
||||
listener, err := net.Listen("tcp", cfg.Address.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("listen %q: %w", dflags.Address.Value, err)
|
||||
return xerrors.Errorf("listen %q: %w", cfg.Address.Value, err)
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
var tlsConfig *tls.Config
|
||||
if dflags.TLSEnable.Value {
|
||||
if cfg.TLSEnable.Value {
|
||||
tlsConfig, err = configureTLS(
|
||||
dflags.TLSMinVersion.Value,
|
||||
dflags.TLSClientAuth.Value,
|
||||
dflags.TLSCertFiles.Value,
|
||||
dflags.TLSKeyFiles.Value,
|
||||
dflags.TLSClientCAFile.Value,
|
||||
cfg.TLSMinVersion.Value,
|
||||
cfg.TLSClientAuth.Value,
|
||||
cfg.TLSCertFiles.Value,
|
||||
cfg.TLSKeyFiles.Value,
|
||||
cfg.TLSClientCAFile.Value,
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("configure tls: %w", err)
|
||||
|
@ -197,7 +201,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
Scheme: "http",
|
||||
Host: tcpAddr.String(),
|
||||
}
|
||||
if dflags.TLSEnable.Value {
|
||||
if cfg.TLSEnable.Value {
|
||||
localURL.Scheme = "https"
|
||||
}
|
||||
|
||||
|
@ -210,26 +214,26 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
|
||||
// If the access URL is empty, we attempt to run a reverse-proxy
|
||||
// tunnel to make the initial setup really simple.
|
||||
if dflags.AccessURL.Value == "" {
|
||||
if cfg.AccessURL.Value == "" {
|
||||
cmd.Printf("Opening tunnel so workspaces can connect to your deployment. For production scenarios, specify an external access URL\n")
|
||||
tunnel, tunnelErr, err = devtunnel.New(ctxTunnel, logger.Named("devtunnel"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create tunnel: %w", err)
|
||||
}
|
||||
dflags.AccessURL.Value = tunnel.URL
|
||||
cfg.AccessURL.Value = tunnel.URL
|
||||
|
||||
if dflags.WildcardAccessURL.Value == "" {
|
||||
if cfg.WildcardAccessURL.Value == "" {
|
||||
u, err := parseURL(ctx, tunnel.URL)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse tunnel url: %w", err)
|
||||
}
|
||||
|
||||
// Suffixed wildcard access URL.
|
||||
dflags.WildcardAccessURL.Value = fmt.Sprintf("*--%s", u.Hostname())
|
||||
cfg.WildcardAccessURL.Value = fmt.Sprintf("*--%s", u.Hostname())
|
||||
}
|
||||
}
|
||||
|
||||
accessURLParsed, err := parseURL(ctx, dflags.AccessURL.Value)
|
||||
accessURLParsed, err := parseURL(ctx, cfg.AccessURL.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse URL: %w", err)
|
||||
}
|
||||
|
@ -264,17 +268,17 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
return err
|
||||
}
|
||||
|
||||
sshKeygenAlgorithm, err := gitsshkey.ParseAlgorithm(dflags.SSHKeygenAlgorithm.Value)
|
||||
sshKeygenAlgorithm, err := gitsshkey.ParseAlgorithm(cfg.SSHKeygenAlgorithm.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse ssh keygen algorithm %s: %w", dflags.SSHKeygenAlgorithm.Value, err)
|
||||
return xerrors.Errorf("parse ssh keygen algorithm %s: %w", cfg.SSHKeygenAlgorithm.Value, err)
|
||||
}
|
||||
|
||||
// Validate provided auto-import templates.
|
||||
var (
|
||||
validatedAutoImportTemplates = make([]coderd.AutoImportTemplate, len(dflags.AutoImportTemplates.Value))
|
||||
seenValidatedAutoImportTemplates = make(map[coderd.AutoImportTemplate]struct{}, len(dflags.AutoImportTemplates.Value))
|
||||
validatedAutoImportTemplates = make([]coderd.AutoImportTemplate, len(cfg.AutoImportTemplates.Value))
|
||||
seenValidatedAutoImportTemplates = make(map[coderd.AutoImportTemplate]struct{}, len(cfg.AutoImportTemplates.Value))
|
||||
)
|
||||
for i, autoImportTemplate := range dflags.AutoImportTemplates.Value {
|
||||
for i, autoImportTemplate := range cfg.AutoImportTemplates.Value {
|
||||
var v coderd.AutoImportTemplate
|
||||
switch autoImportTemplate {
|
||||
case "kubernetes":
|
||||
|
@ -292,27 +296,27 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
|
||||
defaultRegion := &tailcfg.DERPRegion{
|
||||
EmbeddedRelay: true,
|
||||
RegionID: dflags.DerpServerRegionID.Value,
|
||||
RegionCode: dflags.DerpServerRegionCode.Value,
|
||||
RegionName: dflags.DerpServerRegionName.Value,
|
||||
RegionID: cfg.DERPServerRegionID.Value,
|
||||
RegionCode: cfg.DERPServerRegionCode.Value,
|
||||
RegionName: cfg.DERPServerRegionName.Value,
|
||||
Nodes: []*tailcfg.DERPNode{{
|
||||
Name: fmt.Sprintf("%db", dflags.DerpServerRegionID.Value),
|
||||
RegionID: dflags.DerpServerRegionID.Value,
|
||||
Name: fmt.Sprintf("%db", cfg.DERPServerRegionID.Value),
|
||||
RegionID: cfg.DERPServerRegionID.Value,
|
||||
HostName: accessURLParsed.Hostname(),
|
||||
DERPPort: accessURLPort,
|
||||
STUNPort: -1,
|
||||
ForceHTTP: accessURLParsed.Scheme == "http",
|
||||
}},
|
||||
}
|
||||
if !dflags.DerpServerEnable.Value {
|
||||
if !cfg.DERPServerEnable.Value {
|
||||
defaultRegion = nil
|
||||
}
|
||||
derpMap, err := tailnet.NewDERPMap(ctx, defaultRegion, dflags.DerpServerSTUNAddresses.Value, dflags.DerpConfigURL.Value, dflags.DerpConfigPath.Value)
|
||||
derpMap, err := tailnet.NewDERPMap(ctx, defaultRegion, cfg.DERPServerSTUNAddresses.Value, cfg.DERPConfigURL.Value, cfg.DERPConfigPath.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create derp map: %w", err)
|
||||
}
|
||||
|
||||
appHostname := strings.TrimSpace(dflags.WildcardAccessURL.Value)
|
||||
appHostname := strings.TrimSpace(cfg.WildcardAccessURL.Value)
|
||||
var appHostnameRegex *regexp.Regexp
|
||||
if appHostname != "" {
|
||||
appHostnameRegex, err = httpapi.CompileHostnamePattern(appHostname)
|
||||
|
@ -329,45 +333,45 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
Database: databasefake.New(),
|
||||
DERPMap: derpMap,
|
||||
Pubsub: database.NewPubsubInMemory(),
|
||||
CacheDir: dflags.CacheDir.Value,
|
||||
CacheDir: cfg.CacheDirectory.Value,
|
||||
GoogleTokenValidator: googleTokenValidator,
|
||||
SecureAuthCookie: dflags.SecureAuthCookie.Value,
|
||||
SecureAuthCookie: cfg.SecureAuthCookie.Value,
|
||||
SSHKeygenAlgorithm: sshKeygenAlgorithm,
|
||||
TracerProvider: tracerProvider,
|
||||
Telemetry: telemetry.NewNoop(),
|
||||
AutoImportTemplates: validatedAutoImportTemplates,
|
||||
MetricsCacheRefreshInterval: dflags.MetricsCacheRefreshInterval.Value,
|
||||
AgentStatsRefreshInterval: dflags.AgentStatRefreshInterval.Value,
|
||||
MetricsCacheRefreshInterval: cfg.MetricsCacheRefreshInterval.Value,
|
||||
AgentStatsRefreshInterval: cfg.AgentStatRefreshInterval.Value,
|
||||
Experimental: ExperimentalEnabled(cmd),
|
||||
DeploymentFlags: dflags,
|
||||
DeploymentConfig: &cfg,
|
||||
}
|
||||
if tlsConfig != nil {
|
||||
options.TLSCertificates = tlsConfig.Certificates
|
||||
}
|
||||
|
||||
if dflags.OAuth2GithubClientSecret.Value != "" {
|
||||
if cfg.OAuth2GithubClientSecret.Value != "" {
|
||||
options.GithubOAuth2Config, err = configureGithubOAuth2(accessURLParsed,
|
||||
dflags.OAuth2GithubClientID.Value,
|
||||
dflags.OAuth2GithubClientSecret.Value,
|
||||
dflags.OAuth2GithubAllowSignups.Value,
|
||||
dflags.OAuth2GithubAllowedOrganizations.Value,
|
||||
dflags.OAuth2GithubAllowedTeams.Value,
|
||||
dflags.OAuth2GithubEnterpriseBaseURL.Value,
|
||||
cfg.OAuth2GithubClientID.Value,
|
||||
cfg.OAuth2GithubClientSecret.Value,
|
||||
cfg.OAuth2GithubAllowSignups.Value,
|
||||
cfg.OAuth2GithubAllowedOrgs.Value,
|
||||
cfg.OAuth2GithubAllowedTeams.Value,
|
||||
cfg.OAuth2GithubEnterpriseBaseURL.Value,
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("configure github oauth2: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if dflags.OIDCClientSecret.Value != "" {
|
||||
if dflags.OIDCClientID.Value == "" {
|
||||
if cfg.OIDCClientSecret.Value != "" {
|
||||
if cfg.OIDCClientID.Value == "" {
|
||||
return xerrors.Errorf("OIDC client ID be set!")
|
||||
}
|
||||
if dflags.OIDCIssuerURL.Value == "" {
|
||||
if cfg.OIDCIssuerURL.Value == "" {
|
||||
return xerrors.Errorf("OIDC issuer URL must be set!")
|
||||
}
|
||||
|
||||
oidcProvider, err := oidc.NewProvider(ctx, dflags.OIDCIssuerURL.Value)
|
||||
oidcProvider, err := oidc.NewProvider(ctx, cfg.OIDCIssuerURL.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("configure oidc provider: %w", err)
|
||||
}
|
||||
|
@ -377,25 +381,25 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
}
|
||||
options.OIDCConfig = &coderd.OIDCConfig{
|
||||
OAuth2Config: &oauth2.Config{
|
||||
ClientID: dflags.OIDCClientID.Value,
|
||||
ClientSecret: dflags.OIDCClientSecret.Value,
|
||||
ClientID: cfg.OIDCClientID.Value,
|
||||
ClientSecret: cfg.OIDCClientSecret.Value,
|
||||
RedirectURL: redirectURL.String(),
|
||||
Endpoint: oidcProvider.Endpoint(),
|
||||
Scopes: dflags.OIDCScopes.Value,
|
||||
Scopes: cfg.OIDCScopes.Value,
|
||||
},
|
||||
Verifier: oidcProvider.Verifier(&oidc.Config{
|
||||
ClientID: dflags.OIDCClientID.Value,
|
||||
ClientID: cfg.OIDCClientID.Value,
|
||||
}),
|
||||
EmailDomain: dflags.OIDCEmailDomain.Value,
|
||||
AllowSignups: dflags.OIDCAllowSignups.Value,
|
||||
EmailDomain: cfg.OIDCEmailDomain.Value,
|
||||
AllowSignups: cfg.OIDCAllowSignups.Value,
|
||||
}
|
||||
}
|
||||
|
||||
if dflags.InMemoryDatabase.Value {
|
||||
if cfg.InMemoryDatabase.Value {
|
||||
options.Database = databasefake.New()
|
||||
options.Pubsub = database.NewPubsubInMemory()
|
||||
} else {
|
||||
sqlDB, err := sql.Open(sqlDriver, dflags.PostgresURL.Value)
|
||||
sqlDB, err := sql.Open(sqlDriver, cfg.PostgresURL.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("dial postgres: %w", err)
|
||||
}
|
||||
|
@ -427,7 +431,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
return xerrors.Errorf("migrate up: %w", err)
|
||||
}
|
||||
options.Database = database.New(sqlDB)
|
||||
options.Pubsub, err = database.NewPubsub(ctx, sqlDB, dflags.PostgresURL.Value)
|
||||
options.Pubsub, err = database.NewPubsub(ctx, sqlDB, cfg.PostgresURL.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create pubsub: %w", err)
|
||||
}
|
||||
|
@ -450,26 +454,26 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
}
|
||||
|
||||
// Parse the raw telemetry URL!
|
||||
telemetryURL, err := parseURL(ctx, dflags.TelemetryURL.Value)
|
||||
telemetryURL, err := parseURL(ctx, cfg.TelemetryURL.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse telemetry url: %w", err)
|
||||
}
|
||||
// Disable telemetry if the in-memory database is used unless explicitly defined!
|
||||
if dflags.InMemoryDatabase.Value && !cmd.Flags().Changed(dflags.TelemetryEnable.Flag) {
|
||||
dflags.TelemetryEnable.Value = false
|
||||
if cfg.InMemoryDatabase.Value && !cmd.Flags().Changed(cfg.TelemetryEnable.Flag) {
|
||||
cfg.TelemetryEnable.Value = false
|
||||
}
|
||||
if dflags.TelemetryEnable.Value {
|
||||
if cfg.TelemetryEnable.Value {
|
||||
options.Telemetry, err = telemetry.New(telemetry.Options{
|
||||
BuiltinPostgres: builtinPostgres,
|
||||
DeploymentID: deploymentID,
|
||||
Database: options.Database,
|
||||
Logger: logger.Named("telemetry"),
|
||||
URL: telemetryURL,
|
||||
GitHubOAuth: dflags.OAuth2GithubClientID.Value != "",
|
||||
OIDCAuth: dflags.OIDCClientID.Value != "",
|
||||
OIDCIssuerURL: dflags.OIDCIssuerURL.Value,
|
||||
Prometheus: dflags.PromEnabled.Value,
|
||||
STUN: len(dflags.DerpServerSTUNAddresses.Value) != 0,
|
||||
GitHubOAuth: cfg.OAuth2GithubClientID.Value != "",
|
||||
OIDCAuth: cfg.OIDCClientID.Value != "",
|
||||
OIDCIssuerURL: cfg.OIDCIssuerURL.Value,
|
||||
Prometheus: cfg.PrometheusEnable.Value,
|
||||
STUN: len(cfg.DERPServerSTUNAddresses.Value) != 0,
|
||||
Tunnel: tunnel != nil,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -480,11 +484,11 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
|
||||
// This prevents the pprof import from being accidentally deleted.
|
||||
_ = pprof.Handler
|
||||
if dflags.PprofEnabled.Value {
|
||||
if cfg.PprofEnable.Value {
|
||||
//nolint:revive
|
||||
defer serveHandler(ctx, logger, nil, dflags.PprofAddress.Value, "pprof")()
|
||||
defer serveHandler(ctx, logger, nil, cfg.PprofAddress.Value, "pprof")()
|
||||
}
|
||||
if dflags.PromEnabled.Value {
|
||||
if cfg.PrometheusEnable.Value {
|
||||
options.PrometheusRegistry = prometheus.NewRegistry()
|
||||
closeUsersFunc, err := prometheusmetrics.ActiveUsers(ctx, options.PrometheusRegistry, options.Database, 0)
|
||||
if err != nil {
|
||||
|
@ -501,7 +505,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
//nolint:revive
|
||||
defer serveHandler(ctx, logger, promhttp.InstrumentMetricHandler(
|
||||
options.PrometheusRegistry, promhttp.HandlerFor(options.PrometheusRegistry, promhttp.HandlerOpts{}),
|
||||
), dflags.PromAddress.Value, "prometheus")()
|
||||
), cfg.PrometheusAddress.Value, "prometheus")()
|
||||
}
|
||||
|
||||
// We use a separate coderAPICloser so the Enterprise API
|
||||
|
@ -513,7 +517,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
}
|
||||
|
||||
client := codersdk.New(localURL)
|
||||
if dflags.TLSEnable.Value {
|
||||
if cfg.TLSEnable.Value {
|
||||
// Secure transport isn't needed for locally communicating!
|
||||
client.HTTPClient.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
|
@ -537,8 +541,8 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
_ = daemon.Close()
|
||||
}
|
||||
}()
|
||||
for i := 0; i < dflags.ProvisionerDaemonCount.Value; i++ {
|
||||
daemon, err := newProvisionerDaemon(ctx, coderAPI, logger, dflags.CacheDir.Value, errCh, false)
|
||||
for i := 0; i < cfg.ProvisionerDaemons.Value; i++ {
|
||||
daemon, err := newProvisionerDaemon(ctx, coderAPI, logger, cfg.CacheDirectory.Value, errCh, false)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create provisioner daemon: %w", err)
|
||||
}
|
||||
|
@ -604,7 +608,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
return xerrors.Errorf("notify systemd: %w", err)
|
||||
}
|
||||
|
||||
autobuildPoller := time.NewTicker(dflags.AutobuildPollInterval.Value)
|
||||
autobuildPoller := time.NewTicker(cfg.AutobuildPollInterval.Value)
|
||||
defer autobuildPoller.Stop()
|
||||
autobuildExecutor := executor.New(ctx, options.Database, logger, autobuildPoller.C)
|
||||
autobuildExecutor.Run()
|
||||
|
@ -669,7 +673,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
if dflags.Verbose.Value {
|
||||
if ok, _ := cmd.Flags().GetBool(varVerbose); ok {
|
||||
cmd.Printf("Shutting down provisioner daemon %d...\n", id)
|
||||
}
|
||||
err := shutdownWithTimeout(provisionerDaemon.Shutdown, 5*time.Second)
|
||||
|
@ -682,7 +686,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
cmd.PrintErrf("Close provisioner daemon %d: %s\n", id, err)
|
||||
return
|
||||
}
|
||||
if dflags.Verbose.Value {
|
||||
if ok, _ := cmd.Flags().GetBool(varVerbose); ok {
|
||||
cmd.Printf("Gracefully shut down provisioner daemon %d\n", id)
|
||||
}
|
||||
}()
|
||||
|
@ -734,7 +738,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg := createConfig(cmd)
|
||||
logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr()))
|
||||
if dflags.Verbose.Value {
|
||||
if ok, _ := cmd.Flags().GetBool(varVerbose); ok {
|
||||
logger = logger.Leveled(slog.LevelDebug)
|
||||
}
|
||||
|
||||
|
@ -755,7 +759,7 @@ func Server(dflags *codersdk.DeploymentFlags, newAPI func(context.Context, *code
|
|||
},
|
||||
})
|
||||
|
||||
deployment.AttachFlags(root.Flags(), dflags, false)
|
||||
deployment.AttachFlags(root.Flags(), vip, false)
|
||||
|
||||
return root
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ type Options struct {
|
|||
MetricsCacheRefreshInterval time.Duration
|
||||
AgentStatsRefreshInterval time.Duration
|
||||
Experimental bool
|
||||
DeploymentFlags *codersdk.DeploymentFlags
|
||||
DeploymentConfig *codersdk.DeploymentConfig
|
||||
}
|
||||
|
||||
// New constructs a Coder API handler.
|
||||
|
@ -286,9 +286,9 @@ func New(options *Options) *API {
|
|||
})
|
||||
})
|
||||
})
|
||||
r.Route("/flags", func(r chi.Router) {
|
||||
r.Route("/config", func(r chi.Router) {
|
||||
r.Use(apiKeyMiddleware)
|
||||
r.Get("/deployment", api.deploymentFlags)
|
||||
r.Get("/deployment", api.deploymentConfig)
|
||||
})
|
||||
r.Route("/audit", func(r chi.Router) {
|
||||
r.Use(
|
||||
|
|
|
@ -91,7 +91,7 @@ type Options struct {
|
|||
IncludeProvisionerDaemon bool
|
||||
MetricsCacheRefreshInterval time.Duration
|
||||
AgentStatsRefreshInterval time.Duration
|
||||
DeploymentFlags *codersdk.DeploymentFlags
|
||||
DeploymentConfig *codersdk.DeploymentConfig
|
||||
|
||||
// Overriding the database is heavily discouraged.
|
||||
// It should only be used in cases where multiple Coder
|
||||
|
@ -268,7 +268,7 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can
|
|||
AutoImportTemplates: options.AutoImportTemplates,
|
||||
MetricsCacheRefreshInterval: options.MetricsCacheRefreshInterval,
|
||||
AgentStatsRefreshInterval: options.AgentStatsRefreshInterval,
|
||||
DeploymentFlags: options.DeploymentFlags,
|
||||
DeploymentConfig: options.DeploymentConfig,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package coderd
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/coder/coder/coderd/httpapi"
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
)
|
||||
|
||||
func (api *API) deploymentConfig(rw http.ResponseWriter, r *http.Request) {
|
||||
if !api.Authorize(r, rbac.ActionRead, rbac.ResourceDeploymentConfig) {
|
||||
httpapi.Forbidden(rw)
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(r.Context(), rw, http.StatusOK, api.DeploymentConfig)
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package coderd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/cli/config"
|
||||
"github.com/coder/coder/cli/deployment"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/testutil"
|
||||
)
|
||||
|
||||
func TestDeploymentConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
hi := "hi"
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
vip := deployment.NewViper()
|
||||
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
fs.String(config.FlagName, hi, "usage")
|
||||
cfg, err := deployment.Config(fs, vip)
|
||||
require.NoError(t, err)
|
||||
// values should be returned
|
||||
cfg.AccessURL.Value = hi
|
||||
// values should not be returned
|
||||
cfg.OAuth2GithubClientSecret.Value = hi
|
||||
cfg.OIDCClientSecret.Value = hi
|
||||
cfg.PostgresURL.Value = hi
|
||||
cfg.SCIMAPIKey.Value = hi
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
DeploymentConfig: &cfg,
|
||||
})
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
scrubbed, err := client.DeploymentConfig(ctx)
|
||||
require.NoError(t, err)
|
||||
// ensure normal values pass through
|
||||
require.EqualValues(t, hi, scrubbed.AccessURL.Value)
|
||||
// ensure secrets are removed
|
||||
require.Empty(t, scrubbed.OAuth2GithubClientSecret.Value)
|
||||
require.Empty(t, scrubbed.OIDCClientSecret.Value)
|
||||
require.Empty(t, scrubbed.PostgresURL.Value)
|
||||
require.Empty(t, scrubbed.SCIMAPIKey.Value)
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package coderd
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/coder/coder/cli/deployment"
|
||||
"github.com/coder/coder/coderd/httpapi"
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
)
|
||||
|
||||
func (api *API) deploymentFlags(rw http.ResponseWriter, r *http.Request) {
|
||||
if !api.Authorize(r, rbac.ActionRead, rbac.ResourceDeploymentFlags) {
|
||||
httpapi.Forbidden(rw)
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(r.Context(), rw, http.StatusOK, deployment.RemoveSensitiveValues(*api.DeploymentFlags))
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package coderd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/cli/deployment"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/testutil"
|
||||
)
|
||||
|
||||
const (
|
||||
secretValue = "********"
|
||||
)
|
||||
|
||||
func TestDeploymentFlagSecrets(t *testing.T) {
|
||||
t.Parallel()
|
||||
hi := "hi"
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
df := deployment.Flags()
|
||||
// check if copy works for non-secret values
|
||||
df.AccessURL.Value = hi
|
||||
// check if secrets are removed
|
||||
df.OAuth2GithubClientSecret.Value = hi
|
||||
df.OIDCClientSecret.Value = hi
|
||||
df.PostgresURL.Value = hi
|
||||
df.SCIMAuthHeader.Value = hi
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
DeploymentFlags: df,
|
||||
})
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
scrubbed, err := client.DeploymentFlags(ctx)
|
||||
require.NoError(t, err)
|
||||
// ensure df is unchanged
|
||||
require.EqualValues(t, hi, df.OAuth2GithubClientSecret.Value)
|
||||
// ensure normal values pass through
|
||||
require.EqualValues(t, hi, scrubbed.AccessURL.Value)
|
||||
// ensure secrets are removed
|
||||
require.EqualValues(t, secretValue, scrubbed.OAuth2GithubClientSecret.Value)
|
||||
require.EqualValues(t, secretValue, scrubbed.OIDCClientSecret.Value)
|
||||
require.EqualValues(t, secretValue, scrubbed.PostgresURL.Value)
|
||||
require.EqualValues(t, secretValue, scrubbed.SCIMAuthHeader.Value)
|
||||
}
|
|
@ -142,9 +142,9 @@ var (
|
|||
Type: "license",
|
||||
}
|
||||
|
||||
// ResourceDeploymentFlags
|
||||
ResourceDeploymentFlags = Object{
|
||||
Type: "deployment_flags",
|
||||
// ResourceDeploymentConfig
|
||||
ResourceDeploymentConfig = Object{
|
||||
Type: "deployment_config",
|
||||
}
|
||||
|
||||
ResourceReplicas = Object{
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package codersdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// DeploymentConfig is the central configuration for the coder server.
|
||||
// Secret values should specify `json:"-"` to prevent them from being returned by the API.
|
||||
type DeploymentConfig struct {
|
||||
AccessURL DeploymentConfigField[string] `json:"access_url"`
|
||||
WildcardAccessURL DeploymentConfigField[string] `json:"wildcard_access_url"`
|
||||
Address DeploymentConfigField[string] `json:"address"`
|
||||
AutobuildPollInterval DeploymentConfigField[time.Duration] `json:"autobuild_poll_interval"`
|
||||
DERPServerEnable DeploymentConfigField[bool] `json:"derp_server_enabled"`
|
||||
DERPServerRegionID DeploymentConfigField[int] `json:"derp_server_region_id"`
|
||||
DERPServerRegionCode DeploymentConfigField[string] `json:"derp_server_region_code"`
|
||||
DERPServerRegionName DeploymentConfigField[string] `json:"derp_server_region_name"`
|
||||
DERPServerSTUNAddresses DeploymentConfigField[[]string] `json:"derp_server_stun_address"`
|
||||
DERPServerRelayURL DeploymentConfigField[string] `json:"derp_server_relay_address"`
|
||||
DERPConfigURL DeploymentConfigField[string] `json:"derp_config_url"`
|
||||
DERPConfigPath DeploymentConfigField[string] `json:"derp_config_path"`
|
||||
PrometheusEnable DeploymentConfigField[bool] `json:"prometheus_enabled"`
|
||||
PrometheusAddress DeploymentConfigField[string] `json:"prometheus_address"`
|
||||
PprofEnable DeploymentConfigField[bool] `json:"pprof_enabled"`
|
||||
PprofAddress DeploymentConfigField[string] `json:"pprof_address"`
|
||||
CacheDirectory DeploymentConfigField[string] `json:"cache_directory"`
|
||||
InMemoryDatabase DeploymentConfigField[bool] `json:"in_memory_database"`
|
||||
ProvisionerDaemons DeploymentConfigField[int] `json:"provisioner_daemon_count"`
|
||||
PostgresURL DeploymentConfigField[string] `json:"-"`
|
||||
OAuth2GithubClientID DeploymentConfigField[string] `json:"oauth2_github_client_id"`
|
||||
OAuth2GithubClientSecret DeploymentConfigField[string] `json:"-"`
|
||||
OAuth2GithubAllowedOrgs DeploymentConfigField[[]string] `json:"oauth2_github_allowed_orgs"`
|
||||
OAuth2GithubAllowedTeams DeploymentConfigField[[]string] `json:"oauth2_github_allowed_teams"`
|
||||
OAuth2GithubAllowSignups DeploymentConfigField[bool] `json:"oauth2_github_allow_signups"`
|
||||
OAuth2GithubEnterpriseBaseURL DeploymentConfigField[string] `json:"oauth2_github_enterprise_base_url"`
|
||||
OIDCAllowSignups DeploymentConfigField[bool] `json:"oidc_allow_signups"`
|
||||
OIDCClientID DeploymentConfigField[string] `json:"oidc_client_id"`
|
||||
OIDCClientSecret DeploymentConfigField[string] `json:"-"`
|
||||
OIDCEmailDomain DeploymentConfigField[string] `json:"oidc_email_domain"`
|
||||
OIDCIssuerURL DeploymentConfigField[string] `json:"oidc_issuer_url"`
|
||||
OIDCScopes DeploymentConfigField[[]string] `json:"oidc_scopes"`
|
||||
TelemetryEnable DeploymentConfigField[bool] `json:"telemetry_enable"`
|
||||
TelemetryTrace DeploymentConfigField[bool] `json:"telemetry_trace_enable"`
|
||||
TelemetryURL DeploymentConfigField[string] `json:"telemetry_url"`
|
||||
TLSEnable DeploymentConfigField[bool] `json:"tls_enable"`
|
||||
TLSCertFiles DeploymentConfigField[[]string] `json:"tls_cert_files"`
|
||||
TLSClientCAFile DeploymentConfigField[string] `json:"tls_client_ca_file"`
|
||||
TLSClientAuth DeploymentConfigField[string] `json:"tls_client_auth"`
|
||||
TLSKeyFiles DeploymentConfigField[[]string] `json:"tls_key_files"`
|
||||
TLSMinVersion DeploymentConfigField[string] `json:"tls_min_version"`
|
||||
TraceEnable DeploymentConfigField[bool] `json:"trace_enable"`
|
||||
SecureAuthCookie DeploymentConfigField[bool] `json:"secure_auth_cookie"`
|
||||
SSHKeygenAlgorithm DeploymentConfigField[string] `json:"ssh_keygen_algorithm"`
|
||||
AutoImportTemplates DeploymentConfigField[[]string] `json:"auto_import_templates"`
|
||||
MetricsCacheRefreshInterval DeploymentConfigField[time.Duration] `json:"metrics_cache_refresh_interval"`
|
||||
AgentStatRefreshInterval DeploymentConfigField[time.Duration] `json:"agent_stat_refresh_interval"`
|
||||
AuditLogging DeploymentConfigField[bool] `json:"audit_logging"`
|
||||
BrowserOnly DeploymentConfigField[bool] `json:"browser_only"`
|
||||
SCIMAPIKey DeploymentConfigField[string] `json:"-"`
|
||||
UserWorkspaceQuota DeploymentConfigField[int] `json:"user_workspace_quota"`
|
||||
}
|
||||
|
||||
type Flaggable interface {
|
||||
string | bool | int | time.Duration | []string
|
||||
}
|
||||
|
||||
type DeploymentConfigField[T Flaggable] struct {
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
Usage string `json:"usage"`
|
||||
Flag string `json:"flag"`
|
||||
Shorthand string `json:"shorthand"`
|
||||
Enterprise bool `json:"enterprise"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Value T `json:"value"`
|
||||
}
|
||||
|
||||
// DeploymentConfig returns the deployment config for the coder server.
|
||||
func (c *Client) DeploymentConfig(ctx context.Context) (DeploymentConfig, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, "/api/v2/config/deployment", nil)
|
||||
if err != nil {
|
||||
return DeploymentConfig{}, xerrors.Errorf("execute request: %w", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return DeploymentConfig{}, readBodyAsError(res)
|
||||
}
|
||||
|
||||
var df DeploymentConfig
|
||||
return df, json.NewDecoder(res.Body).Decode(&df)
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
package codersdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type DeploymentFlags struct {
|
||||
AccessURL *StringFlag `json:"access_url" typescript:",notnull"`
|
||||
WildcardAccessURL *StringFlag `json:"wildcard_access_url" typescript:",notnull"`
|
||||
Address *StringFlag `json:"address" typescript:",notnull"`
|
||||
AutobuildPollInterval *DurationFlag `json:"autobuild_poll_interval" typescript:",notnull"`
|
||||
DerpServerEnable *BoolFlag `json:"derp_server_enabled" typescript:",notnull"`
|
||||
DerpServerRegionID *IntFlag `json:"derp_server_region_id" typescript:",notnull"`
|
||||
DerpServerRegionCode *StringFlag `json:"derp_server_region_code" typescript:",notnull"`
|
||||
DerpServerRegionName *StringFlag `json:"derp_server_region_name" typescript:",notnull"`
|
||||
DerpServerSTUNAddresses *StringArrayFlag `json:"derp_server_stun_address" typescript:",notnull"`
|
||||
DerpServerRelayAddress *StringFlag `json:"derp_server_relay_address" typescript:",notnull"`
|
||||
DerpConfigURL *StringFlag `json:"derp_config_url" typescript:",notnull"`
|
||||
DerpConfigPath *StringFlag `json:"derp_config_path" typescript:",notnull"`
|
||||
PromEnabled *BoolFlag `json:"prom_enabled" typescript:",notnull"`
|
||||
PromAddress *StringFlag `json:"prom_address" typescript:",notnull"`
|
||||
PprofEnabled *BoolFlag `json:"pprof_enabled" typescript:",notnull"`
|
||||
PprofAddress *StringFlag `json:"pprof_address" typescript:",notnull"`
|
||||
CacheDir *StringFlag `json:"cache_dir" typescript:",notnull"`
|
||||
InMemoryDatabase *BoolFlag `json:"in_memory_database" typescript:",notnull"`
|
||||
ProvisionerDaemonCount *IntFlag `json:"provisioner_daemon_count" typescript:",notnull"`
|
||||
PostgresURL *StringFlag `json:"postgres_url" typescript:",notnull"`
|
||||
OAuth2GithubClientID *StringFlag `json:"oauth2_github_client_id" typescript:",notnull"`
|
||||
OAuth2GithubClientSecret *StringFlag `json:"oauth2_github_client_secret" typescript:",notnull"`
|
||||
OAuth2GithubAllowedOrganizations *StringArrayFlag `json:"oauth2_github_allowed_organizations" typescript:",notnull"`
|
||||
OAuth2GithubAllowedTeams *StringArrayFlag `json:"oauth2_github_allowed_teams" typescript:",notnull"`
|
||||
OAuth2GithubAllowSignups *BoolFlag `json:"oauth2_github_allow_signups" typescript:",notnull"`
|
||||
OAuth2GithubEnterpriseBaseURL *StringFlag `json:"oauth2_github_enterprise_base_url" typescript:",notnull"`
|
||||
OIDCAllowSignups *BoolFlag `json:"oidc_allow_signups" typescript:",notnull"`
|
||||
OIDCClientID *StringFlag `json:"oidc_client_id" typescript:",notnull"`
|
||||
OIDCClientSecret *StringFlag `json:"oidc_client_secret" typescript:",notnull"`
|
||||
OIDCEmailDomain *StringFlag `json:"oidc_email_domain" typescript:",notnull"`
|
||||
OIDCIssuerURL *StringFlag `json:"oidc_issuer_url" typescript:",notnull"`
|
||||
OIDCScopes *StringArrayFlag `json:"oidc_scopes" typescript:",notnull"`
|
||||
TelemetryEnable *BoolFlag `json:"telemetry_enable" typescript:",notnull"`
|
||||
TelemetryTraceEnable *BoolFlag `json:"telemetry_trace_enable" typescript:",notnull"`
|
||||
TelemetryURL *StringFlag `json:"telemetry_url" typescript:",notnull"`
|
||||
TLSEnable *BoolFlag `json:"tls_enable" typescript:",notnull"`
|
||||
TLSCertFiles *StringArrayFlag `json:"tls_cert_files" typescript:",notnull"`
|
||||
TLSClientCAFile *StringFlag `json:"tls_client_ca_file" typescript:",notnull"`
|
||||
TLSClientAuth *StringFlag `json:"tls_client_auth" typescript:",notnull"`
|
||||
TLSKeyFiles *StringArrayFlag `json:"tls_key_files" typescript:",notnull"`
|
||||
TLSMinVersion *StringFlag `json:"tls_min_version" typescript:",notnull"`
|
||||
TraceEnable *BoolFlag `json:"trace_enable" typescript:",notnull"`
|
||||
SecureAuthCookie *BoolFlag `json:"secure_auth_cookie" typescript:",notnull"`
|
||||
SSHKeygenAlgorithm *StringFlag `json:"ssh_keygen_algorithm" typescript:",notnull"`
|
||||
AutoImportTemplates *StringArrayFlag `json:"auto_import_templates" typescript:",notnull"`
|
||||
MetricsCacheRefreshInterval *DurationFlag `json:"metrics_cache_refresh_interval" typescript:",notnull"`
|
||||
AgentStatRefreshInterval *DurationFlag `json:"agent_stat_refresh_interval" typescript:",notnull"`
|
||||
Verbose *BoolFlag `json:"verbose" typescript:",notnull"`
|
||||
AuditLogging *BoolFlag `json:"audit_logging" typescript:",notnull"`
|
||||
BrowserOnly *BoolFlag `json:"browser_only" typescript:",notnull"`
|
||||
SCIMAuthHeader *StringFlag `json:"scim_auth_header" typescript:",notnull"`
|
||||
UserWorkspaceQuota *IntFlag `json:"user_workspace_quota" typescript:",notnull"`
|
||||
}
|
||||
|
||||
type StringFlag struct {
|
||||
Name string `json:"name"`
|
||||
Flag string `json:"flag"`
|
||||
EnvVar string `json:"env_var"`
|
||||
Shorthand string `json:"shorthand"`
|
||||
Description string `json:"description"`
|
||||
Enterprise bool `json:"enterprise"`
|
||||
Secret bool `json:"secret"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Default string `json:"default"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type BoolFlag struct {
|
||||
Name string `json:"name"`
|
||||
Flag string `json:"flag"`
|
||||
EnvVar string `json:"env_var"`
|
||||
Shorthand string `json:"shorthand"`
|
||||
Description string `json:"description"`
|
||||
Enterprise bool `json:"enterprise"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Default bool `json:"default"`
|
||||
Value bool `json:"value"`
|
||||
}
|
||||
|
||||
type IntFlag struct {
|
||||
Name string `json:"name"`
|
||||
Flag string `json:"flag"`
|
||||
EnvVar string `json:"env_var"`
|
||||
Shorthand string `json:"shorthand"`
|
||||
Description string `json:"description"`
|
||||
Enterprise bool `json:"enterprise"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Default int `json:"default"`
|
||||
Value int `json:"value"`
|
||||
}
|
||||
|
||||
type DurationFlag struct {
|
||||
Name string `json:"name"`
|
||||
Flag string `json:"flag"`
|
||||
EnvVar string `json:"env_var"`
|
||||
Shorthand string `json:"shorthand"`
|
||||
Description string `json:"description"`
|
||||
Enterprise bool `json:"enterprise"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Default time.Duration `json:"default"`
|
||||
Value time.Duration `json:"value"`
|
||||
}
|
||||
|
||||
type StringArrayFlag struct {
|
||||
Name string `json:"name"`
|
||||
Flag string `json:"flag"`
|
||||
EnvVar string `json:"env_var"`
|
||||
Shorthand string `json:"shorthand"`
|
||||
Description string `json:"description"`
|
||||
Enterprise bool `json:"enterprise"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Default []string `json:"default"`
|
||||
Value []string `json:"value"`
|
||||
}
|
||||
|
||||
// DeploymentFlags returns the deployment level flags for the coder server.
|
||||
func (c *Client) DeploymentFlags(ctx context.Context) (DeploymentFlags, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, "/api/v2/flags/deployment", nil)
|
||||
if err != nil {
|
||||
return DeploymentFlags{}, xerrors.Errorf("execute request: %w", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return DeploymentFlags{}, readBodyAsError(res)
|
||||
}
|
||||
|
||||
var df DeploymentFlags
|
||||
return df, json.NewDecoder(res.Body).Decode(&df)
|
||||
}
|
|
@ -102,7 +102,7 @@ to log in and manage templates.
|
|||
# This env variable controls whether or not to auto-import the
|
||||
# "kubernetes" template on first startup. This will not work unless
|
||||
# coder.serviceAccount.workspacePerms is true.
|
||||
- name: CODER_TEMPLATE_AUTOIMPORT
|
||||
- name: CODER_AUTO_IMPORT_TEMPLATES
|
||||
value: "kubernetes"
|
||||
|
||||
#tls:
|
||||
|
|
|
@ -24,10 +24,10 @@ import (
|
|||
)
|
||||
|
||||
func server() *cobra.Command {
|
||||
dflags := deployment.Flags()
|
||||
cmd := agpl.Server(dflags, func(ctx context.Context, options *agplcoderd.Options) (*agplcoderd.API, io.Closer, error) {
|
||||
if dflags.DerpServerRelayAddress.Value != "" {
|
||||
_, err := url.Parse(dflags.DerpServerRelayAddress.Value)
|
||||
vip := deployment.NewViper()
|
||||
cmd := agpl.Server(vip, func(ctx context.Context, options *agplcoderd.Options) (*agplcoderd.API, io.Closer, error) {
|
||||
if options.DeploymentConfig.DERPServerRelayURL.Value != "" {
|
||||
_, err := url.Parse(options.DeploymentConfig.DERPServerRelayURL.Value)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("derp-server-relay-address must be a valid HTTP URL: %w", err)
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func server() *cobra.Command {
|
|||
}
|
||||
options.DERPServer.SetMeshKey(meshKey)
|
||||
|
||||
if dflags.AuditLogging.Value {
|
||||
if options.DeploymentConfig.AuditLogging.Value {
|
||||
options.Auditor = audit.NewAuditor(audit.DefaultFilter,
|
||||
backends.NewPostgres(options.Database, true),
|
||||
backends.NewSlog(options.Logger),
|
||||
|
@ -58,13 +58,13 @@ func server() *cobra.Command {
|
|||
}
|
||||
|
||||
o := &coderd.Options{
|
||||
AuditLogging: dflags.AuditLogging.Value,
|
||||
BrowserOnly: dflags.BrowserOnly.Value,
|
||||
SCIMAPIKey: []byte(dflags.SCIMAuthHeader.Value),
|
||||
UserWorkspaceQuota: dflags.UserWorkspaceQuota.Value,
|
||||
AuditLogging: options.DeploymentConfig.AuditLogging.Value,
|
||||
BrowserOnly: options.DeploymentConfig.BrowserOnly.Value,
|
||||
SCIMAPIKey: []byte(options.DeploymentConfig.SCIMAPIKey.Value),
|
||||
UserWorkspaceQuota: options.DeploymentConfig.UserWorkspaceQuota.Value,
|
||||
RBAC: true,
|
||||
DERPServerRelayAddress: dflags.DerpServerRelayAddress.Value,
|
||||
DERPServerRegionID: dflags.DerpServerRegionID.Value,
|
||||
DERPServerRelayAddress: options.DeploymentConfig.DERPServerRelayURL.Value,
|
||||
DERPServerRegionID: options.DeploymentConfig.DERPServerRegionID.Value,
|
||||
|
||||
Options: options,
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ func server() *cobra.Command {
|
|||
return api.AGPL, api, nil
|
||||
})
|
||||
|
||||
deployment.AttachFlags(cmd.Flags(), dflags, true)
|
||||
deployment.AttachFlags(cmd.Flags(), vip, true)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
15
go.mod
15
go.mod
|
@ -164,7 +164,18 @@ require (
|
|||
|
||||
require github.com/jmoiron/sqlx v1.3.5
|
||||
|
||||
require github.com/cakturk/go-netstat v0.0.0-20200220111822-e5b49efee7a5
|
||||
require (
|
||||
github.com/cakturk/go-netstat v0.0.0-20200220111822-e5b49efee7a5
|
||||
github.com/spf13/viper v1.13.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
|
||||
|
@ -252,7 +263,7 @@ require (
|
|||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect
|
||||
github.com/opencontainers/runc v1.1.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/pion/transport v0.13.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
|
|
16
go.sum
16
go.sum
|
@ -594,6 +594,8 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3
|
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
||||
|
@ -1232,6 +1234,8 @@ github.com/mafredri/udp v0.1.2-0.20220805105907-b2872e92e98d/go.mod h1:GUd681aT3
|
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
|
@ -1485,8 +1489,10 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv
|
|||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.4 h1:MHHO+ZUPwPZQ6BmnnT81iQg5cuurp78CRH7rNsguSMk=
|
||||
github.com/pelletier/go-toml/v2 v2.0.4/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw=
|
||||
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
|
||||
|
@ -1678,6 +1684,8 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y
|
|||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
|
||||
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
|
||||
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
|
||||
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
|
@ -1701,6 +1709,8 @@ github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/swaggest/assertjson v1.7.0 h1:SKw5Rn0LQs6UvmGrIdaKQbMR1R3ncXm5KNon+QJ7jtw=
|
||||
github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
|
@ -2706,6 +2716,8 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
|||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
|
|
|
@ -47,10 +47,10 @@ coder:
|
|||
# This env variable controls whether or not to auto-import the "kubernetes"
|
||||
# template on first startup. This will not work unless
|
||||
# coder.serviceAccount.workspacePerms is true.
|
||||
- name: CODER_TEMPLATE_AUTOIMPORT
|
||||
- name: CODER_AUTO_IMPORT_TEMPLATES
|
||||
value: "kubernetes"
|
||||
|
||||
tls:
|
||||
secretNames:
|
||||
secretNames:
|
||||
- my-tls-secret-name
|
||||
```
|
||||
|
|
|
@ -441,6 +441,10 @@ func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, err
|
|||
jsonOptional bool
|
||||
)
|
||||
if err == nil {
|
||||
if jsonTag.Name == "-" {
|
||||
// Completely ignore this field.
|
||||
continue
|
||||
}
|
||||
jsonName = jsonTag.Name
|
||||
if len(jsonTag.Options) > 0 && jsonTag.Options[0] == "omitempty" {
|
||||
jsonOptional = true
|
||||
|
|
|
@ -256,7 +256,7 @@ export const AppRouter: FC = () => {
|
|||
element={
|
||||
<AuthAndFrame>
|
||||
<RequirePermission
|
||||
isFeatureVisible={Boolean(permissions?.viewDeploymentFlags)}
|
||||
isFeatureVisible={Boolean(permissions?.viewDeploymentConfig)}
|
||||
>
|
||||
<DeploySettingsLayout>
|
||||
<GeneralSettingsPage />
|
||||
|
@ -270,7 +270,7 @@ export const AppRouter: FC = () => {
|
|||
element={
|
||||
<AuthAndFrame>
|
||||
<RequirePermission
|
||||
isFeatureVisible={Boolean(permissions?.viewDeploymentFlags)}
|
||||
isFeatureVisible={Boolean(permissions?.viewDeploymentConfig)}
|
||||
>
|
||||
<DeploySettingsLayout>
|
||||
<SecuritySettingsPage />
|
||||
|
@ -284,7 +284,7 @@ export const AppRouter: FC = () => {
|
|||
element={
|
||||
<AuthAndFrame>
|
||||
<RequirePermission
|
||||
isFeatureVisible={Boolean(permissions?.viewDeploymentFlags)}
|
||||
isFeatureVisible={Boolean(permissions?.viewDeploymentConfig)}
|
||||
>
|
||||
<DeploySettingsLayout>
|
||||
<NetworkSettingsPage />
|
||||
|
@ -298,7 +298,7 @@ export const AppRouter: FC = () => {
|
|||
element={
|
||||
<AuthAndFrame>
|
||||
<RequirePermission
|
||||
isFeatureVisible={Boolean(permissions?.viewDeploymentFlags)}
|
||||
isFeatureVisible={Boolean(permissions?.viewDeploymentConfig)}
|
||||
>
|
||||
<DeploySettingsLayout>
|
||||
<AuthSettingsPage />
|
||||
|
|
|
@ -667,9 +667,9 @@ export const getAgentListeningPorts = async (
|
|||
return response.data
|
||||
}
|
||||
|
||||
export const getDeploymentFlags =
|
||||
async (): Promise<TypesGen.DeploymentFlags> => {
|
||||
const response = await axios.get(`/api/v2/flags/deployment`)
|
||||
export const getDeploymentConfig =
|
||||
async (): Promise<TypesGen.DeploymentConfig> => {
|
||||
const response = await axios.get(`/api/v2/config/deployment`)
|
||||
return response.data
|
||||
}
|
||||
|
||||
|
|
|
@ -126,19 +126,6 @@ export interface AzureInstanceIdentityToken {
|
|||
readonly encoding: string
|
||||
}
|
||||
|
||||
// From codersdk/flags.go
|
||||
export interface BoolFlag {
|
||||
readonly name: string
|
||||
readonly flag: string
|
||||
readonly env_var: string
|
||||
readonly shorthand: string
|
||||
readonly description: string
|
||||
readonly enterprise: boolean
|
||||
readonly hidden: boolean
|
||||
readonly default: boolean
|
||||
readonly value: boolean
|
||||
}
|
||||
|
||||
// From codersdk/buildinfo.go
|
||||
export interface BuildInfoResponse {
|
||||
readonly external_url: string
|
||||
|
@ -264,75 +251,67 @@ export interface DERPRegion {
|
|||
readonly latency_ms: number
|
||||
}
|
||||
|
||||
// From codersdk/flags.go
|
||||
export interface DeploymentFlags {
|
||||
readonly access_url: StringFlag
|
||||
readonly wildcard_access_url: StringFlag
|
||||
readonly address: StringFlag
|
||||
readonly autobuild_poll_interval: DurationFlag
|
||||
readonly derp_server_enabled: BoolFlag
|
||||
readonly derp_server_region_id: IntFlag
|
||||
readonly derp_server_region_code: StringFlag
|
||||
readonly derp_server_region_name: StringFlag
|
||||
readonly derp_server_stun_address: StringArrayFlag
|
||||
readonly derp_server_relay_address: StringFlag
|
||||
readonly derp_config_url: StringFlag
|
||||
readonly derp_config_path: StringFlag
|
||||
readonly prom_enabled: BoolFlag
|
||||
readonly prom_address: StringFlag
|
||||
readonly pprof_enabled: BoolFlag
|
||||
readonly pprof_address: StringFlag
|
||||
readonly cache_dir: StringFlag
|
||||
readonly in_memory_database: BoolFlag
|
||||
readonly provisioner_daemon_count: IntFlag
|
||||
readonly postgres_url: StringFlag
|
||||
readonly oauth2_github_client_id: StringFlag
|
||||
readonly oauth2_github_client_secret: StringFlag
|
||||
readonly oauth2_github_allowed_organizations: StringArrayFlag
|
||||
readonly oauth2_github_allowed_teams: StringArrayFlag
|
||||
readonly oauth2_github_allow_signups: BoolFlag
|
||||
readonly oauth2_github_enterprise_base_url: StringFlag
|
||||
readonly oidc_allow_signups: BoolFlag
|
||||
readonly oidc_client_id: StringFlag
|
||||
readonly oidc_client_secret: StringFlag
|
||||
readonly oidc_email_domain: StringFlag
|
||||
readonly oidc_issuer_url: StringFlag
|
||||
readonly oidc_scopes: StringArrayFlag
|
||||
readonly telemetry_enable: BoolFlag
|
||||
readonly telemetry_trace_enable: BoolFlag
|
||||
readonly telemetry_url: StringFlag
|
||||
readonly tls_enable: BoolFlag
|
||||
readonly tls_cert_files: StringArrayFlag
|
||||
readonly tls_client_ca_file: StringFlag
|
||||
readonly tls_client_auth: StringFlag
|
||||
readonly tls_key_files: StringArrayFlag
|
||||
readonly tls_min_version: StringFlag
|
||||
readonly trace_enable: BoolFlag
|
||||
readonly secure_auth_cookie: BoolFlag
|
||||
readonly ssh_keygen_algorithm: StringFlag
|
||||
readonly auto_import_templates: StringArrayFlag
|
||||
readonly metrics_cache_refresh_interval: DurationFlag
|
||||
readonly agent_stat_refresh_interval: DurationFlag
|
||||
readonly verbose: BoolFlag
|
||||
readonly audit_logging: BoolFlag
|
||||
readonly browser_only: BoolFlag
|
||||
readonly scim_auth_header: StringFlag
|
||||
readonly user_workspace_quota: IntFlag
|
||||
// From codersdk/deploymentconfig.go
|
||||
export interface DeploymentConfig {
|
||||
readonly access_url: DeploymentConfigField<string>
|
||||
readonly wildcard_access_url: DeploymentConfigField<string>
|
||||
readonly address: DeploymentConfigField<string>
|
||||
readonly autobuild_poll_interval: DeploymentConfigField<number>
|
||||
readonly derp_server_enabled: DeploymentConfigField<boolean>
|
||||
readonly derp_server_region_id: DeploymentConfigField<number>
|
||||
readonly derp_server_region_code: DeploymentConfigField<string>
|
||||
readonly derp_server_region_name: DeploymentConfigField<string>
|
||||
readonly derp_server_stun_address: DeploymentConfigField<string[]>
|
||||
readonly derp_server_relay_address: DeploymentConfigField<string>
|
||||
readonly derp_config_url: DeploymentConfigField<string>
|
||||
readonly derp_config_path: DeploymentConfigField<string>
|
||||
readonly prometheus_enabled: DeploymentConfigField<boolean>
|
||||
readonly prometheus_address: DeploymentConfigField<string>
|
||||
readonly pprof_enabled: DeploymentConfigField<boolean>
|
||||
readonly pprof_address: DeploymentConfigField<string>
|
||||
readonly cache_directory: DeploymentConfigField<string>
|
||||
readonly in_memory_database: DeploymentConfigField<boolean>
|
||||
readonly provisioner_daemon_count: DeploymentConfigField<number>
|
||||
readonly oauth2_github_client_id: DeploymentConfigField<string>
|
||||
readonly oauth2_github_allowed_orgs: DeploymentConfigField<string[]>
|
||||
readonly oauth2_github_allowed_teams: DeploymentConfigField<string[]>
|
||||
readonly oauth2_github_allow_signups: DeploymentConfigField<boolean>
|
||||
readonly oauth2_github_enterprise_base_url: DeploymentConfigField<string>
|
||||
readonly oidc_allow_signups: DeploymentConfigField<boolean>
|
||||
readonly oidc_client_id: DeploymentConfigField<string>
|
||||
readonly oidc_email_domain: DeploymentConfigField<string>
|
||||
readonly oidc_issuer_url: DeploymentConfigField<string>
|
||||
readonly oidc_scopes: DeploymentConfigField<string[]>
|
||||
readonly telemetry_enable: DeploymentConfigField<boolean>
|
||||
readonly telemetry_trace_enable: DeploymentConfigField<boolean>
|
||||
readonly telemetry_url: DeploymentConfigField<string>
|
||||
readonly tls_enable: DeploymentConfigField<boolean>
|
||||
readonly tls_cert_files: DeploymentConfigField<string[]>
|
||||
readonly tls_client_ca_file: DeploymentConfigField<string>
|
||||
readonly tls_client_auth: DeploymentConfigField<string>
|
||||
readonly tls_key_files: DeploymentConfigField<string[]>
|
||||
readonly tls_min_version: DeploymentConfigField<string>
|
||||
readonly trace_enable: DeploymentConfigField<boolean>
|
||||
readonly secure_auth_cookie: DeploymentConfigField<boolean>
|
||||
readonly ssh_keygen_algorithm: DeploymentConfigField<string>
|
||||
readonly auto_import_templates: DeploymentConfigField<string[]>
|
||||
readonly metrics_cache_refresh_interval: DeploymentConfigField<number>
|
||||
readonly agent_stat_refresh_interval: DeploymentConfigField<number>
|
||||
readonly audit_logging: DeploymentConfigField<boolean>
|
||||
readonly browser_only: DeploymentConfigField<boolean>
|
||||
readonly user_workspace_quota: DeploymentConfigField<number>
|
||||
}
|
||||
|
||||
// From codersdk/flags.go
|
||||
export interface DurationFlag {
|
||||
// From codersdk/deploymentconfig.go
|
||||
export interface DeploymentConfigField<T extends Flaggable> {
|
||||
readonly key: string
|
||||
readonly name: string
|
||||
readonly usage: string
|
||||
readonly flag: string
|
||||
readonly env_var: string
|
||||
readonly shorthand: string
|
||||
readonly description: string
|
||||
readonly enterprise: boolean
|
||||
readonly hidden: boolean
|
||||
// This is likely an enum in an external package ("time.Duration")
|
||||
readonly default: number
|
||||
// This is likely an enum in an external package ("time.Duration")
|
||||
readonly value: number
|
||||
readonly value: T
|
||||
}
|
||||
|
||||
// From codersdk/features.go
|
||||
|
@ -387,19 +366,6 @@ export interface Healthcheck {
|
|||
readonly threshold: number
|
||||
}
|
||||
|
||||
// From codersdk/flags.go
|
||||
export interface IntFlag {
|
||||
readonly name: string
|
||||
readonly flag: string
|
||||
readonly env_var: string
|
||||
readonly shorthand: string
|
||||
readonly description: string
|
||||
readonly enterprise: boolean
|
||||
readonly hidden: boolean
|
||||
readonly default: number
|
||||
readonly value: number
|
||||
}
|
||||
|
||||
// From codersdk/licenses.go
|
||||
export interface License {
|
||||
readonly id: number
|
||||
|
@ -564,33 +530,6 @@ export interface ServerSentEvent {
|
|||
readonly data: any
|
||||
}
|
||||
|
||||
// From codersdk/flags.go
|
||||
export interface StringArrayFlag {
|
||||
readonly name: string
|
||||
readonly flag: string
|
||||
readonly env_var: string
|
||||
readonly shorthand: string
|
||||
readonly description: string
|
||||
readonly enterprise: boolean
|
||||
readonly hidden: boolean
|
||||
readonly default: string[]
|
||||
readonly value: string[]
|
||||
}
|
||||
|
||||
// From codersdk/flags.go
|
||||
export interface StringFlag {
|
||||
readonly name: string
|
||||
readonly flag: string
|
||||
readonly env_var: string
|
||||
readonly shorthand: string
|
||||
readonly description: string
|
||||
readonly enterprise: boolean
|
||||
readonly secret: boolean
|
||||
readonly hidden: boolean
|
||||
readonly default: string
|
||||
readonly value: string
|
||||
}
|
||||
|
||||
// From codersdk/templates.go
|
||||
export interface Template {
|
||||
readonly id: string
|
||||
|
@ -999,3 +938,6 @@ export type WorkspaceStatus =
|
|||
|
||||
// From codersdk/workspacebuilds.go
|
||||
export type WorkspaceTransition = "delete" | "start" | "stop"
|
||||
|
||||
// From codersdk/deploymentconfig.go
|
||||
export type Flaggable = string | boolean | number | string[]
|
||||
|
|
|
@ -11,9 +11,9 @@ import React, {
|
|||
import { useActor } from "@xstate/react"
|
||||
import { XServiceContext } from "xServices/StateContext"
|
||||
import { Loader } from "components/Loader/Loader"
|
||||
import { DeploymentFlags } from "api/typesGenerated"
|
||||
import { DeploymentConfig } from "api/typesGenerated"
|
||||
|
||||
type DeploySettingsContextValue = { deploymentFlags: DeploymentFlags }
|
||||
type DeploySettingsContextValue = { deploymentConfig: DeploymentConfig }
|
||||
|
||||
const DeploySettingsContext = createContext<
|
||||
DeploySettingsContextValue | undefined
|
||||
|
@ -33,9 +33,9 @@ export const DeploySettingsLayout: React.FC<PropsWithChildren> = ({
|
|||
children,
|
||||
}) => {
|
||||
const xServices = useContext(XServiceContext)
|
||||
const [state, send] = useActor(xServices.deploymentFlagsXService)
|
||||
const [state, send] = useActor(xServices.deploymentConfigXService)
|
||||
const styles = useStyles()
|
||||
const { deploymentFlags } = state.context
|
||||
const { deploymentConfig } = state.context
|
||||
|
||||
useEffect(() => {
|
||||
if (state.matches("idle")) {
|
||||
|
@ -48,8 +48,10 @@ export const DeploySettingsLayout: React.FC<PropsWithChildren> = ({
|
|||
<Stack className={styles.wrapper} direction="row" spacing={5}>
|
||||
<Sidebar />
|
||||
<main className={styles.content}>
|
||||
{deploymentFlags ? (
|
||||
<DeploySettingsContext.Provider value={{ deploymentFlags }}>
|
||||
{deploymentConfig ? (
|
||||
<DeploySettingsContext.Provider
|
||||
value={{ deploymentConfig: deploymentConfig }}
|
||||
>
|
||||
{children}
|
||||
</DeploySettingsContext.Provider>
|
||||
) : (
|
||||
|
|
|
@ -5,7 +5,7 @@ import TableCell from "@material-ui/core/TableCell"
|
|||
import TableContainer from "@material-ui/core/TableContainer"
|
||||
import TableHead from "@material-ui/core/TableHead"
|
||||
import TableRow from "@material-ui/core/TableRow"
|
||||
import { DeploymentFlags } from "api/typesGenerated"
|
||||
import { DeploymentConfig } from "api/typesGenerated"
|
||||
import {
|
||||
OptionDescription,
|
||||
OptionName,
|
||||
|
@ -13,7 +13,7 @@ import {
|
|||
} from "components/DeploySettingsLayout/Option"
|
||||
import React from "react"
|
||||
|
||||
const OptionsTable: React.FC<{ options: Partial<DeploymentFlags> }> = ({
|
||||
const OptionsTable: React.FC<{ options: Partial<DeploymentConfig> }> = ({
|
||||
options,
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
|
|
|
@ -22,7 +22,7 @@ export const Navbar: React.FC = () => {
|
|||
featureVisibility[FeatureNames.AuditLog] &&
|
||||
Boolean(permissions?.viewAuditLog)
|
||||
const canViewDeployment =
|
||||
experimental && Boolean(permissions?.viewDeploymentFlags)
|
||||
experimental && Boolean(permissions?.viewDeploymentConfig)
|
||||
const onSignOut = () => authSend("SIGN_OUT")
|
||||
|
||||
return (
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Helmet } from "react-helmet-async"
|
|||
import { pageTitle } from "util/page"
|
||||
|
||||
const AuthSettingsPage: React.FC = () => {
|
||||
const { deploymentFlags } = useDeploySettings()
|
||||
const { deploymentConfig: deploymentConfig } = useDeploySettings()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -32,7 +32,7 @@ const AuthSettingsPage: React.FC = () => {
|
|||
/>
|
||||
|
||||
<Badges>
|
||||
{deploymentFlags.oidc_client_id.value ? (
|
||||
{deploymentConfig.oidc_client_id.value ? (
|
||||
<EnabledBadge />
|
||||
) : (
|
||||
<DisabledBadge />
|
||||
|
@ -41,12 +41,12 @@ const AuthSettingsPage: React.FC = () => {
|
|||
|
||||
<OptionsTable
|
||||
options={{
|
||||
oidc_client_id: deploymentFlags.oidc_client_id,
|
||||
oidc_client_secret: deploymentFlags.oidc_client_secret,
|
||||
oidc_allow_signups: deploymentFlags.oidc_allow_signups,
|
||||
oidc_email_domain: deploymentFlags.oidc_email_domain,
|
||||
oidc_issuer_url: deploymentFlags.oidc_issuer_url,
|
||||
oidc_scopes: deploymentFlags.oidc_scopes,
|
||||
oidc_client_id: deploymentConfig.oidc_client_id,
|
||||
oidc_client_secret: deploymentConfig.oidc_client_secret,
|
||||
oidc_allow_signups: deploymentConfig.oidc_allow_signups,
|
||||
oidc_email_domain: deploymentConfig.oidc_email_domain,
|
||||
oidc_issuer_url: deploymentConfig.oidc_issuer_url,
|
||||
oidc_scopes: deploymentConfig.oidc_scopes,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -60,7 +60,7 @@ const AuthSettingsPage: React.FC = () => {
|
|||
/>
|
||||
|
||||
<Badges>
|
||||
{deploymentFlags.oauth2_github_client_id.value ? (
|
||||
{deploymentConfig.oauth2_github_client_id.value ? (
|
||||
<EnabledBadge />
|
||||
) : (
|
||||
<DisabledBadge />
|
||||
|
@ -69,17 +69,17 @@ const AuthSettingsPage: React.FC = () => {
|
|||
|
||||
<OptionsTable
|
||||
options={{
|
||||
oauth2_github_client_id: deploymentFlags.oauth2_github_client_id,
|
||||
oauth2_github_client_id: deploymentConfig.oauth2_github_client_id,
|
||||
oauth2_github_client_secret:
|
||||
deploymentFlags.oauth2_github_client_secret,
|
||||
deploymentConfig.oauth2_github_client_secret,
|
||||
oauth2_github_allow_signups:
|
||||
deploymentFlags.oauth2_github_allow_signups,
|
||||
oauth2_github_allowed_organizations:
|
||||
deploymentFlags.oauth2_github_allowed_organizations,
|
||||
deploymentConfig.oauth2_github_allow_signups,
|
||||
oauth2_github_allowed_orgs:
|
||||
deploymentConfig.oauth2_github_allowed_orgs,
|
||||
oauth2_github_allowed_teams:
|
||||
deploymentFlags.oauth2_github_allowed_teams,
|
||||
deploymentConfig.oauth2_github_allowed_teams,
|
||||
oauth2_github_enterprise_base_url:
|
||||
deploymentFlags.oauth2_github_enterprise_base_url,
|
||||
deploymentConfig.oauth2_github_enterprise_base_url,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Helmet } from "react-helmet-async"
|
|||
import { pageTitle } from "util/page"
|
||||
|
||||
const GeneralSettingsPage: React.FC = () => {
|
||||
const { deploymentFlags } = useDeploySettings()
|
||||
const { deploymentConfig: deploymentConfig } = useDeploySettings()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -22,9 +22,9 @@ const GeneralSettingsPage: React.FC = () => {
|
|||
|
||||
<OptionsTable
|
||||
options={{
|
||||
access_url: deploymentFlags.access_url,
|
||||
address: deploymentFlags.address,
|
||||
wildcard_access_url: deploymentFlags.wildcard_access_url,
|
||||
access_url: deploymentConfig.access_url,
|
||||
address: deploymentConfig.address,
|
||||
wildcard_access_url: deploymentConfig.wildcard_access_url,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Helmet } from "react-helmet-async"
|
|||
import { pageTitle } from "util/page"
|
||||
|
||||
const NetworkSettingsPage: React.FC = () => {
|
||||
const { deploymentFlags } = useDeploySettings()
|
||||
const { deploymentConfig: deploymentConfig } = useDeploySettings()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -22,10 +22,10 @@ const NetworkSettingsPage: React.FC = () => {
|
|||
|
||||
<OptionsTable
|
||||
options={{
|
||||
derp_server_enabled: deploymentFlags.derp_server_enabled,
|
||||
derp_server_region_name: deploymentFlags.derp_server_region_name,
|
||||
derp_server_stun_address: deploymentFlags.derp_server_stun_address,
|
||||
derp_config_url: deploymentFlags.derp_config_url,
|
||||
derp_server_enabled: deploymentConfig.derp_server_enabled,
|
||||
derp_server_region_name: deploymentConfig.derp_server_region_name,
|
||||
derp_server_stun_address: deploymentConfig.derp_server_stun_address,
|
||||
derp_config_url: deploymentConfig.derp_config_url,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -16,7 +16,7 @@ import { pageTitle } from "util/page"
|
|||
import { XServiceContext } from "xServices/StateContext"
|
||||
|
||||
const SecuritySettingsPage: React.FC = () => {
|
||||
const { deploymentFlags } = useDeploySettings()
|
||||
const { deploymentConfig: deploymentConfig } = useDeploySettings()
|
||||
const xServices = useContext(XServiceContext)
|
||||
const [entitlementsState] = useActor(xServices.entitlementsXService)
|
||||
|
||||
|
@ -34,8 +34,8 @@ const SecuritySettingsPage: React.FC = () => {
|
|||
|
||||
<OptionsTable
|
||||
options={{
|
||||
ssh_keygen_algorithm: deploymentFlags.ssh_keygen_algorithm,
|
||||
secure_auth_cookie: deploymentFlags.secure_auth_cookie,
|
||||
ssh_keygen_algorithm: deploymentConfig.ssh_keygen_algorithm,
|
||||
secure_auth_cookie: deploymentConfig.secure_auth_cookie,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -89,10 +89,10 @@ const SecuritySettingsPage: React.FC = () => {
|
|||
|
||||
<OptionsTable
|
||||
options={{
|
||||
tls_enable: deploymentFlags.tls_enable,
|
||||
tls_cert_files: deploymentFlags.tls_cert_files,
|
||||
tls_key_files: deploymentFlags.tls_key_files,
|
||||
tls_min_version: deploymentFlags.tls_min_version,
|
||||
tls_enable: deploymentConfig.tls_enable,
|
||||
tls_cert_files: deploymentConfig.tls_cert_files,
|
||||
tls_key_files: deploymentConfig.tls_key_files,
|
||||
tls_min_version: deploymentConfig.tls_min_version,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { createContext, FC, ReactNode } from "react"
|
|||
import { ActorRefFrom } from "xstate"
|
||||
import { authMachine } from "./auth/authXService"
|
||||
import { buildInfoMachine } from "./buildInfo/buildInfoXService"
|
||||
import { deploymentFlagsMachine } from "./deploymentFlags/deploymentFlagsMachine"
|
||||
import { deploymentConfigMachine } from "./deploymentConfig/deploymentConfigMachine"
|
||||
import { entitlementsMachine } from "./entitlements/entitlementsXService"
|
||||
import { siteRolesMachine } from "./roles/siteRolesXService"
|
||||
|
||||
|
@ -13,7 +13,7 @@ interface XServiceContextType {
|
|||
entitlementsXService: ActorRefFrom<typeof entitlementsMachine>
|
||||
siteRolesXService: ActorRefFrom<typeof siteRolesMachine>
|
||||
// Since the info here is used by multiple deployment settings page and we don't want to refetch them every time
|
||||
deploymentFlagsXService: ActorRefFrom<typeof deploymentFlagsMachine>
|
||||
deploymentConfigXService: ActorRefFrom<typeof deploymentConfigMachine>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,7 +34,7 @@ export const XServiceProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
|||
buildInfoXService: useInterpret(buildInfoMachine),
|
||||
entitlementsXService: useInterpret(entitlementsMachine),
|
||||
siteRolesXService: useInterpret(siteRolesMachine),
|
||||
deploymentFlagsXService: useInterpret(deploymentFlagsMachine),
|
||||
deploymentConfigXService: useInterpret(deploymentConfigMachine),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -16,7 +16,7 @@ export const checks = {
|
|||
createTemplates: "createTemplates",
|
||||
deleteTemplates: "deleteTemplates",
|
||||
viewAuditLog: "viewAuditLog",
|
||||
viewDeploymentFlags: "viewDeploymentFlags",
|
||||
viewDeploymentConfig: "viewDeploymentConfig",
|
||||
createGroup: "createGroup",
|
||||
} as const
|
||||
|
||||
|
@ -57,7 +57,7 @@ export const permissionsToCheck = {
|
|||
},
|
||||
action: "read",
|
||||
},
|
||||
[checks.viewDeploymentFlags]: {
|
||||
[checks.viewDeploymentConfig]: {
|
||||
object: {
|
||||
resource_type: "deployment_flags",
|
||||
},
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import { getDeploymentConfig } from "api/api"
|
||||
import { DeploymentConfig } from "api/typesGenerated"
|
||||
import { createMachine, assign } from "xstate"
|
||||
|
||||
export const deploymentConfigMachine = createMachine(
|
||||
{
|
||||
id: "deploymentConfigMachine",
|
||||
predictableActionArguments: true,
|
||||
initial: "idle",
|
||||
schema: {
|
||||
context: {} as {
|
||||
deploymentConfig?: DeploymentConfig
|
||||
getDeploymentConfigError?: unknown
|
||||
},
|
||||
events: {} as { type: "LOAD" },
|
||||
services: {} as {
|
||||
getDeploymentConfig: {
|
||||
data: DeploymentConfig
|
||||
}
|
||||
},
|
||||
},
|
||||
tsTypes: {} as import("./deploymentConfigMachine.typegen").Typegen0,
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
LOAD: {
|
||||
target: "loading",
|
||||
},
|
||||
},
|
||||
},
|
||||
loading: {
|
||||
invoke: {
|
||||
src: "getDeploymentConfig",
|
||||
onDone: {
|
||||
target: "loaded",
|
||||
actions: ["assignDeploymentConfig"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: ["assignGetDeploymentConfigError"],
|
||||
},
|
||||
},
|
||||
},
|
||||
loaded: {
|
||||
type: "final",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
services: {
|
||||
getDeploymentConfig: getDeploymentConfig,
|
||||
},
|
||||
actions: {
|
||||
assignDeploymentConfig: assign({
|
||||
deploymentConfig: (_, { data }) => data,
|
||||
}),
|
||||
assignGetDeploymentConfigError: assign({
|
||||
getDeploymentConfigError: (_, { data }) => data,
|
||||
}),
|
||||
},
|
||||
},
|
||||
)
|
|
@ -1,62 +0,0 @@
|
|||
import { getDeploymentFlags } from "api/api"
|
||||
import { DeploymentFlags } from "api/typesGenerated"
|
||||
import { createMachine, assign } from "xstate"
|
||||
|
||||
export const deploymentFlagsMachine = createMachine(
|
||||
{
|
||||
id: "deploymentFlagsMachine",
|
||||
predictableActionArguments: true,
|
||||
initial: "idle",
|
||||
schema: {
|
||||
context: {} as {
|
||||
deploymentFlags?: DeploymentFlags
|
||||
getDeploymentFlagsError?: unknown
|
||||
},
|
||||
events: {} as { type: "LOAD" },
|
||||
services: {} as {
|
||||
getDeploymentFlags: {
|
||||
data: DeploymentFlags
|
||||
}
|
||||
},
|
||||
},
|
||||
tsTypes: {} as import("./deploymentFlagsMachine.typegen").Typegen0,
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
LOAD: {
|
||||
target: "loading",
|
||||
},
|
||||
},
|
||||
},
|
||||
loading: {
|
||||
invoke: {
|
||||
src: "getDeploymentFlags",
|
||||
onDone: {
|
||||
target: "loaded",
|
||||
actions: ["assignDeploymentFlags"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: ["assignGetDeploymentFlagsError"],
|
||||
},
|
||||
},
|
||||
},
|
||||
loaded: {
|
||||
type: "final",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
services: {
|
||||
getDeploymentFlags,
|
||||
},
|
||||
actions: {
|
||||
assignDeploymentFlags: assign({
|
||||
deploymentFlags: (_, { data }) => data,
|
||||
}),
|
||||
assignGetDeploymentFlagsError: assign({
|
||||
getDeploymentFlagsError: (_, { data }) => data,
|
||||
}),
|
||||
},
|
||||
},
|
||||
)
|
Loading…
Reference in New Issue