ShinobiLayer: Windowsにおけるslcli config setupで生成した環境変数ファイルについて

[SoftLayer Advent Calendar 2015](http://qiita.com/advent-calendar/2015/softlayer)の10日目の記事です。

#1. python.exe/pip.exeの配置場所
Windows 7でPython 3.5.0を入れたら、pythonとpipの実行バイナリーは以下に導入された。

```text:python.exe
C:\Users\<user_name>\AppData\Local\Programs\Python\Python35-32\python.exe
```

```text:pip.exe
C:\Users\<user_name>\AppData\Local\Programs\Python\Python35-32\Scripts\pip.exe
```

#2. SoftLayerモジュールの配置先
 `pip install SoftLayer`を実行してSoftLayerのAPIモジュールをダウンロードしたら、`C:\Users\<user_name>\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\SoftLayer`配下に配置された。

```text:SoftLayerモジュールの配置場所
C:\>pip install SoftLayer
C:\>pip show SoftLayer
---
Metadata-Version: 2.0
Name: SoftLayer
Version: 4.1.1
Summary: A library for SoftLayer's API
Home-page: http://github.com/softlayer/softlayer-python
Author: SoftLayer Technologies, Inc.
Author-email: sldn@softlayer.com
License: MIT
Location: c:\users\<user_name>\appdata\local\programs\python\python35-32\lib\site-packages
Requires: six, requests, prompt-toolkit, prettytable, click
```

#3. 環境変数ファイルの配置先
`slcli config setup`を使って環境変数を設定したら、`C:\Users\<username>\AppData\Roaming\softlayer`に環境変数ファイルが作られていた。

##考察1: なぜこんな場所に配置されるのか？
SoftLayer\CLI\core.pyには以下のように書かれている。

```py:SoftLayer\CLI\core.py
@click.option('--config', '-C',
              required=False,
              default=click.get_app_dir('softlayer', force_posix=True),
              help="Config file location",
              type=click.Path(resolve_path=True))
```

下記リンクにあるとおり、click.get_app_dir関数内でroamingを指定していない時はroaming=Trueがデフォルト値なのでなので、Windows7では`C:\Users\<username>\AppData\Roaming\softlayer`になる。一方、Linuxでは`~/.softlayer`になる。

http://click.pocoo.org/5/api/ より引用

```text:click.get_app_dir

Mac OS X:
    ~/Library/Application Support/Foo Bar
Mac OS X (POSIX):
    ~/.foo-bar
Unix:
    ~/.config/foo-bar
Unix (POSIX):
    ~/.foo-bar
Win XP (roaming):
    C:\Documents and Settings\<user>\Local Settings\Application Data\Foo Bar
Win XP (not roaming):
    C:\Documents and Settings\<user>\Application Data\Foo Bar
Win 7 (roaming):
    C:\Users\<user>\AppData\Roaming\Foo Bar
Win 7 (not roaming):
    C:\Users\<user>\AppData\Local\Foo Bar 
```

#4. Windowsで自作したスクリプトではこの環境変数ファイルが自動的に呼ばれない！？

`slcli config setup`で環境変数ファイルを事前に作成しておけば、**Linuxでは以下のサンプルスクリプトは実行できるのだが、Windowsでは環境変数ファイルが見つからないためエラーになってしまう**。

```python:sample.py
import SoftLayer
client = SoftLayer.create_client_from_env()
print(client['Account'].getObject())
```

前述のとおり、Linuxでは`slcli config setup`で設定した環境変数の情報は'~/.softlayer'に保管される。SoftLayer\config.pyには、以下のコードから分かるように、デフォルトで'/etc/softlayer.conf'と'~/.softlayer'を探しに行くようにハードコーディングされているので、いったん`slcli config setup`で環境変数ファイルを作成してしまえば、`client = SoftLayer.create_client_from_env()`の呼び出しの中で特にconfigファイルの場所を指定しなくても呼び出せること分かる。

```text:SoftLayer\config.py
    config_files = ['/etc/softlayer.conf', '~/.softlayer']
    if kwargs.get('config_file'):
        config_files.append(kwargs.get('config_file'))
    config_files = [os.path.expanduser(f) for f in config_files]
```

一方、Windowsには'/etc/softlayer.conf'や'~/.softlayer'なんていうファイルは存在しない。os.path.expanduser関数によって、それぞれ'/etc/softlayer.conf'および'C:\\Users\\IBM_ADMIN/.softlayer'に展開されるが、Windowsでは.softlayerのような拡張子だけあってファイル名が存在しないファイルは作れないので、やはりWindowsではどちらも参照できない（まぁ、もともとこんな場所に`slcli config setup`ではファイルは作らないけど。。。）。なので、**Windowsでは`slcli config setup`で作成された環境変数ファイルは、`client = SoftLayer.create_client_from_env()`のように環境変数ファイルを明示的に指定しないコードで参照されることはない。**

#5. LinuxでもWindowsでもslcli config setupで作成した環境変数ファイルを参照するための改善案
##案1
SoftLayerのpythonモジュールを修正。config.pyにおいて、以下のようにコードを修正すれば、`slcli config setup`で作成した環境変数ファイルが`client = SoftLayer.create_client_from_env()`のように引数なしでLinux/Windowsの両方でちゃんと呼び出されるようになる。clickモジュールに依存することになるので、そんなに綺麗とはいえないかもしれない・・・。

```text:SoftLayer\config.py
    import click
    config_files = ['/etc/softlayer.conf']
    config_files.append(click.get_app_dir('softlayer', force_posix=True))
    if kwargs.get('config_file'):
        config_files.append(kwargs.get('config_file'))
    config_files = [os.path.expanduser(f) for f in config_files]
```

##案2
呼び出す側で修正。これもLinux/Windowsの両方で動く。まぁ、当面はこちらが現実的かな。。。

```python:sample.py
import SoftLayer
import click
client = SoftLayer.create_client_from_env(config_file=click.get_app_dir('softlayer', force_posix=True))
print(client['Account'].getObject())
```