[Oracle Cloud] Windows Serverにoci cliをインストールする

# はじめに

[[Oracle Cloud] Windows Serverインスタンスを使ってみた](https://qiita.com/NSO-KC/items/69d43e8a711eaea0b092)の記事で作成したWindows Serverにoci cliをいれます。

インストール方法は[コマンドライン(CLI)でOCIを操作する - Oracle Cloud Infrastructureアドバンスド](https://community.oracle.com/tech/welcome/discussion/4474263/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3-cli-%E3%81%A7oci%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B-oracle-cloud-infrastructure%E3%82%A2%E3%83%89%E3%83%90%E3%83%B3%E3%82%B9%E3%83%89)を参考にしています。

最初にPythonをインストールしてから、oci cliをインストールします。

# 前提
* 認証は、インスタンス・プリンシパルで行っています。
* 作成済みのバケットに対して、オブジェクトをアップロードするという前提で、以下のポリシーを適用しています。

```
Allow dynamic-group <動的グループ名> to manage objects in compartment <コンパートメント名>
Allow dynamic-group <動的グループ名> to use buckets in compartment <コンパートメント名>
```
* BUCKET01という名前で、バケットを事前に作成しています。

# 手順

## Pythonのインストール
インストール方法は[コマンドライン(CLI)でOCIを操作する - Oracle Cloud Infrastructureアドバンスド](https://community.oracle.com/tech/welcome/discussion/4474263/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3-cli-%E3%81%A7oci%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B-oracle-cloud-infrastructure%E3%82%A2%E3%83%89%E3%83%90%E3%83%B3%E3%82%B9%E3%83%89)には、2018年8月現在ではPython3では複数のエラーが発生するとの注釈がありましたが、2021年現在Python3.8でインストールしたところ問題なくインストールできました。

[Pythonのダウンロードサイト](https://www.python.org/downloads/windows/)から、Pythonをダウンロードします。2021年1月現在、最新はPython3.9.1でしたが、へたれなので一つバージョンが低い[3.8.7](https://www.python.org/downloads/release/python-387/)で試しました。

Windowsインストーラを端末にダウンロードして、リモートデスクトップで接続したWindows Serverにコピペでアップロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456818/b28d5623-47b4-b53c-5a5a-42ac13913e85.png)

Windows ServerにアップロードしたPythonインストーラを起動します。Pythonのインストールオプションは好みです。余計なものはインストールしたくないので、「Customized Installation」を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456818/183d95a0-5645-5ca8-d780-50ed678abeb4.png)

pythonのバイナリを他のユーザと共有するように構成したかったので、「pip」と[for all users(required elavation)]だけ残してインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456818/4073dcec-7d7e-dfee-418f-b28e2bd05a80.png)

「install for all users」と、「Add Python to environment variables」、「Precompile standard library」にチェックして、「Install」を実行します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456818/1f4b5dfb-c033-de6d-312d-6b7ef5997c62.png)

なお、「install for all users」のチェックを外すとインストール先のデフォルトが以下のようにopcユーザのホームディレクトリ配下になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456818/cb790e1d-2514-80f7-24ab-6ae904bdd110.png)

「Add Python to environment variables」にチェックをいれないと、pythonコマンドにパスがとおらなくなるので注意してください。「Precompile standard library」にチェックをいれたのは、パフォーマンス早くなるかなといった軽いノリでしたが、調べたところ初回アクセス時にどちらにしろ初回コンパイルされるので大した差はないようです。。

インストールが完了したら、PowerShell(管理者として実行)を起動してpython -versionと実行してバージョン情報が返ってくることを確認します

```CONSOLE
PS:> python --version
Python 3.8.7
```

## oci cliのインストール
最初に、pipをupdateします

```CONSOLE
PS:> python -m pip install --upgrade pip
----------------< 出力例 >----------------
Collecting pip
  Downloading pip-21.0-py3-none-any.whl (1.5 MB)
     |████████████████████████████████| 1.5 MB 6.8 MB/s
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 20.2.3
    Uninstalling pip-20.2.3:
      Successfully uninstalled pip-20.2.3
Successfully installed pip-21.0
```

