yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/rds_mysql_backup.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package qcloud 16 17 import ( 18 "fmt" 19 "time" 20 21 "yunion.io/x/log" 22 "yunion.io/x/pkg/errors" 23 "yunion.io/x/pkg/util/timeutils" 24 "yunion.io/x/pkg/utils" 25 26 api "yunion.io/x/cloudmux/pkg/apis/compute" 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 "yunion.io/x/cloudmux/pkg/multicloud" 29 ) 30 31 type SMySQLInstanceBackup struct { 32 multicloud.SDBInstanceBackupBase 33 QcloudTags 34 rds *SMySQLInstance 35 36 Name string 37 Size int 38 Date string 39 IntranetUrl string 40 InternetUrl string 41 Type string 42 BackupId int 43 Status string 44 FinishTime string 45 Creator string 46 StartTime string 47 Method string 48 Way string 49 } 50 51 func (self *SMySQLInstanceBackup) GetId() string { 52 return fmt.Sprintf("%d", self.BackupId) 53 } 54 55 func (self *SMySQLInstanceBackup) GetGlobalId() string { 56 return self.GetId() 57 } 58 59 func (self *SMySQLInstanceBackup) GetName() string { 60 if len(self.Name) > 0 { 61 return self.Name 62 } 63 return self.GetId() 64 } 65 66 func (self *SMySQLInstanceBackup) GetEngine() string { 67 return api.DBINSTANCE_TYPE_MYSQL 68 } 69 70 func (self *SMySQLInstanceBackup) GetStatus() string { 71 switch self.Status { 72 case "SUCCESS": 73 return api.DBINSTANCE_BACKUP_READY 74 case "FAILED": 75 return api.DBINSTANCE_BACKUP_CREATE_FAILED 76 case "RUNNING": 77 return api.DBINSTANCE_BACKUP_CREATING 78 default: 79 return api.DBINSTANCE_BACKUP_UNKNOWN 80 } 81 } 82 83 func (self *SMySQLInstanceBackup) GetEngineVersion() string { 84 return self.rds.EngineVersion 85 } 86 87 func (self *SMySQLInstanceBackup) GetDBInstanceId() string { 88 return self.rds.InstanceId 89 } 90 91 func (self *SMySQLInstanceBackup) GetStartTime() time.Time { 92 start, err := timeutils.ParseTimeStr(self.StartTime) 93 if err != nil { 94 return time.Time{} 95 } 96 return start.Add(time.Hour * -8) 97 } 98 99 func (self *SMySQLInstanceBackup) GetEndTime() time.Time { 100 end, err := timeutils.ParseTimeStr(self.FinishTime) 101 if err != nil { 102 return time.Time{} 103 } 104 return end.Add(time.Hour * -8) 105 } 106 107 func (self *SMySQLInstanceBackup) GetBackupSizeMb() int { 108 return self.Size / 1024 / 1024 109 } 110 111 func (self *SMySQLInstanceBackup) GetDBNames() string { 112 return "" 113 } 114 115 func (self *SMySQLInstanceBackup) GetBackupMode() string { 116 if self.Way == "manual" { 117 return api.BACKUP_MODE_MANUAL 118 } 119 return api.BACKUP_MODE_AUTOMATED 120 } 121 122 func (self *SMySQLInstanceBackup) Delete() error { 123 return self.rds.region.DeleteBackup(self.rds.InstanceId, fmt.Sprintf("%d", self.BackupId)) 124 } 125 126 func (self *SMySQLInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { 127 backups := []cloudprovider.ICloudDBInstanceBackup{} 128 for { 129 part, total, err := self.region.DescribeMySQLBackups(self.InstanceId, len(backups), 100) 130 if err != nil { 131 return nil, errors.Wrapf(err, "DescribeMySQLBackups") 132 } 133 for i := range part { 134 part[i].rds = self 135 backups = append(backups, &part[i]) 136 } 137 if len(backups) >= total { 138 break 139 } 140 } 141 return backups, nil 142 } 143 144 func (self *SRegion) DescribeMySQLBackups(instanceId string, offset, limit int) ([]SMySQLInstanceBackup, int, error) { 145 if limit < 1 || limit > 100 { 146 limit = 100 147 } 148 params := map[string]string{ 149 "Offset": fmt.Sprintf("%d", offset), 150 "Limit": fmt.Sprintf("%d", limit), 151 } 152 if len(instanceId) > 0 { 153 params["InstanceId"] = instanceId 154 } 155 resp, err := self.cdbRequest("DescribeBackups", params) 156 if err != nil { 157 return nil, 0, errors.Wrapf(err, "DescribeBackups") 158 } 159 backups := []SMySQLInstanceBackup{} 160 err = resp.Unmarshal(&backups, "Items") 161 if err != nil { 162 return nil, 0, errors.Wrapf(err, "resp.Unmarshal") 163 } 164 totalCount, _ := resp.Float("TotalCount") 165 return backups, int(totalCount), nil 166 } 167 168 func (self *SRegion) DeleteBackup(instanceId, id string) error { 169 params := map[string]string{ 170 "InstanceId": instanceId, 171 "BackupId": id, 172 } 173 _, err := self.cdbRequest("DeleteBackup", params) 174 if err != nil { 175 return errors.Wrapf(err, "DeleteBackup") 176 } 177 return nil 178 } 179 180 func (self *SRegion) GetMySQLInstanceBackup(instanceId, backupId string) (*SMySQLInstanceBackup, error) { 181 backups := []SMySQLInstanceBackup{} 182 for { 183 part, total, err := self.DescribeMySQLBackups(instanceId, len(backups), 100) 184 if err != nil { 185 return nil, errors.Wrapf(err, "DescribeMySQLBackups") 186 } 187 for i := range part { 188 if fmt.Sprintf("%d", part[i].BackupId) == backupId { 189 return &part[i], nil 190 } 191 } 192 backups = append(backups, part...) 193 if len(backups) >= total { 194 break 195 } 196 } 197 return nil, fmt.Errorf("failed to found rds %s backup %s", instanceId, backupId) 198 } 199 200 func (self *SRegion) waitMySQLBackupReady(instanceId, backupId string) error { 201 return cloudprovider.Wait(time.Second*20, time.Minute*30, func() (bool, error) { 202 backup, err := self.GetMySQLInstanceBackup(instanceId, backupId) 203 if err != nil { 204 return false, errors.Wrapf(err, "GetMySQLInstanceBackup") 205 } 206 log.Infof("backup %s for instance %s status %s", backup.GetName(), instanceId, backup.Status) 207 if utils.IsInStringArray(backup.Status, []string{"FAILED", "SUCCESS"}) { 208 return true, nil 209 } 210 return false, nil 211 }) 212 } 213 214 func (self *SRegion) CreateMySQLBackup(instanceId string, tables map[string]string) (string, error) { 215 params := map[string]string{ 216 "InstanceId": instanceId, 217 "BackupMethod": "physical", 218 } 219 if len(tables) > 0 { 220 params["BackupMethod"] = "logical" 221 idx := 0 222 for db, table := range tables { 223 params[fmt.Sprintf("BackupDBTableList.%d.Db", idx)] = db 224 if len(table) > 0 { 225 params[fmt.Sprintf("BackupDBTableList.%d.Table", idx)] = table 226 } 227 idx++ 228 } 229 } 230 resp, err := self.cdbRequest("CreateBackup", params) 231 if err != nil { 232 return "", errors.Wrapf(err, "CreateBackup") 233 } 234 _backupId, _ := resp.Float("BackupId") 235 backupId := fmt.Sprintf("%d", int(_backupId)) 236 err = self.waitMySQLBackupReady(instanceId, backupId) 237 if err != nil { 238 return "", errors.Wrapf(err, "waitBackupReady") 239 } 240 return backupId, nil 241 }