@@ -6,17 +6,15 @@ package backup
66import (
77 "errors"
88 "fmt"
9- "os"
109 "path/filepath"
10+ "sort"
1111 "strings"
1212 "time"
1313
1414 "github.com/CodeMonkeyCybersecurity/eos/pkg/backup"
15- "github.com/CodeMonkeyCybersecurity/eos/pkg/crypto"
1615 eos "github.com/CodeMonkeyCybersecurity/eos/pkg/eos_cli"
1716 "github.com/CodeMonkeyCybersecurity/eos/pkg/eos_err"
1817 "github.com/CodeMonkeyCybersecurity/eos/pkg/eos_io"
19- "github.com/CodeMonkeyCybersecurity/eos/pkg/vault"
2018 "github.com/spf13/cobra"
2119 "github.com/uptrace/opentelemetry-go-extra/otelzap"
2220 "go.uber.org/zap"
@@ -28,9 +26,9 @@ var quickBackupCmd = &cobra.Command{
2826 Short : "Quick backup of current (or specified) directory" ,
2927 Long : `Instantly backup the current directory or specified path with timestamp.
3028
31- This command "just works" - no configuration needed :
32- - Auto-creates local repository at ~/. eos/quick-backups
33- - Auto-generates secure password (stored in Vault or local file)
29+ This command reuses your existing backup configuration:
30+ - Uses the default repository defined in /etc/ eos/backup.yaml
31+ - Honors repository credentials and password files you already manage
3432- Timestamps each backup automatically
3533- Recursive by default
3634
@@ -71,16 +69,21 @@ Restore:
7169 zap .Strings ("tags" , tags ),
7270 zap .Bool ("dry_run" , dryRun ))
7371
74- // Ensure quick backup repository exists
75- if err := ensureQuickBackupRepo ( rc ); err != nil {
72+ repoName , repoConfig , err := resolveQuickBackupRepository ( rc )
73+ if err != nil {
7674 if eos_err .IsExpectedUserError (err ) {
7775 return err
7876 }
79- return fmt . Errorf ( "initializing quick backup repository: %w" , err )
77+ return err
8078 }
8179
82- // Create backup client
83- client , err := backup .NewClient (rc , "quick-backups" )
80+ logger .Info ("Using repository for quick backup" ,
81+ zap .String ("repository" , repoName ),
82+ zap .String ("backend" , repoConfig .Backend ),
83+ zap .String ("url" , repoConfig .URL ))
84+
85+ // Create backup client using existing repository configuration
86+ client , err := backup .NewClient (rc , repoName )
8487 if err != nil {
8588 return fmt .Errorf ("creating backup client: %w" , err )
8689 }
@@ -123,118 +126,62 @@ Restore:
123126
124127 logger .Info ("terminal prompt:" , zap .String ("output" , string (output )))
125128 logger .Info ("terminal prompt:" , zap .String ("output" , fmt .Sprintf ("\n ✓ Backup complete: %s" , absPath )))
126- logger .Info ("terminal prompt:" , zap .String ("output" , "Repository: ~/.eos/quick-backups" ))
129+ logger .Info ("terminal prompt:" , zap .String ("output" ,
130+ fmt .Sprintf ("Repository: %s (%s)" , repoName , repoConfig .URL )))
127131 logger .Info ("terminal prompt:" , zap .String ("output" , "Restore: eos restore ." ))
128132
129133 return nil
130134 }),
131135}
132136
133- // ensureQuickBackupRepo creates the quick backup repository if it doesn't exist
134- func ensureQuickBackupRepo (rc * eos_io.RuntimeContext ) error {
137+ func resolveQuickBackupRepository (rc * eos_io.RuntimeContext ) (string , backup.Repository , error ) {
135138 logger := otelzap .Ctx (rc .Ctx )
136139
137140 config , err := backup .LoadConfig (rc )
138141 if err != nil {
139- config = & backup.Config {
140- Repositories : make (map [string ]backup.Repository ),
141- Profiles : make (map [string ]backup.Profile ),
142- }
143- }
144-
145- repoName := backup .QuickBackupRepositoryName
146- repoConfig , exists := config .Repositories [repoName ]
147-
148- homeDir , err := os .UserHomeDir ()
149- if err != nil {
150- return fmt .Errorf ("getting home directory: %w" , err )
151- }
152-
153- defaultRepoPath := filepath .Join (homeDir , backup .QuickBackupRelativePath )
154-
155- if repoConfig .URL == "" {
156- repoConfig .URL = defaultRepoPath
157- }
158- if repoConfig .Backend == "" {
159- repoConfig .Backend = "local"
160- }
161- if repoConfig .Name == "" {
162- repoConfig .Name = repoName
163- }
164-
165- if err := os .MkdirAll (repoConfig .URL , 0700 ); err != nil {
166- return fmt .Errorf ("creating repository directory: %w" , err )
167- }
168-
169- if _ , err := ensureQuickBackupPassword (rc , repoConfig .URL ); err != nil {
170- return fmt .Errorf ("ensuring password: %w" , err )
171- }
172-
173- config .Repositories [repoName ] = repoConfig
174- config .DefaultRepository = repoName
175-
176- if err := backup .SaveConfig (rc , config ); err != nil {
177- return fmt .Errorf ("saving configuration: %w" , err )
178- }
179-
180- client , err := backup .NewClient (rc , repoName )
181- if err != nil {
182- return fmt .Errorf ("creating backup client: %w" , err )
142+ return "" , backup.Repository {}, fmt .Errorf ("loading backup configuration: %w" , err )
183143 }
184144
185- configPath := filepath .Join (repoConfig .URL , "config" )
186- _ , statErr := os .Stat (configPath )
187-
188- if err := client .InitRepository (); err != nil {
189- if errors .Is (err , backup .ErrResticNotInstalled ) {
190- logger .Info ("terminal prompt:" , zap .String ("output" ,
191- "Restic is not installed. Install restic (e.g., sudo apt-get install restic) and rerun eos backup ." ))
192- userErr := eos_err .DependencyError ("restic" , "initialize quick backup repository" , err )
193- return eos_err .NewExpectedError (rc .Ctx , userErr )
145+ repoName := strings .TrimSpace (config .DefaultRepository )
146+ if repoName != "" {
147+ if _ , ok := config .Repositories [repoName ]; ! ok {
148+ return "" , backup.Repository {}, fmt .Errorf ("default repository %q not found in configuration" , repoName )
194149 }
195- return err
196- }
197-
198- if ! exists || os .IsNotExist (statErr ) {
199- logger .Info ("terminal prompt:" , zap .String ("output" , "✓ Quick backup repository created at ~/.eos/quick-backups" ))
150+ repo := config .Repositories [repoName ]
151+ logger .Info ("Using default repository for quick backup" ,
152+ zap .String ("repository" , repoName ))
153+ return repoName , repo , nil
200154 }
201- return nil
202- }
203-
204- // ensureQuickBackupPassword retrieves or generates the password for quick backups.
205- func ensureQuickBackupPassword (rc * eos_io.RuntimeContext , repoPath string ) (string , error ) {
206- logger := otelzap .Ctx (rc .Ctx )
207155
208- passwordFile := filepath .Join (repoPath , ".password" )
209- if data , err := os .ReadFile (passwordFile ); err == nil {
210- password := strings .TrimSpace (string (data ))
211- if password != "" {
212- return password , nil
213- }
214- logger .Warn ("Quick backup password file is empty, generating new password" ,
215- zap .String ("path" , passwordFile ))
156+ if _ , ok := config .Repositories [backup .QuickBackupRepositoryName ]; ok {
157+ repo := config .Repositories [backup .QuickBackupRepositoryName ]
158+ logger .Info ("Using quick backup repository from configuration" ,
159+ zap .String ("repository" , backup .QuickBackupRepositoryName ))
160+ return backup .QuickBackupRepositoryName , repo , nil
216161 }
217162
218- vaultAddr := os .Getenv ("VAULT_ADDR" )
219- if vaultAddr == "" {
220- vaultAddr = "https://localhost:8200"
163+ if len (config .Repositories ) == 0 {
164+ return "" , backup.Repository {}, fmt .Errorf ("no repositories configured; add at least one in /etc/eos/backup.yaml" )
221165 }
222- // TODO: Implement Vault password storage for quick backups once client supports WriteKV.
223- _ , _ = vault .NewClient (vaultAddr , logger .Logger ().Logger )
224166
225- password , err := crypto .GeneratePassword (backup .QuickBackupPasswordLength )
226- if err != nil {
227- return "" , fmt .Errorf ("generating password: %w" , err )
167+ if len (config .Repositories ) == 1 {
168+ for name := range config .Repositories {
169+ repo := config .Repositories [name ]
170+ logger .Info ("Using sole configured repository for quick backup" ,
171+ zap .String ("repository" , name ))
172+ return name , repo , nil
173+ }
228174 }
229175
230- if err := os .WriteFile (passwordFile , []byte (password ), 0600 ); err != nil {
231- return "" , fmt .Errorf ("writing password file: %w" , err )
176+ repoNames := make ([]string , 0 , len (config .Repositories ))
177+ for name := range config .Repositories {
178+ repoNames = append (repoNames , name )
232179 }
180+ sort .Strings (repoNames )
233181
234- logger .Info ("Password stored in local file" ,
235- zap .String ("path" , passwordFile ))
236-
237- return password , nil
182+ return "" , backup.Repository {}, eos_err .NewExpectedError (rc .Ctx , fmt .Errorf (
183+ "multiple repositories configured (%s) but no default_repository set; update /etc/eos/backup.yaml to select one" ,
184+ strings .Join (repoNames , ", " )))
238185}
239186
240187func init () {
0 commit comments