ablog

不器用で落着きのない技術者のメモ

AWS CLI で 1TB の S3 オブジェクトをリスト表示する

準備

$ sudo mkfs -t ext4 /dev/sdb
$ sudo mkdir /ebs
$ sudo chmod o+w /ebs
$ sudo vi /etc/fstab
$ sudo mount -a
$ df -h
  • 1TBのファイルを作成する
$ nohup time dd if=/dev/urandom of=/ebs/1tb.dat bs=1M count=1048576 &
$ ls -l 1tb.dat
-rw-rw-r-- 1 ec2-user ec2-user 1099511627776 Jun  9 11:23 1tb.dat
$ ls -lh 1tb.dat
-rw-rw-r-- 1 ec2-user ec2-user 1.0T Jun  9 11:23 1tb.dat
  • 1TBのファイルをS3にアップロードする
$ aws configure set default.s3.multipart_chunksize 128MB
$ aws configure set default.s3.max_concurrent_requests 32
$ nohup time aws s3 cp 1tb.dat s3://az-20190609/ &

AWS CLI で表示する

  • S3 にアップロードしたファイル(オブジェクト)をリスト表示する。
$ aws s3 ls s3://az-20190609/1tb.dat
2019-06-09 11:36:01 1099511627776★ 1tb.dat
$ aws s3 ls --human-readable s3://az-20190609/1tb.dat
2019-06-09 11:36:01    1.0 TiB★ 1tb.dat

AWS CLI の出力箇所

class ListCommand(S3Command):
    NAME = 'ls'
    DESCRIPTION = ("List S3 objects and common prefixes under a prefix or "
                   "all S3 buckets. Note that the --output and --no-paginate "
                   "arguments are ignored for this command.")
    USAGE = "<S3Uri> or NONE"
    ARG_TABLE = [{'name': 'paths', 'nargs': '?', 'default': 's3://',
                  'positional_arg': True, 'synopsis': USAGE}, RECURSIVE,
                 PAGE_SIZE, HUMAN_READABLE, SUMMARIZE, REQUEST_PAYER]

    def _run_main(self, parsed_args, parsed_globals):
        super(ListCommand, self)._run_main(parsed_args, parsed_globals)
        self._empty_result = False
        self._at_first_page = True
        self._size_accumulator = 0
        self._total_objects = 0
        self._human_readable = parsed_args.human_readable
        path = parsed_args.paths
        if path.startswith('s3://'):
            path = path[5:]
        bucket, key = find_bucket_key(path)
        if not bucket:
            self._list_all_buckets()
        elif parsed_args.dir_op:
            # Then --recursive was specified.
            self._list_all_objects_recursive(
                bucket, key, parsed_args.page_size, parsed_args.request_payer)
        else:
            self._list_all_objects( ★
                bucket, key, parsed_args.page_size, parsed_args.request_payer)
        if parsed_args.summarize:
            self._print_summary()
        if key:
            # User specified a key to look for. We should return an rc of one
            # if there are no matching keys and/or prefixes or return an rc
            # of zero if there are matching keys or prefixes.
            return self._check_no_objects()
        else:
            # This covers the case when user is trying to list all of of
            # the buckets or is trying to list the objects of a bucket
            # (without specifying a key). For both situations, a rc of 0
            # should be returned because applicable errors are supplied by
            # the server (i.e. bucket not existing). These errors will be
            # thrown before reaching the automatic return of rc of zero.
            return 0

    def _list_all_objects(self, bucket, key, page_size=None, ★
                          request_payer=None):
        paginator = self.client.get_paginator('list_objects_v2')
        paging_args = {
            'Bucket': bucket, 'Prefix': key, 'Delimiter': '/',
            'PaginationConfig': {'PageSize': page_size}
        }
        if request_payer is not None:
            paging_args['RequestPayer'] = request_payer
        iterator = paginator.paginate(**paging_args)
        for response_data in iterator:
            self._display_page(response_data) ★

    def _display_page(self, response_data, use_basename=True):
        common_prefixes = response_data.get('CommonPrefixes', [])
        contents = response_data.get('Contents', []) ★
        if not contents and not common_prefixes:
            self._empty_result = True
            return
        for common_prefix in common_prefixes:
            prefix_components = common_prefix['Prefix'].split('/')
            prefix = prefix_components[-2]
            pre_string = "PRE".rjust(30, " ")
            print_str = pre_string + ' ' + prefix + '/\n'
            uni_print(print_str)
        for content in contents:
            last_mod_str = self._make_last_mod_str(content['LastModified'])
            self._size_accumulator += int(content['Size'])
            self._total_objects += 1
            size_str = self._make_size_str(content['Size'])
            if use_basename:
                filename_components = content['Key'].split('/')
                filename = filename_components[-1]
            else:
                filename = content['Key']
            print_str = last_mod_str + ' ' + size_str + ' ' + \ ★
                filename + '\n'
            uni_print(print_str)
        self._at_first_page = False

(中略)

    def _make_size_str(self, size):
        """
        This function creates the size string when objects are being listed.
        """
        if self._human_readable:
            size_str = human_readable_size(size)
        else:
            size_str = str(size) ★
        return size_str.rjust(10, ' ') ★

str.rjust(width[, fillchar])
width の長さをもつ右寄せした文字列を返します。パディングには fillchar で指定された文字(デフォルトではスペース)が使われます。 width が len(s) 以下の場合、元の文字列が返されます。

バージョン 2.4 で変更: 引数 fillchar に対応.

5. 組み込み型 — Python 2.7.16 ドキュメント

CloudWatchメトリクス

f:id:yohei-a:20190609224505p:plain
f:id:yohei-a:20190609224530p:plain
f:id:yohei-a:20190609224509p:plain
f:id:yohei-a:20190609224517p:plain
f:id:yohei-a:20190609224523p:plain

1オブジェクトの最大サイズは 5TB

  • 1 回のオペレーションでオブジェクトをアップロードする — 1 回の PUT オペレーションでアップロードできるオブジェクトの最大サイズは 5 GB です。詳細については、「1 回のオペレーションでのオブジェクトのアップロード」を参照してください。
  • オブジェクトをいくつかに分けてアップロードする — マルチパートアップロード API を使用すると、最大 5 TB の大容量オブジェクトをアップロードできます。
オブジェクトのアップロード - Amazon Simple Storage Service