TerraformでAzure DevOpsをプロビジョニングする

タイトルの通り、Terraform使ってAzure DevOpsをプロビジョニングする方法です。

前提

組織登録

まずは、Terraform実行する前に以下の画面から組織の登録を行う必要があります。

azure.microsoft.com

このような画面になるはずです。

URLは https://dev.azure.com/your-org となりますが、これを後で利用します。

Personal Access Tokenの取得

画面右上からPersonal Access Tokenを取得しておきます。


Terraform定義準備

TerraformのAzure DevOps ProviderはMSがGithubに公開しているので、これを利用します。

このようなディレクトリ構成を作ります。

.
├── main.tf
├── terraform.d
│   └── plugins
│       └── linux_amd64
│           └── terraform-provider-azuredevops_v0.1.0

Terraformの定義の準備

Githubのサンプルを参考に以下のように作ってみます。

variable "org_name" {}
variable "personal_access_token" {}

provider "azuredevops" {
  version               = ">= 0.0.1"
  org_service_url       = "https://dev.azure.com/${var.org_name}/"
  personal_access_token = var.personal_access_token
}

resource "azuredevops_azure_git_repository" "repository" {
  project_id = azuredevops_project.project.id
  name       = "My Awesome Repo"
  initialization {
    init_type = "Clean"
  }
}

resource "azuredevops_azure_git_repository" "repository" {
  project_id = azuredevops_project.project.id
  name       = "My Awesome Repo"
  initialization {
    init_type = "Clean"
  }
}

resource "azuredevops_build_definition" "build_definition" {
  project_id = azuredevops_project.project.id
  name       = "My Awesome Build Pipeline"
  path       = "\\"

  repository {
    repo_type   = "TfsGit"
    repo_name   = azuredevops_azure_git_repository.repository.name
    branch_name = azuredevops_azure_git_repository.repository.default_branch
    yml_path    = "azure-pipelines.yml"
  }
}

Azure DevOps Providerのインストール

上記の定義で使われている azuredevops のProviderをインストールします。

以下のURLでMSがGithubで公開しています。

github.com

まずはGolangでビルドする必要があるので、Docker使ってビルドします。

ディレクトリ作成して、Golangのイメージを起動します。

$ mkdir -p terraform.d/plugins/linux_amd64
$ docker run --rm -it -v $(pwd)/terraform.d/plugins/linux_amd64:/plugin  golang:buster /bin/bash
root@70557c0bfefc:/go#

以下のようにビルドします。

VER=v0.1.0
mkdir -p $GOPATH/src/github.com/terraform-providers/

# ↓ -b を抜かせば最新版でビルドできます
git clone https://github.com/microsoft/terraform-provider-azuredevops.git -b ${VER} --depth 1
cd ./terraform-provider-azuredevops/  
go build -o /plugin/terraform-provider-azuredevops_${VER}
exit

戻ったらProviderが認識されているか確認します。

$ terraform init

Initializing the backend...

Initializing provider plugins...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Terraformの実行

まずは terraform plan を実行してみます。パラメータを聞かれるので、最初の手順で作成した組織名と、取得したPersonal Access Tokenを入力します。

$ terraform plan
var.org_name
  Enter a value: your-org

var.personal_access_token
  Enter a value: xxxxxxxxxxx

成功したら同様の方法で apply していきます。

$ terraform apply

Azure DevOpsのサービスが展開できました。

f:id:yomon8:20200408180106p:plain

スキーマの確認

スキーマの出力をすると設定できる内容を確認することができます。

