L'infrastructure en tant que code (IaC) a transformé la gestion informatique, et Terraform d'HashiCorp a été un pilier dans ce domaine.

Mais que se passerait-il si vous pouviez combiner la puissance des providers de Terraform avec la flexibilité des langages de programmation populaires comme Python et JavaScript ?

C'est prĂ©cisĂ©ment ce que propose Pulumi et le Pulumi Terraform Bridge. 🙏

Vous avez été relativement nombreux/ses à vouloir un article sur ce sujet, c'est maintenant chose faite.

Avant de commencer, je souhaiterais prĂ©ciser qu'il vous faudra quelques connaissances en Go pour y arriver sans trop de difficultĂ©. đŸ«Ą

C'est parti, allons-y !

RĂ©cupĂ©ration des prĂ©requis 😄

Vous devez, avant de commencer avoir en votre possession :

  • GNU Make (pour le Makefile)
  • Golang (vers 1.18 ou supĂ©rieur)
  • Goreleaser
  • Git (obviously).

Et le "Terraform Bridge Provider Boilerplate" : https://github.com/pulumi/pulumi-tf-provider-boilerplate

Ce projet doit ĂȘtre forkĂ© chez vous, en respectant le format suivant :

pulumi-<provider_name>

Ce qui donne par exemple :

pulumi-maas

Ni plus, ni moins ! Ne reste plus qu'Ă  cloner le repo chez vous :

git clone https://github.com/juhnny5/pulumi-maas.git
cd pulumi-maas/

Initialiser le repo

Le boilerplate, comme son nom l'indique fournit une base qu'il va falloir un peu adapter par rapport à notre provider à créer.

Pour ce faire, nous allons utiliser la commande suivante :

make prepare NAME=maas REPOSITORY=github.com/juhnny5/pulumi-maas

Cette commande va venir modifier les différents fichiers nécessaires au build et à la transformation, notamment le go.mod par exemple.

Elle va Ă©galement gĂ©nĂ©rer les ressources qui vont nous ĂȘtre utiles par la suite :

  • provider/cmd/pulumi-resource-maas
  • provider/cmd/pulumi-tfgen-maas
  • provider/resources.go

Cette commande modifie pas mal de choses, mais, dans mon cas, je vais chercher Ă  convertir un provider qui n'est pas dans le repo officiel de Terraform. En effet, le provider de MaaS est sur le repo de l'orga du mĂȘme nom, Ă  savoir :

GitHub - maas/terraform-provider-maas: Terraform MAAS provider
Terraform MAAS provider. Contribute to maas/terraform-provider-maas development by creating an account on GitHub.

Ainsi, dans le fichier Makefile, il me suffira de modifier les variables de cette sorte :

PROJECT_NAME := maas Package

SHELL            := /bin/bash
PACK             := maas
ORG              := juhnny5
PROJECT          := github.com/${ORG}/pulumi-${PACK}
NODE_MODULE_NAME := @juhnny5/${PACK}
TF_NAME          := ${PACK}
PROVIDER_PATH    := provider
VERSION_PATH     := ${PROVIDER_PATH}/pkg/version.Version

TFGEN           := pulumi-tfgen-${PACK}
PROVIDER        := pulumi-resource-${PACK}
VERSION         := $(shell pulumictl get version)

TESTPARALLELISM := 4

WORKING_DIR     := $(shell pwd)

OS := $(shell uname)
EMPTY_TO_AVOID_SED := ""

Dans mon exemple, j'utilise un provider Terraform en source qui est un peu particulier. En effet, si on regarde le go.mod du projet, celui-ci, on se rend compte que le nom du projet n'est pas le FQDN du projet sur GitHub mais simplement le nom du repo.

module terraform-provider-maas

go 1.19

require (
	github.com/bflad/tfproviderlint v0.28.1
	github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
	github.com/hashicorp/terraform-plugin-docs v0.16.0
	github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0
	github.com/maas/gomaasclient v0.0.0-20230512141257-d73401ee0dc8
	github.com/stretchr/testify v1.8.4
)

Ainsi, cÎté boilerplate, il faudra modifier notre go.mod également pour que nous puissions utiliser cette lib en entrée. Ainsi donc :

vi provider/go.mod

On va remplacer le nom en spĂ©cifiant la version souhaitĂ©e. 🙃

module github.com/juhnny5/pulumi-maas/provider

go 1.19

replace (
	github.com/hashicorp/terraform-plugin-sdk/v2 => github.com/pulumi/terraform-plugin-sdk/v2 v2.0.0-20230710100801-03a71d0fca3d
	terraform-provider-maas v1.2.0 => github.com/maas/terraform-provider-maas v1.2.0
)

require (
	github.com/pulumi/pulumi-terraform-bridge/v3 v3.57.0
	github.com/pulumi/pulumi/sdk/v3 v3.76.1
	terraform-provider-maas v1.2.0
)

Ainsi, nous pourrons utiliser le nom terraform-provider-maas dans notre code. A noter que cette subtilité n'est pas toujours présente, cette manipulation est à réaliser dans le cas ou le provider source ne spécifie pas le FQDN Github dans son go.mod.

