Pubblicato il 02/09/2023 da alnao nella categoria AWS

Simple Storage Service, abbreviato con la sigla S3, è il principale servizio di archiviazione del servizio Cloud di AWS, studiato per memorizzare e recuperare qualsiasi volume di dati, in qualunque momento e da qualunque luogo. Le caratteristiche principali del servizio sono: gli oggetti sono salvati in contenitori chiamati bucket (non a caso il logo di questo servizio è proprio un secchio), ogni elemento ha un nome (key), gli oggetti sono organizzati in strutture (path), l’accesso agli oggetti può essere personalizzato grazie a regole IAM, gli accessi possono essere salvati in registri specifici nel servizio CloudWatch. E’ possibile cancellare o spostare oggetti e il servizio permette di attivare il sistema di versioning per avere la storia di tutti gli oggetti. Per qualsiasi informazione e approfondimenti si può fare riferimento alla pagina dedicata al servizio S3 nel sito ufficiale.


La AWS-CLI mette a disposizione tutta una serie di comandi per la gestione dei bucket e degli oggetti, in particolare “mb” può essere usato per creare bucket:

$ aws s3 mb s3://bucket-name

ricordandosi che il nome deve essere globalmente unico (globally unique unique across all of Amazon S3) e deve rispettare le regole imposte da AWS. La lista dei bucket disponibili si recupera con il comando:

$ aws s3 ls

e per cancellare un bucket (che non contiene nessun oggetto) si usa il comando rb:

$ aws s3 rb s3://bucket-name

Per ottenere la lista di tutti gli oggetti contenuti in un bucket:

$ aws s3 ls bucket-name

E per muovere oggetti tra bucket o scaricare un oggetto cancellandolo si usa la sintassi:

$ aws s3 mv s3://bucket-name/example.txt s3://bucket-name2/
$ aws s3 mv s3://bucket-name/filename.txt ./

Mentre per copiare tra bucket o dal sistema locale da/per un bucket si usa la sintassi:

$ aws s3 cp s3://bucket-name/example.txt s3://my-bucket/
$ aws s3 cp ./filename.txt s3://bucket-name
$ aws s3 cp s3://bucket-name/filename.txt ./

I comandi possono essere combinati con i comandi Linux, per esempio per scrivere o leggere un oggetto:

$ echo "hello world" | aws s3 cp - s3://bucket-name/filename.txt
$ aws s3 cp s3://bucket-name/filename.txt -

Il comando Sync permette di tenere sincronizzato una cartella locale con un bucket, quindi eventuali orfani vengono cancellati e nuovi file vengono copiati, la sintassi preve solo la cartella sorgente e il bucket di destinazione:

$ aws s3 sync . s3://my-bucket/path

Per svuotare un bucket da tutti gli oggetti contenuti si può usare il comando rm con il parametro ricorsivo:

$ aws s3 rm s3://my-bucket/path --recursive

è ovvio che bisogna sempre prestate attenzione a questo ultimo comandi in quanto rimuove tutti gli oggetti e, senza sistema di versionamento attivo, gli oggetti vengono cancellati in maniera permanente. Tutti i parametri e le caratteristiche di questo comando sono disponibili alla pagina della documentazione ufficiale.


I template CloudFormation spesso hanno al proprio interno definizione o riferimenti a bucket S3, il tipo specifico AWS::S3::Bucket che ha come unico parametro obbligatorio il nome (che deve sempre rispettare le regole previste da AWS)

Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !Ref NomeBucket

La documentazione ufficiale è ricca di esempi e può essere sempre consultata come fonte principale di informazioni. Il più semplice esempio è la gestione di siti web esposti dallo stesso servizio S3 senza l’uso di CloudFront o altri servizi dedicati, ispirato alla documentazione ufficiale con in aggiunta le regole ACL, nel template è indispensabile aggiungere la regola di accesso al bucket tramite un oggetto di tipo BucketPolicy:

