update metadata in s3 - python

I use Amazon boto v2.38 to write python script to access my S3 bucket.
I want to update a file in my bucket (I know it is called "key" in S3). The path is MyBucket/myfile/demo.txt . Besides, I want to also update its metadata named "name". Here is the code I tried:
# connect to key
conn = boto.connect_s3()
bucket = conn.get_bucket("MyBucket")
my_key = Key(bucket)
my_key.key = "myfile/demo.txt"
# if key exists, then update the file & its metadata
if my_key.exists():
new_meta_data = {"name": "xyz"}
# update metadata
my_key.copy("MyBucket", my_key.name, new_meta_data, preserve_acl=True)
# update file content in S3 by using the local file demo.txt
my_key.set_contents_from_filename("demo.txt")
However, it doesn't work... I don't see metadata get updated. Why?

You can just update the key's local metadata and then perform the file update:
import boto
conn = boto.connect_s3()
bucket = conn.get_bucket("MyBucket")
key = bucket.get_key('myfile/demo.txt')
key.set_metadata('name', 'xyz')
key.set_contents_from_filename('demo.txt')
Now name should appear as metadata within S3. Note, however, that the ACL might change when you do this.
It can also be done with key.set_remote_metadata(). This does not require that you update the key's content (but you can if you want):
conn = boto.connect_s3()
bucket = conn.get_bucket('MyBucket')
key = bucket.get_key('myfile/demo.txt')
key.set_remote_metadata({'name': 'xyz'}, {}, True)

