github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/backups/files.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package backups 5 6 import ( 7 "os" 8 "path/filepath" 9 10 "github.com/juju/errors" 11 12 "github.com/juju/juju/mongo" 13 ) 14 15 // TODO(ericsnow) lp-1392876 16 // Pull these from authoritative sources (see 17 // github.com/juju/juju/juju/paths, etc.): 18 const ( 19 sshDir = "/home/ubuntu/.ssh" 20 21 agentsDir = "agents" 22 agentsConfs = "machine-*" 23 toolsDir = "tools" 24 initDir = "init" 25 26 sshIdentFile = "system-identity" 27 nonceFile = "nonce.txt" 28 authKeysFile = "authorized_keys" 29 30 dbPEM = mongo.FileNameDBSSLKey 31 dbSecret = "shared-secret" 32 dbSecretSnapDir = "/var/snap/juju-db/common" 33 ) 34 35 // BackupDirToUse returns the desired backup staging dir. 36 func BackupDirToUse(configuredDir string) string { 37 if configuredDir != "" { 38 return configuredDir 39 } 40 return os.TempDir() 41 } 42 43 // Paths holds the paths that backups needs. 44 type Paths struct { 45 BackupDir string 46 DataDir string 47 LogsDir string 48 } 49 50 // DiskUsage instances are used to find disk usage for a path. 51 type DiskUsage interface { 52 Available(path string) uint64 53 } 54 55 // GetFilesToBackUp returns the paths that should be included in the 56 // backup archive. 57 func GetFilesToBackUp(rootDir string, paths *Paths) ([]string, error) { 58 var glob string 59 60 glob = filepath.Join(rootDir, paths.DataDir, agentsDir, agentsConfs) 61 agentConfs, err := filepath.Glob(glob) 62 if err != nil { 63 return nil, errors.Annotate(err, "failed to fetch agent config files") 64 } 65 66 glob = filepath.Join(rootDir, paths.DataDir, initDir, "*") 67 serviceConfs, err := filepath.Glob(glob) 68 if err != nil { 69 return nil, errors.Annotate(err, "failed to fetch service config files") 70 } 71 72 backupFiles := []string{ 73 filepath.Join(rootDir, paths.DataDir, toolsDir), 74 filepath.Join(rootDir, paths.DataDir, sshIdentFile), 75 filepath.Join(rootDir, paths.DataDir, dbPEM), 76 } 77 78 // Handle shared-secret (may be in /var/lib/juju or /var/snap/juju-db/common). 79 secret := filepath.Join(rootDir, paths.DataDir, dbSecret) 80 if _, err := os.Stat(secret); err != nil { 81 if !os.IsNotExist(err) { 82 return nil, errors.Trace(err) 83 } 84 secretSnap := filepath.Join(rootDir, dbSecretSnapDir, dbSecret) 85 logger.Tracef("shared-secret not found at %q, trying %q", secret, secretSnap) 86 if _, err := os.Stat(secretSnap); err != nil { 87 return nil, errors.Trace(err) 88 } 89 secret = secretSnap 90 } 91 backupFiles = append(backupFiles, secret) 92 93 backupFiles = append(backupFiles, agentConfs...) 94 backupFiles = append(backupFiles, serviceConfs...) 95 96 // Handle nonce.txt (might not exist). 97 nonce := filepath.Join(rootDir, paths.DataDir, nonceFile) 98 if _, err := os.Stat(nonce); err != nil { 99 if !os.IsNotExist(err) { 100 return nil, errors.Trace(err) 101 } 102 logger.Errorf("skipping missing file %q", nonce) 103 } else { 104 backupFiles = append(backupFiles, nonce) 105 } 106 107 // Handle user SSH files (might not exist). 108 SSHDir := filepath.Join(rootDir, sshDir) 109 if _, err := os.Stat(SSHDir); err != nil { 110 if !os.IsNotExist(err) { 111 return nil, errors.Trace(err) 112 } 113 logger.Errorf("skipping missing dir %q", SSHDir) 114 } else { 115 backupFiles = append(backupFiles, filepath.Join(SSHDir, authKeysFile)) 116 } 117 118 return backupFiles, nil 119 }