S3BucketPolicy:
  Type: AWS::S3::BucketPolicy
  Properties:
    Bucket: !Ref NomeBucket
    PolicyDocument:
    Version: 2012-10-17
    Statement:
     - Sid: AllowSSLRequestsOnly
       Action: 's3:GetObject'
       Effect: Allow
       Resource: !Join
         - ''
         - - 'arn:aws:s3:::'
           - !Ref NomeBucket
           - /*
       Principal: '*'

L’esempio completo funzionante può essere trovato al solito repository

github.com/alnao/AWSCloudFormationExamples/tree/master/Esempio03bucketS3sito

La libreria CDK mette a disposizione classi per la gestione dei bucket, la documentazione ufficiale è ricca di esempi pratici. Per il linguaggio Java la principale risorsa è proprio il builder di Bucket:

Bucket bucket = Bucket.Builder.create(this, "MyBucket")
  .versioned(true)
  .encryption(BucketEncryption.KMS_MANAGED)
  .build();

Per il linguaggio Python la creazione di bucket è ancora più semplice, un esempio ripreso dalla guida ufficiale:

from aws_cdk import (aws_s3 as s3,core)
class MyStack(core.Stack):
  def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
  super().__init__(scope, id, **kwargs)
  # Create an S3 bucket
  bucket = s3.Bucket(self, "MyBucket",
    bucket_name="my-unique-bucket-name",#unique bucket name
    versioned=True, # enable versioning for the bucket
    encryption=s3.BucketEncryption.S3_MANAGED
  )
app = core.App()
MyStack(app, "MyStack")
app.synth()

La libreria SDK è ricca di classi e metodi per la gestione dei bucket e dei contenuti, per il linguaggio di programmazione Python il sito ufficiale mette a disposizione diversi esempi i principali metodi messi a disposizione del servizio S3 sono:

def bucket_list(profile_name):
  boto3.setup_default_session(profile_name=profile_name)
  s3_client = boto3.client("s3")
  return s3_client.list_buckets()["Buckets"]
def object_list(bucket_name, path):
  s3_client = boto3.client("s3")
  response={"objects":[],"folders":[]}
  response["objects"]=[]
  response["folders"]=[]
  if not path: #objects = list(bucket.objects.all())
    response = s3_client.list_objects_v2(
      Bucket=bucket_name, Delimiter="/",
    )
    if "Contents" in response:
      response["objects"]=response["Contents"]
    if "CommonPrefixes" in response:
      response["folders"]=response["CommonPrefixes"]
  else: #objects = list(bucket.objects.filter(Prefix=path))
    response = s3_client.list_objects_v2(
      Bucket=bucket_name, Delimiter="/",
      Prefix=path,
    )
    if "Contents" in response:
      response["objects"]=response["Contents"]
    if "CommonPrefixes" in response:
      response["folders"]=response["CommonPrefixes"]
  return rimuovi_folder_padre(path,response)
def object_list_paginator(bucket_name, path):
  s3_client = boto3.client("s3")
  response={"objects":[],"folders":[]}
  response["objects"]=[]
  response["folders"]=[]
  s3_paginator = s3_client.get_paginator('list_objects_v2')
  for page in s3_paginator.paginate(Bucket=bucket_name, Prefix=path,
        Delimiter='/'): #, StartAfter=start_after):
    if "Contents" in page:
      response["objects"]=response["objects"] + page["Contents"] 
    if "CommonPrefixes" in page:
     response["folders"]=response["folders"] + page["CommonPrefixes"]
  return rimuovi_folder_padre(path,response)
def rimuovi_folder_padre(folder_name, list):
  s3_client = boto3.client("s3")
  el={}
  to_remove=False
  if "objects" in list:
    for o in list["objects"]:
      if o["Key"]==folder_name or o["Key"]==folder_name+"/" :
        el=o
        to_remove=True
  if to_remove:
    list["objects"].remove(el)
  return list
def content_object_text(bucket_name, key):
  s3_client = boto3.client("s3")
  content=s3_client.get_object(Bucket=bucket_name,Key=key)["Body"].iter_lines()
  lista=[]
  for line in content:
    lista.append(str(line.decode("utf-8")))
  return lista
def content_object_presigned(bucket_name, key):
  s3_client_p = boto3.client('s3',region_name="eu-west-1",
     config=boto3.session.Config(signature_version='s3v4',))
  response = s3_client_p.generate_presigned_url('get_object', 
     Params={'Bucket': bucket_name, 'Key':key},ExpiresIn=3600)
  return response
def write_test_file(bucket_name, key, body):
  s3_client = boto3.client("s3")
  OUT_string_encoded = body.encode("utf-8")
  s3_client.put_object(Bucket=bucket_name, Key=key, Body=OUT_string_encoded)
  return True
def delete_all_content_folder(bucket_name,path): 
  s3_client = boto3.client("s3")
  objects = s3_client.list_objects(Bucket=bucket_name, Prefix=path)
  i=0
  for object in objects['Contents']:
    s3_client.delete_object(Bucket=bucket_name, Key=object['Key'])
    i=i+1
  s3_client.delete_object(Bucket=bucket_name, Key=path)
  return i

Nel la libreria per il linguaggio Java le classi disponibili sono nel package:

software.amazon.awssdk.services.s3

Per esempio per ottenere la lista completa di tutti i bucket si può usare il semplice metodo:

S3Client client = S3Client.builder().build();
...
public static List<Bucket> getBucketList(S3Client s3Client){
  ArrayList<Bucket> l=new ArrayList<Bucket>();
  ListBucketsRequest listBucketsRequest = ListBucketsRequest.builder().build();
  ListBucketsResponse listBuckets = s3Client.listBuckets(listBucketsRequest);
  listBuckets.buckets().stream().forEach(x -> l.add(x));
  return l;
}

Un semplice esempio dei vari metodi messi a disposizione della libreria può essere trovato al solito repository oppure mella documentazione ufficiale sono disponibili molti esempi di gestione dei bucket

MENU