yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/dbinstance_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 apsara
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	"github.com/coredns/coredns/plugin/pkg/log"
    23  
    24  	"yunion.io/x/pkg/errors"
    25  	"yunion.io/x/pkg/utils"
    26  
    27  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    28  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    29  	"yunion.io/x/cloudmux/pkg/multicloud"
    30  )
    31  
    32  type SDBInstanceBackup struct {
    33  	multicloud.SDBInstanceBackupBase
    34  	ApsaraTags
    35  	region *SRegion
    36  
    37  	BackupDBNames             string
    38  	BackupIntranetDownloadURL string
    39  	BackupDownloadURL         string
    40  	BackupEndTime             time.Time
    41  	BackupId                  string
    42  	BackupLocation            string
    43  	BackupMethod              string
    44  	BackupMode                string
    45  	BackupScale               string
    46  	BackupSize                int
    47  	BackupStartTime           time.Time
    48  	BackupStatus              string
    49  	BackupType                string
    50  	DBInstanceId              string
    51  	HostInstanceID            int
    52  	MetaStatus                string
    53  	StoreStatus               string
    54  }
    55  
    56  func (backup *SDBInstanceBackup) GetId() string {
    57  	return backup.BackupId
    58  }
    59  
    60  func (backup *SDBInstanceBackup) GetGlobalId() string {
    61  	return backup.BackupId
    62  }
    63  
    64  func (backup *SDBInstanceBackup) GetName() string {
    65  	return backup.BackupId
    66  }
    67  
    68  func (backup *SDBInstanceBackup) GetStartTime() time.Time {
    69  	return backup.BackupStartTime
    70  }
    71  
    72  func (backup *SDBInstanceBackup) GetEndTime() time.Time {
    73  	return backup.BackupEndTime
    74  }
    75  
    76  func (backup *SDBInstanceBackup) GetBackupMode() string {
    77  	switch backup.BackupMode {
    78  	case "Manual":
    79  		return api.BACKUP_MODE_MANUAL
    80  	default:
    81  		return api.BACKUP_MODE_AUTOMATED
    82  	}
    83  }
    84  
    85  func (backup *SDBInstanceBackup) GetStatus() string {
    86  	switch backup.BackupStatus {
    87  	case "Success":
    88  		return api.DBINSTANCE_BACKUP_READY
    89  	case "Failed":
    90  		return api.DBINSTANCE_BACKUP_FAILED
    91  	default:
    92  		return api.DBINSTANCE_BACKUP_UNKNOWN
    93  	}
    94  }
    95  
    96  func (backup *SDBInstanceBackup) GetBackupSizeMb() int {
    97  	return backup.BackupSize / 1024 / 1024
    98  }
    99  
   100  func (backup *SDBInstanceBackup) GetDBNames() string {
   101  	return backup.BackupDBNames
   102  }
   103  
   104  func (backup *SDBInstanceBackup) GetEngine() string {
   105  	instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId)
   106  	if instance != nil {
   107  		return instance.Engine
   108  	}
   109  	return ""
   110  }
   111  
   112  func (backup *SDBInstanceBackup) GetEngineVersion() string {
   113  	instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId)
   114  	if instance != nil {
   115  		return instance.EngineVersion
   116  	}
   117  	return ""
   118  }
   119  
   120  func (backup *SDBInstanceBackup) GetDBInstanceId() string {
   121  	return backup.DBInstanceId
   122  }
   123  
   124  func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string, offset int, limit int) ([]SDBInstanceBackup, int, error) {
   125  	if limit > 50 || limit <= 0 {
   126  		limit = 50
   127  	}
   128  	params := map[string]string{
   129  		"RegionId":     region.RegionId,
   130  		"PageSize":     fmt.Sprintf("%d", limit),
   131  		"PageNumber":   fmt.Sprintf("%d", (offset/limit)+1),
   132  		"DBInstanceId": instanceId,
   133  	}
   134  	if len(backupId) > 0 {
   135  		params["BackupId"] = backupId
   136  	}
   137  	body, err := region.rdsRequest("DescribeBackups", params)
   138  	if err != nil {
   139  		return nil, 0, errors.Wrap(err, "DescribeBackups")
   140  	}
   141  	backups := []SDBInstanceBackup{}
   142  	err = body.Unmarshal(&backups, "Items", "Backup")
   143  	if err != nil {
   144  		return nil, 0, errors.Wrap(err, "Unmarshal")
   145  	}
   146  	total, _ := body.Int("TotalRecordCount")
   147  	return backups, int(total), nil
   148  }
   149  
   150  func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) {
   151  	dbinstnaces, err := region.GetIDBInstances()
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	ibackups := []cloudprovider.ICloudDBInstanceBackup{}
   156  	for i := 0; i < len(dbinstnaces); i++ {
   157  		_dbinstance := dbinstnaces[i].(*SDBInstance)
   158  		_ibackup, err := _dbinstance.GetIDBInstanceBackups()
   159  		if err != nil {
   160  			return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance)
   161  		}
   162  		ibackups = append(ibackups, _ibackup...)
   163  	}
   164  	return ibackups, nil
   165  }
   166  
   167  func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) {
   168  	backups := []SDBInstanceBackup{}
   169  	for {
   170  		parts, total, err := rds.region.GetDBInstanceBackups(rds.DBInstanceId, "", len(backups), 50)
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  		backups = append(backups, parts...)
   175  		if len(backups) >= total {
   176  			break
   177  		}
   178  	}
   179  
   180  	ibackups := []cloudprovider.ICloudDBInstanceBackup{}
   181  	for i := 0; i < len(backups); i++ {
   182  		backups[i].region = rds.region
   183  		ibackups = append(ibackups, &backups[i])
   184  	}
   185  	return ibackups, nil
   186  }
   187  
   188  func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) {
   189  	params := map[string]string{
   190  		"DBInstanceId": rds.DBInstanceId,
   191  	}
   192  	switch rds.Engine {
   193  	case api.DBINSTANCE_TYPE_MYSQL:
   194  		if utils.IsInStringArray(rds.EngineVersion, []string{"5.7", "8.0"}) && ((utils.IsInStringArray(rds.GetStorageType(), []string{
   195  			api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_ESSD,
   196  			api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD,
   197  		}) && rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_HA) ||
   198  			(rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD &&
   199  				rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_BASIC)) {
   200  			params["BackupMethod"] = "Snapshot"
   201  		} else {
   202  			params["BackupMethod"] = "Physical"
   203  			if len(conf.Databases) > 0 {
   204  				params["BackupStrategy"] = "db"
   205  				params["DBName"] = strings.Join(conf.Databases, ",")
   206  				params["BackupMethod"] = "Logical"
   207  			}
   208  		}
   209  	case api.DBINSTANCE_TYPE_MARIADB:
   210  		params["BackupMethod"] = "Snapshot"
   211  	case api.DBINSTANCE_TYPE_SQLSERVER:
   212  		params["BackupMethod"] = "Physical"
   213  	case api.DBINSTANCE_TYPE_POSTGRESQL:
   214  		if rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD {
   215  			params["BackupMethod"] = "Physical"
   216  		} else {
   217  			params["BackupMethod"] = "Snapshot"
   218  		}
   219  	case api.DBINSTANCE_TYPE_PPAS:
   220  		params["BackupMethod"] = "Physical"
   221  	}
   222  	body, err := rds.region.rdsRequest("CreateBackup", params)
   223  	if err != nil {
   224  		return "", errors.Wrap(err, "CreateBackup")
   225  	}
   226  	jobId, err := body.GetString("BackupJobId")
   227  	if err != nil {
   228  		return "", errors.Wrap(err, "body.BackupJobId")
   229  	}
   230  	return "", rds.region.waitBackupCreateComplete(rds.DBInstanceId, jobId)
   231  }
   232  
   233  func (backup *SDBInstanceBackup) Delete() error {
   234  	return backup.region.DeleteDBInstanceBackup(backup.DBInstanceId, backup.BackupId)
   235  }
   236  
   237  func (region *SRegion) DeleteDBInstanceBackup(instanceId string, backupId string) error {
   238  	params := map[string]string{
   239  		"DBInstanceId": instanceId,
   240  		"BackupId":     backupId,
   241  	}
   242  	_, err := region.rdsRequest("DeleteBackup", params)
   243  	return err
   244  }
   245  
   246  type SDBInstanceBackupJob struct {
   247  	BackupProgressStatus string
   248  	Process              string
   249  	JobMode              string
   250  	TaskAction           string
   251  	BackupStatus         string
   252  	BackupJobId          string
   253  }
   254  
   255  type SDBInstanceBackupJobs struct {
   256  	BackupJob []SDBInstanceBackupJob
   257  }
   258  
   259  func (region *SRegion) GetDBInstanceBackupJobs(instanceId, jobId string) (*SDBInstanceBackupJobs, error) {
   260  	params := map[string]string{
   261  		"DBInstanceId": instanceId,
   262  		"ClientToken":  utils.GenRequestId(20),
   263  		"BackupMode":   "Manual",
   264  	}
   265  	if len(jobId) > 0 {
   266  		params["BackupJobId"] = jobId
   267  	}
   268  	body, err := region.rdsRequest("DescribeBackupTasks", params)
   269  	if err != nil {
   270  		return nil, errors.Wrap(err, "DescribeBackupTasks")
   271  	}
   272  
   273  	jobs := SDBInstanceBackupJobs{}
   274  
   275  	err = body.Unmarshal(&jobs, "Items")
   276  	if err != nil {
   277  		return nil, errors.Wrapf(err, "body.Unmarshal(%s)", body)
   278  	}
   279  
   280  	return &jobs, nil
   281  }
   282  
   283  func (region *SRegion) waitBackupCreateComplete(instanceId, jobId string) error {
   284  	for i := 0; i < 20*40; i++ {
   285  		jobs, err := region.GetDBInstanceBackupJobs(instanceId, jobId)
   286  		if err != nil {
   287  			return errors.Wrapf(err, "region.GetDBInstanceBackupJobs(%s, %s)", instanceId, jobId)
   288  		}
   289  		if len(jobs.BackupJob) == 0 {
   290  			return nil
   291  		}
   292  		for _, job := range jobs.BackupJob {
   293  			log.Infof("instance %s backup job %s status: %s(%s)", instanceId, jobId, job.BackupStatus, job.Process)
   294  			if job.BackupStatus == "Finished" && job.BackupJobId == jobId {
   295  				return nil
   296  			}
   297  			if job.BackupStatus == "Failed" && job.BackupJobId == jobId {
   298  				return fmt.Errorf("instance %s backup job %s failed", instanceId, jobId)
   299  			}
   300  		}
   301  		time.Sleep(time.Second * 3)
   302  	}
   303  	return fmt.Errorf("timeout for waiting create job complete")
   304  }