test.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #!/usr/bin/env python3
  2. # /// script
  3. # requires-python = ">=3.12"
  4. # dependencies = [
  5. # "boto3",
  6. # ]
  7. # ///
  8. import argparse
  9. import json
  10. import random
  11. import string
  12. import subprocess
  13. from enum import Enum
  14. from pathlib import Path
  15. import boto3
  16. REGION_NAME = "us-east-1"
  17. class Actions(str, Enum):
  18. Get = "Get"
  19. Put = "Put"
  20. List = "List"
  21. def get_user_dir(bucket_name, user, with_bucket=True):
  22. if with_bucket:
  23. return f"{bucket_name}/user-id-{user}"
  24. return f"user-id-{user}"
  25. def create_power_user():
  26. power_user_key = "power_user_key"
  27. power_user_secret = "power_user_secret"
  28. command = f"s3.configure -apply -user poweruser -access_key {power_user_key} -secret_key {power_user_secret} -actions Admin"
  29. print("Creating Power User...")
  30. subprocess.run(
  31. ["docker", "exec", "-i", "seaweedfs-master-1", "weed", "shell"],
  32. input=command,
  33. text=True,
  34. stdout=subprocess.PIPE,
  35. )
  36. print(
  37. f"Power User created with key: {power_user_key} and secret: {power_user_secret}"
  38. )
  39. return power_user_key, power_user_secret
  40. def create_bucket(s3_client, bucket_name):
  41. print(f"Creating Bucket {bucket_name}...")
  42. s3_client.create_bucket(Bucket=bucket_name)
  43. print(f"Bucket {bucket_name} created.")
  44. def upload_file(s3_client, bucket_name, user, file_path, custom_remote_path=None):
  45. user_dir = get_user_dir(bucket_name, user, with_bucket=False)
  46. if custom_remote_path:
  47. remote_path = custom_remote_path
  48. else:
  49. remote_path = f"{user_dir}/{str(Path(file_path).name)}"
  50. print(f"Uploading {file_path} for {user}... on {user_dir}")
  51. s3_client.upload_file(file_path, bucket_name, remote_path)
  52. print(f"File {file_path} uploaded for {user}.")
  53. def create_user(iam_client, user):
  54. print(f"Creating user {user}...")
  55. response = iam_client.create_access_key(UserName=user)
  56. print(
  57. f"User {user} created with access key: {response['AccessKey']['AccessKeyId']}"
  58. )
  59. return response
  60. def list_files(s3_client, bucket_name, path=None):
  61. if path is None:
  62. path = ""
  63. print(f"Listing files of s3://{bucket_name}/{path}...")
  64. try:
  65. response = s3_client.list_objects_v2(Bucket=bucket_name, Prefix=path)
  66. if "Contents" in response:
  67. for obj in response["Contents"]:
  68. print(f"\t - {obj['Key']}")
  69. else:
  70. print("No files found.")
  71. except Exception as e:
  72. print(f"Error listing files: {e}")
  73. def create_policy_for_user(
  74. iam_client, user, bucket_name, actions=[Actions.Get, Actions.List]
  75. ):
  76. print(f"Creating policy for {user} on {bucket_name}...")
  77. policy_document = {
  78. "Version": "2012-10-17",
  79. "Statement": [
  80. {
  81. "Effect": "Allow",
  82. "Action": [f"s3:{action.value}*" for action in actions],
  83. "Resource": [
  84. f"arn:aws:s3:::{get_user_dir(bucket_name, user)}/*",
  85. ],
  86. }
  87. ],
  88. }
  89. policy_name = f"{user}-{bucket_name}-full-access"
  90. policy_json = json.dumps(policy_document)
  91. filepath = f"/tmp/{policy_name}.json"
  92. with open(filepath, "w") as f:
  93. f.write(json.dumps(policy_document, indent=2))
  94. iam_client.put_user_policy(
  95. PolicyName=policy_name, PolicyDocument=policy_json, UserName=user
  96. )
  97. print(f"Policy for {user} on {bucket_name} created.")
  98. def main():
  99. parser = argparse.ArgumentParser(description="SeaweedFS S3 Test Script")
  100. parser.add_argument(
  101. "--s3-url", default="http://127.0.0.1:8333", help="S3 endpoint URL"
  102. )
  103. parser.add_argument(
  104. "--iam-url", default="http://127.0.0.1:8111", help="IAM endpoint URL"
  105. )
  106. args = parser.parse_args()
  107. bucket_name = (
  108. f"test-bucket-{''.join(random.choices(string.digits + 'abcdef', k=8))}"
  109. )
  110. sentinel_file = "/tmp/SENTINEL"
  111. with open(sentinel_file, "w") as f:
  112. f.write("Hello World")
  113. print(f"SENTINEL file created at {sentinel_file}")
  114. power_user_key, power_user_secret = create_power_user()
  115. admin_s3_client = get_s3_client(args, power_user_key, power_user_secret)
  116. iam_client = get_iam_client(args, power_user_key, power_user_secret)
  117. create_bucket(admin_s3_client, bucket_name)
  118. upload_file(admin_s3_client, bucket_name, "Alice", sentinel_file)
  119. upload_file(admin_s3_client, bucket_name, "Bob", sentinel_file)
  120. list_files(admin_s3_client, bucket_name)
  121. alice_user_info = create_user(iam_client, "Alice")
  122. bob_user_info = create_user(iam_client, "Bob")
  123. alice_key = alice_user_info["AccessKey"]["AccessKeyId"]
  124. alice_secret = alice_user_info["AccessKey"]["SecretAccessKey"]
  125. bob_key = bob_user_info["AccessKey"]["AccessKeyId"]
  126. bob_secret = bob_user_info["AccessKey"]["SecretAccessKey"]
  127. # Make sure Admin can read any files
  128. list_files(admin_s3_client, bucket_name)
  129. list_files(
  130. admin_s3_client,
  131. bucket_name,
  132. get_user_dir(bucket_name, "Alice", with_bucket=False),
  133. )
  134. list_files(
  135. admin_s3_client,
  136. bucket_name,
  137. get_user_dir(bucket_name, "Bob", with_bucket=False),
  138. )
  139. # Create read policy for Alice and Bob
  140. create_policy_for_user(iam_client, "Alice", bucket_name)
  141. create_policy_for_user(iam_client, "Bob", bucket_name)
  142. alice_s3_client = get_s3_client(args, alice_key, alice_secret)
  143. # Make sure Alice can read her files
  144. list_files(
  145. alice_s3_client,
  146. bucket_name,
  147. get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
  148. )
  149. # Make sure Bob can read his files
  150. bob_s3_client = get_s3_client(args, bob_key, bob_secret)
  151. list_files(
  152. bob_s3_client,
  153. bucket_name,
  154. get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
  155. )
  156. # Update policy to include write
  157. create_policy_for_user(iam_client, "Alice", bucket_name, actions=[Actions.Put, Actions.Get, Actions.List]) # fmt: off
  158. create_policy_for_user(iam_client, "Bob", bucket_name, actions=[Actions.Put, Actions.Get, Actions.List]) # fmt: off
  159. print("############################# Make sure Alice can write her files")
  160. upload_file(
  161. alice_s3_client,
  162. bucket_name,
  163. "Alice",
  164. sentinel_file,
  165. custom_remote_path=f"{get_user_dir(bucket_name, 'Alice', with_bucket=False)}/SENTINEL_by_Alice",
  166. )
  167. print("############################# Make sure Bob can write his files")
  168. upload_file(
  169. bob_s3_client,
  170. bucket_name,
  171. "Bob",
  172. sentinel_file,
  173. custom_remote_path=f"{get_user_dir(bucket_name, 'Bob', with_bucket=False)}/SENTINEL_by_Bob",
  174. )
  175. print("############################# Make sure Alice can read her new files")
  176. list_files(
  177. alice_s3_client,
  178. bucket_name,
  179. get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
  180. )
  181. print("############################# Make sure Bob can read his new files")
  182. list_files(
  183. bob_s3_client,
  184. bucket_name,
  185. get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
  186. )
  187. print("############################# Make sure Bob cannot read Alice's files")
  188. list_files(
  189. bob_s3_client,
  190. bucket_name,
  191. get_user_dir(bucket_name, "Alice", with_bucket=False) + "/",
  192. )
  193. print("############################# Make sure Alice cannot read Bob's files")
  194. list_files(
  195. alice_s3_client,
  196. bucket_name,
  197. get_user_dir(bucket_name, "Bob", with_bucket=False) + "/",
  198. )
  199. def get_iam_client(args, access_key, secret_key):
  200. iam_client = boto3.client(
  201. "iam",
  202. endpoint_url=args.iam_url,
  203. region_name=REGION_NAME,
  204. aws_access_key_id=access_key,
  205. aws_secret_access_key=secret_key,
  206. )
  207. return iam_client
  208. def get_s3_client(args, access_key, secret_key):
  209. s3_client = boto3.client(
  210. "s3",
  211. endpoint_url=args.s3_url,
  212. region_name=REGION_NAME,
  213. aws_access_key_id=access_key,
  214. aws_secret_access_key=secret_key,
  215. )
  216. return s3_client
  217. if __name__ == "__main__":
  218. main()