The following code change the key metadata in boto3:
import boto3 as aws
s3 = aws.resource('s3')
obj = s3.Bucket('MyBucket').Object('objectKey')
obj.put(Metadata={'name':'newName'}
According to the docs, set_metadata must be used. I have tested it and the foloowing code works with boto2 and changes the meatadata:
import boto as aws
cx=aws.connect_s3()
bucket=cx.get_bucket('MyBucket')
obj=bucket.get_key('objectKey')
obj.set_metadata('name', 'newName')

Using Boto3, be careful if using "put_object" with metadata, this will change your actual metadatas, if you want to to create Object with metadatas, then add metadata or update an existing metadata, use the below :
import sys
import os
import boto3
from boto3 import client
param_1= sys.argv[1]
param_2= sys.argv[2]
param_3= sys.argv[3]
param_4= sys.argv[4]
param_5= sys.argv[5]
objectNMAE='THIEF.jpg'
s3ressource = client(
service_name='s3',
endpoint_url= param_3,
aws_access_key_id= param_1,
aws_secret_access_key=param_2,
use_ssl=True,
)
def createmetdata(bucketname,objectname):
s3ressource.upload_file(objectname, bucketname, objectname, ExtraArgs={"Metadata": {"metadata1":"ImageName","metadata2":"ImagePROPERTIES" ,"metadata3":"ImageCREATIONDATE"}})
def ADDmetadata(bucketname,objectname):
s3_object = s3ressource.get_object(Bucket=bucketname, Key=objectname)
k = s3ressource.head_object(Bucket = bucketname, Key = objectname)
m = k["Metadata"]
m["new_metadata"] = "ImageNEWMETADATA"
s3ressource.copy_object(Bucket = bucketname, Key = objectname, CopySource = bucketname + '/' + objectname, Metadata = m, MetadataDirective='REPLACE')
def CHANGEmetadata(bucketname,objectname):
s3_object = s3ressource.get_object(Bucket=bucketname, Key=objectname)
k = s3ressource.head_object(Bucket = bucketname, Key = objectname)
m = k["Metadata"]
m.update({'metadata3':'ImageCREATIONDATEEEEEEEEEEEEEEEEEEEEEEEEEE'})
s3ressource.copy_object(Bucket = bucketname, Key = objectname, CopySource = bucketname + '/' + objectname, Metadata = m, MetadataDirective='REPLACE')
def readmetadata (bucketname,objectname):
ALLDATAOFOBJECT = s3ressource.get_object(Bucket=bucketname, Key=objectname)
ALLDATAOFOBJECTMETADATA=ALLDATAOFOBJECT['Metadata']
print ALLDATAOFOBJECTMETADATA
createmetdata(param_4,objectNMAE)
readmetadata(param_4,objectNMAE)
ADDmetadata(param_4,objectNMAE)
readmetadata(param_4,objectNMAE)
CHANGEmetadata(param_4,objectNMAE)
readmetadata(param_4,objectNMAE)

Related

Possible to use boto3/SDK service resource cross account? [duplicate]

I'm trying to use the AssumeRole in such a way that i'm traversing multiple accounts and retrieving assets for those accounts. I've made it to this point:
import boto3
stsclient = boto3.client('sts')
assumedRoleObject = sts_client.assume_role(
RoleArn="arn:aws:iam::account-of-role-to-assume:role/name-of-role",
RoleSessionName="AssumeRoleSession1")
Great, i have the assumedRoleObject. But now i want to use that to list things like ELBs or something that isn't a built-in low level resource.
How does one go about doing that? If i may ask - please code out a full example, so that everyone can benefit.
Here's a code snippet from the official AWS documentation where an s3 resource is created for listing all s3 buckets. boto3 resources or clients for other services can be built in a similar fashion.
# create an STS client object that represents a live connection to the
# STS service
sts_client = boto3.client('sts')
# Call the assume_role method of the STSConnection object and pass the role
# ARN and a role session name.
assumed_role_object=sts_client.assume_role(
RoleArn="arn:aws:iam::account-of-role-to-assume:role/name-of-role",
RoleSessionName="AssumeRoleSession1"
)
# From the response that contains the assumed role, get the temporary
# credentials that can be used to make subsequent API calls
credentials=assumed_role_object['Credentials']
# Use the temporary credentials that AssumeRole returns to make a
# connection to Amazon S3
s3_resource=boto3.resource(
's3',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken'],
)
# Use the Amazon S3 resource object that is now configured with the
# credentials to access your S3 buckets.
for bucket in s3_resource.buckets.all():
print(bucket.name)
To get a session with an assumed role:
import botocore
import boto3
import datetime
from dateutil.tz import tzlocal
assume_role_cache: dict = {}
def assumed_role_session(role_arn: str, base_session: botocore.session.Session = None):
base_session = base_session or boto3.session.Session()._session
fetcher = botocore.credentials.AssumeRoleCredentialFetcher(
client_creator = base_session.create_client,
source_credentials = base_session.get_credentials(),
role_arn = role_arn,
extra_args = {
# 'RoleSessionName': None # set this if you want something non-default
}
)
creds = botocore.credentials.DeferredRefreshableCredentials(
method = 'assume-role',
refresh_using = fetcher.fetch_credentials,
time_fetcher = lambda: datetime.datetime.now(tzlocal())
)
botocore_session = botocore.session.Session()
botocore_session._credentials = creds
return boto3.Session(botocore_session = botocore_session)
# usage:
session = assumed_role_session('arn:aws:iam::ACCOUNTID:role/ROLE_NAME')
ec2 = session.client('ec2') # ... etc.
The resulting session's credentials will be automatically refreshed when required which is quite nice.
Note: my previous answer was outright wrong but I can't delete it, so I've replaced it with a better and working answer.
You can assume role using STS token, like:
class Boto3STSService(object):
def __init__(self, arn):
sess = Session(aws_access_key_id=ARN_ACCESS_KEY,
aws_secret_access_key=ARN_SECRET_KEY)
sts_connection = sess.client('sts')
assume_role_object = sts_connection.assume_role(
RoleArn=arn, RoleSessionName=ARN_ROLE_SESSION_NAME,
DurationSeconds=3600)
self.credentials = assume_role_object['Credentials']
This will give you temporary access key and secret keys, with session token. With these temporary credentials, you can access any service. For Eg, if you want to access ELB, you can use the below code:
self.tmp_credentials = Boto3STSService(arn).credentials
def get_boto3_session(self):
tmp_access_key = self.tmp_credentials['AccessKeyId']
tmp_secret_key = self.tmp_credentials['SecretAccessKey']
security_token = self.tmp_credentials['SessionToken']
boto3_session = Session(
aws_access_key_id=tmp_access_key,
aws_secret_access_key=tmp_secret_key, aws_session_token=security_token
)
return boto3_session
def get_elb_boto3_connection(self, region):
sess = self.get_boto3_session()
elb_conn = sess.client(service_name='elb', region_name=region)
return elb_conn
with reference to the solution by #jarrad which is not working as of Feb 2021, and as a solution that does not use STS explicitly please see the following
import boto3
import botocore.session
from botocore.credentials import AssumeRoleCredentialFetcher, DeferredRefreshableCredentials
def get_boto3_session(assume_role_arn=None):
session = boto3.Session(aws_access_key_id="abc", aws_secret_access_key="def")
if not assume_role_arn:
return session
fetcher = AssumeRoleCredentialFetcher(
client_creator=_get_client_creator(session),
source_credentials=session.get_credentials(),
role_arn=assume_role_arn,
)
botocore_session = botocore.session.Session()
botocore_session._credentials = DeferredRefreshableCredentials(
method='assume-role',
refresh_using=fetcher.fetch_credentials
)
return boto3.Session(botocore_session=botocore_session)
def _get_client_creator(session):
def client_creator(service_name, **kwargs):
return session.client(service_name, **kwargs)
return client_creator
the function can be called as follows
ec2_client = get_boto3_session(role_arn='my_role_arn').client('ec2', region_name='us-east-1')
If you want a functional implementation, this is what I settled on:
def filter_none_values(kwargs: dict) -> dict:
"""Returns a new dictionary excluding items where value was None"""
return {k: v for k, v in kwargs.items() if v is not None}
def assume_session(
role_session_name: str,
role_arn: str,
duration_seconds: Optional[int] = None,
region_name: Optional[str] = None,
) -> boto3.Session:
"""
Returns a session with the given name and role.
If not specified, duration will be set by AWS, probably at 1 hour.
If not specified, region will be left unset.
Region can be overridden by each client or resource spawned from this session.
"""
assume_role_kwargs = filter_none_values(
{
"RoleSessionName": role_session_name,
"RoleArn": role_arn,
"DurationSeconds": duration_seconds,
}
)
credentials = boto3.client("sts").assume_role(**assume_role_kwargs)["Credentials"]
create_session_kwargs = filter_none_values(
{
"aws_access_key_id": credentials["AccessKeyId"],
"aws_secret_access_key": credentials["SecretAccessKey"],
"aws_session_token": credentials["SessionToken"],
"region_name": region_name,
}
)
return boto3.Session(**create_session_kwargs)
def main() -> None:
session = assume_session(
"MyCustomSessionName",
"arn:aws:iam::XXXXXXXXXXXX:role/TheRoleIWantToAssume",
region_name="us-east-1",
)
client = session.client(service_name="ec2")
print(client.describe_key_pairs())
import json
import boto3
roleARN = 'arn:aws:iam::account-of-role-to-assume:role/name-of-role'
client = boto3.client('sts')
response = client.assume_role(RoleArn=roleARN,
RoleSessionName='RoleSessionName',
DurationSeconds=900)
dynamodb_client = boto3.client('dynamodb', region_name='us-east-1',
aws_access_key_id=response['Credentials']['AccessKeyId'],
aws_secret_access_key=response['Credentials']['SecretAccessKey'],
aws_session_token = response['Credentials']['SessionToken'])
response = dynamodb_client.get_item(
Key={
'key1': {
'S': '1',
},
'key2': {
'S': '2',
},
},
TableName='TestTable')
print(response)
#!/usr/bin/env python3
import boto3
sts_client = boto3.client('sts')
assumed_role = sts_client.assume_role(RoleArn = "arn:aws:iam::123456789012:role/example_role",
RoleSessionName = "AssumeRoleSession1",
DurationSeconds = 1800)
session = boto3.Session(
aws_access_key_id = assumed_role['Credentials']['AccessKeyId'],
aws_secret_access_key = assumed_role['Credentials']['SecretAccessKey'],
aws_session_token = assumed_role['Credentials']['SessionToken'],
region_name = 'us-west-1'
)
# now we make use of the role to retrieve a parameter from SSM
client = session.client('ssm')
response = client.get_parameter(
Name = '/this/is/a/path/parameter',
WithDecryption = True
)
print(response)
Assuming that 1) the ~/.aws/config or ~/.aws/credentials file is populated with each of the roles that you wish to assume and that 2) the default role has AssumeRole defined in its IAM policy for each of those roles, then you can simply (in pseudo-code) do the following and not have to fuss with STS:
import boto3
# get all of the roles from the AWS config/credentials file using a config file parser
profiles = get_profiles()
for profile in profiles:
# this is only used to fetch the available regions
initial_session = boto3.Session(profile_name=profile)
# get the regions
regions = boto3.Session.get_available_regions('ec2')
# cycle through the regions, setting up session, resource and client objects
for region in regions:
boto3_session = boto3.Session(profile_name=profile, region_name=region)
boto3_resource = boto3_session.resource(service_name='s3', region_name=region)
boto3_client = boto3_session.client(service_name='s3', region_name=region)
[ do something interesting with your session/resource/client here ]
Credential Setup (boto3 - Shared Credentials File)
Assume Role Setup (AWS)
After a few days of searching, this is the simplest solution I have found. explained here but does not have a usage example.
import boto3
for profile in boto3.Session().available_profiles:
boto3.DEFAULT_SESSION = boto3.session.Session(profile_name=profile)
s3 = boto3.resource('s3')
for bucket in s3.buckets.all():
print(bucket)
This will switch the default role you will be using. To not make the profile the default, just do not assign it to boto3.DEFAULT_SESSION. but instead, do the following.
testing_profile = boto3.session.Session(profile_name='mainTesting')
s3 = testing_profile.resource('s3')
for bucket in s3.buckets.all():
print(bucket)
Important to note that the .aws credentials need to be set in a specific way.
[default]
aws_access_key_id = default_access_id
aws_secret_access_key = default_access_key
[main]
aws_access_key_id = main_profile_access_id
aws_secret_access_key = main_profile_access_key
[mainTesting]
source_profile = main
role_arn = Testing role arn
mfa_serial = mfa_arn_for_main_role
[mainProduction]
source_profile = main
role_arn = Production role arn
mfa_serial = mfa_arn_for_main_role
I don't know why but the mfa_serial key has to be on the roles for this to work instead of the source account which would make more sense.
Here's the code snippet I used
sts_client = boto3.client('sts')
assumed_role_object = sts_client.assume_role(
RoleArn=<arn of the role to assume>,
RoleSessionName="<role session name>"
)
print(assumed_role_object)
credentials = assumed_role_object['Credentials']
session = Session(
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken']
)
self.s3 = session.client('s3')

