diff --git a/content/pulumi/_index.md b/content/pulumi/_index.md index f1a4adaf47e611..e2489949d92fd0 100644 --- a/content/pulumi/_index.md +++ b/content/pulumi/_index.md @@ -51,7 +51,7 @@ Pulumi ESC provides centralized management of environments, secrets, and configu {{}} -{{}} +{{}} To learn more about Pulumi. {{}} diff --git a/content/pulumi/installing.md b/content/pulumi/installing.md index 7f25bcf7049ce4..908fda6811adfc 100644 --- a/content/pulumi/installing.md +++ b/content/pulumi/installing.md @@ -1,7 +1,7 @@ --- -title: Install Pulumi +title: Get started pcx_content_type: how-to -weight: 2 +weight: 1 meta: title: Install Pulumi --- diff --git a/content/pulumi/tutorial/_index.md b/content/pulumi/tutorial/_index.md index e46c36986f74d3..e28f55adf1b7f2 100644 --- a/content/pulumi/tutorial/_index.md +++ b/content/pulumi/tutorial/_index.md @@ -1,7 +1,7 @@ --- pcx_content_type: navigation title: Tutorials -weight: 1 +weight: 2 --- # Tutorials @@ -18,4 +18,4 @@ Before you begin, make sure you [install Pulumi](/pulumi/installing/). * Brief introduction to deploying a Cloudflare Workers application with Pulumi. * Introduction of `pulumi new`, `up`, and `destroy`. -* Cloudflare resources defined: Worker script, Worker route, and DNS record. \ No newline at end of file +* Cloudflare resources defined: Worker script, Worker route, and DNS record. diff --git a/content/pulumi/tutorial/add-site.md b/content/pulumi/tutorial/add-site.md index 7071cb7eed669e..b63dac84e7ee5a 100644 --- a/content/pulumi/tutorial/add-site.md +++ b/content/pulumi/tutorial/add-site.md @@ -4,44 +4,35 @@ pcx_content_type: tutorial weight: 1 meta: title: Add a site +languages: + - JavaScript + - TypeScript + - Python --- -# Add a site to Cloudflare with Pulumi IaC +# Add site to Cloudflare -In this tutorial, you will go through step-by-step instructions to bring an existing site to Cloudflare using Pulumi Infrastructure as Code (IaC) so that you can become familiar with the resource management lifecycle. In particular, you will create a Zone and a DNS record to resolve your newly added site. This tutorial adopts the IaC principle to complete the steps listed in the [Add a Site tutorial](/fundamentals/setup/manage-domains/add-site/). +In this tutorial, you will go through step-by-step instructions to bring an existing site to Cloudflare using Pulumi Infrastructure as Code (IaC) so that you can become familiar with the resource management lifecycle. In particular, you will create a Zone and a DNS record to resolve your newly added site. This tutorial adopts the IaC principle to complete the steps listed in the [Add site tutorial](/fundamentals/setup/manage-domains/add-site/). {{}} {{}} - {{}} Ensure you have: -* A Cloudflare account and API Token with permission to edit the resources in this tutorial. If you need to, sign up for a [Cloudflare account](https://dash.cloudflare.com/sign-up/workers-and-pages) before continuing. +* A Cloudflare account and API Token with permission to edit the resources in this tutorial. If you need to, sign up for a [Cloudflare account](https://dash.cloudflare.com/sign-up/workers-and-pages) before continuing. Your token must have: + * `Zone-Zone-Edit` permission + * `Zone-DNS-Edit` permission + * `include-All zones from an account-` zone resource * A Pulumi Cloud account. You can sign up for an [always-free, individual tier](https://app.pulumi.com/signup). -* [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) and the [Pulumi CLI](/pulumi/installing/) installed on your machine. -* A registered domain name. You may use `example.com` to complete the tutorial partially. +* The [Pulumi CLI](/pulumi/installing/) is installed on your machine. +* A [Pulumi-supported programming language](https://github.com/pulumi/pulumi?tab=readme-ov-file#languages) is configured. (TypeScript, JavaScript, Python, Go, .NET, Java, or use YAML) +* A domain name. You may use `example.com` to complete the tutorial. {{}} - -{{}} - {{}} ### a. Create a directory @@ -64,61 +55,245 @@ $ pulumi login ### c. Create a program {{}} -A Pulumi program is code written in a [supported programming language](https://www.pulumi.com/docs/languages-sdks/) that defines infrastructure resources. We use TypeScript. +To create a program, select your language of choice and run the `pulumi` command: -{{}} +{{}} +{{}} -To create a program, run: +```sh +$ pulumi new javascript --name addsite-cloudflare --yes +# wait a few seconds while the project is initialized +``` + +{{}} +{{}} + +```sh +$ pulumi new typescript --name addsite-cloudflare --yes +# wait a few seconds while the project is initialized +``` + +{{}} +{{}} + +```sh +$ pulumi new python --name addsite-cloudflare --yes +# wait a few seconds while the project is initialized +``` + +{{}} +{{}} ```sh -$ pulumi new https://github.com/pulumi/tutorials/tree/cloudflare-typescript-add-site-begin +$ pulumi new go --name addsite-cloudflare --yes +# wait a few seconds while the project is initialized ``` -Complete the prompts with defaults where available; otherwise, provide the requested information. You will need: +{{}} +{{}} + +```sh +$ pulumi new java --name addsite-cloudflare --yes +# wait a few seconds while the project is initialized +``` + +{{}} +{{}} + +```sh +$ pulumi new csharp --name addsite-cloudflare --yes +# wait a few seconds while the project is initialized +``` + +{{}} +{{}} + +```sh +$ pulumi new yaml --name addsite-cloudflare --yes +``` + +{{}} +{{}} + +### d. Save your settings + +You will need: - Your Cloudflare [account ID](/fundamentals/setup/find-account-and-zone-ids/). -- A registered domain. For instance, `example.com` - A valid Cloudflare API [token](/fundamentals/api/get-started/create-token/). +- A domain. For instance, `example.com`. + +{{}} + +```sh +# Define an ESC Environment name +$ E=my-dev-env + +# Create a new Pulumi ESC Environment +$ pulumi config env init --env $E --yes --stack dev + +# Replace API_TOKEN with your Cloudflare API Token +$ pulumi env set $E --secret pulumiConfig.cloudflare:apiToken API_TOKEN + +# Replace abc123 with your Cloudflare Account ID +$ pulumi env set $E --plaintext pulumiConfig.accountId abc123 + +# Replace example.com with your registered domain, or leave as is +$ pulumi env set $E --plaintext pulumiConfig.domain example.com + +# Review your ESC Environment +$ pulumi env open $E +{ + "pulumiConfig": { + "accountId": "111222333", + "cloudflare:apiToken": "abc123abc123", + "domain": "example.com" + } +} +``` -### d. Create a stack +### e. Create a stack {{}} -A Pulumi stack is an instance of a Pulumi program. Stacks are independently configurable and may represent different environments (development, staging, production) or feature branches. +To instantiate your `dev` stack, run: +```sh +$ pulumi up --yes --stack dev +# wait a few seconds for the stack to be instantiated. +``` + +At this point, you have not defined any resources so you'll have an empty stack. + +{{}} +{{}} +{{}} -To create a stack, run: +You will now add the Pulumi Cloudflare package and a Cloudflare Zone resource to your Pulumi program. + +### a. Install dependencies + +{{}} +{{}} ```sh -$ pulumi up --yes +$ npm install @pulumi/cloudflare +added 1 package ... ``` -### d. (Optional) Verify the stack creation +{{}} +{{}} -Review the value of `myTestOutput` to confirm the stack creation. +```sh +$ npm install @pulumi/cloudflare +added 1 package ... +``` + +{{}} +{{}} ```sh -$ pulumi stack output myTestOutput -Hurray! +$ echo "pulumi_cloudflare>=5.35,<6.0.0" >> requirements.txt +$ source venv/bin/activate +$ pip install -r requirements.txt +... +Collecting pulumi-cloudflare +... ``` -{{}} +{{}} +{{}} -{{}} +```sh +$ go get github.com/pulumi/pulumi-cloudflare/sdk/v3/go/cloudflare +go: downloading github.com/pulumi/pulumi-cloudflare ... +``` -{{}} +1. Open your `pom.xml` file. +2. Add the Pulumi Cloudflare dependency inside the `` section. + +```xml + + com.pulumi + cloudflare + 5.35.1 + +``` + +1. Run: + +```sh +$ mvn clean install +... +[INFO] BUILD SUCCESS +... +``` + +{{}} +{{}} + +```sh +$ dotnet add package Pulumi.Cloudflare +... +info : Adding PackageReference for package 'Pulumi.Cloudflare' into project +... +``` + +{{}} +{{}} + +There are no dependencies to download for YAML. Skip ahead. + +{{}} +{{}} + +### b. Modify the program + +Replace the contents of your entrypoint file with the following: + +{{}} +{{}} + +```js +--- +filename: index.js +--- +"use strict"; +const pulumi = require("@pulumi/pulumi"); +const cloudflare = require("@pulumi/cloudflare"); + +const config = new pulumi.Config(); +const accountId = config.require("accountId"); +const domain = config.require("domain"); -You will now add a Cloudflare Zone to the Pulumi stack. +// Create a Cloudflare resource (Zone) +const zone = new cloudflare.Zone("my-zone", { + zone: domain, + accountId: accountId, + plan: "free", + jumpStart: true, +}); -### a. Modify the program +// Export the zone ID +exports.zoneId = zone.id; +``` -Replace the contents of your `index.ts` file with the following: +{{}} +{{}} ```typescript --- @@ -135,27 +310,185 @@ const domain = config.require("domain") const zone = new cloudflare.Zone("my-zone", { zone: domain, accountId: accountId, - plan: "free", + plan: "free", jumpStart: true, }); -// Export the zone ID +// Export the zone ID export const zoneId = zone.id; ``` -### b. Install dependencies +{{}} +{{}} -```sh -$ npm install @pulumi/cloudflare +```py +--- +filename: __main__.py +--- +import pulumi +import pulumi_cloudflare as cloudflare + +account_id = pulumi.Config().require("accountId") +domain = pulumi.Config().require("domain") + +# Create a Cloudflare resource (Zone) +zone = cloudflare.Zone("my-zone", + zone=domain, + account_id=account_id, + plan="free", + jump_start=True) + +# Export the zone ID +pulumi.export("zoneId", zone.id) +``` + +{{}} +{{}} + +```go +--- +filename: main.go +--- +package main + +import ( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v3/go/cloudflare" +) + +func main() { + pulumi.Run(func(ctx *pulumi.Context) error { + domain, _ := ctx.GetConfig("domain") + + // Create a Cloudflare resource (Zone) + zone, err := cloudflare.NewZone(ctx, "my-zone", &cloudflare.ZoneArgs{ + Zone: pulumi.String(domain), + Plan: pulumi.String("free"), + JumpStart: pulumi.Bool(true), + }) + if err != nil { + return err + } + + // Export the zone ID + ctx.Export("zoneId", zone.ID()) + return nil + }) +} ``` +{{}} +{{}} + +The entrypoint file is under the `src/main/java/myproject` directory. + +```java +--- +filename: App.java +--- +package myproject; + +import com.pulumi.Pulumi; +import com.pulumi.Context; +import com.pulumi.cloudflare.ZoneArgs; +import com.pulumi.cloudflare.Zone; + + +public class App { + public static void main(String[] args) { + Pulumi.run(ctx -> { + var config = ctx.config(); + + String accountId = config.require("accountId"); + String domain = config.require("domain"); + + var zone = new Zone("my-zone", ZoneArgs.builder() + .zone(domain) + .accountId(accountId) + .plan("free") + .jumpStart(true) + .build()); + + ctx.export("zoneId", zone.id()); + }); + } +} +``` + +{{}} +{{}} + +```csharp +--- +filename: Program.cs +--- +using System.Threading.Tasks; +using Pulumi; +using Pulumi.Cloudflare; + +class Program +{ + static Task Main() => Deployment.RunAsync(); + + class MyStack : Stack + { + public MyStack() + { + var config = new Pulumi.Config(); + var accountId = config.Require("accountId"); + var domain = config.Require("domain"); + + var zone = new Zone("my-zone", new ZoneArgs + { + ZoneName = domain, + AccountId = accountId, + Plan = "free", + JumpStart = true + }); + + this.ZoneId = zone.Id; + } + + [Output] + public Output ZoneId { get; set; } + } +} +``` + +{{}} +{{}} + +```yaml +--- +filename: Pulumi.dev.yaml +--- +environment: + - my-dev-env + +resources: + myZone: + type: cloudflare:Zone + properties: + zone: ${domain} + accountId: ${accountId} + plan: "free" + jumpStart: true + +outputs: + zoneId: ${myZone.id} +``` + +{{}} +{{}} + ### c. Apply the changes ```sh -$ pulumi up --yes +$ pulumi up --yes --stack dev +# wait a few seconds while the changes take effect ``` -### c. (Optional) Review the Zone ID +### d. (Optional) Review the zone Review the value of `zoneId` to confirm the Zone creation. @@ -165,31 +498,117 @@ d8fcb6d731fe1c2d75e2e8d6ad63fad5 ``` {{}} - {{}} -Once you have added a domain to Cloudflare, that domain will receive two assigned authoritative nameservers. +Once you have added a domain to Cloudflare, that domain will receive two assigned authoritative nameservers. {{}} -### a. Update the program +### a. Update the program + +Towards the end of your entrypoint file, below the `zoneId` variable, add the following: -At the end of your `index.ts` file, add the following: +{{}} +{{}} + +```js +--- +filename: index.js +--- +exports.nameservers = zone.nameServers; +exports.status = zone.status; +``` + +{{}} +{{}} ```typescript +--- +filename: index.ts +--- export const nameservers = zone.nameServers; export const status = zone.status; ``` +{{}} +{{}} + +```py +--- +filename: __main__.py +--- +pulumi.export('nameservers', zone.name_servers) +pulumi.export('status', zone.status) +``` + +{{}} +{{}} + +```go +--- +filename: main.go +--- +ctx.Export("nameservers", zone.NameServers) +ctx.Export("status", zone.Status) +``` + +{{}} +{{}} + +```java +--- +filename: App.java +--- +ctx.export("nameservers", zone.nameServers()); +ctx.export("status", zone.status()); +``` + +{{}} +{{}} + +1. Add `using System.Collections.Immutable;` at the top of your `Program.cs` file. +2. Below `this.ZoneId = zone.Id;`, add: + + ```csharp + --- + filename: Program.cs + --- + this.Nameservers = zone.NameServers; + this.Status = zone.Status; + ``` + +3. Below `public Output ZoneId { get; set; }`, add: + + ```csharp + --- + filename: Program.cs + --- + public Output> Nameservers { get; set; } + public Output Status { get; set; } + ``` + +{{}} +{{}} + +```yaml +--- +filename: Pulumi.dev.yaml +--- +nameservers: ${exampleZone.nameServers} +status: ${exampleZone.status} +``` + +{{}} +{{}} + ### b. Apply the changes ```sh -$ pulumi up --yes +$ pulumi up --yes --stack dev ``` ### c. Obtain the nameservers @@ -197,43 +616,78 @@ $ pulumi up --yes Review the value of `nameservers` to retrieve the assigned nameservers: ```sh -$ pulumi stack output nameservers -["emerie.ns.cloudflare.com","miguel.ns.cloudflare.com"] +$ pulumi stack output --stack dev ``` ### d. Update your registrar {{}} Update the nameservers at your registrar to activate Cloudflare services for your domain. Instructions are registrar-specific. You may be able to find guidance under [this consolidated list of common registrars](/dns/zone-setups/full-setup/setup/#update-your-registrar). {{}} ### e. Check your domain status -Once successfully registered, your domain status will change to `active`. +Once successfully registered, your domain `status` will change to `active`. ```sh -$ pulumi stack output status -active +$ pulumi stack output ``` {{}} - {{}} You will now add a DNS record to your domain. ### a. Modify your program -Replace the contents of your `index.ts` file with the following: +Below is the final version of how your Pulumi program entrypoint file should look. +Replace the contents of your entrypoint file with the following: + +{{}} +{{}} + +```js +--- +filename: index.js +--- +"use strict"; +const pulumi = require("@pulumi/pulumi"); +const cloudflare = require("@pulumi/cloudflare"); + +const config = new pulumi.Config(); +const accountId = config.require("accountId"); +const domain = config.require("domain"); + +// Create a Cloudflare resource (Zone) +const zone = new cloudflare.Zone("my-zone", { + zone: domain, + accountId: accountId, + plan: "free", + jumpStart: true, +}); + +// Export the zone ID +exports.zoneId = zone.id; +exports.nameservers = zone.nameServers; +exports.status = zone.status; + +const record = new cloudflare.Record("my-record", { + zoneId: zone.id, + name: domain, + value: "192.0.2.1", + type: "A", + proxied: true, +}); +``` + +{{}} +{{}} ```typescript --- @@ -254,7 +708,7 @@ const zone = new cloudflare.Zone("my-zone", { jumpStart: true, }); -// Export the zone ID +// Export the zone ID export const zoneId = zone.id; // Export the Cloudflare-assigned nameservers. @@ -271,20 +725,242 @@ const record = new cloudflare.Record("my-record", { type: "A", proxied: true, }); +``` + +{{}} +{{}} + +```py +--- +filename: __main__.py +--- +import pulumi +import pulumi_cloudflare as cloudflare + +account_id = pulumi.Config().require("accountId") +domain = pulumi.Config().require("domain") + +# Create a Cloudflare resource (Zone) +zone = cloudflare.Zone("my-zone", + zone=domain, + account_id=account_id, + plan="free", + jump_start=True) + +# Export the zone ID +pulumi.export("zoneId", zone.id) +pulumi.export('nameservers', zone.name_servers) +pulumi.export('status', zone.status) + +record = cloudflare.Record("my-record", + zone_id=zone.id, + name=domain, + value="192.0.2.1", + type="A", + proxied=True +) ``` +{{}} +{{}} + +```go +--- +filename: main.go +--- +package main + +import ( + cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v3/go/cloudflare" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +func main() { + pulumi.Run(func(ctx *pulumi.Context) error { + domain, _ := ctx.GetConfig("domain") + + // Create a Cloudflare resource (Zone) + zone, err := cloudflare.NewZone(ctx, "my-zone", &cloudflare.ZoneArgs{ + Zone: pulumi.String(domain), + Plan: pulumi.String("free"), + JumpStart: pulumi.Bool(true), + }) + if err != nil { + return err + } + + // Export the zone ID + ctx.Export("zoneId", zone.ID()) + ctx.Export("nameservers", zone.NameServers) + ctx.Export("status", zone.Status) + + _, err = cloudflare.NewRecord(ctx, "my-record", &cloudflare.RecordArgs{ + ZoneId: zone.ID(), + Name: pulumi.String(domain), + Value: pulumi.String("192.0.2.1"), + Type: pulumi.String("A"), + Proxied: pulumi.Bool(true), + }) + if err != nil { + return err + } + + return nil + }) +} + +``` + +{{}} +{{}} + +```java +--- +filename: App.java +--- +package myproject; + +import com.pulumi.Pulumi; +import com.pulumi.Context; +import com.pulumi.cloudflare.ZoneArgs; +import com.pulumi.cloudflare.Zone; +import com.pulumi.cloudflare.Record; +import com.pulumi.cloudflare.RecordArgs; + + +public class App { + public static void main(String[] args) { + Pulumi.run(ctx -> { + var config = ctx.config(); + + String accountId = config.require("accountId"); + String domain = config.require("domain"); + + var zone = new Zone("my-zone", ZoneArgs.builder() + .zone(domain) + .accountId(accountId) + .plan("free") + .jumpStart(true) + .build()); + + ctx.export("zoneId", zone.id()); + ctx.export("nameservers", zone.nameServers()); + ctx.export("status", zone.status()); + + new Record("my-record", RecordArgs.builder() + .zoneId(zone.id()) + .name(domain) + .value("192.0.2.1") + .type("A") + .proxied(true) + .build()); + }); + } +} +``` + +{{}} +{{}} + +```csharp +--- +filename: Program.cs +--- +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi; +using Pulumi.Cloudflare; + +class Program +{ + static Task Main() => Deployment.RunAsync(); + + class MyStack : Stack + { + public MyStack() + { + var config = new Pulumi.Config(); + var accountId = config.Require("accountId"); + var domain = config.Require("domain"); + + var zone = new Zone("my-zone", new ZoneArgs + { + ZoneName = domain, + AccountId = accountId, + Plan = "free", + JumpStart = true + }); + + this.ZoneId = zone.Id; + this.Nameservers = zone.NameServers; + this.Status = zone.Status; + + new Record("my-record", new RecordArgs + { + ZoneId = zone.Id, + Name = domain, + Value = "192.0.2.1", + Type = "A", + Proxied = true + }); + + } + + [Output] + public Output ZoneId { get; set; } + public Output> Nameservers { get; set; } + public Output Status { get; set; } + } +} +``` + +{{}} +{{}} + +```yaml +--- +filename: Pulumi.dev.yaml +--- +environment: + - my-dev-env + +resources: + myZone: + type: cloudflare:Zone + properties: + zone: ${domain} + accountId: ${accountId} + plan: "free" + jumpStart: true + + myRecord: + type: cloudflare:Record + properties: + zoneId: ${myZone.id} + name: ${domain} + value: 192.0.2.1 + type: A + proxied: true +outputs: + zoneId: ${myZone.id} + nameservers: ${exampleZone.nameServers} + status: ${exampleZone.status} +``` + +{{}} +{{}} + ### b. Apply the changes ```sh -$ pulumi up --yes +$ pulumi up --yes --stack dev ``` {{}} +{{}} -{{}} - -You will run two `nslookup` commands against the Cloudflare-assigned nameservers. +You will run two `nslookup` commands against the Cloudflare-assigned nameservers. To test your site, run: @@ -296,10 +972,11 @@ $ nslookup $DOMAIN $NS1 $ nslookup $DOMAIN $NS2 ``` -Confirm your response returns IP address(es) for your site. +For .NET use `Nameservers` as the Output. -{{}} +Confirm your response returns the IP address(es) for your site. +{{}} {{}} In this last step, you will remove the resources and stack used throughout the tutorial. @@ -307,7 +984,7 @@ In this last step, you will remove the resources and stack used throughout the t ### a. Delete the resources ```sh -$ pulumi destroy +$ pulumi destroy --yes ``` ### b. Remove the stack @@ -317,12 +994,11 @@ $ pulumi stack rm dev ``` {{}} - {{}} -You have incrementally defined Cloudflare resources needed to add a site to Cloudflare. After each new resource, you apply the changes to your stack via the `pulumi up` command. You declare the resources in TypeScript and let Pulumi handle the rest. +You have incrementally defined Cloudflare resources needed to add a site to Cloudflare. After each new resource, you apply the changes to your `dev` stack via the `pulumi up` command. You declare the resources in your programming language of choice and let Pulumi handle the rest. -Follow the [Hello World tutorial](/pulumi/tutorial/hello-world/) next to deploy your first app with Pulumi. -{{}} +Follow the [Hello World tutorial](/pulumi/tutorial/hello-world/) to deploy a serverless app with Pulumi. -{{}} \ No newline at end of file +{{}} +{{}} diff --git a/content/pulumi/tutorial/hello-world.md b/content/pulumi/tutorial/hello-world.md index 77f4640a5335b9..2d9aeafe8ad12b 100644 --- a/content/pulumi/tutorial/hello-world.md +++ b/content/pulumi/tutorial/hello-world.md @@ -323,6 +323,7 @@ $ curl "https://$(pulumi stack output url)" ``` + {{