Skip to content

Commit 632f5a5

Browse files
committed
chore: move provisioner keys commands into slim build
1 parent b3a3671 commit 632f5a5

File tree

4 files changed

+374
-371
lines changed

4 files changed

+374
-371
lines changed

enterprise/cli/provisionerdaemons.go

Lines changed: 1 addition & 367 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,6 @@
1-
//go:build !slim
2-
31
package cli
42

5-
import (
6-
"context"
7-
"errors"
8-
"fmt"
9-
"net/http"
10-
"os"
11-
"regexp"
12-
"time"
13-
14-
"github.com/google/uuid"
15-
"github.com/prometheus/client_golang/prometheus"
16-
"github.com/prometheus/client_golang/prometheus/collectors"
17-
"github.com/prometheus/client_golang/prometheus/promhttp"
18-
"golang.org/x/xerrors"
19-
20-
"cdr.dev/slog"
21-
"cdr.dev/slog/sloggers/sloghuman"
22-
agpl "github.com/coder/coder/v2/cli"
23-
"github.com/coder/coder/v2/cli/clilog"
24-
"github.com/coder/coder/v2/cli/cliui"
25-
"github.com/coder/coder/v2/cli/cliutil"
26-
"github.com/coder/coder/v2/coderd/database"
27-
"github.com/coder/coder/v2/codersdk"
28-
"github.com/coder/coder/v2/codersdk/drpc"
29-
"github.com/coder/coder/v2/provisioner/terraform"
30-
"github.com/coder/coder/v2/provisionerd"
31-
provisionerdproto "github.com/coder/coder/v2/provisionerd/proto"
32-
"github.com/coder/coder/v2/provisionersdk"
33-
"github.com/coder/coder/v2/provisionersdk/proto"
34-
"github.com/coder/serpent"
35-
)
3+
import "github.com/coder/serpent"
364

