PulumiのProviderをTerraformのProviderから実際に作成してみた

Terraform Pulumi、 [こんな](https://pulumi.io/reference/vs/terraform.html) 感じで比較されてますよね。

なるほど・・・と思う点と、そうかぁ？(笑)と思う点があります。

`The major difference` の２点目は少し納得。

ただそれを読んでいて、ここがすごく気になった。

```
We have a tool, tf2pulumi, that converts Terraform HCL to Pulumi. It is open source on GitHub, and works for most projects we have come across; if you run into a snag, Issues and Pull Requests are welcome! Download and use it now.
```

`tf2pulumi` ・・・？

確かに僕にPulumiを教えてくれた人も、 `Pulumiって主要クラウドしかサポートしてないけど、Terraformのプロバイダさえあれば何でも出来るらしい` ということを言っていた。

そんな中、 [前回の記事](https://qiita.com/keiichi-hikita/items/e21713716840aca6292c) にもコメントを頂き納得。

**TerraformのProviderがあればPulumiのProviderも比較的簡単に作れる**

ということなんですね。

で、実際にやってみました。

## Providerを変換してみた

いろいろ調べていたら [ここ](https://github.com/pulumi/pulumi-terraform/blob/master/README.md) にたどり着きました。

まずはgvmで新しいpkgset作って、 `Building and Testing` までは終わらせる。
makeしても何も起きないなーと思っていたのですが、 `This repo on its own isn't particularly interesting, until it is used to create a new Pulumi provider.` ってことのようですね。ここまでは前提だと。

中段に `Adapting a New Terraform Provider` という一節があり、ここからが本番のようです。

これによると、

- cmd/pulumi-tfgen-aws/
- cmd/pulumi-resource-aws/
- resources.go

を用意すればいいとある。（上の2つはディレクトリになってるけど、実際はその中のmain.goを書く）

自分の場合は、作っているプロバイダが、 [terraform-provider-ecl](https://github.com/nttcom/terraform-provider-ecl) なので、

- cmd/pulumi-tfgen-ecl/
- cmd/pulumi-resource-ecl/
- resources.go

となりますね。


## 事前作業

前提としてECL(Enterprise Cloud)のProviderはOpenStackのをベースにしてるんで、

- まずは pulumi/openstack をForkしてきて名前を変える。
- sdkフォルダを空にする

ってのをやりました。

で、そのリポジトリが、 [ここ](https://github.com/keiichi-hikita/pulumi-ecl) 。

その上で、

- PULUMI_ROOTも然るべき場所に設定しておく。自分の場合は **~/.pulumi/**

とし、

- Gopkg.lock等、dep関連の各種ライブラリの参照パスやプロバイダ名などを変えていく。要らないものを消す。
- dep ensureする

みたいなことをやっていきました。

１つハマったのは、dep ensureした後、事前に `vendor/github.com/pulumi/pulumi-terraform/pkg/tfgen/gitinfo.go` の以下を書き換えておかないと駄目でしたね。

Enterprise Cloudのプロバイダはterraform-providers配下には存在しないのでハードコードされていると困る。

```
const (
	tfGitHub         = "github.com"
	tfProvidersOrg   = "nttcom" <-- ここに terraform-providersがハードコードされてたのを修正
	tfProviderPrefix = "terraform-provider"
)
```

さてここからmakeに向けて進んでいきます。

## pulumi-ecl の Makefile 修正

僕の場合はvirtualenv使っているんで、pulumi-eclのMakefileの以下を修正する必要がありました。

`pip install --user` はエラーとなるので、 `--user` を除去。

```
install::
	GOBIN=$(PULUMI_BIN) go install -ldflags "-X github.com/keiichi-hikita/pulumi-ecl/pkg/version.Version=${VERSION}" ${PROJECT}/cmd/${PROVIDER}
	[ ! -e "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)" ] || rm -rf "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)"
	mkdir -p "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)"
	cp -r ${PACKDIR}/nodejs/bin/. "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)"
	rm -rf "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)/node_modules"
	cd "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)" && \
		yarn install --offline --production && \
		(yarn unlink > /dev/null 2>&1 || true) && \
		yarn link
	cd ${PACKDIR}/python/bin && $(PIP) install -e . <-- ここにあった --user を除去
```

ちなみに僕の場合、python2環境じゃないとmakeができませんでした。
なぜかMakefileの $PYTHON が python2 になってしまう。。。
これって仕様？（多分違うと思うけど）

ですが、実際に生成されるpulumi_eclをimportする段階で型宣言文でsyntax error引くので、pulumi providerを利用するvirtualenvはpython3ベースで作りましょう。


とりあえず上記の変更をしてMakefileはコミットしてありますが分岐しないと何でしょうね本当は。

この2つはIssueでも切って提案してみようかなぁ。。
（でも修正点2は自分自身で解決策がわからないけど。自身がvirtualenvかどうかって判別できるんかな）

## ファイル修正

その上で下記3点を修正する。それがこれら。

### cmd/pulumi-tfgen-ecl/main.go

https://github.com/keiichi-hikita/pulumi-ecl/blob/master/cmd/pulumi-resource-ecl/main.go

### cmd/pulumi-resource-ecl/

https://github.com/keiichi-hikita/pulumi-ecl/blob/master/cmd/pulumi-tfgen-ecl/main.go

### resources.go

https://github.com/keiichi-hikita/pulumi-ecl/blob/master/resources.go

これでmakeの準備は整いました。

## make してみよう

この状態で、 `pulumi-ecl` 配下で `make` すると、以下のようなドキュメントが無いよwarningが大量に出るけどsdkは出力されました。

```
warning: Could not find docs for resource ecl_compute_volume_attach_v2; consider overriding doc source location
warning: Could not find docs for resource ecl_compute_volume_v2; consider overriding doc source location
warning: Could not find docs for resource ecl_imagestorages_image_v2; consider overriding doc source location

...
```

当然dep利用なんで、コンパイル対象は `$GOPATH/src` 配下の然るべきパスで無いと駄目です。
適当な場所にcloneしてる場合はsymlinkでも貼っておきましょう。

makeの一番最後の処理で、該当のvirtualenv配下にpip install -eでインストールされているので、importも出来る状態になってます。


```python

% python                                                             (git)-[initial-setup]
Python 3.6.6 (default, Oct  3 2018, 13:51:45)
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.10.44.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from pulumi_ecl import compute
>>>
```

エラー出ません。行けましたね。

## 実際にPulumiから発動

こんな **__main__.py** を作ってリソース作成をしてみます。

```python

% cat __main__.py
import pulumi

from pulumi_ecl import compute


# Create an OpenStack resource (Compute Keypair)
keypair = compute.Keypair('pulumi-keypair1')

# Create an OpenStack resource (Compute Instance)
instance = compute.Instance('instance01',
        name='instance01-pulumi',
	flavor_name='1CPU-4GB',
        key_pair=keypair.name,
	image_name='Ubuntu-18.04.1_64_virtual-server_02')

# Export the IP of the instance
pulumi.export('instance_ip', instance.access_ip_v4)
```

無事行けました〜

```
% pulumi up
Previewing update (dev):

     Type                     Name             Plan
 +   pulumi:pulumi:Stack      pulumi_work-dev  create
 +   ├─ ecl:compute:Keypair   pulumi-keypair1  create
 +   └─ ecl:compute:Instance  instance01       create

Resources:
    + 3 to create

Do you want to perform this update? yes
Updating (dev):

     Type                     Name             Status
 +   pulumi:pulumi:Stack      pulumi_work-dev  created
 +   ├─ ecl:compute:Keypair   pulumi-keypair1  created
 +   └─ ecl:compute:Instance  instance01       created

Outputs:
    instance_ip: "192.168.99.11"

Resources:
    + 3 created

Duration: 17s

Permalink: https://app.pulumi.com/keiichi-hikita/pulumi_work/dev/updates/22
```

以上、Terraform-ProviderからPulumiのProviderにConvert成功しました。

公式プロバイダではないためにいろいろハマりましたがいけますね。

こりゃー便利ですが、Terraform的にはいいところどりされて悔しい感はないのだろうかと思ってしまいます。