つづいてoci cliをインストールします。

```CONSOLE
PS:> pip install oci-cli
----------------< 出力例 >----------------
Collecting pip
  Downloading pip-21.0-py3-none-any.whl (1.5 MB)
     |████████████████████████████████| 1.5 MB 6.8 MB/s
Installing collected packages: pip
//省略//
Successfully installed PyYAML-5.1.2 arrow-0.17.0 certifi-2020.12.5 cffi-1.14.4 click-6.7 configparser-4.0.2 cryptography-3.2.1 jmespath-0.10.0 oci-2.29.0 oci-cli-2.20.0 pyOpenSSL-19.1.0 pycparser-2.20 python-dateutil-2.8.1 pytz-2020.5 retrying-1.3.3 six-1.14.0 terminaltables-3.1.0
⇒ 最終行にSuccessfully installed～と出力されることを確認します。

PS:> oci --version
2.20.0
⇒ バージョン番号が表示されること
```

## oci cli実行環境の作成
oci cliの実行ユーザは、opcとは別のユーザを使ってみます。同じPowershellのプロンプトからocicliという名前でユーザを作成してみます。Remote Desktop権限も許可しました。runasつかってユーザ切り替えてpowershell起動すればいいのですが、実際にどのユーザの権限で実行されているかわかりづらいなと思ったので、ocicliユーザでリモデに再ログインしてから確認しました。

```CONSOLE
## ocicliユーザを作成
PS:> net user /add ocicli <パスワード>
コマンドは正常に終了しました。

## ocicliユーザをremote desktop usersグループに追加
PS:> net localgroup "Remote Desktop users" ocicli /add
コマンドは正常に終了しました。
```

opcユーザからログアウトし、ocicliユーザで再度ログインします
再ログイン後、再度PowerShellを起動します。管理者権限ないやつです。

とりえあず、ociコマンドにパスがとおっていることを確認します

```CONSOLE
PS:> oci --version
2.20.0
```

クラウド・リソースにアクセスするための設定を作成していきます。IAMユーザを使用するのであれば、oci setup configを実行すればよいのですが、IAMユーザの情報入力やAPIキーの入力をスキップできなくてめんどくさいので設定ファイルは自分で作りました。

```CONSOLE
## ホームディレクトリ配下に.ociディレクトリを作ります。
PS:> $OCI_CONFIG_DIR=$env:HOMEDRIVE + $env:HOMEPATH + "\.oci"
PS:> mkdir $OCI_CONFIG_DIR

## configファイルを作成してから、notepadで開いて編集します
PS:> New-Item $OCI_CONFIG_DIR\config
PS:> notepad $OCI_CONFIG_DIR\config
[DEFAULT]
tenancy=ocid1.tenancy.oc1..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
region=ap-tokyo-1
↑DEFAULTプロファイルとして、自身のテナンシのOCIDとリージョンを記載します。

## 同じように、oci_cli_rcファイルを作成して、デフォルトコンパートメントを指定します。oci cliコマンド実行時に都度compartment-idを指定するのであれば、このファイルを作成する必要はありません
PS:> New-Item $OCI_CONFIG_DIR\oci_cli_rc
PS:> notepad $OCI_CONFIG_DIR\oci_cli_rc
[DEFAULT]
compartment-id = ocid1.compartment.oc1..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

PS:> dir $OCI_CONFIG_DIR
----------------< 出力例 >----------------
    ディレクトリ: C:\Users\ocicli\.oci

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        1/30/2021   7:48 PM            117 config
-a----        1/30/2021   7:50 PM            111 oci_cli_rc
⇒2つのファイルが作成されているはずです(oci_cli_rcファイルは任意)
```

Object Storageに、アップロード・削除できることを確認します。ここでは、バケット名をBUCKET01という名前で作成しています

