Pulumi Provider (for Enterprise Cloud 2.0) を再度Terraform 0.12リリースを契機に作り直してみる

## はじめに

以前 [PulumiのProviderをTerraformのProviderから実際に作成してみた](https://qiita.com/keiichi-hikita/items/aa69eb4716db49cabeda) という記事を書きましたが、Terrafofm 0.12が出たのと(0.12.1が出ているのは無視)、pulumi-terraformもmoduleモードに対応したようなので、改めてPulumiのプロバイダを作ってみました。

## 結果だけ書くと

本記事の内容を書いていくにあたって、 [こちら](https://github.com/keiichi-hikita/pulumi-ecl) の `Pulumi Provider for Enterprise Cloud 2.0` が最新化されています。

## 今回やりたかったこと

- TerraformのプロバイダをPulumi用に変換する
    - 変換対象のTerraformプロバイダは [こちら](https://github.com/nttcom/terraform-provider-ecl)
    - nttcom organization配下にあるのがポイント
- go1.12で作業する
    - 各種dep系の手順は無視してモジュールモード想定でやってみる
- で、その手順を本記事にまとめる
- （ちなみに自分のホームディレクトリは `/Users/yuzu`）

## やってみてどうだった？

- 思ったよりはすんなり
- でも意外なところでハマりました

## そのための手順 超概要

1. [pulumi-terraform](https://github.com/pulumi/pulumi-terraform) のバイナリをコンパイル
    - 正確にはバイナリはどうでも良くて、そのためのbuildとかtestとかをやるため
2. それを使って [pulumi-ecl](https://github.com/keiichi-hikita/pulumi-ecl) のsdkを再生成 


## 1. [pulumi-terraform](https://github.com/pulumi/pulumi-terraform) のバイナリをコンパイル

基本的に [pulumi-terraform のREADME](https://github.com/pulumi/pulumi-terraform/blob/master/README.md) に従って作業するのですが、

- [Prerequisites](https://github.com/pulumi/pulumi-terraform#prerequisites)
- [Building and Testing](https://github.com/pulumi/pulumi-terraform#building-and-testing)

あたりを見ると、まだ `$GOPATH` , `dep` あたりを意識した形になってます。
とはいえgo1.12対応しているっぽいのと、 `go.mod` とか置いてあってdep非依存になっていたので手順を無視して以下をやってみました。

### Cloneしてくる

自分は Gitリポジトリはすべて `~/dev` 配下にcloneしているので、

```
% cd ~/dev
% git clone https://github.com/pulumi/pulumi-terraform
```


### gvm環境づくり

最初に `go.1.12` ベースでgvm環境だけ作り直します。

```bash
% gvm use go1.12
Now using version go1.12
% gvm pkgset list

gvm go package sets (go1.12)

=>  global
    terraform-provider

% gvm pkgset create pulumi
% gvm pkgset use pulumi
Now using version go1.12@pulumi
% gvm pkgset list

gvm go package sets (go1.12)

    global
=>  pulumi
    terraform-provider
```

これで専用のpkgsetになりました。

### 前回ハマった場所の書き換えは不要そう

前回、 [事前作業](https://qiita.com/keiichi-hikita/items/aa69eb4716db49cabeda#%E4%BA%8B%E5%89%8D%E4%BD%9C%E6%A5%AD) の中で、 `tfProvidersOrg` がハードコードされていたのでどうにかならないかなぁ・・・と思っていましたが、現在は `ProviderInfo` 経由で渡せるようになっているようですね。

https://github.com/pulumi/pulumi-terraform/blob/master/pkg/tfbridge/info.go#L58-L64

これはおそらく、 `pulumi-ecl` 側で `tfgen` を呼び出しているところから何かしらで挿入可能なんだろうなと推測。
ということで今は何もしません。

### make 開始

```bash
% cd ~/dev/pulumi-terraform
% makeする

go: finding github.com/hashicorp/terraform v0.12.0-rc1.0.20190509225429-28b2383eacae
go: finding github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709
go: finding github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f

...

=======================
Pulumi Terraform Bridge
=======================
go build github.com/pulumi/pulumi-terraform/pkg/tfgen
go build github.com/pulumi/pulumi-terraform/pkg/tfbridge
go install -ldflags "-X github.com/pulumi/pulumi-terraform/pkg/version.Version=v0.18.3-dev.1559684733+g7ace3e9" github.com/pulumi/pulumi-terraform/cmd/pulumi-resource-terraform
cd sdk/nodejs/ && \
		yarn install && \
		yarn run tsc
yarn install v1.12.3
warning ../../../package.json: No license field
info No lockfile found.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 📃  Building fresh packages...
success Saved lockfile.
warning Your current version of Yarn is out of date. The latest version is "1.16.0", while you're on "1.12.3".
info To upgrade, run the following command:
$ brew upgrade yarn
✨  Done in 10.44s.
yarn run v1.12.3
warning ../../../package.json: No license field
$ /Users/yuzu/dev/pulumi-terraform/sdk/nodejs/node_modules/.bin/tsc
✨  Done in 3.07s.
cp LICENSE sdk/nodejs/package.json sdk/nodejs/yarn.lock \
		sdk/nodejs/bin
cp README.package.md sdk/nodejs/bin/README.md
sed -i.bak 's/${VERSION}/v0.18.3-dev.1559684733+g7ace3e9/g' sdk/nodejs/bin/package.json
LINT:
golangci-lint run
/bin/bash: golangci-lint: command not found
make: *** [lint] Error 127
```

`/bin/bash: golangci-lint: command not found`

ほほう。
[golangci-lint](https://github.com/golangci/golangci-lint) がありませんよ・・・と。

↑を見るとインストール方法が書いてあります。
その時点での最新版が `v1.16.0` だったので、

```bash
% mkdir $GOPATH/bin
% curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b /Users/yuzu/.gvm/pkgsets/go1.12/global/bin v1.16.0
```

公式のやり方だとインストールパスの指定方法が、 `$(go env GOPATH)/bin` だったのですが、gvmg使っていると$GOPATHが2つのパスを `:` で結合した形で返ってしまうのでベタに指定しました。

ついでに自分は node.js 環境は ndenv を使っているのですが、これに関連して yarn についても [こちら](https://qiita.com/pinemz/items/d758aede73e388c7b57a) を使って最新化しておきました。（Warningが鬱陶しかったので）

では改めて、

```bash
% make

...

cp README.package.md sdk/nodejs/bin/README.md
sed -i.bak 's/${VERSION}/v0.18.3-dev.1559684733+g7ace3e9/g' sdk/nodejs/bin/package.json
LINT:
golangci-lint run // <-- 突破！
INSTALL:
mkdir: /opt/pulumi/bin: Permission denied <-- だめー
make: *** [install] Error 1
```

どうやら `build/common.mk` で `$PULUMI_ROOT` にディレクトリを作りに行ってしまうので、この時点でセットが必要。

```
% export PULUMI_ROOT=/Users/yuzu/.pulumi
% make

...

38891985'
[ -terraform/examples/localstate ] Wrote output to /var/folders/gd/b_32smw96wd66bhn3ttbyjdm0000gn/T/p-it-ug-30-hiki-localstate-34e3acc1-538891985/command-output/pulumi-stack-rm.20190605-151712.20da9.log
--- PASS: TestExamples (0.00s)
    --- PASS: TestExamples//Users/yuzu/dev/pulumi-terraform/examples/localstate (44.34s)
PASS
coverage: 0.0% of statements
ok  	github.com/pulumi/pulumi-terraform/examples	44.365s	coverage: 0.0% of statements
```


ということで `pulumi-resource-terraform` が作成できました。


```
% cd ~/.gvm/pkgsets/go1.12/pulumi/bin  <-- 要は$GOPATH/binです
% ls
dep*                       pulumi-resource-terraform*
```

## 2. それを使って [pulumi-ecl](https://github.com/keiichi-hikita/pulumi-ecl) のsdkを再生成

以前作った [こちら](https://github.com/keiichi-hikita/pulumi-ecl) をそのまま更新していくことにします。
masterが最新版なのでブランチ切って作業開始。


### pulumi-ecl 側 Makefileの修正（を確認）

前回書いた [こちら](https://qiita.com/keiichi-hikita/items/aa69eb4716db49cabeda#pulumi-ecl-%E3%81%AE-makefile-%E4%BF%AE%E6%AD%A3) をベースに進めます。
特にしばらく触っていなかったので何ら問題ないですね。
[ここ](https://github.com/keiichi-hikita/pulumi-ecl/blob/master/Makefile#L56) にあった、 `--user` を消したのでしたね。

### go.modの修正

一旦requireブロックを空にしちゃいます。

あと、 `pulumi-terraform` をローカル参照に切り替え。（GitHubOrg問題が解決した今、実は現時点では必要なかったりしますが）

pulumi-eclのgo.mod

```go
module github.com/keiichi-hikita/pulumi-ecl

require ( // <-- requireを空に（どうせmakeで埋まる)
)

replace (
	github.com/pulumi/pulumi-terraform => ../pulumi-terraform
)
```


### 正式リリースしたので Terraformプロバイダへの参照パスを変更

その他import文を修正します。

当時のTerraformプロバイダは暫定パスで公開していたのですが、正式なパスである [こちら](https://github.com/ngpf-public/terraform-provider-ecl/ecl) に変更

結果が [こちら](https://github.com/keiichi-hikita/pulumi-ecl/blob/master/resources.go#L21) です。


### make開始

おさらいですが、コンパイルする際はpython環境をpython2にしておく必要があるっぽかった。
pyenvで2.7系の環境にスイッチしておきます。

また、[先程書いたように](https://github.com/pulumi/pulumi-terraform/blob/master/pkg/tfbridge/info.go#L58-L64) ProviderInfo 経由で、 `info.GitHubOrg` を渡してあげないといけないわけですね。

このために、

`pulumi-ecl/cmd/pulumi-tfgen-ecl/main.go` を細工します。

`tfgen.Main` の第3引数経由で渡せるようなので、 [ここ](https://github.com/keiichi-hikita/pulumi-ecl/blob/master/resources.go#L67)に追記をします。

```
...

	prov := tfbridge.ProviderInfo{
		P:           p,
		Name:        "ecl",
		GitHubOrg:   "nttcom", // <-- こういう感じ
```

また、 `$PULUMI_ROOT` の設定は同じく必要です。

で、makeしたのですが・・・

```bash
...

go: github.com/Nvveen/Gotty@v0.0.0-20170406111628-a8b993ba6abd: unknown revision a8b993ba6abd
go: error loading module requirements
```

なんだろう・・・と思ったら、どうやら `pulumi-terraform` 側でいくつか go.mod 内のreplaceをしてるんですね・・・。

pulumi-terraformのgo.mod

```go
replace (
	github.com/Nvveen/Gotty => github.com/ijc25/Gotty v0.0.0-20170406111628-a8b993ba6abd
	github.com/golang/glog => github.com/pulumi/glog v0.0.0-20180820174630-7eaa6ffb71e4
)
```

ということで、 `pulumi-ecl` 側にもこの２行を追記。結果 `pulumi-ecl` 側のgo.modがこうなってます。

```go
module github.com/keiichi-hikita/pulumi-ecl

replace (
	github.com/Nvveen/Gotty => github.com/ijc25/Gotty v0.0.0-20170406111628-a8b993ba6abd
	github.com/golang/glog => github.com/pulumi/glog v0.0.0-20180820174630-7eaa6ffb71e4
	github.com/pulumi/pulumi-terraform => ../pulumi-terraform // <-- この行は別になくても困らない
)
```

で改めてmakeです。

```go
% make                                                            (git)-[for_terraform_012]
=======================
Enteprise Cloud Package
=======================
BUILD:
go install -ldflags "-X github.com/pulumi/pulumi-ecl/pkg/version.Version=v0.17.1-dev.1552631198+g1a644ba.dirty" github.com/keiichi-hikita/pulumi-ecl/cmd/pulumi-tfgen-ecl
# github.com/pulumi/pulumi-terraform/pkg/tfbridge
../pulumi-terraform/pkg/tfbridge/provider.go:189:5: cannot use (*Provider)(nil) (type *Provider) as type pulumirpc.ResourceProviderServer in assignment:
	*Provider does not implement pulumirpc.ResourceProviderServer (wrong type for Configure method)
		have Configure("context".Context, *pulumirpc.ConfigureRequest) (*empty.Empty, error)
		want Configure("context".Context, *pulumirpc.ConfigureRequest) (*pulumirpc.ConfigureResponse, error)
../pulumi-terraform/pkg/tfbridge/serve.go:30:21: cannot use NewProvider("context".TODO(), host, module, version, info.P, info) (type *Provider) as type pulumirpc.ResourceProviderServer in return argument:
	*Provider does not implement pulumirpc.ResourceProviderServer (wrong type for Configure method)
		have Configure("context".Context, *pulumirpc.ConfigureRequest) (*empty.Empty, error)
		want Configure("context".Context, *pulumirpc.ConfigureRequest) (*pulumirpc.ConfigureResponse, error)
make: *** [build] Error 2
```

まだ出るかっ!! :angry: 

とはいえコード見ると「あーたしかに」・・・って感じ。

[type ResourceProviderServer interface](https://github.com/pulumi/pulumi/blob/master/sdk/proto/go/provider.pb.go#L1234) を実装するにあたって、確かにメソッドはフルカバーしてますが、実装が正しくないわけですね。

要求としては、Configureメソッドは `(*ConfigureResponse, error)` を返さないとだめなのに、 `(*pbempty.Empty, error) ` を返しているのでインタフェースとしての条件を満たしてない。

ということで以下２箇所を直します。

#### https://github.com/pulumi/pulumi-terraform/blob/master/pkg/tfbridge/provider.go#L319

変更前

```go
func (p *Provider) Configure(ctx context.Context, req *pulumirpc.ConfigureRequest) (*pbempty.Empty, error) {
```

変更後

```go
func (p *Provider) Configure(ctx context.Context, req *pulumirpc.ConfigureRequest) (*pulumirpc.ConfigureResponse, error) {
```

#### https://github.com/pulumi/pulumi-terraform/blob/master/pkg/tfbridge/provider.go#L414

変更前

```go
    return &pbempty.Empty{}, nil
```

変更後

```go
    return &pulumirpc.ConfigureResponse{}, nil
```


### その他いろいろ修正

正式リリースに伴い追加されたり削除された機能をいろいろ修正。
`pulumi-ecl/resources.go` の修正ですね。
ここでは省略します。


### 最後のmake !!

```bash
=======================
Enteprise Cloud Package
=======================
BUILD:
go install -ldflags "-X github.com/pulumi/pulumi-ecl/pkg/version.Version=v0.17.1-dev.1552631198+g1a644ba.dirty" github.com/keiichi-hikita/pulumi-ecl/cmd/pulumi-tfgen-ecl
go install -ldflags "-X github.com/pulumi/pulumi-ecl/pkg/version.Version=v0.17.1-dev.1552631198+g1a644ba.dirty" github.com/keiichi-hikita/pulumi-ecl/cmd/pulumi-resource-ecl
for LANGUAGE in "nodejs" "python" "go" ; do \
		pulumi-tfgen-ecl $LANGUAGE --overlays overlays/$LANGUAGE/ --out sdk/$LANGUAGE/ || exit 3 ; \
	done
warning: 18 documentation sections ignored

...

Successfully installed pulumi-ecl
LINT:
golangci-lint run
TEST FAST:
```

うっし、通った！！ :tada: 

sdkのsetup.pyをみると、

```python
      install_requires=[
          'parver>=0.2.1',
          'pulumi>=0.17.0,<0.18.0',
          'semver>=2.8.1'
```

とかはいっているので `parver` , `semver` をpip install。
んで、sdkをimport !!

```python
% python
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
>>>
```
通りますね。

ちなみにsdk群は `install -e .` してますんで、コンパイルさえされれば即座に使えるようになってます。

```bash
% pip list
Package          Version                    Location
---------------- -------------------------- -----------------------------------------
Arpeggio         1.9.0
attrs            19.1.0
grpcio           1.19.0
parver           0.2.1
pip              19.1.1
protobuf         3.7.0
pulumi           0.17.1
pulumi-ecl       0.17.1.dev1552631198+dirty /Users/yuzu/dev/pulumi-ecl/sdk/python/bin
pulumi-openstack 0.17.0
semver           2.8.1
setuptools       39.0.1
six              1.12.0
```

## まとめ

ということで改めて作り直してみた [pulumi-ecl](https://github.com/keiichi-hikita/pulumi-ecl) です。
masterへのマージも完了したのでお使いいただけますです。

ちょいちょい苦労しましたが、もう少しすると安定的に、

- pulumi-terraformをCI的にmake
- pulumi-eclをmake

だけで行ける作業のようですが、まだいろいろ足したり引いたりが必要な状態ですね。

Interfaceがおかしかった件はパッチ投げても良いかもなぁとか思うけど、多分数日後には直ってるんだろう :sweat_smile: