[Cloudian #8] Python(boto3)で、バケットのバージョニング設定をしてみる


## はじめに
[Cloudian](https://cloudian.com/jp/)は、AWSのS3完全互換のAPIを持ったオブジェクトストレージです。
[前回](https://qiita.com/yamahiro/items/350b6b31e0a3ea8d16ff)は、Python(boto3)で、バケットを削除してみました。

今回は、Python(boto3)で、オブジェクトストレージのバケットのバージョニング設定を行っていこうと思います。


## バケットのバージョニング設定
バージョニング機能を有効にして、その動作を確認します。  
バケット 「pythonbucket2」は、既に作成されており存在しているものとします。


## 1. バケットのバージョニングを有効化 / put_bucket_versioning()
put_bucket_versioning()の引数に、バージョニングの状態を変更するバケット名と変更する状態(ここでは’Enabled’)を渡して実行し、バージョニング機能を有効にします。

以下の例では、バケット「pythonbucket2」のバージョニング機能の状態を有効 (’Status’: ‘Enabled’)に変更しています。

```python:test1.py
import boto3

client = boto3.client(
    's3',
    endpoint_url='https://xxx.yyy.com'
)


# バケット名:pythonbucket2 のバージョニング機能の有効化
client.put_bucket_versioning(
    Bucket='pythonbucket2',
    VersioningConfiguration={'Status': 'Enabled'}
)
```


```bash
{'ResponseMetadata': {'RequestId': '9dad3e00-0e30-1dbc-a754-06bdfcde1d5e',
  'HostId': '',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {'date': 'Sun, 13 Dec 2020 22:30:33 GMT',
   'x-amz-request-id': '9dad3e00-0e30-1dbc-a754-06bdfcde1d5e',
   'content-length': '0',
   'server': 'CloudianS3'},
  'RetryAttempts': 0}}
```

> **注意**
> バケットのバージョニング機能は、有効化するとその後、無効化することはできません。  
> バージョニング機 能を一時停止させたい場合には、後述するように VersioningConfiguration の Status に 「Suspended」を渡して put_bucket_versioning()を実行します。



## 2. バケットのバージョニング状態の確認 / get_bucket_versioning()
get_bucket_versioning()の引数に、バージョニングの状態を確認するバケット名を渡して実行します。

以下の例では、バケット「pythonbucket2」のバージョニング状態を取得しています。

```python:test1.py
import boto3

client = boto3.client(
    's3',
    endpoint_url='https://xxx.yyy.com'
)


# バケット名:pythonbucket2 のバージョニング状態を取得
client.get_bucket_versioning(Bucket='pythonbucket2')
```

```bash
 {'ResponseMetadata': {'RequestId': '9dad3e02-0e30-1dbc-a754-06bdfcde1d5e',
  'HostId': '',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {'date': 'Sun, 13 Dec 2020 22:30:36 GMT',
   'x-amz-request-id': '9dad3e02-0e30-1dbc-a754-06bdfcde1d5e',
   'content-type': 'application/xml;charset=UTF-8',
   'content-length': '161',
   'server': 'CloudianS3'},
  'RetryAttempts': 0},
 'Status': 'Enabled'}

```
![3-7-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/962155/fd8a511e-147b-d480-da79-299382e51f6f.png "3-7-1.png")


## 3. バージョニングが有効にされたバケットにファイルをアップロード
バージョニング機能が有効化されたバケットに対して、前述の S3 Transfers の upload_file()を使用して、同じキーで複数回、ファイルをアップロードしてみます。

以下の例では、バージョニング機能が有効化されたバケット「pythonbucket2」に、キーに「10mb.dat」を設定してファイルを計 4 回アップロードしています。

```python:upload1.py
import boto3

from boto3.s3.transfer import S3Transfer
from boto3.s3.transfer import TransferConfig


client = boto3.client(
    's3',
    endpoint_url='https://xxx.yyy.com'
)

config = TransferConfig(
    multipart_threshold = 8 * 1024 * 1024,
    max_concurrency = 10,
    multipart_chunksize = 8388608,
    num_download_attempts = 10,
    max_io_queue = 100
)


# S3Transfer オブジェクトの作成
transfer = S3Transfer(client, config)


# 【1 回目】
transfer.upload_file('fileup/10mb.dat', 'pythonbucket2', '10mb.dat')


# 【2 回目】
transfer.upload_file('fileup/10mb.dat', 'pythonbucket2', '10mb.dat',
    extra_args={
	    'ACL': 'public-read',
	    'Metadata': {
	                    'Purpose': 'boto3 demo 1',
	                    'Engineer': 'yamahiro',
	                    'Company': 'nw'
	                },
	    'ServerSideEncryption': 'AES256'
	    }
    )


# 【3 回目】
transfer.upload_file('fileup/10mb.dat', 'pythonbucket2', '10mb.dat',
    extra_args={
                'ACL': 'public-read',
                'Metadata': {
                    'Purpose': 'boto3 demo 2',
                    'Engineer': 'miki',
                    'Company': 'nw'
                },
                	'ServerSideEncryption': 'AES256'
                }
    )
    
    
# 【4 回目】
transfer.upload_file('fileup/10mb.dat', 'pythonbucket2', '10mb.dat',
    extra_args={'ServerSideEncryption': 'AES256'}
)      
```

> ※ アップロード時にユーザー定義のメタデータを付加 
> extra_args={Metadata': {'名前': '値', .....}} 
>
> ※ アップロード時に暗号化(AES256)を指定
> 'ServerSideEncryption': 'AES256'

 
 
## 4. バージョニングされたオブジェクトのリスト表示 / list_object_versions()
バージョニングされた(今現在、最新バージョンではない)オブジェクト(ファイル)をリスト表示するには、list_object_versions()を実行します。

### 加工せずに表示
以下の例では 、list_object_versions() の引数にバケット名
(Bucket='pythonbucket2’)のみを設定し、全ての戻り値を表示しています

```python
client.list_object_versions(Bucket='pythonbucket2')
```

```bash
{'ResponseMetadata': {'RequestId': '9dad3e3e-0e30-1dbc-a754-06bdfcde1d5e',
  'HostId': '',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {'date': 'Sun, 13 Dec 2020 22:35:45 GMT',
   'x-amz-request-id': '9dad3e3e-0e30-1dbc-a754-06bdfcde1d5e',
   'x-gmt-policyid': 'b46db4b3ebb2180b046ad1065c9702e1',
   'x-amz-bucket-region': 'region1',
   'content-type': 'application/xml;charset=UTF-8',
   'content-length': '1674',
   'server': 'CloudianS3'},
  'RetryAttempts': 0},
 'IsTruncated': False,
 'KeyMarker': '',
 'VersionIdMarker': '',
 'Versions': [{'ETag': '"669fdad9e309b552f1e9cf7b489c1f73-2"',
   'Size': 10485760,
   'StorageClass': 'STANDARD',
   'Key': '10mb.dat',
   'VersionId': 'fe14c26d-16ea-60bf-a754-06bdfcde1d5e',
   'IsLatest': True,
   'LastModified': datetime.datetime(2020, 12, 13, 22, 31, 14, 996000, tzinfo=tzutc()),
   'Owner': {'ID': '27b8e84694ca0b529d5379049564ebe1'}},
  {'ETag': '"669fdad9e309b552f1e9cf7b489c1f73-2"',
   'Size': 10485760,
   'StorageClass': 'STANDARD',
   'Key': '10mb.dat',
   'VersionId': 'fe14c26d-18b5-d1ef-a754-06bdfcde1d5e',
   'IsLatest': False,
   'LastModified': datetime.datetime(2020, 12, 13, 22, 31, 11, 985000, tzinfo=tzutc()),
   'Owner': {'ID': '27b8e84694ca0b529d5379049564ebe1'}},
  {'ETag': '"669fdad9e309b552f1e9cf7b489c1f73-2"',
   'Size': 10485760,
   'StorageClass': 'STANDARD',
   'Key': '10mb.dat',
   'VersionId': 'fe14c26d-1a6a-119f-a754-06bdfcde1d5e',
   'IsLatest': False,
   'LastModified': datetime.datetime(2020, 12, 13, 22, 31, 9, 126000, tzinfo=tzutc()),
   'Owner': {'ID': '27b8e84694ca0b529d5379049564ebe1'}},
  {'ETag': '"669fdad9e309b552f1e9cf7b489c1f73-2"',
   'Size': 10485760,
   'StorageClass': 'STANDARD',
   'Key': '10mb.dat',
   'VersionId': 'fe14c26d-1e9b-382f-a754-06bdfcde1d5e',
   'IsLatest': False,
   'LastModified': datetime.datetime(2020, 12, 13, 22, 31, 2, 93000, tzinfo=tzutc()),
   'Owner': {'ID': '27b8e84694ca0b529d5379049564ebe1'}}],
 'Name': 'pythonbucket2',
 'Prefix': '',
 'MaxKeys': 1000,
 'EncodingType': 'url'}
```

list_object_versions()からは非常に多くの情報が返されるため、以降の例では出力を絞り込んで表示させます。

### バージョニングされたオブジェクトに関する情報に絞り込んで表示
以下の例では 、list_object_versions() の引数にバケット名 (Bucket='pythonbucket2’)のみを設定し、出力をキーとバージョンID、最終変更日時に絞って表示しています。

```python
for version in client.list_object_versions(Bucket='pythonbucket2')['Versions']:
    print(version['Key'],version['VersionId'], version['LastModified'].strftime("%Y/%m/%d %H:%M:%S"))
```
```bash
10mb.dat fe14c26d-16ea-60bf-a754-06bdfcde1d5e 2020/12/13 22:31:14
10mb.dat fe14c26d-18b5-d1ef-a754-06bdfcde1d5e 2020/12/13 22:31:11
10mb.dat fe14c26d-1a6a-119f-a754-06bdfcde1d5e 2020/12/13 22:31:09
10mb.dat fe14c26d-1e9b-382f-a754-06bdfcde1d5e 2020/12/13 22:31:02 
```
 
![3-7-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/962155/2ab84864-401b-9305-2739-3b27f58795b2.png "3-7-4.png")


## 5. バケットのバージョニングを一時停止/ put_bucket_versioning()
put_bucket_versioning()の引数に、バージョニングの状態を変更するバケット名と変更する状態(ここでは’Suspended’)を渡して実行し、バージョニング機能を一時停止します。 

以下の例では、バケット「pythonbucket1」のバージョニング機能を一時停止 (VersioningConfiguration={'Status': 'Suspended'})させています。

```python
client.put_bucket_versioning( Bucket='pythonbucket2', VersioningConfiguration={'Status': 'Suspended'} )
```

```bash
{'ResponseMetadata': {'RequestId': '9dad3e02-0e30-1dbc-a754-06bdfcde1d5e',
  'HostId': '',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {'date': 'Sun, 13 Dec 2020 22:30:36 GMT',
   'x-amz-request-id': '9dad3e02-0e30-1dbc-a754-06bdfcde1d5e',
   'content-type': 'application/xml;charset=UTF-8',
   'content-length': '161',
   'server': 'CloudianS3'},
  'RetryAttempts': 0},
 'Status': 'Enabled'}
```

上記の put_bucket_versioning()実行後、バケット「pythonbucket1」のバージョニ ング機能の状態を表示させ、バージョニング機能が一時停止していることを確認しています。

```python
client.get_bucket_versioning(Bucket='pythonbucket2')
```

```bash
{'ResponseMetadata': {'RequestId': '9dad3e44-0e30-1dbc-a754-06bdfcde1d5e',
  'HostId': '',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {'date': 'Sun, 13 Dec 2020 22:36:23 GMT',
   'x-amz-request-id': '9dad3e44-0e30-1dbc-a754-06bdfcde1d5e',
   'content-type': 'application/xml;charset=UTF-8',
   'content-length': '163',
   'server': 'CloudianS3'},
  'RetryAttempts': 0},
 'Status': 'Suspended'}
```

![3-7-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/962155/a7c6394f-c734-4a76-27d9-cc82e96392fc.png "3-7-5.png")


## まとめ
Python(boto3)で、バケットのバージョニング設定をしてみました。

[次回](https://qiita.com/yamahiro/items/3c364a603037a2d8d9a5)も、Pythonでオブジェクトストレージ/Cloudianをいろいろ操作していきたいと思います。