Delete CloudTrail along with the S3 bucket attached to it using Boto3

I am working on a python script to delete a CloudTrail along with the S3 bucket associated with it, I am not getting any error but the code also does not delete the S3 bucket.I am able to delete the cloudtrail. This is the code that I have:
def lambda_handler(event, context):
import boto3
import pprint
client=boto3.client('ec2')
s3_resource=boto3.client('s3')
all_regions=client.describe_regions()
#pprint.pprint(all_regions)
list_of_regions=[]
del_list = []
Bucket_names=[]
for each_reg in all_regions['Regions']:
list_of_regions.append(each_reg['RegionName'])
#print(each_reg['RegionName'])
#print(list_of_regions)
for each_reg in list_of_regions:
client = boto3.client('cloudtrail', region_name=each_reg)
trailnames=[trail['TrailARN'] for trail in client.list_trails()['Trails']]
#print(trailnames,each_reg)#List out the Trails Name
for data in trailnames:
#print(data)
response = client.describe_trails(trailNameList=[data])
#print(response)
Bucket_Name =response['trailList'][0].get('S3BucketName')
#print(Bucket_Name)
Bucket_names.append(Bucket_Name)
#print(Bucket_Name)
#home_region = response['trailList'][0].get('HomeRegion')
#print(home_region)
#home_client = boto3.client('cloudtrail', region_name=home_region)
#print(home_client)
#del_response =home_client.delete_trail(Name=data)
#print(data)
for buckets in Bucket_names:
s3_resource = boto3.client('s3', region_name=each_reg)
#print(buckets)
objects = s3_resource.list_objects(Bucket=buckets)['Contents']
#print(objects)
#a=objects
#print(a[5].get('Key'))
file_key_name=objects[0].get('Key')
#print(file_key_name)
copy_source_bucket = {'Bucket': buckets, 'Key': file_key_name}
#s3_resource.copy(copy_source_bucket, buckets, file_key_name, ExtraArgs={'ACL': 'bucket-owner-full-control'})
copy_objectss=s3_resource.copy_object(Bucket = buckets, Key = file_key_name, CopySource = copy_source_bucket,ACL='bucket-owner-full-control',MetadataDirective='REPLACE')
print(copy_objectss)
s3_del = client.delete_bucket(
Bucket='buckets'
)
I feel you need to purge all the objects in the S3 bucket before deleting the bucket, see this link for how to delete all objects in a bucket: https://stackoverflow.com/a/43328646/431432

