是否可以让 Ansible 与 Pulumi 一起工作?

Is getting Ansible to work with Pulumi possible?

我希望在循环中创建多个 droplet (DigitalOcean),然后 运行 Ansible 之后在 droplet 上设置所需的软件和安全措施。这可能像地形一样吗?如果是这样,这在 javascript/typescript 代码中看起来如何?

google 中没有任何内容可以创建此示例或使用 Ansible 提及 Pulumi。

是的,这是可能的。

您可以选择以下两种方式之一:

您可以在 DigitalOcean 液滴的 userdata 中指定您的 ansible 运行。这适用于所有语言 SDK。

或者,如果您想拥有与 Terraform 的远程执行供应器类似的功能,您可以使用 Pulumi 的 dynamic providers 创建供应器。

动态提供程序目前在 TypeScript 和 Python SDK 中可用。您可以找到 python 示例 here and a TypeScript example here

这是一个示例,说明如何使用它通过剧本部署 wordpress,使用 local.Command 提供程序并在远程主机上进行 ansible 配置

import * as command from '@pulumi/command'
import * as pulumi from '@pulumi/pulumi'
import * as fs from 'fs'
import {URL} from 'url'
import YAML from 'yaml'

const __dirname = new URL('.', import.meta.url).pathname
nunjucks.configure(`${__dirname}/templates`)

export interface WordPressArgs {
  fqdn: pulumi.Input<string>
  ip: pulumi.Input<string>
  sshPort: pulumi.Input<number>
  sshPrivateKey: pulumi.Input<string>
  sshUser: pulumi.Input<string>
  domainUser: pulumi.Input<string>
  domainUserHomeDir?: pulumi.Input<string>
  domainUserDocumentRootDir?: pulumi.Input<string>
  nginxUser?: pulumi.Input<string>
  wordpressLanguage?: pulumi.Input<string>
  wordpressDbName: pulumi.Input<string>
  wordpressDbUser: pulumi.Input<string>
  wordpressDbPassword: pulumi.Input<string>
  wordpressDbHost?: pulumi.Input<string>
  wordpressTitle?: pulumi.Input<string>
  wordpressAdminUser?: pulumi.Input<string>
  wordpressAdminPassword: pulumi.Input<string>
  wordpressAdminEmail?: pulumi.Input<string>
  deploymentEnvironment?: pulumi.Input<'production' | 'staging' | 'testing'>
}

export class WordPress extends pulumi.ComponentResource {
  private readonly wordPressInstallCommand: pulumi.Output<string>

  constructor(
    name: string,
    args: WordPressArgs,
    opts?: pulumi.ComponentResourceOptions
  ) {
    super('system:virtualmin:wordpress', name, {}, opts)

    const cmd = pulumi
      .all(
        [
          args.fqdn,
          args.ip,
          args.sshPort,
          args.sshUser,
          args.sshPrivateKey,
          args.domainUser,
          args.nginxUser,
          args.wordpressLanguage,
          args.wordpressDbHost,
          args.wordpressDbName,
          args.wordpressDbUser,
          args.wordpressDbPassword,
          args.wordpressTitle,
          args.wordpressAdminUser,
          args.wordpressAdminPassword,
          args.wordpressAdminEmail,
          args.deploymentEnvironment]
      )
      .apply((
          [
            fqdn,
            ip,
            sshPort,
            sshUser,
            sshPrivateKey,
            domainUser,
            nginxUser,
            wordpressLanguage,
            wordpressDbHost,
            wordpressDbName,
            wordpressDbUser,
            wordpressDbPassword,
            wordpressTitle,
            wordpressAdminUser,
            wordpressAdminPassword,
            wordpressAdminEmail,
            deploymentEnvironment]
        ) => {

          fs.writeFileSync(
            `/tmp/ansible.pem`,
            sshPrivateKey.toString(),
            {mode: 0o600}
          )

          fs.writeFileSync(
            '/tmp/inventory',
            YAML.stringify(
              {
                all: {
                  hosts: {
                    remote: {
                      ansible_host: ip,
                      ansible_port: sshPort,
                      ansible_user: sshUser,
                      ansible_private_key_file: '/tmp/ansible.pem',
                      ansible_host_key_checking: false
                    }
                  }
                }
              }),
            {mode: 0o600}
          )

          const playbookVars = pulumi.interpolate`${JSON.stringify({
            fqdn,
            deployment_environment: deploymentEnvironment || 'staging',
            domain_user: domainUser,
            nginx_user: nginxUser || 'www-data',
            wordpress_language: wordpressLanguage || 'en_US',
            wordpress_db_host: wordpressDbHost || 'localhost:3306',
            wordpress_db_name: wordpressDbName,
            wordpress_db_user: wordpressDbUser,
            wordpress_db_password: wordpressDbPassword,
            wordpress_title: wordpressTitle || 'Just a WordPress site',
            wordpress_admin_user: wordpressAdminUser || 'admin',
            wordpress_admin_password: wordpressAdminPassword,
            wordpress_admin_email: wordpressAdminEmail,
            ssl_cert_dir: '/etc/ssl/certs',
            ssl_key_dir: '/etc/ssl/private'
          })}`
          return {create: pulumi.interpolate`ANSIBLE_STDOUT_CALLBACK=json ansible-playbook -i /tmp/inventory ${__dirname}/playbooks/install-wordpress.yaml -e '${playbookVars}'`}
        }
      )


    this.wordPressInstallCommand = cmd.create
    const wordPressInstallation = new command.local.Command(
      'wordpress-installation',
      {
        create: this.wordPressInstallCommand,
      },
      {parent: this}
    )

    this.registerOutputs()
  }
}