vitess.io/vitess@v0.16.2/go/vt/mysqlctl/filebackupstorage/file.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package filebackupstorage implements the BackupStorage interface 18 // for a local filesystem (which can be an NFS mount). 19 package filebackupstorage 20 21 import ( 22 "context" 23 "fmt" 24 "io" 25 "os" 26 "path" 27 28 "github.com/spf13/pflag" 29 30 "vitess.io/vitess/go/vt/concurrency" 31 "vitess.io/vitess/go/vt/mysqlctl/backupstorage" 32 "vitess.io/vitess/go/vt/servenv" 33 ) 34 35 var ( 36 // FileBackupStorageRoot is where the backups will go. 37 // Exported for test purposes. 38 FileBackupStorageRoot string 39 ) 40 41 func registerFlags(fs *pflag.FlagSet) { 42 fs.StringVar(&FileBackupStorageRoot, "file_backup_storage_root", "", "Root directory for the file backup storage.") 43 } 44 45 func init() { 46 servenv.OnParseFor("vtbackup", registerFlags) 47 servenv.OnParseFor("vtctl", registerFlags) 48 servenv.OnParseFor("vtctld", registerFlags) 49 servenv.OnParseFor("vttablet", registerFlags) 50 } 51 52 // FileBackupHandle implements BackupHandle for local file system. 53 type FileBackupHandle struct { 54 fbs *FileBackupStorage 55 dir string 56 name string 57 readOnly bool 58 errors concurrency.AllErrorRecorder 59 } 60 61 // RecordError is part of the concurrency.ErrorRecorder interface. 62 func (fbh *FileBackupHandle) RecordError(err error) { 63 fbh.errors.RecordError(err) 64 } 65 66 // HasErrors is part of the concurrency.ErrorRecorder interface. 67 func (fbh *FileBackupHandle) HasErrors() bool { 68 return fbh.errors.HasErrors() 69 } 70 71 // Error is part of the concurrency.ErrorRecorder interface. 72 func (fbh *FileBackupHandle) Error() error { 73 return fbh.errors.Error() 74 } 75 76 // Directory is part of the BackupHandle interface 77 func (fbh *FileBackupHandle) Directory() string { 78 return fbh.dir 79 } 80 81 // Name is part of the BackupHandle interface 82 func (fbh *FileBackupHandle) Name() string { 83 return fbh.name 84 } 85 86 // AddFile is part of the BackupHandle interface 87 func (fbh *FileBackupHandle) AddFile(ctx context.Context, filename string, filesize int64) (io.WriteCloser, error) { 88 if fbh.readOnly { 89 return nil, fmt.Errorf("AddFile cannot be called on read-only backup") 90 } 91 p := path.Join(FileBackupStorageRoot, fbh.dir, fbh.name, filename) 92 return os.Create(p) 93 } 94 95 // EndBackup is part of the BackupHandle interface 96 func (fbh *FileBackupHandle) EndBackup(ctx context.Context) error { 97 if fbh.readOnly { 98 return fmt.Errorf("EndBackup cannot be called on read-only backup") 99 } 100 return nil 101 } 102 103 // AbortBackup is part of the BackupHandle interface 104 func (fbh *FileBackupHandle) AbortBackup(ctx context.Context) error { 105 if fbh.readOnly { 106 return fmt.Errorf("AbortBackup cannot be called on read-only backup") 107 } 108 return fbh.fbs.RemoveBackup(ctx, fbh.dir, fbh.name) 109 } 110 111 // ReadFile is part of the BackupHandle interface 112 func (fbh *FileBackupHandle) ReadFile(ctx context.Context, filename string) (io.ReadCloser, error) { 113 if !fbh.readOnly { 114 return nil, fmt.Errorf("ReadFile cannot be called on read-write backup") 115 } 116 p := path.Join(FileBackupStorageRoot, fbh.dir, fbh.name, filename) 117 return os.Open(p) 118 } 119 120 // FileBackupStorage implements BackupStorage for local file system. 121 type FileBackupStorage struct{} 122 123 // ListBackups is part of the BackupStorage interface 124 func (fbs *FileBackupStorage) ListBackups(ctx context.Context, dir string) ([]backupstorage.BackupHandle, error) { 125 // ReadDir already sorts the results 126 p := path.Join(FileBackupStorageRoot, dir) 127 fi, err := os.ReadDir(p) 128 if err != nil { 129 if os.IsNotExist(err) { 130 return nil, nil 131 } 132 return nil, err 133 } 134 135 result := make([]backupstorage.BackupHandle, 0, len(fi)) 136 for _, info := range fi { 137 if !info.IsDir() { 138 continue 139 } 140 if info.Name() == "." || info.Name() == ".." { 141 continue 142 } 143 result = append(result, &FileBackupHandle{ 144 fbs: fbs, 145 dir: dir, 146 name: info.Name(), 147 readOnly: true, 148 }) 149 } 150 return result, nil 151 } 152 153 // StartBackup is part of the BackupStorage interface 154 func (fbs *FileBackupStorage) StartBackup(ctx context.Context, dir, name string) (backupstorage.BackupHandle, error) { 155 // Make sure the directory exists. 156 p := path.Join(FileBackupStorageRoot, dir) 157 if err := os.MkdirAll(p, os.ModePerm); err != nil { 158 return nil, err 159 } 160 161 // Create the subdirectory for this named backup. 162 p = path.Join(p, name) 163 if err := os.Mkdir(p, os.ModePerm); err != nil { 164 return nil, err 165 } 166 167 return &FileBackupHandle{ 168 fbs: fbs, 169 dir: dir, 170 name: name, 171 readOnly: false, 172 }, nil 173 } 174 175 // RemoveBackup is part of the BackupStorage interface 176 func (fbs *FileBackupStorage) RemoveBackup(ctx context.Context, dir, name string) error { 177 p := path.Join(FileBackupStorageRoot, dir, name) 178 return os.RemoveAll(p) 179 } 180 181 // Close implements BackupStorage. 182 func (fbs *FileBackupStorage) Close() error { 183 return nil 184 } 185 186 func init() { 187 backupstorage.BackupStorageMap["file"] = &FileBackupStorage{} 188 }