简易版文件中转站
大家可能会遇到这种场景:
- 容器里面的日志帮忙拉下来下,我要定位下问题
- 我有一个安装包下载不下来,我需要上传到服务器
- 我有一些比较重要的日志, 需要定期归档到云端, 避免占用本地空间
那么如何解决这些问题呢?
解决方案
由于可能面临复杂网络下(多层跳板机)的上传和下载问题, 通过点对点传(比如SCP之类)的很难行得通,所以选择用中转站的方式,比如 OSS
OSS在产品开发过程中也经常用到比如:
- 用户上传了一个视频,我需要找个地方存储
- 用户上传了一些图片, 我需要找个地方存储
寻找现成工具
我们寻找有没有现有的客户端:
- 阿里有
OSS browser, 但不能通过CLI调用 - 多个云商客户端不能通用
自己做一个简单的工具
1. 准备好你的阿里云bucket资源
2. 查看阿里云 oss sdk使用样例
我们通过编写一些测试用例来熟悉基本操作(获取Bucket、上传文件)
操作目录
-
oss_test.go- 声明一个全局 OSS 客户端变量
var ( client *oss.Client )- 声明出所需变量,并从环境变量中获取
var ( AccessKey = os.Getenv("ALI_AK") AccessSecret = os.Getenv("ALI_SK") OssEndpoint = os.Getenv("ALI_OSS_ENDPOINT") BucketName = os.Getenv("ALI_BUCKET_NAME") )- init函数在程序执行前 初始化全局客户端变量
func init() { c, err := oss.New(OssEndpoint, AccessKey, AccessSecret) if err != nil{ panic(err) } client = c }- 获取Bucket列表函数
func TestBucketList(t *testing.T) { lsRes, err := client.ListBuckets() if err != nil{ t.Log(err) } for _, bucket := range lsRes.Buckets{ fmt.Println("Buckets:", bucket.Name) } }- 上传文件函数
- 获取bucket对象
- 上传文件到该 Bucket
- 获取下载地址并设置时间限制
func TestUploadFile(t *testing.T) { bucket, err := client.Bucket(BucketName) if err != nil{ t.Log(err) } // 第一个参数是上传到Bucket后的位置, 第二个为该文件夹下的文件(此处为自己) err = bucket.PutObjectFromFile("mydir/test.go", "oss_test.go") if err != nil{ t.Log(err) } downloadURL, err := bucket.SignURL(file_path, oss.HTTPGet, 60*60*24) if err != nil { return err } fmt.Printf("文件下载URL: %s \n", downloadURL) fmt.Println("请在1天之内下载.") } -
settings.json文件- 若该文件或目录前缀路径没有需自己建立
- 为了使我们的测试用例获取环境变量
- 我们可以加入以下代码让测试用例在本文件夹下的
/etc/unit_test.env文件内加载环境变量
{
"go.testEnvFile": "${workspaceFolder}/etc/unit_test.env",
"commentTranslate.source": "Baidu"
}
unit_test.env- 填写你自己的相关配置,例子如下
- AccessKey和AccessSecret从右上角账号栏
获取
ALI_AK=X56ZAMDE23
ALI_SK=WONM1235AA
ALI_OSS_ENDPOINT=oss-cn-beijing.aliyuncs.com
ALI_BUCKET_NAME=my-bucket
- 测试用例显示Print打印
默认情况下 我们在测试用例中使用print的时候 控制台是不打印 这些中间环节信息的, 如果我们需要打印 就需要进行配置, 如何配置?
vscode 的 go 插件在 执行测试用例的时候 是调用 go test 来执行的, 但是他没有加上 -v 参数, 因此我们通过 vscode 配置上该参数就可以了
注意这里配置的是 vscode 全局参数, 因此只需要配置一次,后面所有项目都可以生效
然后添加如下参数即可
去试一试吧!
3. 开始工具的编写
- 所需变量与 upload 函数和测试用例相同,不重复论述
- 设置用户所需传递的参数
- -h:打印帮助信息
- -f:输入上传文件的名称
func loadParams() {
flag.StringVar(&uploadFile, "f", "", "上传文件的名称")
flag.BoolVar(&help, "h", false, "打印帮助信息")
flag.Parse()
if help{
usage()
os.Exit(0)
}
}
- 帮助信息
usage()
func usage(){
// 1. 打印一些描述信息
fmt.Fprintf(os.Stderr, `cloud-station version: 0.0.1
Usage: cloud-station [-h] -f <uplaod_file_path>
Options:
`)
// 2. 打印有哪些参数可以使用, 就像-f
flag.PrintDefaults()
}
- 参数合法性检测
- 我们可以在 创建 OSS 客户端实例前对 创建所需参数 进行校验
func validate() error {
if endpoint == "" || acessKey == "" || acessSecret == "" {
return fmt.Errorf("endpoint, access_key access_secret has one empty")
}
if uploadFile == "" {
return fmt.Errorf("upload file path required")
}
return nil
}
- 串联逻辑,编写入口函数
func main() {
// 参数加载
loadParams()
// 参数验证
if err := validate(); err != nil {
fmt.Printf("参数校验异常: %s\n", err)
usage()
os.Exit(1)
}
if err := upload(uploadFile); err != nil {
fmt.Printf("上传文件异常: %s\n", err)
os.Exit(1)
}
fmt.Printf("文件: %s 上传完成\n", uploadFile)
}
实现结果,快去试试吧!
客户如何使用你提供的工具
- 提供多个平台的版本(Linux, Windows, MacOS)
- 用户如何获取到你的工具, 上传到一个工具仓库,提供下载链接
- 为你的工具添加一个使用文档
来自用户的抱怨
- 我上传大文件 没进度条, 不知道啥时候能传输完成
- 没有传输速率, 不知道上传快慢
总结
我们以写脚本的一个模式写了一个工具, 他能最快的解决我们问题, 但是其中还是有一些简单的技巧
- 面向过程开发的思维模式
- 合理抽象函数
- 合理使用变量
- 注意校验用户输入
请看下节 系统方式开发文件中转站