Go语言利用原生mc命令实现一个跨账号拷贝

Go 语言通过执行 mc 命令实现跨账号拷贝的示例代码:

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
    "sync"
)

// MC配置结构
type MCConfig struct {
    SourceAlias      string
    DestinationAlias string
    Workers          int
}

// 复制任务结构
type CopyTask struct {
    SourcePath      string
    DestinationPath string
}

// 配置mc客户端
func configureMC(sourceEndpoint, sourceAccessKey, sourceSecretKey, 
                destEndpoint, destAccessKey, destSecretKey string) error {
    // 配置源端点
    sourceCmd := exec.Command("mc", "alias", "set", "source", 
                            sourceEndpoint, sourceAccessKey, sourceSecretKey)
    if err := sourceCmd.Run(); err != nil {
        return fmt.Errorf("error configuring source alias: %v", err)
    }

    // 配置目标端点
    destCmd := exec.Command("mc", "alias", "set", "destination", 
                          destEndpoint, destAccessKey, destSecretKey)
    if err := destCmd.Run(); err != nil {
        return fmt.Errorf("error configuring destination alias: %v", err)
    }

    return nil
}

// 列出对象
func listObjects(mcAlias, bucket, prefix string) ([]string, error) {
    cmd := exec.Command("mc", "ls", "--recursive", 
                       fmt.Sprintf("%s/%s/%s", mcAlias, bucket, prefix))
    
    output, err := cmd.Output()
    if err != nil {
        return nil, fmt.Errorf("error listing objects: %v", err)
    }

    var objects []string
    scanner := bufio.NewScanner(strings.NewReader(string(output)))
    for scanner.Scan() {
        line := scanner.Text()
        // 解析mc ls的输出,提取对象路径
        parts := strings.Fields(line)
        if len(parts) >= 4 {
            objects = append(objects, parts[len(parts)-1])
        }
    }

    return objects, nil
}

// 复制单个对象
func copyObject(task CopyTask) error {
    cmd := exec.Command("mc", "cp", task.SourcePath, task.DestinationPath)
    
    // 获取命令的标准输出和错误输出
    output, err := cmd.CombinedOutput()
    if err != nil {
        return fmt.Errorf("error copying %s: %v\nOutput: %s", 
                         task.SourcePath, err, string(output))
    }

    fmt.Printf("Successfully copied: %s\n", task.SourcePath)
    return nil
}

// 并行复制对象
func copyObjects(tasks []CopyTask, workers int) error {
    var wg sync.WaitGroup
    errorsChan := make(chan error, len(tasks))
    tasksChan := make(chan CopyTask, len(tasks))

    // 启动工作协程
    for i := 0; i < workers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for task := range tasksChan {
                if err := copyObject(task); err != nil {
                    errorsChan <- err
                }
            }
        }()
    }

    // 发送任务
    for _, task := range tasks {
        tasksChan <- task
    }
    close(tasksChan)

    // 等待所有工作完成
    wg.Wait()
    close(errorsChan)

    // 收集错误
    var errors []error
    for err := range errorsChan {
        errors = append(errors, err)
    }

    if len(errors) > 0 {
        return fmt.Errorf("encountered %d errors during copy: %v", 
                         len(errors), errors)
    }

    return nil
}

func main() {
    // MC配置
    config := MCConfig{
        SourceAlias:      "source",
        DestinationAlias: "destination",
        Workers:          5,
    }

    // 配置MC客户端
    err := configureMC(
        "source-endpoint:9000",      // 源端点
        "source-access-key",         // 源访问密钥
        "source-secret-key",         // 源密钥
        "destination-endpoint:9000", // 目标端点
        "dest-access-key",          // 目标访问密钥
        "dest-secret-key",          // 目标密钥
    )
    if err != nil {
        log.Fatalf("Error configuring mc: %v", err)
    }

    // 源和目标桶配置
    sourceBucket := "source-bucket"
    destBucket := "dest-bucket"
    prefix := "some/prefix/"

    // 列出所有需要复制的对象
    objects, err := listObjects(config.SourceAlias, sourceBucket, prefix)
    if err != nil {
        log.Fatalf("Error listing objects: %v", err)
    }

    // 创建复制任务
    var tasks []CopyTask
    for _, object := range objects {
        sourceFullPath := fmt.Sprintf("%s/%s/%s", 
                                    config.SourceAlias, sourceBucket, object)
        destFullPath := fmt.Sprintf("%s/%s/%s", 
                                  config.DestinationAlias, destBucket, object)
        
        tasks = append(tasks, CopyTask{
            SourcePath:      sourceFullPath,
            DestinationPath: destFullPath,
        })
    }

    // 开始复制
    fmt.Printf("Starting to copy %d objects with %d workers\n", 
               len(tasks), config.Workers)
    if err := copyObjects(tasks, config.Workers); err != nil {
        log.Fatalf("Error during copy: %v", err)
    }

    fmt.Println("Copy completed successfully")
}

这个实现:

  1. 使用 exec.Command 执行 mc 命令
  2. 首先配置源和目标的 mc alias
  3. 使用 mc ls 命令列出需要复制的对象
  4. 使用 mc cp 命令执行实际的复制操作
  5. 支持并行复制多个对象
  6. 包含错误处理和日志记录

使用前请确保:

  1. mc 命令行工具已经安装在系统中
  2. mc 命令可以在系统 PATH 中找到
  3. 有适当的权限执行 mc 命令
  4. 源和目标的访问凭证正确

你可以这样使用这个程序:

  1. 修改配置参数(端点、访问密钥等)
  2. 设置源桶和目标桶
  3. 设置要复制的前缀路径
  4. 运行程序

程序会并行复制对象,并显示进度信息。如果发生错误,会收集并报告这些错误。

要添加更多功能,你可以:

  1. 添加进度条显示
  2. 添加重试机制
  3. 添加详细的日志记录
  4. 添加断点续传功能
  5. 添加配置文件支持

希望这个实现对你有帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值