@@ -2,23 +2,14 @@ package nixcache
2
2
3
3
import (
4
4
"context"
5
- "fmt"
6
- "io/fs"
5
+ "errors"
7
6
"os"
8
- "os/exec"
9
- "os/user"
10
- "path/filepath"
11
7
"time"
12
8
13
- "github.com/AlecAivazis/survey/v2"
14
9
"go.jetpack.io/devbox/internal/build"
15
- "go.jetpack.io/devbox/internal/debug"
16
10
"go.jetpack.io/devbox/internal/devbox/providers/identity"
17
- "go.jetpack.io/devbox/internal/envir"
18
- "go.jetpack.io/devbox/internal/fileutil"
19
- "go.jetpack.io/devbox/internal/nix"
20
11
"go.jetpack.io/devbox/internal/redact"
21
- "go.jetpack.io/devbox/internal/ux "
12
+ "go.jetpack.io/devbox/internal/setup "
22
13
"go.jetpack.io/pkg/api"
23
14
nixv1alpha1 "go.jetpack.io/pkg/api/gen/priv/nix/v1alpha1"
24
15
"go.jetpack.io/pkg/filecache"
@@ -33,154 +24,53 @@ func Get() *Provider {
33
24
}
34
25
35
26
func (p * Provider ) Configure (ctx context.Context , username string ) error {
36
- debug .Log ("checking if nix cache is configured for %s" , username )
37
-
38
- rootConfig , err := p .rootAWSConfigPath ()
39
- if err != nil {
40
- return err
41
- }
42
- debug .Log ("root aws config path is: %s" , rootConfig )
43
- awsConfigExists := fileutil .Exists (rootConfig )
27
+ return p .configure (ctx , username , false )
28
+ }
44
29
45
- cfg , err := nix .CurrentConfig (ctx )
46
- if err != nil {
47
- return err
48
- }
49
- trusted , _ := cfg .IsUserTrusted (ctx , username )
30
+ func (p * Provider ) ConfigureReprompt (ctx context.Context , username string ) error {
31
+ return p .configure (ctx , username , true )
32
+ }
50
33
51
- configured := awsConfigExists && trusted
52
- debug .Log ("nix cache configured = %v (awsConfigExists == %v && trusted == %v)" , configured , awsConfigExists , trusted )
53
- if configured {
54
- return nil
34
+ func (p * Provider ) configure (ctx context.Context , username string , reprompt bool ) error {
35
+ setupTasks := []struct {
36
+ key string
37
+ task setup.Task
38
+ }{
39
+ {"nixcache-setup-aws" , & awsSetupTask {username }},
40
+ {"nixcache-setup-nix" , & nixSetupTask {username }},
41
+ }
42
+ if reprompt {
43
+ for _ , t := range setupTasks {
44
+ setup .Reset (t .key )
45
+ }
55
46
}
56
47
48
+ // If we're already root, then do the setup without prompting the user
49
+ // for confirmation.
57
50
if os .Getuid () == 0 {
58
- err := p .configureRoot (ctx , username )
59
- if err != nil {
60
- return redact .Errorf ("update ~root/.aws/config with devbox credentials: %s" , err )
51
+ for _ , t := range setupTasks {
52
+ err := setup .Run (ctx , t .key , t .task )
53
+ if err != nil {
54
+ return redact .Errorf ("nixcache: run setup: %v" , err )
55
+ }
61
56
}
62
57
return nil
63
58
}
64
59
65
- _ , err = nix .DaemonVersion (ctx )
66
- if err == nil {
67
- // It looks like this is a multi-user install running a Nix
68
- // daemon, so we need to configure AWS S3 authentication for the
69
- // root user.
70
- if err := p .sudoConfigureRoot (ctx , username ); err != nil {
71
- return err
60
+ // Otherwise, ask the user to confirm if it's okay to sudo.
61
+ const sudoPrompt = "Devbox requires root to configure the Nix daemon to use your organization's Devbox cache. Allow sudo?"
62
+ for _ , t := range setupTasks {
63
+ err := setup .ConfirmRun (ctx , t .key , t .task , sudoPrompt )
64
+ if errors .Is (err , setup .ErrUserRefused ) {
65
+ return nil
66
+ }
67
+ if err != nil {
68
+ return redact .Errorf ("nixcache: run setup: %v" , err )
72
69
}
73
70
}
74
71
return nil
75
72
}
76
73
77
- func (p * Provider ) rootAWSConfigPath () (string , error ) {
78
- u , err := user .LookupId ("0" )
79
- if err != nil {
80
- return "" , redact .Errorf ("lookup root user: %s" , err )
81
- }
82
- if u .HomeDir == "" {
83
- return "" , redact .Errorf ("empty root user home directory: %s" , u .Username , err )
84
- }
85
- return filepath .Join (u .HomeDir , ".aws" , "config" ), nil
86
- }
87
-
88
- func (p * Provider ) configureRoot (ctx context.Context , username string ) error {
89
- exe := p .executable ()
90
- if exe == "" {
91
- return redact .Errorf ("get path to current devbox executable" )
92
- }
93
- sudo , err := exec .LookPath ("sudo" )
94
- if err != nil {
95
- return redact .Errorf ("get path to sudo executable: %s" , err )
96
- }
97
- path , err := p .rootAWSConfigPath ()
98
- if err != nil {
99
- return err
100
- }
101
-
102
- // Rename the .aws directory in case it already exists. We should
103
- // improve this to be more careful with existing ~root/.aws/configs, but
104
- // this seems rare enough that it should be okay for the initial
105
- // implementation.
106
- dir := filepath .Dir (path )
107
- _ = os .Rename (dir , dir + ".bak" ) // ignore errors for non-existent dir
108
- _ = os .Mkdir (dir , 0o755 ) // ignore errors for dir exists (don't os.MkdirAll the home directory)
109
-
110
- config , err := os .OpenFile (path , os .O_WRONLY | os .O_CREATE | os .O_TRUNC , fs .FileMode (0o644 ))
111
- if err != nil {
112
- return err
113
- }
114
- defer config .Close ()
115
-
116
- // TODO(gcurtis): it would be nice to use a non-default profile if
117
- // https://github.com/NixOS/nix/issues/5525 ever gets fixed.
118
- _ , err = fmt .Fprintf (config , `# This file was generated by Devbox.
119
- # Any overwritten configs can be found in the .aws.bak directory.
120
-
121
- [default]
122
- # sudo as the configured user so that their cached credential files have the
123
- # correct ownership.
124
- credential_process = %s -u %s -i %s cache credentials
125
- ` , sudo , username , exe )
126
- if err != nil {
127
- return err
128
- }
129
- if err := config .Close (); err != nil {
130
- return err
131
- }
132
-
133
- if err := nix .IncludeDevboxConfig (ctx , username ); err != nil {
134
- return redact .Errorf ("modify nix config: %v" , err )
135
- }
136
- return nil
137
- }
138
-
139
- func (p * Provider ) sudoConfigureRoot (ctx context.Context , username string ) error {
140
- // TODO(gcurtis): save the user's response so that we don't pester them
141
- // every time if it's a no.
142
- prompt := & survey.Confirm {
143
- Message : "Devbox requires root to configure the Nix daemon to use your organization's private cache. Allow sudo?" ,
144
- }
145
- ok := false
146
- if err := survey .AskOne (prompt , & ok ); err != nil {
147
- return err
148
- }
149
- if ! ok {
150
- return nil
151
- }
152
-
153
- exe := p .executable ()
154
- if exe == "" {
155
- return redact .Errorf ("get path to current devbox executable" )
156
- }
157
-
158
- cmd := exec .CommandContext (ctx , "sudo" , exe , "cache" , "configure" , "--user" , username )
159
- cmd .Stdin = os .Stdin
160
- cmd .Stdout = os .Stdout
161
- cmd .Stderr = os .Stderr
162
-
163
- debug .Log ("running sudo: %s" , cmd )
164
- if err := cmd .Run (); err != nil {
165
- return fmt .Errorf ("failed to relaunch with sudo: %w" , err )
166
- }
167
-
168
- // Print a warning if we were unable to automatically make the user
169
- // trusted.
170
- checkIfUserCanAddSubstituter (ctx )
171
- return nil
172
- }
173
-
174
- func (* Provider ) executable () string {
175
- if exe := os .Getenv (envir .LauncherPath ); exe != "" {
176
- return exe
177
- }
178
- if exe , err := os .Executable (); err == nil {
179
- return exe
180
- }
181
- return ""
182
- }
183
-
184
74
// Credentials fetches short-lived credentials that grant access to the user's
185
75
// private cache.
186
76
func (p * Provider ) Credentials (ctx context.Context ) (AWSCredentials , error ) {
@@ -250,38 +140,6 @@ func (p *Provider) URI(ctx context.Context) (string, error) {
250
140
return uri , nil
251
141
}
252
142
253
- func checkIfUserCanAddSubstituter (ctx context.Context ) {
254
- // we need to ensure that the user can actually use the extra
255
- // substituter. If the user did a root install, then we need to add
256
- // the trusted user/substituter to the nix.conf file and restart the daemon.
257
-
258
- // This check is not perfect, so we still try to use the substituter even if
259
- // it fails
260
-
261
- // TODOs:
262
- // * Also check if cache is enabled in nix.conf
263
- // * Test on single user install
264
- // * Automate making user trusted if needed
265
- cfg , err := nix .CurrentConfig (ctx )
266
- if err != nil {
267
- return
268
- }
269
-
270
- u , err := user .Current ()
271
- if err != nil {
272
- return
273
- }
274
- trusted , _ := cfg .IsUserTrusted (ctx , u .Username )
275
- if ! trusted {
276
- ux .Fwarning (
277
- os .Stderr ,
278
- "In order to use a custom nix cache you must be a trusted user. Please " +
279
- "add your username to nix.conf (usually located at /etc/nix/nix.conf)" +
280
- " and restart the nix daemon.\n " ,
281
- )
282
- }
283
- }
284
-
285
143
// AWSCredentials are short-lived credentials that grant access to a private Nix
286
144
// cache in S3. It marshals to JSON per the schema described in
287
145
// `aws help config-vars` under "Sourcing Credentials From External Processes".
0 commit comments