java.nio.file.AccessDeniedException while reading csv from S3

We are trying to read some partners data from their S3 using spark. We have the following code set up for that puprose:
S3_BUCKET = 'BUCKET_NAME'
ROLE_SESSION_NAME = 'SESSION_NAME'
BASE_ROLE_ARN = 'BASE_ROLE_ARN/'
ROLE_ARN = BASE_ROLE_ARN + ROLE_NAME
DURATION_SECONDS = 3600
client = boto3.client('sts')
role = client.assume_role(
RoleArn=ROLE_ARN,
RoleSessionName=ROLE_SESSION_NAME,
DurationSeconds=DURATION_SECONDS,
ExternalId=EXTERNAL_ID
)
s3_session = boto3.session.Session(
aws_access_key_id=role['Credentials']['AccessKeyId'],
aws_secret_access_key=role['Credentials']['SecretAccessKey'],
aws_session_token=role['Credentials']['SessionToken']
)
s3_credentials = s3_session.get_credentials().get_frozen_credentials()
s3_key = s3_credentials.access_key
s3_secret = s3_credentials.secret_key
s3_session_token = s3_credentials.token
We then use the following code to read the data:
input_path = 's3a://some_input_path/'
input_data = spark_sql_context.read.csv(input_path, header = True)
Also, we make sure that everything is set correctly as for spark config:
spark_context._jsc.hadoopConfiguration().set(
"fs.s3a.access.key", s3_key
)
spark_context._jsc.hadoopConfiguration().set(
"fs.s3a.secret.key", s3_secret
)
spark_context._jsc.hadoopConfiguration().set(
"fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.TemporaryAWSCredentialsProvider"
)
spark_context._jsc.hadoopConfiguration().set(
"fs.s3a.session.token", s3_session_token
)
But when trying to read the data, we see the following exception:
: java.nio.file.AccessDeniedException: s3a://the_input_path: getFileStatus on s3a://the_input_path: com.amazonaws.services.s3.model.AmazonS3Exception: Forbidden (Service: Amazon S3; Status Code: 403; Error Code: 403 Forbidden; Request ID: F08F9B987FF8DED9; S3 Extended Request ID: TRjfFjALAk7phRDxKdUlucY4yocQY2mNO4r7N6Qf9fSDzSa+TpZfimwbAzXdU+s11BBLBblfgik=), S3 Extended Request ID: TRjfFjALAk7phRDxKdUlucY4yocQY2mNO4r7N6Qf9fSDzSa+TpZfimwbAzXdU+s11BBLBblfgik=:403 Forbidden
at org.apache.hadoop.fs.s3a.S3AUtils.translateException(S3AUtils.java:218)
at org.apache.hadoop.fs.s3a.S3AUtils.translateException(S3AUtils.java:145)
at org.apache.hadoop.fs.s3a.S3AFileSystem.s3GetFileStatus(S3AFileSystem.java:2184)
at org.apache.hadoop.fs.s3a.S3AFileSystem.innerGetFileStatus(S3AFileSystem.java:2149)
at org.apache.hadoop.fs.s3a.S3AFileSystem.getFileStatus(S3AFileSystem.java:2088)
at org.apache.hadoop.fs.FileSystem.exists(FileSystem.java:1683)
at org.apache.hadoop.fs.s3a.S3AFileSystem.exists(S3AFileSystem.java:2976)
This gets more weird as the following code snippet works just fine:
import os
import boto3
import sys
ROLE_NAME = 'ROLE_NAME'
EXTERNAL_ID = 'EXTERNAL_ID'
S3_BUCKET = 'BUCKET_NAME'
# ------------------------------------------------ DO NOT ALTER BELOW ------------------------------------------------ #
ROLE_SESSION_NAME = 'SESSION_NAME'
BASE_ROLE_ARN = 'BASE_ROLE_ARN'
ROLE_ARN = BASE_ROLE_ARN + ROLE_NAME
DURATION_SECONDS = 3600
client = boto3.client('sts')
role = client.assume_role(
RoleArn=ROLE_ARN,
RoleSessionName=ROLE_SESSION_NAME,
DurationSeconds=DURATION_SECONDS,
ExternalId=EXTERNAL_ID
)
session = boto3.session.Session(
aws_access_key_id=role['Credentials']['AccessKeyId'],
aws_secret_access_key=role['Credentials']['SecretAccessKey'],
aws_session_token=role['Credentials']['SessionToken']
)
S3 = session.resource('s3')
my_bucket = S3.Bucket(S3_BUCKET)
for object_summary in my_bucket.objects.filter(Prefix='SOME_PREFIX'):
print (object_summary.key)
Any idea why we might be seeing that exception while trying to read files from the S3 path using spark? Are we missing something?