$ terraform providers schema -json | jq
{
  "format_version": "0.1",
  "provider_schemas": {
    "azuredevops": {
      "provider": {
        "version": 0,
        "block": {
          "attributes": {
            "org_service_url": {
              "type": "string",
              "description": "The url of the Azure DevOps instance which should be used.",
              "required": true
            },
            "personal_access_token": {
              "type": "string",
              "description": "The personal access token which should be used.",
              "required": true,
              "sensitive": true
            }
          }
        }
      },
      "resource_schemas": {
        "azuredevops_agent_pool": {
          "version": 0,
          "block": {
            "attributes": {
              "auto_provision": {
                "type": "bool",
                "optional": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "name": {
                "type": "string",
                "required": true
              },
              "pool_type": {
                "type": "string",
                "optional": true
              }
            }
          }
        },
        "azuredevops_azure_git_repository": {
          "version": 0,
          "block": {
            "attributes": {
              "default_branch": {
                "type": "string",
                "computed": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "is_fork": {
                "type": "bool",
                "computed": true
              },
              "name": {
                "type": "string",
                "required": true
              },
              "project_id": {
                "type": "string",
                "required": true
              },
              "remote_url": {
                "type": "string",
                "computed": true
              },
              "size": {
                "type": "number",
                "computed": true
              },
              "ssh_url": {
                "type": "string",
                "computed": true
              },
              "url": {
                "type": "string",
                "computed": true
              },
              "web_url": {
                "type": "string",
                "computed": true
              }
            },
            "block_types": {
              "initialization": {
                "nesting_mode": "set",
                "block": {
                  "attributes": {
                    "init_type": {
                      "type": "string",
                      "required": true
                    },
                    "source_type": {
                      "type": "string",
                      "optional": true
                    },
                    "source_url": {
                      "type": "string",
                      "optional": true
                    }
                  }
                },
                "min_items": 1,
                "max_items": 1
              }
            }
          }
        },
        "azuredevops_build_definition": {
          "version": 0,
          "block": {
            "attributes": {
              "agent_pool_name": {
                "type": "string",
                "optional": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "name": {
                "type": "string",
                "optional": true
              },
              "path": {
                "type": "string",
                "optional": true
              },
              "project_id": {
                "type": "string",
                "required": true
              },
              "revision": {
                "type": "number",
                "computed": true
              },
              "variable_groups": {
                "type": [
                  "set",
                  "number"
                ],
                "optional": true
              }
            },
            "block_types": {
              "repository": {
                "nesting_mode": "set",
                "block": {
                  "attributes": {
                    "branch_name": {
                      "type": "string",
                      "optional": true
                    },
                    "repo_name": {
                      "type": "string",
                      "required": true
                    },
                    "repo_type": {
                      "type": "string",
                      "required": true
                    },
                    "service_connection_id": {
                      "type": "string",
                      "optional": true
                    },
                    "yml_path": {
                      "type": "string",
                      "required": true
                    }
                  }
                },
                "min_items": 1,
                "max_items": 1
              }
            }
          }
        },
        "azuredevops_group": {
          "version": 0,
          "block": {
            "attributes": {
              "description": {
                "type": "string",
                "optional": true
              },
              "descriptor": {
                "type": "string",
                "computed": true
              },
              "display_name": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "domain": {
                "type": "string",
                "computed": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "mail": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "members": {
                "type": [
                  "set",
                  "string"
                ],
                "optional": true,
                "computed": true
              },
              "origin": {
                "type": "string",
                "computed": true
              },
              "origin_id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "principal_name": {
                "type": "string",
                "computed": true
              },
              "scope": {
                "type": "string",
                "optional": true
              },
              "subject_kind": {
                "type": "string",
                "computed": true
              },
              "url": {
                "type": "string",
                "computed": true
              }
            }
          }
        },
        "azuredevops_group_membership": {
          "version": 0,
          "block": {
            "attributes": {
              "group": {
                "type": "string",
                "required": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "members": {
                "type": [
                  "set",
                  "string"
                ],
                "required": true
              },
              "mode": {
                "type": "string",
                "optional": true
              }
            }
          }
        },
        "azuredevops_project": {
          "version": 0,
          "block": {
            "attributes": {
              "description": {
                "type": "string",
                "optional": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "process_template_id": {
                "type": "string",
                "computed": true
              },
              "project_name": {
                "type": "string",
                "required": true
              },
              "version_control": {
                "type": "string",
                "optional": true
              },
              "visibility": {
                "type": "string",
                "optional": true
              },
              "work_item_template": {
                "type": "string",
                "optional": true
              }
            }
          }
        },
        "azuredevops_serviceendpoint_dockerhub": {
          "version": 0,
          "block": {
            "attributes": {
              "description": {
                "type": "string",
                "optional": true
              },
              "docker_email": {
                "type": "string",
                "description": "The DockerHub email address which should be used.",
                "required": true
              },
              "docker_password": {
                "type": "string",
                "description": "The DockerHub password which should be used.",
                "required": true,
                "sensitive": true
              },
              "docker_password_hash": {
                "type": "string",
                "description": "A bcrypted hash of the attribute 'docker_password'",
                "computed": true,
                "sensitive": true
              },
              "docker_username": {
                "type": "string",
                "description": "The DockerHub username which should be used.",
                "required": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "project_id": {
                "type": "string",
                "required": true
              },
              "service_endpoint_name": {
                "type": "string",
                "required": true
              }
            }
          }
        },
        "azuredevops_serviceendpoint_github": {
          "version": 0,
          "block": {
            "attributes": {
              "description": {
                "type": "string",
                "optional": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "project_id": {
                "type": "string",
                "required": true
              },
              "service_endpoint_name": {
                "type": "string",
                "required": true
              }
            },
            "block_types": {
              "auth_oath": {
                "nesting_mode": "set",
                "block": {
                  "attributes": {
                    "oauth_configuration_id": {
                      "type": "string",
                      "required": true
                    }
                  }
                },
                "max_items": 1
              },
              "auth_personal": {
                "nesting_mode": "set",
                "block": {
                  "attributes": {
                    "personal_access_token": {
                      "type": "string",
                      "description": "The GitHub personal access token which should be used.",
                      "required": true,
                      "sensitive": true
                    },
                    "personal_access_token_hash": {
                      "type": "string",
                      "description": "A bcrypted hash of the attribute 'personal_access_token'",
                      "computed": true,
                      "sensitive": true
                    }
                  }
                },
                "max_items": 1
              }
            }
          }
        },
        "azuredevops_user_entitlement": {
          "version": 0,
          "block": {
            "attributes": {
              "account_license_type": {
                "type": "string",
                "optional": true
              },
              "descriptor": {
                "type": "string",
                "computed": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "origin": {
                "type": "string",
                "optional": true
              },
              "origin_id": {
                "type": "string",
                "optional": true
              },
              "principal_name": {
                "type": "string",
                "optional": true
              }
            }
          }
        },
        "azuredevops_variable_group": {
          "version": 0,
          "block": {
            "attributes": {
              "allow_access": {
                "type": "bool",
                "optional": true
              },
              "description": {
                "type": "string",
                "optional": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "name": {
                "type": "string",
                "required": true
              },
              "project_id": {
                "type": "string",
                "required": true
              }
            },
            "block_types": {
              "variable": {
                "nesting_mode": "set",
                "block": {
                  "attributes": {
                    "is_secret": {
                      "type": "bool",
                      "optional": true
                    },
                    "name": {
                      "type": "string",
                      "required": true
                    },
                    "value": {
                      "type": "string",
                      "optional": true
                    }
                  }
                },
                "min_items": 1
              }
            }
          }
        }
      },
      "data_source_schemas": {
        "azuredevops_group": {
          "version": 0,
          "block": {
            "attributes": {
              "descriptor": {
                "type": "string",
                "computed": true
              },
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "name": {
                "type": "string",
                "required": true
              },
              "project_id": {
                "type": "string",
                "required": true
              }
            }
          }
        },
        "azuredevops_projects": {
          "version": 0,
          "block": {
            "attributes": {
              "id": {
                "type": "string",
                "optional": true,
                "computed": true
              },
              "project_name": {
                "type": "string",
                "optional": true
              },
              "projects": {
                "type": [
                  "set",
                  [
                    "object",
                    {
                      "name": "string",
                      "project_id": "string",
                      "project_url": "string",
                      "state": "string"
                    }
                  ]
                ],
                "computed": true
              },
              "state": {
                "type": "string",
                "optional": true
              }
            }
          }
        }
      }
    }
  }
}