Search code examples
pythonflaskminio

Upload to Minio directly from Flask service


I want to store a file from a Flask service to a Minio Bucket without storing it in a directory first. What I can do so far is have the user upload a file using a Flask service, store it in a directory, and then use the put_object function from Minio to upload it. Is something like that possible?

Below you can see the upload_file flask method and the upload_object method that utilizes the put_object function from Minio:

UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', '7z', 'iso'}

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/', methods=['GET','POST'])
def upload_file():
    if request.method == 'POST':
        # check if the post request has the file part
        if 'file' not in request.files:
            flash('No file part') 
            return 'No file found'
        file = request.files['file']
        # if user does not select file, browser also
        # submit an empty part without filename
        if file.filename == '':
            flash('No selected file')
            return 'msg error'
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save('uploads/'+filename)
            print(file.filename)
            # upload file to minio service
            upload_object(name=str(file.filename))
            return 'object stored in bucket'

    return '''
    <!doctype html>
    <title>Upload IPS File</title>
    <h1>Upload IPS File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

And the upload_object():

def upload_object(name):
    try:
        path = 'uploads/'+str(name)
        print(path)
        file_data = open(path, 'rb')
        print(file_data)
        file_stat = os.stat('uploads/'+str(name))
        print(minioClient.put_object('miniotestbucket', str(name), file_data, file_stat.st_size))
    except ResponseError as e: 
        print(e)
    except FileNotFoundError as e:
        print(e)

I already checked this Question but I did not quite understand what was needed to do.


Solution

  • It should absolutely be possible since you just read the file content after saving it. This post tells a bit more about FileStorage. Since FileStorage extends stream you have many of the same features while reading the file from the request as when reading it from a file on disk. Since you cannot stat the file I used another way to tell the size of the file found here.

    You can try something like this:

    @app.route("/", methods=["GET", "POST"])
    def upload_file():
        if request.method == "POST":
            uploaded_file = request.files["file"]
            if uploaded_file:
                bucket_name = "miniotestbucket"
                size = os.fstat(uploaded_file.fileno()).st_size
    
                minioClient.put_object(
                    bucket_name, uploaded_file.filename, uploaded_file, size
                )
    
                return "object stored in bucket"
    
        return """
        <!doctype html>
        <title>Upload IPS File</title>
        <h1>Upload IPS File</h1>
        <form method=post enctype=multipart/form-data>
          <input type=file name=file>
          <input type=submit value=Upload>
        </form>
        """
    

    I don't have access to a Minio bucket but I did some testing by uploading a YAML file and reading the contents with yaml.load() which worked just fine.