Automate BigQuery schema/table creation from csv file using Python

I want to automatically create BQ table/s from a desktop folder containing csv files( i.e Automatically create schema and load to a new table)
If the same file is loaded next time just update the existing table, if a new file is loaded then create a new table. Is it possible to automate using Python?.
Current Code:
import pandas as pd
from google.cloud import bigquery
def bqDataLoad(event, context):
bucketName = event['test_vs']
blobName = event['gf-dev-models']
fileName = "gs://" + bucketName + "/" + blobName
bigqueryClient = bigquery.Client()
tableRef = bigqueryClient.dataset("gf-dev-models-204097").table("test_vs")
dataFrame = pd.read_csv(fileName) bigqueryJob = bigqueryClient.load_table_from_dataframe(dataFrame, tableRef) bigqueryJob.result()
#Project id = gf-dev-models
#dataset = gf-dev-models-204097
#table name = want a new table created
Here is my answer with reference to your question in the comment section:
Credential in Code:
You can create a service account with desired BigQuery roles and download JSON key file (example: data-lab.json).
import os
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = "data-lab.json"
Create Schema Automatically & Loading data to BigQuery:
from google.cloud import bigquery
bigqueryClient = bigquery.Client()
jobConfig = bigquery.LoadJobConfig()
jobConfig.skip_leading_rows = 1
jobConfig.source_format = bigquery.SourceFormat.CSV
jobConfig.write_disposition = bigquery.WriteDisposition.WRITE_APPEND
jobConfig.autodetect=True
datasetName = "dataset-name"
targetTable = "table-name"
uri = "gs://bucket-name/file-name.csv"
tableRef = bigqueryClient.dataset(datasetName).table(targetTable)
bigqueryJob = bigqueryClient.load_table_from_uri(uri, tableRef, job_config=jobConfig)
bigqueryJob.result()