```CONSOLE
## デスクトップ上に、テスト用のアップロードファイルを作成します
PS:> $file_upload=$env:HOMEDRIVE + $env:HOMEPATH + "\Desktop\upload_file.txt"
PS:> hostname > $file_upload
PS:> type $file_upload
----------------< 出力例 >----------------
winsrv01
⇒ ファイルが存在して、ホスト名が出力されていること

## 環境変数OCI_CLI_AUTHにインスタンスプリンシパルを使うための設定をします。ociコマンドオプションとして--auth=instnace_principalを指定する場合は不要です。
PS:> $env:OCI_CLI_AUTH = "instance_principal"

## まず、バケット一覧を取得してみます。目的のバケットをリストできることを確認します。
PS:> oci os bucket list --output=table --query 'data[*].{"name": "name"}'
----------------< 出力例 >----------------
+--------------+
| name         |
+--------------+
| BUCKET01     |
+--------------+

## なお、以下のようなエラーが出力される場合は、インスタンス・プリンシパルの設定が有効になっていません
# ERROR: The config file at ~\.oci\config is invalid:

#+Config Errors+---------+-------------------------------------------------------------------------------#---+
#| Key         | Error   | Hint                                                                             #|
#+-------------+---------+-------------------------------------------------------------------------------#---+
#| key_file    | missing | the full path and filename of the private PEM key file                           #|
#| user        | missing | log into the console and go to the user's settings page to find their OCID       #|
#| fingerprint | missing | openssl rsa -pubout -outform DER -in <path to your private key> | openssl md5 #-c |
#+-------------+---------+----------------------------------------------------------------------------------+
## 以下のようなエラーになる場合は、おさらくポリシー設定が間違っています
#ServiceError:
#{
#    "code": "NamespaceNotFound",
#    "message": "You do not have authorization to perform this request, or the requested resource could not be found.",
#    "opc-request-id": "nrt-1:xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
#    "status": 404
#}

## テスト用のファイルをアップロードしてみます。アップロード後のObject名はアップロードファイルのフルパスの\マークを/に変更した名前にしてみます。
PS:> $bucket_name="BUCKET01"
PS:> $object_name=$file_upload -replace "\\","/"
PS:> oci os object put -bn $bucket_name --file $file_upload --name $object_name
----------------< 出力例 >----------------
Uploading object  [####################################]  100%
{
  "etag": "fe3fa2fa-303b-4791-abfc-9fda9179e472",
  "last-modified": "Sat, 30 Jan 2021 11:07:05 GMT",
  "opc-content-md5": "UwRiMY1rhdJFvWi+JEVjbw=="
}
⇒ 成功すると、上記のように出力されます

## アップロードされたファイルをリストしてみます
PS:> oci os object list -bn $bucket_name --output=table --query 'data[*].{name: name,size: size, \"time-created\": \"time-created\"}'
----------------< 出力例 >----------------
+-----------------------------------------+------+----------------------------------+
| name                                    | size | time-created                     |
+-----------------------------------------+------+----------------------------------+
| C:/Users/ocicli/Desktop/upload_file.txt | 22   | 2021-01-30T11:07:05.956000+00:00 |
+-----------------------------------------+------+----------------------------------+

## 削除してみます
PS:> oci os object delete -bn $bucket_name --name $object_name
----------------< 出力例 >----------------
Are you sure you want to delete this resource? [y/N]: y
⇒ --forceオプションをつけない場合は、消すかどうかのプロンプトが返ってくるのでyと入力します

## もう一度同じリストコマンドを実行します。結果が返ってこないことを確認します
PS:> oci os object list -bn $bucket_name --output=table --query 'data[*].{name: name,size: size, \"time-created\": \"time-created\"}'
----------------< 出力例 >----------------
Query returned empty result, no output to show.

```

Windowsのociは、Linuxのociとはエスケープの仕方が違って、すこし戸惑いました。ダブルクォートもエスケープしないといけないのですね。