You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							274 lines
						
					
					
						
							8.0 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							274 lines
						
					
					
						
							8.0 KiB
						
					
					
				
								#!/usr/bin/env python3
							 | 
						|
								# /// script
							 | 
						|
								# requires-python = ">=3.12"
							 | 
						|
								# dependencies = [
							 | 
						|
								#     "boto3",
							 | 
						|
								# ]
							 | 
						|
								# ///
							 | 
						|
								
							 | 
						|
								import argparse
							 | 
						|
								import json
							 | 
						|
								import random
							 | 
						|
								import string
							 | 
						|
								import subprocess
							 | 
						|
								from enum import Enum
							 | 
						|
								from pathlib import Path
							 | 
						|
								
							 | 
						|
								import boto3
							 | 
						|
								
							 | 
						|
								REGION_NAME = "us-east-1"
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								class Actions(str, Enum):
							 | 
						|
								    Get = "Get"
							 | 
						|
								    Put = "Put"
							 | 
						|
								    List = "List"
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def get_user_dir(bucket_name, user, with_bucket=True):
							 | 
						|
								    if with_bucket:
							 | 
						|
								        return f"{bucket_name}/user-id-{user}"
							 | 
						|
								
							 | 
						|
								    return f"user-id-{user}"
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def create_power_user():
							 | 
						|
								    power_user_key = "power_user_key"
							 | 
						|
								    power_user_secret = "power_user_secret"
							 | 
						|
								    command = f"s3.configure -apply -user poweruser -access_key {power_user_key} -secret_key {power_user_secret} -actions Admin"
							 | 
						|
								    print("Creating Power User...")
							 | 
						|
								    subprocess.run(
							 | 
						|
								        ["docker", "exec", "-i", "seaweedfs-master-1", "weed", "shell"],
							 | 
						|
								        input=command,
							 | 
						|
								        text=True,
							 | 
						|
								        stdout=subprocess.PIPE,
							 | 
						|
								    )
							 | 
						|
								    print(
							 | 
						|
								        f"Power User created with key: {power_user_key} and secret: {power_user_secret}"
							 | 
						|
								    )
							 | 
						|
								    return power_user_key, power_user_secret
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def create_bucket(s3_client, bucket_name):
							 | 
						|
								    print(f"Creating Bucket {bucket_name}...")
							 | 
						|
								    s3_client.create_bucket(Bucket=bucket_name)
							 | 
						|
								    print(f"Bucket {bucket_name} created.")
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def upload_file(s3_client, bucket_name, user, file_path, custom_remote_path=None):
							 | 
						|
								    user_dir = get_user_dir(bucket_name, user, with_bucket=False)
							 | 
						|
								    if custom_remote_path:
							 | 
						|
								        remote_path = custom_remote_path
							 | 
						|
								    else:
							 | 
						|
								        remote_path = f"{user_dir}/{str(Path(file_path).name)}"
							 | 
						|
								
							 | 
						|
								    print(f"Uploading {file_path} for {user}... on {user_dir}")
							 | 
						|
								
							 | 
						|
								    s3_client.upload_file(file_path, bucket_name, remote_path)
							 | 
						|
								    print(f"File {file_path} uploaded for {user}.")
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def create_user(iam_client, user):
							 | 
						|
								    print(f"Creating user {user}...")
							 | 
						|
								    response = iam_client.create_access_key(UserName=user)
							 | 
						|
								    print(
							 | 
						|
								        f"User {user} created with access key: {response['AccessKey']['AccessKeyId']}"
							 | 
						|
								    )
							 | 
						|
								    return response
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def list_files(s3_client, bucket_name, path=None):
							 | 
						|
								    if path is None:
							 | 
						|
								        path = ""
							 | 
						|
								    print(f"Listing files of s3://{bucket_name}/{path}...")
							 | 
						|
								    try:
							 | 
						|
								        response = s3_client.list_objects_v2(Bucket=bucket_name, Prefix=path)
							 | 
						|
								        if "Contents" in response:
							 | 
						|
								            for obj in response["Contents"]:
							 | 
						|
								                print(f"\t - {obj['Key']}")
							 | 
						|
								        else:
							 | 
						|
								            print("No files found.")
							 | 
						|
								    except Exception as e:
							 | 
						|
								        print(f"Error listing files: {e}")
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def create_policy_for_user(
							 | 
						|
								    iam_client, user, bucket_name, actions=[Actions.Get, Actions.List]
							 | 
						|
								):
							 | 
						|
								    print(f"Creating policy for {user} on {bucket_name}...")
							 | 
						|
								    policy_document = {
							 | 
						|
								        "Version": "2012-10-17",
							 | 
						|
								        "Statement": [
							 | 
						|
								            {
							 | 
						|
								                "Effect": "Allow",
							 | 
						|
								                "Action": [f"s3:{action.value}*" for action in actions],
							 | 
						|
								                "Resource": [
							 | 
						|
								                    f"arn:aws:s3:::{get_user_dir(bucket_name, user)}/*",
							 | 
						|
								                ],
							 | 
						|
								            }
							 | 
						|
								        ],
							 | 
						|
								    }
							 | 
						|
								    policy_name = f"{user}-{bucket_name}-full-access"
							 | 
						|
								
							 | 
						|
								    policy_json = json.dumps(policy_document)
							 | 
						|
								    filepath = f"/tmp/{policy_name}.json"
							 | 
						|
								    with open(filepath, "w") as f:
							 | 
						|
								        f.write(json.dumps(policy_document, indent=2))
							 | 
						|
								
							 | 
						|
								    iam_client.put_user_policy(
							 | 
						|
								        PolicyName=policy_name, PolicyDocument=policy_json, UserName=user
							 | 
						|
								    )
							 | 
						|
								    print(f"Policy for {user} on {bucket_name} created.")
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def main():
							 | 
						|
								    parser = argparse.ArgumentParser(description="SeaweedFS S3 Test Script")
							 | 
						|
								    parser.add_argument(
							 | 
						|
								        "--s3-url", default="http://127.0.0.1:8333", help="S3 endpoint URL"
							 | 
						|
								    )
							 | 
						|
								    parser.add_argument(
							 | 
						|
								        "--iam-url", default="http://127.0.0.1:8111", help="IAM endpoint URL"
							 | 
						|
								    )
							 | 
						|
								    args = parser.parse_args()
							 | 
						|
								
							 | 
						|
								    bucket_name = (
							 | 
						|
								        f"test-bucket-{''.join(random.choices(string.digits + 'abcdef', k=8))}"
							 | 
						|
								    )
							 | 
						|
								    sentinel_file = "/tmp/SENTINEL"
							 | 
						|
								    with open(sentinel_file, "w") as f:
							 | 
						|
								        f.write("Hello World")
							 | 
						|
								    print(f"SENTINEL file created at {sentinel_file}")
							 | 
						|
								
							 | 
						|
								    power_user_key, power_user_secret = create_power_user()
							 | 
						|
								
							 | 
						|
								    admin_s3_client = get_s3_client(args, power_user_key, power_user_secret)
							 | 
						|
								    iam_client = get_iam_client(args, power_user_key, power_user_secret)
							 | 
						|
								
							 | 
						|
								    create_bucket(admin_s3_client, bucket_name)
							 | 
						|
								    upload_file(admin_s3_client, bucket_name, "Alice", sentinel_file)
							 | 
						|
								    upload_file(admin_s3_client, bucket_name, "Bob", sentinel_file)
							 | 
						|
								    list_files(admin_s3_client, bucket_name)
							 | 
						|
								
							 | 
						|
								    alice_user_info = create_user(iam_client, "Alice")
							 | 
						|
								    bob_user_info = create_user(iam_client, "Bob")
							 | 
						|
								
							 | 
						|
								    alice_key = alice_user_info["AccessKey"]["AccessKeyId"]
							 | 
						|
								    alice_secret = alice_user_info["AccessKey"]["SecretAccessKey"]
							 | 
						|
								    bob_key = bob_user_info["AccessKey"]["AccessKeyId"]
							 | 
						|
								    bob_secret = bob_user_info["AccessKey"]["SecretAccessKey"]
							 | 
						|
								
							 | 
						|
								    # Make sure Admin can read any files
							 | 
						|
								    list_files(admin_s3_client, bucket_name)
							 | 
						|
								    list_files(
							 | 
						|
								        admin_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        get_user_dir(bucket_name, "Alice", with_bucket=False),
							 | 
						|
								    )
							 | 
						|
								    list_files(
							 | 
						|
								        admin_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        get_user_dir(bucket_name, "Bob", with_bucket=False),
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								    # Create read policy for Alice and Bob
							 | 
						|
								    create_policy_for_user(iam_client, "Alice", bucket_name)
							 | 
						|
								    create_policy_for_user(iam_client, "Bob", bucket_name)
							 | 
						|
								
							 | 
						|
								    alice_s3_client = get_s3_client(args, alice_key, alice_secret)
							 | 
						|
								
							 | 
						|
								    # Make sure Alice can read her files
							 | 
						|
								    list_files(
							 | 
						|
								        alice_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								    # Make sure Bob can read his files
							 | 
						|
								    bob_s3_client = get_s3_client(args, bob_key, bob_secret)
							 | 
						|
								    list_files(
							 | 
						|
								        bob_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								    # Update policy to include write
							 | 
						|
								    create_policy_for_user(iam_client, "Alice", bucket_name, actions=[Actions.Put, Actions.Get, Actions.List])  # fmt: off
							 | 
						|
								    create_policy_for_user(iam_client, "Bob", bucket_name, actions=[Actions.Put, Actions.Get, Actions.List])  # fmt: off
							 | 
						|
								
							 | 
						|
								    print("############################# Make sure Alice can write her files")
							 | 
						|
								    upload_file(
							 | 
						|
								        alice_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        "Alice",
							 | 
						|
								        sentinel_file,
							 | 
						|
								        custom_remote_path=f"{get_user_dir(bucket_name, 'Alice', with_bucket=False)}/SENTINEL_by_Alice",
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    print("############################# Make sure Bob can write his files")
							 | 
						|
								    upload_file(
							 | 
						|
								        bob_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        "Bob",
							 | 
						|
								        sentinel_file,
							 | 
						|
								        custom_remote_path=f"{get_user_dir(bucket_name, 'Bob', with_bucket=False)}/SENTINEL_by_Bob",
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    print("############################# Make sure Alice can read her new files")
							 | 
						|
								    list_files(
							 | 
						|
								        alice_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    print("############################# Make sure Bob can read his new files")
							 | 
						|
								    list_files(
							 | 
						|
								        bob_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    print("############################# Make sure Bob cannot read Alice's files")
							 | 
						|
								    list_files(
							 | 
						|
								        bob_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								    print("############################# Make sure Alice cannot read Bob's files")
							 | 
						|
								
							 | 
						|
								    list_files(
							 | 
						|
								        alice_s3_client,
							 | 
						|
								        bucket_name,
							 | 
						|
								        get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
							 | 
						|
								    )
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def get_iam_client(args, access_key, secret_key):
							 | 
						|
								    iam_client = boto3.client(
							 | 
						|
								        "iam",
							 | 
						|
								        endpoint_url=args.iam_url,
							 | 
						|
								        region_name=REGION_NAME,
							 | 
						|
								        aws_access_key_id=access_key,
							 | 
						|
								        aws_secret_access_key=secret_key,
							 | 
						|
								    )
							 | 
						|
								    return iam_client
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def get_s3_client(args, access_key, secret_key):
							 | 
						|
								    s3_client = boto3.client(
							 | 
						|
								        "s3",
							 | 
						|
								        endpoint_url=args.s3_url,
							 | 
						|
								        region_name=REGION_NAME,
							 | 
						|
								        aws_access_key_id=access_key,
							 | 
						|
								        aws_secret_access_key=secret_key,
							 | 
						|
								    )
							 | 
						|
								    return s3_client
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								if __name__ == "__main__":
							 | 
						|
								    main()
							 |