Not printing the statement: print('FaceId: ',index_response['FaceRecords'][0]['Face']['FaceId'])

I have executed complete code..but not priting the last 'print statement'. Someone can help me out..I have uploaded all the pictures into AWS s3 bucket.
import boto3
s3_client = boto3.client('s3', aws_access_key_id='xxxxxxxxxxxxx',
aws_secret_access_key='xxxxxxxxxxxxxxxxx',)
collectionId='xxxxxxxxx' #collection name
rek_client=boto3.client('rekognition', aws_access_key_id='xxxxxxxxxx',
aws_secret_access_key='xxxxxxxxxxxxxxx',)
bucket = 'xxxxxxxxxxx' #S3 bucket name
all_objects = s3_client.list_objects(Bucket =bucket )
for content in all_objects['Contents']:
collection_name, sep, collection_image =content['Key'].parition('/')
label = collection_name
print('indexing: ',label)
if collection_image:
image = content['Key']
index_response=rek_client.index_faces(CollectionId=collectionId,
Image={'S3Object': 'Bucket':bucket,'Name':image}},
ExternalImageId=label,
MaxFaces=1,
QualityFilter="AUTO", DetectionAttributes=['ALL'])
print('FaceId: ',index_response['FaceRecords'][0]['Face']['FaceId'])

Categories