375
func (r *RootCmd) provisionerDaemons() *serpent.Command {
386
cmd := &serpent.Command{
@@ -50,337 +18,3 @@ func (r *RootCmd) provisionerDaemons() *serpent.Command {
5018

5119
return cmd
5220
}
53-
54-
func validateProvisionerDaemonName(name string) error {
55-
if len(name) > 64 {
56-
return xerrors.Errorf("name cannot be greater than 64 characters in length")
57-
}
58-
if ok, err := regexp.MatchString(`^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$`, name); err != nil || !ok {
59-
return xerrors.Errorf("name %q is not a valid hostname", name)
60-
}
61-
return nil
62-
}
63-
64-
func (r *RootCmd) provisionerDaemonStart() *serpent.Command {
65-
var (
66-
cacheDir string
67-
logHuman string
68-
logJSON string
69-
logStackdriver string
70-
logFilter []string
71-
name string
72-
rawTags []string
73-
pollInterval time.Duration
74-
pollJitter time.Duration
75-
preSharedKey string
76-
verbose bool
77-
78-
prometheusEnable bool
79-
prometheusAddress string
80-
)
81-
orgContext := agpl.NewOrganizationContext()
82-
client := new(codersdk.Client)
83-
cmd := &serpent.Command{
84-
Use: "start",
85-
Short: "Run a provisioner daemon",
86-
Middleware: serpent.Chain(
87-
// disable checks and warnings because this command starts a daemon; it is
88-
// not meant for humans typing commands. Furthermore, the checks are
89-
// incompatible with PSK auth that this command uses
90-
r.InitClient(client),
91-
),
92-
Handler: func(inv *serpent.Invocation) error {
93-
ctx, cancel := context.WithCancel(inv.Context())
94-
defer cancel()
95-
96-
stopCtx, stopCancel := inv.SignalNotifyContext(ctx, agpl.StopSignalsNoInterrupt...)
97-
defer stopCancel()
98-
interruptCtx, interruptCancel := inv.SignalNotifyContext(ctx, agpl.InterruptSignals...)
99-
defer interruptCancel()
100-
101-
// This can fail to get the current organization
102-
// if the client is not authenticated as a user,
103-
// like when only PSK is provided.
104-
// This will be cleaner once PSK is replaced
105-
// with org scoped authentication tokens.
106-
org, err := orgContext.Selected(inv, client)
107-
if err != nil {
108-
var cErr *codersdk.Error
109-
if !errors.As(err, &cErr) || cErr.StatusCode() != http.StatusUnauthorized {
110-
return xerrors.Errorf("current organization: %w", err)
111-
}
112-
113-
if preSharedKey == "" {
114-
return xerrors.New("must provide a pre-shared key when not authenticated as a user")
115-
}
116-
117-
org = codersdk.Organization{MinimalOrganization: codersdk.MinimalOrganization{ID: uuid.Nil}}
118-
if orgContext.FlagSelect != "" {
119-
// If we are using PSK, we can't fetch the organization
120-
// to validate org name so we need the user to provide
121-
// a valid organization ID.
122-
orgID, err := uuid.Parse(orgContext.FlagSelect)
123-
if err != nil {
124-
return xerrors.New("must provide an org ID when not authenticated as a user and organization is specified")
125-
}
126-
org = codersdk.Organization{MinimalOrganization: codersdk.MinimalOrganization{ID: orgID}}
127-
}
128-
}
129-
130-
tags, err := agpl.ParseProvisionerTags(rawTags)
131-
if err != nil {
132-
return err
133-
}
134-
135-
if name == "" {
136-
name = cliutil.Hostname()
137-
}
138-
139-
if err := validateProvisionerDaemonName(name); err != nil {
140-
return err
141-
}
142-
143-
logOpts := []clilog.Option{
144-
clilog.WithFilter(logFilter...),
145-
clilog.WithHuman(logHuman),
146-
clilog.WithJSON(logJSON),
147-
clilog.WithStackdriver(logStackdriver),
148-
}
149-
if verbose {
150-
logOpts = append(logOpts, clilog.WithVerbose())
151-
}
152-
153-
logger, closeLogger, err := clilog.New(logOpts...).Build(inv)
154-
if err != nil {
155-
// Fall back to a basic logger
156-
logger = slog.Make(sloghuman.Sink(inv.Stderr))
157-
logger.Error(ctx, "failed to initialize logger", slog.Error(err))
158-
} else {
159-
defer closeLogger()
160-
}
161-
162-
if len(tags) == 0 {
163-
logger.Info(ctx, "note: untagged provisioners can only pick up jobs from untagged templates")
164-
}
165-
166-
// When authorizing with a PSK, we automatically scope the provisionerd
167-
// to organization. Scoping to user with PSK auth is not a valid configuration.
168-
if preSharedKey != "" {
169-
logger.Info(ctx, "psk auth automatically sets tag "+provisionersdk.TagScope+"="+provisionersdk.ScopeOrganization)
170-
tags[provisionersdk.TagScope] = provisionersdk.ScopeOrganization
171-
}
172-
173-
err = os.MkdirAll(cacheDir, 0o700)
174-
if err != nil {
175-
return xerrors.Errorf("mkdir %q: %w", cacheDir, err)
176-
}
177-
178-
tempDir, err := os.MkdirTemp("", "provisionerd")
179-
if err != nil {
180-
return err
181-
}
182-
183-
terraformClient, terraformServer := drpc.MemTransportPipe()
184-
go func() {
185-
<-ctx.Done()
186-
_ = terraformClient.Close()
187-
_ = terraformServer.Close()
188-
}()
189-
190-
errCh := make(chan error, 1)
191-
go func() {
192-
defer cancel()
193-
194-
err := terraform.Serve(ctx, &terraform.ServeOptions{
195-
ServeOptions: &provisionersdk.ServeOptions{
196-
Listener: terraformServer,
197-
Logger: logger.Named("terraform"),
198-
WorkDirectory: tempDir,
199-
},
200-
CachePath: cacheDir,
201-
})
202-
if err != nil && !xerrors.Is(err, context.Canceled) {
203-
select {
204-
case errCh <- err:
205-
default:
206-
}
207-
}
208-
}()
209-
210-
var metrics *provisionerd.Metrics
211-
if prometheusEnable {
212-
logger.Info(ctx, "starting Prometheus endpoint", slog.F("address", prometheusAddress))
213-
214-
prometheusRegistry := prometheus.NewRegistry()
215-
prometheusRegistry.MustRegister(collectors.NewGoCollector())
216-
prometheusRegistry.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))
217-
218-
m := provisionerd.NewMetrics(prometheusRegistry)
219-
m.Runner.NumDaemons.Set(float64(1)) // Set numDaemons to 1 as this is standalone mode.
220-
metrics = &m
221-
222-
closeFunc := agpl.ServeHandler(ctx, logger, promhttp.InstrumentMetricHandler(
223-
prometheusRegistry, promhttp.HandlerFor(prometheusRegistry, promhttp.HandlerOpts{}),
224-
), prometheusAddress, "prometheus")
225-
defer closeFunc()
226-
}
227-
228-
logger.Info(ctx, "starting provisioner daemon", slog.F("tags", tags), slog.F("name", name))
229-
230-
connector := provisionerd.LocalProvisioners{
231-
string(database.ProvisionerTypeTerraform): proto.NewDRPCProvisionerClient(terraformClient),
232-
}
233-
srv := provisionerd.New(func(ctx context.Context) (provisionerdproto.DRPCProvisionerDaemonClient, error) {
234-
return client.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
235-
ID: uuid.New(),
236-
Name: name,
237-
Provisioners: []codersdk.ProvisionerType{
238-
codersdk.ProvisionerTypeTerraform,
239-
},
240-
Tags: tags,
241-
PreSharedKey: preSharedKey,
242-
Organization: org.ID,
243-
})
244-
}, &provisionerd.Options{
245-
Logger: logger,
246-
UpdateInterval: 500 * time.Millisecond,
247-
Connector: connector,
248-
Metrics: metrics,
249-
})
250-
251-
waitForProvisionerJobs := false
252-
var exitErr error
253-
select {
254-
case <-stopCtx.Done():
255-
exitErr = stopCtx.Err()
256-
_, _ = fmt.Fprintln(inv.Stdout, cliui.Bold(
257-
"Stop caught, waiting for provisioner jobs to complete and gracefully exiting. Use ctrl+\\ to force quit",
258-
))
259-
waitForProvisionerJobs = true
260-
case <-interruptCtx.Done():
261-
exitErr = interruptCtx.Err()
262-
_, _ = fmt.Fprintln(inv.Stdout, cliui.Bold(
263-
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
264-
))
265-
case exitErr = <-errCh:
266-
}
267-
if exitErr != nil && !xerrors.Is(exitErr, context.Canceled) {
268-
cliui.Errorf(inv.Stderr, "Unexpected error, shutting down server: %s\n", exitErr)
269-
}
270-
271-
err = srv.Shutdown(ctx, waitForProvisionerJobs)
272-
if err != nil {
273-
return xerrors.Errorf("shutdown: %w", err)
274-
}
275-
276-
// Shutdown does not call close. Must call it manually.
277-
err = srv.Close()
278-
if err != nil {
279-
return xerrors.Errorf("close server: %w", err)
280-
}
281-
282-
cancel()
283-
if xerrors.Is(exitErr, context.Canceled) {
284-
return nil
285-
}
286-
return exitErr
287-
},
288-
}
289-
290-
cmd.Options = serpent.OptionSet{
291-
{
292-
Flag: "cache-dir",
293-
FlagShorthand: "c",
294-
Env: "CODER_CACHE_DIRECTORY",
295-
Description: "Directory to store cached data.",
296-
Default: codersdk.DefaultCacheDir(),
297-
Value: serpent.StringOf(&cacheDir),
298-
},
299-
{
300-
Flag: "tag",
301-
FlagShorthand: "t",
302-
Env: "CODER_PROVISIONERD_TAGS",
303-
Description: "Tags to filter provisioner jobs by.",
304-
Value: serpent.StringArrayOf(&rawTags),
305-
},
306-
{
307-
Flag: "poll-interval",
308-
Env: "CODER_PROVISIONERD_POLL_INTERVAL",
309-
Default: time.Second.String(),
310-
Description: "Deprecated and ignored.",
311-
Value: serpent.DurationOf(&pollInterval),
312-
},
313-
{
314-
Flag: "poll-jitter",
315-
Env: "CODER_PROVISIONERD_POLL_JITTER",
316-
Description: "Deprecated and ignored.",
317-
Default: (100 * time.Millisecond).String(),
318-
Value: serpent.DurationOf(&pollJitter),
319-
},
320-
{
321-
Flag: "psk",
322-
Env: "CODER_PROVISIONER_DAEMON_PSK",
323-
Description: "Pre-shared key to authenticate with Coder server.",
324-
Value: serpent.StringOf(&preSharedKey),
325-
},
326-
{
327-
Flag: "name",
328-
Env: "CODER_PROVISIONER_DAEMON_NAME",
329-
Description: "Name of this provisioner daemon. Defaults to the current hostname without FQDN.",
330-
Value: serpent.StringOf(&name),
331-
Default: "",
332-
},
333-
{
334-
Flag: "verbose",
335-
Env: "CODER_PROVISIONER_DAEMON_VERBOSE",
336-
Description: "Output debug-level logs.",
337-
Value: serpent.BoolOf(&verbose),
338-
Default: "false",
339-
},
340-
{
341-
Flag: "log-human",
342-
Env: "CODER_PROVISIONER_DAEMON_LOGGING_HUMAN",
343-
Description: "Output human-readable logs to a given file.",
344-
Value: serpent.StringOf(&logHuman),
345-
Default: "/dev/stderr",
346-
},
347-
{
348-
Flag: "log-json",
349-
Env: "CODER_PROVISIONER_DAEMON_LOGGING_JSON",
350-
Description: "Output JSON logs to a given file.",
351-
Value: serpent.StringOf(&logJSON),
352-
Default: "",
353-
},
354-
{
355-
Flag: "log-stackdriver",
356-
Env: "CODER_PROVISIONER_DAEMON_LOGGING_STACKDRIVER",
357-
Description: "Output Stackdriver compatible logs to a given file.",
358-
Value: serpent.StringOf(&logStackdriver),
359-
Default: "",
360-
},
361-
{
362-
Flag: "log-filter",
363-
Env: "CODER_PROVISIONER_DAEMON_LOG_FILTER",
364-
Description: "Filter debug logs by matching against a given regex. Use .* to match all debug logs.",
365-
Value: serpent.StringArrayOf(&logFilter),
366-
Default: "",
367-
},
368-
{
369-
Flag: "prometheus-enable",
370-
Env: "CODER_PROMETHEUS_ENABLE",
371-
Description: "Serve prometheus metrics on the address defined by prometheus address.",
372-
Value: serpent.BoolOf(&prometheusEnable),
373-
Default: "false",
374-
},
375-
{
376-
Flag: "prometheus-address",
377-
Env: "CODER_PROMETHEUS_ADDRESS",
378-
Description: "The bind address to serve prometheus metrics.",
379-
Value: serpent.StringOf(&prometheusAddress),
380-
Default: "127.0.0.1:2112",
381-
},
382-
}
383-
orgContext.AttachOptions(cmd)
384-
385-
return cmd
386-
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy