通过python脚本上传本地/远程服务器文件到minio

前言

        将文件上传到MinIO对象存储后,MinIO会将文件存储为对象(.meta文件),并为每个对象生成相应的元数据。元数据是描述对象的属性和信息的数据。

        通常,元数据包括对象的名称、大小、创建日期等。 在MinIO中,对象的元数据存储在独立的数据库中,而不是直接存储在文件本身中。

        因此,从MinIO中检索文件时,将得到一个包含文件元数据的对象。 如果您希望访问原始文件内容,您可以使用MinIO提供的API或客户端工具来检索对象,并将其保存为原始文件格式。       

通过python脚本上传本地/远程服务器文件到minio_第1张图片

需求

        因旧系统改造,需要将原来的服务器上的文件迁移到MinIO,了解后发现无法直接迁移原文件到MinIO,所以想到通过脚本调用MinIO的API上传文件。

实现

        先上代码

import pymysql
import os
import paramiko
from minio import Minio
from minio.error import S3Error
from stat import S_ISDIR

#链接mysql获取需要上传的文件名
def get_sop_url():
    # 连接到 MySQL 数据库
    conn = pymysql.connect(host=mysql_server, port=mysql_port, user=mysql_user, password=mysql_pwd, db=db_name)
    # 创建一个游标对象
    cursor = conn.cursor()
    # 执行查询语句
    cursor.execute("select SUBSTRING(sop,25,LENGTH(sop)) sop from process_sop where sop LIKE '%image%'")
    # 获取查询结果
    results = [row[0] for row in cursor.fetchall()]
    # 关闭游标对象
    cursor.close()
    # 关闭数据库连接
    conn.close()
    print(len(results))
    return results

# 连接到远程服务器
def connect_to_remote_server(hostname, username, password):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(hostname, username=username, password=password)
    return ssh

# 递归遍历文件夹并上传PNG文件到MinIO
def upload_png_files(results, ssh, remote_path, bucket_name, minio_path):
    sftp = ssh.open_sftp()
    try:
        # 遍历远程路径下的文件和文件夹
        for item in sftp.listdir_attr(remote_path):
            item_path = os.path.join(remote_path, item.filename)
            file_name = item.filename
            if S_ISDIR(item.st_mode):
                # 如果是文件夹,则补充url,递归调用函数处理子文件夹
                upload_png_files(results, ssh, item_path + '/', bucket_name, os.path.join(minio_path, file_name + "/"))
            # elif file_name.lower().endswith('.png'): # 通过文件后缀上传
            elif file_name in results: # 通过mysql查询的文件名对比上传
                # 如果是PNG文件,则上传到MinIO
                local_path = os.path.join(local_path_prefix, os.path.relpath(item_path, remote_path))
                os.makedirs(os.path.dirname(local_path), exist_ok=True)
                sftp.get(item_path, local_path)
                print(f"{item.filename} download success")

                # 创建MinIO客户端对象
                client = Minio(minio_server, access_key=minio_user, secret_key=minio_pwd, secure=False)

                # 设置要上传的图像文件的元数据
                metadata = {
                    "Content-Type": "image/png",
                    "X-Amz-Meta-Description": "This is a manually uploaded image"
                }
                content_type = "image/png"

                # 构建MinIO中的对象键
                object_name = os.path.join(minio_path, os.path.relpath(item_path, remote_path))

                # 上传图像文件
                client.fput_object(bucket_name, object_name, local_path, content_type, metadata)
                print(f"{item.filename} upload success to minio")

                # 上传后及时清除提高效率
                results.remove(file_name)

                # 删除本地临时文件
                os.remove(local_path)
    except S3Error as err:
        print(err)
    finally:
        sftp.close()


# 调用函数连接到远程服务器并上传所有PNG文件到MinIO指定路径
# 远程服务器
hostname = "你的源ip"
username = "账号"
password = "密码"
remote_path = "/home/centos/upload/files/"

# 本地路径
local_path_prefix = "E://temp/"

# minio服务器
minio_server = "ip:port"
minio_user = "账号"
minio_pwd = "密码"
bucket_name = "pub"
minio_path = "upload/"

# mysql
mysql_server = "你的mysql数据库ip"
mysql_port = 3306
mysql_user = "root"
mysql_pwd = "root"
db_name = "db_name"

# 链接需要迁移文件的源服务器
ssh = connect_to_remote_server(hostname, username, password)
# 链接mysql获取需要上传的文件名
results = get_sop_url(mysql_server, mysql_port, mysql_user, mysql_pwd, db_name)
# 上传文件
upload_png_files(results, ssh, remote_path, bucket_name, minio_path)
ssh.close()

踩坑记录

坑1——依赖导入

        高版本的MinIO依赖中已经不使用ResponseError了

        所以下面会报错“ImportError cannot import name 'ResponseError'”

from minio.error import ResponseError

        应该使用

from minio.error import S3Error

坑2——SSL链接

client = Minio("ip:port",access_key="minio",secret_key="minio")

        以上代码默认启用https,报错如下:

urllib3.exceptions.MaxRetryError: 
    HTTPSConnectionPool(host='10.11.1.62', port=9000):
    Max retries exceeded with url: /pub?location= (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)')))

        需要使用http,加上 secure=False

client = Minio("ip:port",access_key="minio",secret_key="minio",secure=False)

坑3——设置Content-Type或者Metadata的Content-Type属性

        这两种方式都可以解决类型识别问题

        Metadata 的 Content-Type 是指对象的元数据的类型,而 content-type 是指对象的内容类型。 它可以是任何类型,但通常是 JSON 或 XML。它包含有关对象的信息,例如对象的创建时间、修改时间、大小等。

        content-type 是指对象的内容类型,它可以是任何类型,但通常是文本、图像、视频或音频。它告诉浏览器如何处理对象。

        注意:下图显示的是Content-Type,不是Metadata 的 Content-Type。

        通过python脚本上传本地/远程服务器文件到minio_第2张图片

 坑4——磁盘空间

        因为没有提前查看空间磁盘,导致大批量上传时磁盘空间不够,又重新跑了两天脚本。

        1、查看容器映射的宿主机路径命令:

#docker inspect <容器ID或name>
docker inspect 8192c5361de1

                 通过python脚本上传本地/远程服务器文件到minio_第3张图片

        2、查看宿主机空间分布情况:

df -hl

 通过python脚本上传本地/远程服务器文件到minio_第4张图片

        3、我是将原文件迁移到新的路径,重新docker run 启动minio,指定新的路径,没有尝试修改配置文件的方法,有用过的也请评论告知一下。

        4、启动服务后别忘记修改bucket的访问策略。

通过python脚本上传本地/远程服务器文件到minio_第5张图片

官方文档API

你可能感兴趣的:(python,服务器,java,linux,运维,docker)