Maintenant, il suffit de rajouter la dĂ©pendance vers ce provider Terraform dans notre fichier de resources. đŸ«Ą

Pour ce faire :

vi provider/resources.go

Et y ajouter terraform-provider-maas/maas, de cette sorte :

package maas

import (
	"fmt"
	"path/filepath"

	"terraform-provider-maas/maas"

	"github.com/juhnny5/pulumi-maas/provider/pkg/version"
	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/tokens"
	shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
	shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
	"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
)

Un coup de tfgen đŸ„ž

Pour continuer, il faut lancer la commande :

make tfgen

Modifier les infos du futur provider Pulumi 👀

Par dĂ©faut, lorsque vous avez fait initialisĂ© le projet, le fichier resources.go a ajoutĂ© plusieurs infos concernant le projet.  😋

Nous allons y modifier d'autres infos avant de générer les SDKs. Le nom du Publisher :

	prov := tfbridge.ProviderInfo{
		P:    p,
		Name: "maas",
		// DisplayName is a way to be able to change the casing of the provider
		// name when being displayed on the Pulumi registry
		DisplayName: "MAAS",
		// The default publisher for all packages is Pulumi.
		// Change this to your personal name (or a company name) that you
		// would like to be shown in the Pulumi Registry if this package is published
		// there.
		Publisher: "Julien Briault",
provider/resources.go

Mais également la description et l'org Github si celle-ci n'a pas été correctement modifiée.

Description:       "A Pulumi package for creating and managing Canonical Metal-As-A-Service (MAAS) resources.",
GitHubOrg: "juhnny5",
Repository: "https://github.com/juhnny5/pulumi-maas",
Keywords:   []string{"pulumi", "maas", "category/cloud"},

Ensuite, nous allons spĂ©cifier la configuration de chaque SDK Ă  gĂ©nĂ©rer. Quand je parle de chaque SDK, j'entends par chaque langage de programmation Ă  supporter par votre provider. 😈

Ainsi, vous pouvez obtenir ce résultat :

		JavaScript: &tfbridge.JavaScriptInfo{
			// List any npm dependencies and their versions
			Dependencies: map[string]string{
				"@pulumi/pulumi": "^3.0.0",
			},
			DevDependencies: map[string]string{
				"@types/node": "^10.0.0", // so we can access strongly typed node definitions.
				"@types/mime": "^2.0.0",
			},
			// See the documentation for tfbridge.OverlayInfo for how to lay out this
			// section, or refer to the AWS provider. Delete this section if there are
			// no overlay files.
			//Overlay: &tfbridge.OverlayInfo{},
		},
		Python: &tfbridge.PythonInfo{
			// List any Python dependencies and their version ranges
			PackageName: "pulumi-maas",
			Requires: map[string]string{
				"pulumi": ">=3.0.0,<4.0.0",
			},
		},
		Golang: &tfbridge.GolangInfo{
			ImportBasePath: filepath.Join(
				fmt.Sprintf("github.com/juhnny5/pulumi-%[1]s/sdk/", mainPkg),
				tfbridge.GetModuleMajorVersion(version.Version),
				"go",
				mainPkg,
			),
			GenerateResourceContainerTypes: true,
		},
		CSharp: &tfbridge.CSharpInfo{
			PackageReferences: map[string]string{
				"Pulumi": "3.*",
			},
		},

GĂ©nĂ©rer le code ! â˜ș

Maintenant que l'on est tout bon sur les dĂ©pendances et dans l'initialisation du projet, nous allons pouvoir transformer notre code Terraform en code Pulumi et gĂ©nĂ©rer les SDKs appropriĂ©s. 😄

make build_sdks

Vous retrouverez automatiquement le code des différents SDKS dans sdk/.

Une fois que c'est fait, il ne reste plus qu'à release votre code sur Github, je ne vais pas expliquer comment fonctionne Goreleaser ici, par contre, je vous invite à créer votre fichier de cette sorte :

archives:
  - id: archive
    name_template: '{{ .Binary }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}'
before:
  hooks:
    - make tfgen
builds:
  - binary: pulumi-resource-maas
    dir: provider
    env:
      - CGO_ENABLED=0
    goarch:
      - amd64
      - arm64
    goos:
      - darwin
      - windows
      - linux
    ldflags:
      # The line below MUST align with the module in current provider/go.mod
      - -X github.com/juhnny5/pulumi-maas/provider/pkg/version.Version={{.Tag }}
    main: ./cmd/pulumi-resource-maas/
changelog:
  skip: true
release:
  disable: false
  prerelease: auto
snapshot:
  name_template: '{{ .Tag }}-SNAPSHOT'
.goreleaser.yml

A noter que vous trouverez un exemple dans le dossier deploymen-templates/. Vous y trouverez Ă©galement le README expliquant comment release votre projet.

Pour terminer, vous trouverez tout le code disponible ici si vous souhaitez un exemple concret :

GitHub - juhnny5/pulumi-maas
Contribute to juhnny5/pulumi-maas development by creating an account on GitHub.

Vous l'aurez compris, plus d'excuse pour ne pas migrer vers Pulumi. Le prochain article traitera de comment publier ces diffĂ©rentes ressources (sdks). đŸ€­