diff --git a/content/docs/iac/get-started/aws/begin.md b/content/docs/iac/get-started/aws/begin.md index 12bf1eec7ec9..bd81f19131f9 100644 --- a/content/docs/iac/get-started/aws/begin.md +++ b/content/docs/iac/get-started/aws/begin.md @@ -24,14 +24,6 @@ aliases: - /docs/clouds/aws/get-started/begin/ --- -## Install Pulumi - -Download and install Pulumi for your platform: - -{{< install-pulumi >}} -{{% notes info %}} -All Windows examples in this tutorial assume you are running in PowerShell. -{{% /notes %}} -{{< /install-pulumi >}} +{{< get-started-install-body >}} {{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/_index.md b/content/docs/iac/get-started/azure/_index.md index 6bacb90e76b3..8b45609d405c 100644 --- a/content/docs/iac/get-started/azure/_index.md +++ b/content/docs/iac/get-started/azure/_index.md @@ -19,6 +19,56 @@ aliases: - /docs/clouds/azure/get-started/ --- -{{< cloud-intro "Microsoft Azure" >}} +**Infrastructure as code (IaC)** lets you deploy, change, and manage infrastructure safely, consistently, +and repeatably using code rather than a graphical user interface. + +Complete this step-by-step tutorial to deploy an Azure Blob Storage-based website using IaC. + +## Before you begin + +First, choose your language and ensure you've performed any prerequisites: + +{{< chooser language "typescript,python,go,csharp,java,yaml" / >}} + +{{% choosable language "typescript" %}} + +* An Azure account +* Node.js and npm installed locally + +{{% /choosable %}} + +{{% choosable language "python" %}} + +* An Azure account +* Python and pip, Poetry or uv installed locally + +{{% /choosable %}} + +{{% choosable language "go" %}} + +* An Azure account +* Go installed locally + +{{% /choosable %}} + +{{% choosable language "csharp" %}} + +* An Azure account +* .NET installed locally + +{{% /choosable %}} + +{{% choosable language "java" %}} + +* An Azure account +* Java 11+ and Maven 3.6.1+ installed locally + +{{% /choosable %}} + +{{% choosable language "yaml" %}} + +* An Azure account + +{{% /choosable %}} {{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/begin.md b/content/docs/iac/get-started/azure/begin.md index 2c502f059cef..a72a8c4cb63a 100644 --- a/content/docs/iac/get-started/azure/begin.md +++ b/content/docs/iac/get-started/azure/begin.md @@ -1,8 +1,9 @@ --- -title_tag: Before You Begin | Azure +title_tag: Install Pulumi | Azure meta_desc: This page provides an overview on how to get started with Pulumi when starting an Azure project. -title: Before you begin -h1: "Pulumi & Azure: Before you begin" +title: Install Pulumi +h1: "Get started with Pulumi and Azure" +stepper_link: "I'm ready to begin" weight: 2 menu: iac: @@ -18,74 +19,6 @@ aliases: - /docs/clouds/azure/get-started/begin/ --- -Before you get started using Pulumi, let's run through a few quick steps to ensure your environment is set up correctly. - -### Install Pulumi - -{{< install-pulumi >}} -{{% notes "info" %}} -All Windows examples in this tutorial assume you are running in PowerShell. -{{% /notes %}} -{{< /install-pulumi >}} - -Next, install the required language runtime, if you have not already. - -### Install Language Runtime - -#### Choose Your Language - -{{< chooser language "typescript,python,go,csharp,java,yaml" / >}} - -{{% choosable language "typescript" %}} -{{< install-node >}} -{{% /choosable %}} - -{{% choosable language python %}} -{{< install-python >}} -{{% /choosable %}} - -{{% choosable language go %}} -{{< install-go >}} -{{% /choosable %}} - -{{% choosable language "csharp,fsharp,visualbasic" %}} -{{< install-dotnet >}} -{{% /choosable %}} - -{{% choosable language java %}} -{{< install-java >}} -{{% /choosable %}} - -{{% choosable language yaml %}} -{{< install-yaml >}} -{{% /choosable %}} - -Finally, configure Pulumi with Microsoft Azure. - -### Configure Pulumi to access your Microsoft Azure account - -Pulumi requires cloud credentials to manage and provision resources. Pulumi can authenticate to Azure using a user account or service principal that has **Programmatic access** with rights to deploy and manage your Azure resources. - -{{% notes type="info" %}} -Pulumi relies on the Azure SDK to authenticate requests from your computer to Azure. Your credentials are never sent to pulumi.com. -{{% /notes %}} - -In this guide, you will need a user account with permissions to create and populate Blob storage containers and provide anonymous access to a Blob file. - -When developing locally, we recommend that you install the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) and then authorize access with a user account. - -```bash -az login -``` - -After successfully logging in, you are ready to go. - -{{% notes type="info" %}} -The Azure CLI, and thus Pulumi, will use the default subscription for the account. You can change the active subscription with the [`az account set`](https://docs.microsoft.com/en-us/cli/azure/account?view=azure-cli-latest#az_account_set) command. -{{% /notes %}} - -For additional information on authenticating with Azure, or to login with a service principal, see [Azure Setup](/registry/packages/azure-native/installation-configuration/). - -Next, you'll create a new Pulumi project. +{{< get-started-install-body >}} {{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/configure.md b/content/docs/iac/get-started/azure/configure.md new file mode 100644 index 000000000000..2971f8ff0abb --- /dev/null +++ b/content/docs/iac/get-started/azure/configure.md @@ -0,0 +1,96 @@ +--- +title_tag: Configure access | Azure +title: Configure access +h1: "Get started with Pulumi & Azure" +meta_desc: This page provides an overview on how to get started with Pulumi when starting an Azure project. +weight: 3 +menu: + iac: + name: Configure access + parent: azure-get-started + weight: 3 + +aliases: + - /docs/quickstart/azure/configure/ + - /docs/clouds/azure/get-started/configure/ +--- + +## Configure access to Azure + +Pulumi's CLI needs access to your Azure account to manage cloud resources. + +If you've already installed and configured the Azure CLI, Pulumi will respect and use your configuration settings. + +You must use an Azure account that has rights to deploy and manage resources, such as storage accounts and blob containers. + +### Testing access + +To test that your Azure access is configured properly, run: + +{{% choosable os "linux,macos" %}} + +```bash +$ az account show +``` + +{{% /choosable %}} + +{{% choosable os "windows" %}} + +```powershell +> az account show +``` + +{{% /choosable %}} + +If your Azure subscription details are printed, you are good to go. If not, read on: + +```json +{ + "environmentName": "AzureCloud", + "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", + "isDefault": true, + "name": "My Subscription", + "state": "Enabled", + "tenantId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", + "user": { + "name": "user@example.com", + "type": "user" + } +} +``` + +### Alternative approaches + +If you don't have the Azure CLI installed, or you plan on using Pulumi in a CI/CD pipeline, you can create a service principal and set the following environment variables on your workstation: + +{{% choosable os "linux,macos" %}} + +```bash +$ export ARM_CLIENT_ID="" +$ export ARM_CLIENT_SECRET="" +$ export ARM_TENANT_ID="" +$ export ARM_SUBSCRIPTION_ID="" +``` + +{{% /choosable %}} + +{{% choosable os windows %}} + +```powershell +> $env:ARM_CLIENT_ID = "" +> $env:ARM_CLIENT_SECRET = "" +> $env:ARM_TENANT_ID = "" +> $env:ARM_SUBSCRIPTION_ID = "" +``` + +{{% /choosable %}} + +{{% notes type="info" %}} +Consider using [Pulumi ESC's Azure login support](/docs/esc/integrations/dynamic-login-credentials/azure-login) for dynamic, +short-lived Azure credentials via OpenID Connect (OIDC) instead of long-lived static credentials. This is a security best practice. +{{% /notes %}} + +For detailed information on Pulumi's use of Azure credentials, see [Azure Setup](/registry/packages/azure-native/installation-configuration/). + +{{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/create-component.md b/content/docs/iac/get-started/azure/create-component.md new file mode 100644 index 000000000000..b09c40a75fd9 --- /dev/null +++ b/content/docs/iac/get-started/azure/create-component.md @@ -0,0 +1,866 @@ +--- +title_tag: Create a component | Azure +title: Create a component +h1: "Get started with Pulumi and Azure" +meta_desc: This page provides an overview on how to create infrastructure abstractions with Pulumi. +weight: 7 +menu: + iac: + name: Create a component + parent: azure-get-started + weight: 7 + +aliases: + - /docs/quickstart/azure/create-component/ + - /docs/clouds/azure/get-started/create-component/ +--- + +## Create a component + +[**Components**](/docs/iac/concepts/resources/components/) are infrastructure abstractions that encapsulate +complexity and enable sharing and reuse. Instead of copy-pasting common patterns, you can encode them as components. + +You will now create your first component that packages up your Azure static website so you can easily stamp out +entire websites in just a few lines of code: + +{{% choosable language typescript %}} + +```typescript +const website = new AzureStaticWebsite("my-website", { + files: [ "index.html" ], +}); +``` + +{{% /choosable %}} + +{{% choosable language python %}} + +```python +website = AzureStaticWebsite('my-website', files=['index.html']) +``` + +{{% /choosable %}} + +{{% choosable language go %}} + +```go +website, err := NewAzureStaticWebsite(ctx, "my-website", AzureStaticWebsiteArgs{ + Files: []string{"index.html"}, +}) +if err != nil { + return err +} +``` + +{{% /choosable %}} + +{{% choosable language csharp %}} + +```csharp +var website = new AzureStaticWebsite("my-website", new AzureStaticWebsiteArgs() +{ + Files = new[] { "index.html" } +}); +``` + +{{% /choosable %}} + +{{% choosable language java %}} + +```java +var website = new AzureStaticWebsite("my-website", + new AzureStaticWebsiteArgs(new String[] { "index.html" })); +``` + +{{% /choosable %}} + +{{% choosable language yaml %}} + +{{% notes type="warning" %}} + +Unfortunately, YAML lacks the language facilities to author components. Feel free to [skip ahead](/docs/iac/get-started/azure/b/destroy-stack/). + +{{% /notes %}} + +{{% /choosable %}} + +Using components here also has the benefit that, as the requirements for Azure static websites changes, you can +update the one component definition and have all uses of it benefit. + +### Define a new component + +To define a new component, create a class called `AzureStaticWebsite` that derives from `ComponentResource`. It'll have a mostly-empty +constructor to start with but you will add the Azure resources to it in the next step. You'll also define the inputs for the +component -- the `files` to add to the website -- and outputs -- a single property with the website `url`. + +To get going, create a new file {{< compfile >}} alongside {{< langfile >}} and add the following: + +{{% choosable language typescript %}} + +```typescript +import * as azure from "@pulumi/azure-native"; +import * as pulumi from "@pulumi/pulumi"; + +// Arguments for the Azure hosted static website component. +export interface AzureStaticWebsiteArgs { + files: string[]; // a list of files to serve. +} + +// A component that encapsulates creating an Azure hosted static website. +export class AzureStaticWebsite extends pulumi.ComponentResource { + public readonly url: pulumi.Output; // the website url. + + constructor(name: string, args: AzureStaticWebsiteArgs, opts?: pulumi.ComponentResourceOptions) { + super("quickstart:index:AzureStaticWebsite", name, args, opts); + + // Component initialization will go here next... + + this.registerOutputs({}); // Signal component completion. + } +} +``` + +{{% /choosable %}} + +{{% choosable language python %}} + +```python +import pulumi +from pulumi_azure_native import storage, resources +from typing import List + +# A component that encapsulates creating an Azure hosted static website. +class AzureStaticWebsite(pulumi.ComponentResource): + def __init__(self, name: str, files: List[str] = None, opts = None): + super().__init__('quickstart:index:AzureStaticWebsite', name, { 'files': files }, opts) + + # Component initialization will go here next... + + self.register_outputs({}) # Signal component completion. +``` + +{{% /choosable %}} + +{{% choosable language go %}} + +```go +package main + +import ( + "github.com/pulumi/pulumi-azure-native-sdk/resources/v2" + "github.com/pulumi/pulumi-azure-native-sdk/storage/v2" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +type AzureStaticWebsite struct { + pulumi.ResourceState + Url pulumi.StringOutput // the website url. +} + +type AzureStaticWebsiteArgs struct { + Files []string // a list of files to serve. +} + +func NewAzureStaticWebsite(ctx *pulumi.Context, name string, args AzureStaticWebsiteArgs, opts ...pulumi.ResourceOption) (*AzureStaticWebsite, error) { + self := &AzureStaticWebsite{} + err := ctx.RegisterComponentResource("quickstart:index:AzureStaticWebsite", name, self, opts...) + if err != nil { + return nil, err + } + + // Component initialization will go here next... + + ctx.RegisterResourceOutputs(self, pulumi.Map{}) // Signal component completion. + return self, nil +} +``` + +{{% /choosable %}} + +{{% choosable language csharp %}} + +```csharp +using Pulumi; +using Pulumi.AzureNative.Resources; +using Pulumi.AzureNative.Storage; +using Pulumi.AzureNative.Storage.Inputs; +using System.Collections.Generic; + +public class AzureStaticWebsiteArgs +{ + public string[]? Files { get; set; } +} + +public class AzureStaticWebsite : Pulumi.ComponentResource +{ + public Output Url { get; private set; } + + public AzureStaticWebsite(string name, AzureStaticWebsiteArgs args, ComponentResourceOptions? opts = null) + : base("quickstart:index:AzureStaticWebsite", name, opts) + { + // Component initialization will go here next... + + this.RegisterOutputs(new Dictionary{}); // Signal component completion. + } +} +``` + +{{% /choosable %}} + +{{% choosable language java %}} + +```java +package myproject; + +import com.pulumi.Pulumi; +import com.pulumi.azurenative.resources.ResourceGroup; +import com.pulumi.azurenative.storage.StorageAccount; +import com.pulumi.resources.ComponentResource; +import com.pulumi.resources.ComponentResourceOptions; + +public class AzureStaticWebsiteArgs { + public String[] files; + public AzureStaticWebsiteArgs(String[] files) { + this.files = files; + } +} + +public class AzureStaticWebsite extends ComponentResource { + public Output url; + + public AzureStaticWebsite(String name, AzureStaticWebsiteArgs args, ComponentResourceOptions opts) { + super("quickstart:index:AzureStaticWebsite", name, args, opts); + + // Component initialization will go here next... + + this.registerOutputs(Map.of()); + } +} +``` + +{{% /choosable %}} + +{{% choosable language yaml %}} + +{{% notes type="warning" %}} + +Unfortunately, YAML lacks the language facilities to author components. Feel free to [skip ahead](/docs/iac/get-started/azure/b/destroy-stack/). + +{{% /notes %}} + +{{% /choosable %}} + +This defines a component but it doesn't do much yet. + +### Refactor your code into the component + +Next, make four changes: + +1. Move all resources from {{< langfile >}} into the component's constructor +1. Change each resource to use the component [as the `parent`](/docs/iac/concepts/options/parent/) +1. Generalize the creation of blobs by looping over the list of `files` +1. Assign the resulting website URL to the `url` property of the component + +The resulting {{< compfile >}} file will look like this; feel free to make each edit one at a time if you'd like +to get a feel for things, or simply paste the contents of this into {{< compfile >}}: + +{{% choosable language typescript %}} + +```typescript +import * as azure from "@pulumi/azure-native"; +import * as pulumi from "@pulumi/pulumi"; + +// Arguments for the Azure hosted static website component. +export interface AzureStaticWebsiteArgs { + files: string[]; // a list of files to serve. +} + +// A component that encapsulates creating an Azure hosted static website. +export class AzureStaticWebsite extends pulumi.ComponentResource { + public readonly url: pulumi.Output; // the website url. + + constructor(name: string, args: AzureStaticWebsiteArgs, opts?: pulumi.ComponentResourceOptions) { + super("quickstart:index:AzureStaticWebsite", name, args, opts); + + // Create a resource group + const resourceGroup = new azure.resources.ResourceGroup("my-group", {}, { + // Set the parent to the component (step #2) above. + // Also, do the same for all other resources below. + parent: this, + }); + + // Create a storage account + const storageAccount = new azure.storage.StorageAccount("myaccount", { + resourceGroupName: resourceGroup.name, + kind: azure.storage.Kind.StorageV2, + sku: { + name: azure.storage.SkuName.Standard_LRS, + }, + }, { parent: this }); + + // Enable static website support + const staticWebsite = new azure.storage.StorageAccountStaticWebsite("static-website", { + accountName: storageAccount.name, + resourceGroupName: resourceGroup.name, + indexDocument: "index.html", + }, { parent: this }); + + // Upload each file as a blob: + for (const file of args.files) { + new azure.storage.Blob(file, { + accountName: storageAccount.name, + containerName: staticWebsite.containerName, + resourceGroupName: resourceGroup.name, + source: new pulumi.asset.FileAsset(file), + contentType: "text/html", + }, { parent: this }); + } + + // Capture the URL and make it available as a component property and output: + this.url = storageAccount.primaryEndpoints.apply(pe => pe.web); + this.registerOutputs({ url: this.url }); // Signal component completion. + } +} +``` + +{{% /choosable %}} + +{{% choosable language python %}} + +```python +import pulumi +from pulumi_azure_native import storage, resources +from typing import List + +# A component that encapsulates creating an Azure hosted static website. +class AzureStaticWebsite(pulumi.ComponentResource): + def __init__(self, name: str, files: List[str] = None, opts = None): + super().__init__('quickstart:index:AzureStaticWebsite', name, { 'files': files }, opts) + + # Create a resource group + resource_group = resources.ResourceGroup('my-group', + # Set the parent to the component (step #2) above. + # Also, do the same for all other resources below. + opts=pulumi.ResourceOptions(parent=self), + ) + + # Create a storage account + storage_account = storage.StorageAccount('myaccount', + resource_group_name=resource_group.name, + kind=storage.Kind.STORAGE_V2, + sku={ + 'name': storage.SkuName.STANDARD_LRS, + }, + opts=pulumi.ResourceOptions(parent=self), + ) + + # Enable static website support + static_website = storage.StorageAccountStaticWebsite('static-website', + account_name=storage_account.name, + resource_group_name=resource_group.name, + index_document='index.html', + opts=pulumi.ResourceOptions(parent=self), + ) + + # Upload each file as a blob: + for file in files: + storage.Blob( + file, + account_name=storage_account.name, + container_name=static_website.container_name, + resource_group_name=resource_group.name, + source=pulumi.FileAsset(file), + content_type='text/html', + opts=pulumi.ResourceOptions(parent=self), + ) + + # Capture the URL and make it available as a component property and output: + self.url = storage_account.primary_endpoints.apply(lambda pe: pe.web) + self.register_outputs({ 'url': self.url }) # Signal component completion. +``` + +{{% /choosable %}} + +{{% choosable language go %}} + +```go +package main + +import ( + "github.com/pulumi/pulumi-azure-native-sdk/resources/v2" + "github.com/pulumi/pulumi-azure-native-sdk/storage/v2" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +type AzureStaticWebsite struct { + pulumi.ResourceState + Url pulumi.StringOutput // the website url. +} + +type AzureStaticWebsiteArgs struct { + Files []string // a list of files to serve. +} + +func NewAzureStaticWebsite(ctx *pulumi.Context, name string, args AzureStaticWebsiteArgs, opts ...pulumi.ResourceOption) (*AzureStaticWebsite, error) { + self := &AzureStaticWebsite{} + err := ctx.RegisterComponentResource("quickstart:index:AzureStaticWebsite", name, self, opts...) + if err != nil { + return nil, err + } + + // Create a resource group + resourceGroup, err := resources.NewResourceGroup(ctx, "my-group", nil, + // Set the parent to the component (step #2) above. + // Also, do the same for all other resources below. + pulumi.Parent(self)) + if err != nil { + return nil, err + } + + // Create a storage account + storageAccount, err := storage.NewStorageAccount(ctx, "myaccount", &storage.StorageAccountArgs{ + ResourceGroupName: resourceGroup.Name, + Kind: pulumi.String("StorageV2"), + Sku: &storage.SkuArgs{ + Name: pulumi.String("Standard_LRS"), + }, + }, pulumi.Parent(self)) + if err != nil { + return nil, err + } + + // Enable static website support + staticWebsite, err := storage.NewStorageAccountStaticWebsite(ctx, "static-website", &storage.StorageAccountStaticWebsiteArgs{ + AccountName: storageAccount.Name, + ResourceGroupName: resourceGroup.Name, + IndexDocument: pulumi.String("index.html"), + }, pulumi.Parent(self)) + if err != nil { + return nil, err + } + + // Upload each file as a blob: + for _, file := range args.Files { + _, err = storage.NewBlob(ctx, file, &storage.BlobArgs{ + AccountName: storageAccount.Name, + ContainerName: staticWebsite.ContainerName, + ResourceGroupName: resourceGroup.Name, + Source: pulumi.NewFileAsset(file), + ContentType: pulumi.String("text/html"), + }, pulumi.Parent(self)) + if err != nil { + return nil, err + } + } + + // Capture the URL and make it available as a component property and output: + self.Url = storageAccount.PrimaryEndpoints.ApplyT(func(pe storage.EndpointsResponse) string { + return *pe.Web + }).(pulumi.StringOutput) + + ctx.RegisterResourceOutputs(self, pulumi.Map{"url": self.Url}) // Signal component completion. + return self, nil +} +``` + +{{% /choosable %}} + +{{% choosable language csharp %}} + +```csharp +using Pulumi; +using Pulumi.AzureNative.Resources; +using Pulumi.AzureNative.Storage; +using Pulumi.AzureNative.Storage.Inputs; +using System.Collections.Generic; + +public class AzureStaticWebsiteArgs +{ + public string[]? Files { get; set; } +} + +public class AzureStaticWebsite : Pulumi.ComponentResource +{ + public Output Url { get; private set; } + + public AzureStaticWebsite(string name, AzureStaticWebsiteArgs args, ComponentResourceOptions? opts = null) + : base("quickstart:index:AzureStaticWebsite", name, opts) + { + // Create a resource group + var resourceGroup = new ResourceGroup("my-group", new(), new CustomResourceOptions + { + // Set the parent to the component (step #2) above. + // Also, do the same for all other resources below. + Parent = this, + }); + + // Create a storage account + var storageAccount = new StorageAccount("myaccount", new() + { + ResourceGroupName = resourceGroup.Name, + Kind = Kind.StorageV2, + Sku = new SkuArgs + { + Name = SkuName.Standard_LRS, + }, + }, new CustomResourceOptions + { + Parent = this, + }); + + // Enable static website support + var staticWebsite = new StorageAccountStaticWebsite("static-website", new() + { + AccountName = storageAccount.Name, + ResourceGroupName = resourceGroup.Name, + IndexDocument = "index.html", + }, new CustomResourceOptions + { + Parent = this, + }); + + // Upload each file as a blob: + foreach (var file in args.Files) { + new Blob(file, new() + { + AccountName = storageAccount.Name, + ContainerName = staticWebsite.ContainerName, + ResourceGroupName = resourceGroup.Name, + Source = new FileAsset(file), + ContentType = "text/html", + }, new CustomResourceOptions + { + Parent = this, + }); + } + + // Capture the URL and make it available as a component property and output: + this.Url = storageAccount.PrimaryEndpoints.Apply(pe => pe.Web); + this.RegisterOutputs(new Dictionary{ + ["url"] = this.Url + }); + } +} +``` + +{{% /choosable %}} + +{{% choosable language java %}} + +```java +package myproject; + +import com.pulumi.*; +import com.pulumi.core.*; +import com.pulumi.asset.FileAsset; +import com.pulumi.resources.*; + +import com.pulumi.azurenative.resources.*; +import com.pulumi.azurenative.storage.*; +import com.pulumi.azurenative.storage.inputs.*; + +import java.util.Map; + +class AzureStaticWebsiteArgs extends ResourceArgs { + public String[] files; + public AzureStaticWebsiteArgs(String[] files) { + this.files = files; + } +} + +class AzureStaticWebsite extends ComponentResource { + public Output url; + + public AzureStaticWebsite(String name, AzureStaticWebsiteArgs args) { + this(name, args, null); + } + + public AzureStaticWebsite(String name, AzureStaticWebsiteArgs args, ComponentResourceOptions opts) { + super("quickstart:index:AzureStaticWebsite", name, args, opts); + + // Create a resource group + var resourceGroup = new ResourceGroup("my-group", null, + // Set the parent to the component (step #2) above. + // Also, do the same for all other resources below. + CustomResourceOptions.builder().parent(this).build()); + + // Create a storage account + var storageAccount = new StorageAccount("myaccount", StorageAccountArgs.builder() + .resourceGroupName(resourceGroup.name()) + .kind("StorageV2") + .sku(SkuArgs.builder() + .name("Standard_LRS") + .build()) + .build(), CustomResourceOptions.builder().parent(this).build()); + + // Enable static website support + var staticWebsite = new StorageAccountStaticWebsite("static-website", StorageAccountStaticWebsiteArgs.builder() + .accountName(storageAccount.name()) + .resourceGroupName(resourceGroup.name()) + .indexDocument("index.html") + .build(), CustomResourceOptions.builder().parent(this).build()); + + // Upload each file as a blob: + for (var file : args.files) { + new Blob(file, BlobArgs.builder() + .accountName(storageAccount.name()) + .containerName(staticWebsite.containerName()) + .resourceGroupName(resourceGroup.name()) + .source(new FileAsset(file)) + .contentType("text/html") + .build(), CustomResourceOptions.builder() + .parent(this) + .build()); + } + + // Capture the URL and make it available as a component property and output: + this.url = storageAccount.primaryEndpoints().applyValue(pe -> pe.web().get()); + this.registerOutputs(Map.of("url", this.url)); + } +} +``` + +{{% /choosable %}} + +{{% choosable language yaml %}} + +{{% notes type="warning" %}} + +Unfortunately, YAML lacks the language facilities to author components. Feel free to [skip ahead](/docs/iac/get-started/azure/b/destroy-stack/). + +{{% /notes %}} + +{{% /choosable %}} + +### Instantiate the component + +Now go back to your original file {{< langfile >}}. Now that you have moved all of the resources, you can start over with a clean slate. +Ensure the file is empty and we will build it back up by simply importing and instantiating our new component. + +Add this to your now-empty {{< langfile >}}: + +{{% choosable language typescript %}} + +```typescript +// Import from our new component module: +import { AzureStaticWebsite } from "./website"; + +// Create an instance of our component with the same files as before: +const website = new AzureStaticWebsite("my-website", { + files: [ "index.html" ], +}); + +// And export its autoassigned URL: +export const url = website.url; +``` + +{{% /choosable %}} + +{{% choosable language python %}} + +```python +import pulumi + +# Import from our new component module: +from website import AzureStaticWebsite + +# Create an instance of our component with the same files as before: +website = AzureStaticWebsite('my-website', files=['index.html']) + +# And export its autoassigned URL: +pulumi.export("url", website.url) +``` + +{{% /choosable %}} + +{{% choosable language go %}} + +```go +package main + +import ( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +func main() { + pulumi.Run(func(ctx *pulumi.Context) error { + // Create an instance of our component with the same files as before: + website, err := NewAzureStaticWebsite(ctx, "my-website", AzureStaticWebsiteArgs{ + Files: []string{"index.html"}, + }) + if err != nil { + return err + } + + // And export its autoassigned URL: + ctx.Export("url", website.Url) + return nil + }) +} + +``` + +{{% /choosable %}} + +{{% choosable language csharp %}} + +```csharp +using Pulumi; +using Pulumi.AzureNative.Resources; +using Pulumi.AzureNative.Storage; +using System.Collections.Generic; + +return await Deployment.RunAsync(() => +{ + // Create an instance of our component with the same files as before: + var website = new AzureStaticWebsite("my-website", new AzureStaticWebsiteArgs() + { + Files = new[] { "index.html" } + }); + + // And export its autoassigned URL: + return new Dictionary + { + ["url"] = website.Url + }; +}); +``` + +{{% /choosable %}} + +{{% choosable language java %}} + +```java +package myproject; + +import com.pulumi.Pulumi; + +public class App { + public static void main(String[] args) { + Pulumi.run(ctx -> { + // Create an instance of our component with the same files as before: + var website = new AzureStaticWebsite("my-website", + new AzureStaticWebsiteArgs(new String[] { "index.html" })); + + // And export its autoassigned URL: + ctx.export("url", website.url); + }); + } +} +``` + +{{% /choosable %}} + +{{% choosable language yaml %}} + +{{% notes type="warning" %}} + +Unfortunately, YAML lacks the language facilities to author components. Feel free to [skip ahead](/docs/iac/get-started/azure/b/destroy-stack/). + +{{% /notes %}} + +{{% /choosable %}} + +### Deploy the component + +Now deploy the resulting component instantiation. To do so, run `pulumi up` as usual: + +``` +$ pulumi up +Previewing update (dev) + + Type Name Plan + pulumi:pulumi:Stack quickstart-dev + + ├─ quickstart:index:AzureStaticWebsite my-site create + + │ ├─ azure-native:resources:ResourceGroup my-group create + + │ ├─ azure-native:storage:StorageAccount myaccount create + + │ ├─ azure-native:storage:StorageAccountStaticWebsite static-website create + + │ └─ azure-native:storage:Blob index.html create + - ├─ azure-native:storage:Blob index.html delete + - ├─ azure-native:storage:StorageAccountStaticWebsite static-website delete + - ├─ azure-native:storage:StorageAccount myaccount delete + - └─ azure-native:resources:ResourceGroup my-group delete + +Resources: + + 5 to create + - 4 to delete + 9 changes. 1 unchanged + +Do you want to perform this update? [Use arrows to move, type to filter] + yes +> no + details +``` + +This preview shows you a few things. First, you'll see our `AzureStaticWebsite` component with all of its children +resources neatly parented underneath it. This helps to see what resources relate to which components. Next, +you'll see that your old resources are being destroyed. + +{{% notes type="info" %}} + +If you're wondering why Pulumi didn't simply update the resources in place, it's because certain changes -- like +refactoring resources into a component -- fundamentally change a resource's identity. Many changes like updating +properties or moving resources between files are not disruptive like this. In such cases, you can assign +[aliases](/docs/iac/concepts/options/aliases/) to prevent deletions from happening. + +{{% /notes %}} + +Accept the changes by selecting `yes` and the deployment will occur: + +``` +Updating (dev) + + Type Name Status + pulumi:pulumi:Stack pu-quickstart-dev + + ├─ quickstart:index:AzureStaticWebsite my-site created (0.16s) + + │ ├─ azure-native:resources:ResourceGroup my-group created (1s) + + │ ├─ azure-native:storage:StorageAccount myaccount created (2s) + + │ ├─ azure-native:storage:StorageAccountStaticWebsite static-website created (0.24s) + + │ └─ azure-native:storage:Blob index.html created (0.19s) + - ├─ azure-native:storage:Blob index.html deleted (0.18s) + - ├─ azure-native:storage:StorageAccountStaticWebsite static-website deleted (0.27s) + - ├─ azure-native:storage:StorageAccount myaccount deleted (0.51s) + - └─ azure-native:resources:ResourceGroup my-group deleted (0.58s) + +Outputs: + ~ url: "https://myaccountabc123.z13.web.core.windows.net/" => "https://myaccountxyz789.z13.web.core.windows.net/" + +Resources: + + 5 created + - 4 deleted + 9 changes. 1 unchanged + +Duration: 10s +``` + +Now test out your new website -- it works like before, just with a tidier codebase now! + +{{% choosable os "linux,macos" %}} + +```bash +$ curl $(pulumi stack output url) + + +

Hello, Pulumi!

+ + +``` + +{{% /choosable %}} + +{{% choosable os "windows" %}} + +```powershell +> curl (pulumi stack output url) + + +

Hello, Pulumi!

+ + +``` + +{{% /choosable %}} + +Once you are ready to move on, let's destroy everything we've spun up in this tutorial. + +{{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/create-project.md b/content/docs/iac/get-started/azure/create-project.md index 3b1371f76fd9..1d8839b7dbca 100644 --- a/content/docs/iac/get-started/azure/create-project.md +++ b/content/docs/iac/get-started/azure/create-project.md @@ -3,122 +3,185 @@ title_tag: Create a New Project | Azure meta_desc: This page provides an overview of how to create a new Azure + Pulumi project. title: Create project h1: "Pulumi & Azure: Create project" -weight: 3 +weight: 4 menu: iac: name: Create project identifier: azure-get-started.create-project parent: azure-get-started - weight: 3 + weight: 4 aliases: - /docs/quickstart/azure/create-project/ - /docs/clouds/azure/get-started/create-project/ + - /docs/quickstart/azure/review-project/ + - /docs/clouds/azure/get-started/review-project/ --- -Now that you have set up your environment by installing Pulumi, installing your preferred language runtime, -and configuring your Azure credentials, let's create your first Pulumi program. +## Create a new project -{{< chooser language "typescript,python,go,csharp,java,yaml" / >}} +A [**project**](/docs/iac/concepts/projects) is a program in your chosen language that defines a collection of related cloud resources. In this step, you will create a new project. + +### Initializing your project + +Each project lives in its own directory. Create a new one: + +{{% choosable os "linux,macos" %}} + +```bash +$ mkdir quickstart +``` + +{{% /choosable %}} +{{% choosable os "windows" %}} + +```powershell +> mkdir quickstart +``` + +{{% /choosable %}} + +Change into the new directory: + +{{% choosable os "linux,macos" %}} + +```bash +$ cd quickstart +``` + +{{% /choosable %}} +{{% choosable os "windows" %}} + +```powershell +> cd quickstart +``` + +{{% /choosable %}} + +Now initialize a new Pulumi project for Azure using the `pulumi new` command: {{% choosable language typescript %}} +{{% choosable os "linux,macos" %}} + ```bash -$ mkdir quickstart && cd quickstart $ pulumi new azure-typescript ``` +{{% /choosable %}} +{{% choosable os "windows" %}} + +```powershell +> pulumi new azure-typescript +``` + +{{% /choosable %}} + {{% /choosable %}} {{% choosable language python %}} +{{% choosable os "linux,macos" %}} + ```bash -$ mkdir quickstart && cd quickstart $ pulumi new azure-python ``` +{{% /choosable %}} +{{% choosable os "windows" %}} + +```powershell +> pulumi new azure-python +``` + +{{% /choosable %}} + {{% /choosable %}} {{% choosable language csharp %}} +{{% choosable os "linux,macos" %}} + ```bash -$ mkdir quickstart && cd quickstart $ pulumi new azure-csharp ``` +{{% /choosable %}} +{{% choosable os "windows" %}} + +```powershell +> pulumi new azure-csharp +``` + +{{% /choosable %}} + {{% /choosable %}} {{% choosable language go %}} +{{% choosable os "linux,macos" %}} + ```bash -$ mkdir quickstart && cd quickstart $ pulumi new azure-go ``` +{{% /choosable %}} +{{% choosable os "windows" %}} + +```powershell +> pulumi new azure-go +``` + +{{% /choosable %}} + {{% /choosable %}} {{% choosable language java %}} +{{% choosable os "linux,macos" %}} + ```bash -$ mkdir quickstart && cd quickstart $ pulumi new azure-java ``` {{% /choosable %}} +{{% choosable os "windows" %}} -{{% choosable language yaml %}} - -```bash -$ mkdir quickstart && cd quickstart -$ pulumi new azure-yaml +```powershell +> pulumi new azure-java ``` {{% /choosable %}} -The [`pulumi new`](/docs/cli/commands/pulumi_new) command creates a new Pulumi project with some basic scaffolding based on the cloud and language specified. - -{{< cli-note >}} +{{% /choosable %}} -After logging in, the CLI will proceed with walking you through creating a new project. +{{% choosable language yaml %}} -First, you will be asked for a **project name** and **project description**. Hit `ENTER` to accept the default values or specify new values. +{{% choosable os "linux,macos" %}} +```bash +$ pulumi new azure-yaml ``` -This command will walk you through creating a new Pulumi project. -Enter a value or leave blank to accept the (default), and press . -Press ^C at any time to quit. +{{% /choosable %}} +{{% choosable os "windows" %}} -project name: (quickstart) -project description: (A minimal Azure Native Pulumi program) -Created project 'quickstart' +```powershell +> pulumi new azure-yaml ``` -Next, you will be asked for a **stack name**. Hit `ENTER` to accept the default value of `dev`. - -``` -Please enter your desired stack name. -To create a stack in an organization, use the format / (e.g. `acmecorp/dev`). -stack name: (dev) -Created stack 'dev' -``` +{{% /choosable %}} -For Azure projects, you will be prompted for the Azure location. You can accept the default value of `WestUS` or choose another location. +{{% /choosable %}} -``` -azure-native:location: The Azure location to use: (WestUS2) -Saved config -``` +The `pulumi new` command interactively walks through initializing a new project, as well as creating a +[**stack**](/docs/iac/concepts/stacks) and [**configuring**](/docs/iac/concepts/config) it. A stack is an instance of your +project and you may have many of them -- like `dev`, `staging`, and `prod` -- each with different configuration settings. -To list all available locations, use the `az account list-locations` command. +You will be prompted for configuration values such as an Azure location. You can hit ENTER to accept the default of `WestUS2`, +or can type in another value such as `eastus`: -```bash -$ az account list-locations --output table ``` - -You can then change the region for your stack by using the `pulumi config set` command as shown below: - -```bash -pulumi config set azure-native:location eastus +azure-native:location: The Azure location to use: (WestUS2) eastus ``` -> What are [projects](/docs/concepts/projects/) and [stacks](/docs/concepts/stack/)? Pulumi projects and stacks let you organize Pulumi code. Consider a Pulumi _project_ to be analogous to a GitHub repo---a single place for code---and a _stack_ to be an instance of that code with a separate configuration. For instance, _Project Foo_ may have multiple stacks for different development environments (Dev, Test, or Prod), or perhaps for different cloud configurations (geographic region for example). See [Organizing Projects and Stacks](/docs/using-pulumi/organizing-projects-stacks/) for some best practices on organizing your Pulumi projects and stacks. +{{< cli-note >}} {{% choosable language "typescript" %}} @@ -156,6 +219,289 @@ After the command completes, the project and stack will be ready. {{% /choosable %}} -Next, we'll review the generated project files. +### Review your new project's contents + +If you list the contents of your directory, you'll see some key files: + +{{% choosable language java %}} + +- `src/main/java/myproject` is the project's Java package root + +{{% /choosable %}} + +{{% choosable language "typescript,python,go,csharp,java" %}} + +- {{< langfile >}} contains your project's main code that declares an Azure resource group and storage account +- `Pulumi.yaml` is a [project file](/docs/iac/concepts/projects/project-file) containing metadata about your project like its name + +{{% /choosable %}} +{{% choosable language "yaml" %}} + +- `Pulumi.yaml` is a [project file](/docs/iac/concepts/projects/project-file) containing metadata about your project, like its name, as well as declaring your project's resources + +{{% /choosable %}} + +- `Pulumi.dev.yaml` contains configuration values for the stack you just initialized + +Now examine the code in {{< langfile >}}: + +{{% choosable language typescript %}} + +```typescript +import * as pulumi from "@pulumi/pulumi"; +import * as resources from "@pulumi/azure-native/resources"; +import * as storage from "@pulumi/azure-native/storage"; + +// Create an Azure Resource Group +const resourceGroup = new resources.ResourceGroup("resourceGroup"); + +// Create an Azure resource (Storage Account) +const storageAccount = new storage.StorageAccount("sa", { + resourceGroupName: resourceGroup.name, + sku: { + name: storage.SkuName.Standard_LRS, + }, + kind: storage.Kind.StorageV2, +}); + +// Export the primary key of the Storage Account +const storageAccountKeys = storage.listStorageAccountKeysOutput({ + resourceGroupName: resourceGroup.name, + accountName: storageAccount.name +}); + +export const primaryStorageKey = storageAccountKeys.keys[0].value; +``` + +{{% /choosable %}} +{{% choosable language python %}} + +```python +"""An Azure RM Python Pulumi program""" + +import pulumi +from pulumi_azure_native import storage +from pulumi_azure_native import resources + +# Create an Azure Resource Group +resource_group = resources.ResourceGroup("resource_group") + +# Create an Azure resource (Storage Account) +account = storage.StorageAccount( + "sa", + resource_group_name=resource_group.name, + sku={ + "name": storage.SkuName.STANDARD_LRS, + }, + kind=storage.Kind.STORAGE_V2, +) + +# Export the primary key of the Storage Account +primary_key = ( + pulumi.Output.all(resource_group.name, account.name) + .apply( + lambda args: storage.list_storage_account_keys( + resource_group_name=args[0], account_name=args[1] + ) + ) + .apply(lambda accountKeys: accountKeys.keys[0].value) +) + +pulumi.export("primary_storage_key", primary_key) +``` + +{{% /choosable %}} +{{% choosable language go %}} + +```go +package main + +import ( + "github.com/pulumi/pulumi-azure-native-sdk/resources/v2" + "github.com/pulumi/pulumi-azure-native-sdk/storage/v2" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +func main() { + pulumi.Run(func(ctx *pulumi.Context) error { + // Create an Azure Resource Group + resourceGroup, err := resources.NewResourceGroup(ctx, "resourceGroup", nil) + if err != nil { + return err + } + + // Create an Azure resource (Storage Account) + account, err := storage.NewStorageAccount(ctx, "sa", &storage.StorageAccountArgs{ + ResourceGroupName: resourceGroup.Name, + AccessTier: storage.AccessTierHot, + Sku: &storage.SkuArgs{ + Name: storage.SkuName_Standard_LRS, + }, + Kind: storage.KindStorageV2, + }) + if err != nil { + return err + } + + // Export the primary key of the Storage Account + ctx.Export("primaryStorageKey", pulumi.All(resourceGroup.Name, account.Name).ApplyT( + func(args []interface{}) (string, error) { + resourceGroupName := args[0].(string) + accountName := args[1].(string) + accountKeys, err := storage.ListStorageAccountKeys(ctx, &storage.ListStorageAccountKeysArgs{ + ResourceGroupName: resourceGroupName, + AccountName: accountName, + }) + if err != nil { + return "", err + } + + return accountKeys.Keys[0].Value, nil + }, + )) + + return nil + }) +} +``` + +{{% /choosable %}} +{{% choosable language csharp %}} + +```csharp +using Pulumi; +using Pulumi.AzureNative.Resources; +using Pulumi.AzureNative.Storage; +using Pulumi.AzureNative.Storage.Inputs; +using System.Collections.Generic; + +return await Pulumi.Deployment.RunAsync(() => +{ + // Create an Azure Resource Group + var resourceGroup = new ResourceGroup("resourceGroup"); + + // Create an Azure resource (Storage Account) + var storageAccount = new StorageAccount("sa", new StorageAccountArgs + { + ResourceGroupName = resourceGroup.Name, + Sku = new SkuArgs + { + Name = SkuName.Standard_LRS + }, + Kind = Kind.StorageV2 + }); + + var storageAccountKeys = ListStorageAccountKeys.Invoke(new ListStorageAccountKeysInvokeArgs + { + ResourceGroupName = resourceGroup.Name, + AccountName = storageAccount.Name + }); + + var primaryStorageKey = storageAccountKeys.Apply(accountKeys => + { + var firstKey = accountKeys.Keys[0].Value; + return Output.CreateSecret(firstKey); + }); + + // Export the primary key of the Storage Account + return new Dictionary + { + ["primaryStorageKey"] = primaryStorageKey + }; +}); +``` + +{{% /choosable %}} + +{{% choosable language java %}} + +```java +package myproject; + +import com.pulumi.Pulumi; +import com.pulumi.azurenative.resources.ResourceGroup; +import com.pulumi.azurenative.storage.StorageAccount; +import com.pulumi.azurenative.storage.StorageAccountArgs; +import com.pulumi.azurenative.storage.StorageFunctions; +import com.pulumi.azurenative.storage.enums.Kind; +import com.pulumi.azurenative.storage.enums.SkuName; +import com.pulumi.azurenative.storage.inputs.ListStorageAccountKeysArgs; +import com.pulumi.azurenative.storage.inputs.SkuArgs; +import com.pulumi.core.Either; +import com.pulumi.core.Output; +import com.pulumi.deployment.InvokeOptions; + +public class App { + public static void main(String[] args) { + Pulumi.run(ctx -> { + var resourceGroup = new ResourceGroup("resourceGroup"); + var storageAccount = new StorageAccount("sa", StorageAccountArgs.builder() + .resourceGroupName(resourceGroup.name()) + .sku(SkuArgs.builder() + .name(SkuName.Standard_LRS) + .build()) + .kind(Kind.StorageV2) + .build()); + + var primaryStorageKey = getStorageAccountPrimaryKey( + resourceGroup.name(), + storageAccount.name()); + + ctx.export("primaryStorageKey", primaryStorageKey); + }); + } + + private static Output getStorageAccountPrimaryKey(Output resourceGroupName, + Output accountName) { + return Output.tuple(resourceGroupName, accountName).apply(tuple -> { + var actualResourceGroupName = tuple.t1; + var actualAccountName = tuple.t2; + var invokeResult = StorageFunctions.listStorageAccountKeys(ListStorageAccountKeysArgs.builder() + .resourceGroupName(actualResourceGroupName) + .accountName(actualAccountName) + .build(), InvokeOptions.Empty); + return Output.of(invokeResult) + .applyValue(r -> r.keys().get(0).value()) + .asSecret(); + }); + } +} +``` + +{{% /choosable %}} + +{{% choosable language yaml %}} + +```yaml +name: quickstart +runtime: yaml +description: A minimal Azure Native Pulumi YAML program +resources: + resourceGroup: + type: azure-native:resources:ResourceGroup + sa: + type: azure-native:storage:StorageAccount + properties: + resourceGroupName: ${resourceGroup.name} + sku: + name: Standard_LRS + kind: StorageV2 +variables: + storageAccountKeys: + fn::azure-native:storage:listStorageAccountKeys: + resourceGroupName: ${resourceGroup.name} + accountName: ${sa.name} +outputs: + primaryStorageKey: ${storageAccountKeys.keys[0].value} +``` + +{{% /choosable %}} + +The program declares an Azure Resource Group and Storage Account +[resources](/docs/iac/concepts/resources) and exports the storage account's primary key as a [stack output](/docs/iac/concepts/stacks/#outputs). +Resources are just objects in our language of choice with [properties](/docs/iac/concepts/inputs-outputs) capturing +their inputs and outputs. Exporting the primary key makes it convenient to use afterwards. + +Now you're ready for your first deployment! {{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/deploy-changes.md b/content/docs/iac/get-started/azure/deploy-changes.md deleted file mode 100644 index ebcda6d5493f..000000000000 --- a/content/docs/iac/get-started/azure/deploy-changes.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -title_tag: Deploy the Changes | Azure -meta_desc: Learn how to deploy changes to an Azure project in this guide. -title: Deploy changes -h1: "Pulumi & Azure: Deploy changes" -weight: 7 -menu: - iac: - name: Deploy changes - identifier: azure-get-started.deploy-changes - parent: azure-get-started - weight: 7 -aliases: - - /docs/quickstart/azure/deploy-changes/ - - /docs/clouds/azure/get-started/deploy-changes/ ---- - -Deploy your changes by using `pulumi up` again. - -```bash -$ pulumi up -``` - -Pulumi will run the `preview` step of the update, which computes the minimally disruptive change to achieve the desired state described by the program. - -``` -Previewing update (dev): - - Type Name Plan - pulumi:pulumi:Stack quickstart-dev - + ├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite create - + └─ azure-native:storage:Blob index.html create - -Outputs: - + staticEndpoint : "https://sa8dd8af62.z22.web.core.windows.net/" - -Resources: - + 2 to create - 3 unchanged - -Do you want to perform this update? -> yes - no - details -``` - -Choosing `yes` will proceed with the update by uploading the `index.html` file to a storage container in your account and enabling static website support on the container. - -``` -Do you want to perform this update? yes -Updating (dev): - - Type Name Status - pulumi:pulumi:Stack quickstart-dev - + ├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite created - + └─ azure-native:storage:Blob index.html created - -Outputs: - primaryStorageKey: "" - + staticEndpoint : "https://sa8dd8af62.z22.web.core.windows.net/" - -Resources: - + 2 created - 3 unchanged - -Duration: 4s -``` - -You can check out your new static website at the URL in the `Outputs` section of your update or you can make a `curl` request and see the contents of your `index.html` object printed out in your terminal. - -{{% choosable language typescript %}} - -```bash -$ curl $(pulumi stack output staticEndpoint) -``` - -{{% /choosable %}} - -{{% choosable language python %}} - -```bash -$ curl $(pulumi stack output staticEndpoint) -``` - -{{% /choosable %}} - -{{% choosable language go %}} - -```bash -$ curl $(pulumi stack output staticEndpoint) -``` - -{{% /choosable %}} - -{{% choosable language csharp %}} - -```bash -$ curl $(pulumi stack output staticEndpoint) -``` - -{{% /choosable %}} - -{{% choosable language java %}} - -```bash -$ curl $(pulumi stack output staticEndpoint) -``` - -{{% /choosable %}} - -{{% choosable language yaml %}} - -```bash -$ curl $(pulumi stack output staticEndpoint) -``` - -{{% /choosable %}} - -And in a few moments, you should see: - -```bash - - -

Hello, Pulumi!

- - -``` - -Now that you have deployed your site, you will destroy the resources. - -{{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/deploy-stack.md b/content/docs/iac/get-started/azure/deploy-stack.md index 01192b1579df..86f462266195 100644 --- a/content/docs/iac/get-started/azure/deploy-stack.md +++ b/content/docs/iac/get-started/azure/deploy-stack.md @@ -15,13 +15,15 @@ aliases: - /docs/clouds/azure/get-started/deploy-stack/ --- -Let's go ahead and deploy your stack: +## Deploy to Azure + +Now run `pulumi up` to start deploying your new storage account: ```bash $ pulumi up ``` -This command evaluates your program and determines the resource updates to make. First, a preview is shown that outlines the changes that will be made when you run the update: +This command first shows you a **preview** of the changes that will be made: ``` Previewing update (dev): @@ -40,7 +42,12 @@ Do you want to perform this update? details ``` -Once the preview has finished, you are given three options to choose from. Choosing `details` will show you a rich diff of the changes to be made. Choosing `yes` will create your new storage account in Azure. Choosing `no` will return you to the user prompt without performing the update operation. +No changes have been made yet. You may decline to proceed by selecting `no` or choose `details` to +see more information about the proposed update like your storage account's properties. + +### Performing the update + +To proceed and deploy your new storage account, select `yes`. This begins an **update**: ``` Do you want to perform this update? yes @@ -60,7 +67,14 @@ Resources: Duration: 26s ``` -Remember the output you defined in the previous step? That [stack output](/docs/concepts/stack#outputs) can be seen in the `Outputs:` section of your update. You can access your outputs from the CLI by running the `pulumi stack output [property-name]` command. For example you can print the primary key of your bucket with the following command: +Updates can take some time since they wait for the cloud resources to finish being created. Storage accounts +may take a bit longer, so the update could finish in 20-30 seconds. + +{{< auto-naming-note resource="storage account" suffix="a1b2c3d" >}} + +### Using stack outputs + +The storage account's primary key can be accessed with the `pulumi stack output` command: {{< chooser language "typescript,python,go,csharp,java,yaml" / >}} @@ -114,8 +128,18 @@ $ pulumi stack output primaryStorageKey Running that command will print out the storage account's primary key. +### View your update on Pulumi Cloud + +If you are logged into [Pulumi Cloud](/docs/pulumi-cloud), you'll see "View Live" hyperlinks in the CLI output during your +update. These go to [a page](https://app.pulumi.com) with detailed information about your stack including resources, +configuration, a full history of updates, and more. Click on it to check it out: + + + A stack update with console output, as shown in the Pulumi Service + + {{< console-note >}} -Now that your storage account has been provisioned, let's modify it to host a static website. +Now that the storage account has been provisioned, you'll update it to host a static website. {{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/destroy-stack.md b/content/docs/iac/get-started/azure/destroy-stack.md index 96b30537d228..c3f9acd2e517 100644 --- a/content/docs/iac/get-started/azure/destroy-stack.md +++ b/content/docs/iac/get-started/azure/destroy-stack.md @@ -6,7 +6,7 @@ h1: "Pulumi & Azure: Destroy stack" weight: 8 menu: iac: - name: Destroy stack + name: Cleanup & destroy identifier: azure-get-started.destroy-stack parent: azure-get-started weight: 8 @@ -15,15 +15,27 @@ aliases: - /docs/clouds/azure/get-started/destroy-stack/ --- -Now that you've seen how to deploy changes to our program, let's clean up and tear down the resources that are part of your stack. +## Cleanup & destroy the stack -To destroy resources, run the following: +Our final step is to clean up all of the resources we've provisioned. This is as simple as running `pulumi destroy`: + +{{% choosable os "linux,macos" %}} ```bash -pulumi destroy +$ pulumi destroy ``` -You'll be prompted to make sure you really want to delete these resources. This can take a minute or two; Pulumi waits until all resources are shut down and deleted before it considers the destroy operation to be complete. +{{% /choosable %}} + +{{% choosable os "windows" %}} + +```powershell +> pulumi destroy +``` + +{{% /choosable %}} + +Just like `pulumi up`, `pulumi destroy` shows you a preview before performing any changes: ``` Previewing destroy (dev): @@ -42,7 +54,15 @@ Outputs: Resources: - 5 to delete -Do you want to perform this destroy? yes +Do you want to perform this destroy? +> yes + no + details +``` + +As with an update, we can choose `no` or `details`; select `yes` to proceed: + +``` Destroying (dev): Type Name Status @@ -62,17 +82,29 @@ Resources: Duration: 53s ``` -To delete the stack itself, run [`pulumi stack rm`](/docs/cli/commands/pulumi_stack_rm). Note that this removes the stack -entirely from Pulumi Cloud, along with all of its update history. +At this stage, your stack still exists, but all cloud resources have been deleted from it. + +## Remove the stack + +The final step is to remove the stack itself. Destroy keeps the stack around so that you still have the full +history of what happened to the stack. Running [`pulumi stack rm`](/docs/cli/commands/pulumi_stack_rm) will +delete it entirely, including all history and state snapshots. Be careful, this step cannot be undone! -Congratulations! You've successfully provisioned some cloud resources using Pulumi. By completing this guide you have successfully: +{{% choosable "os" "macos,linux" %}} + +```bash +$ pulumi stack rm +``` + +{{% /choosable %}} +{{% choosable "os" "windows" %}} + +```powershell +> pulumi stack rm +``` -- Created a Pulumi new project. -- Provisioned a new Azure storage account and container. -- Added an `index.html` file to your container. -- Served the `index.html` as a static website. -- Destroyed the resources you've provisioned. +{{% /choosable %}} -On the next page, we have a collection of examples and tutorials that you can deploy as they are or use them as a foundation for your own applications and infrastructure projects. +You'll be prompted to confirm the removal. Confirm it to successfully complete this tutorial. {{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/modify-program.md b/content/docs/iac/get-started/azure/modify-program.md index 9d951c669d08..6ea7df6c86e4 100644 --- a/content/docs/iac/get-started/azure/modify-program.md +++ b/content/docs/iac/get-started/azure/modify-program.md @@ -13,9 +13,30 @@ menu: aliases: - /docs/quickstart/azure/modify-program/ - /docs/clouds/azure/get-started/modify-program/ + - /docs/quickstart/azure/deploy-changes/ + - /docs/clouds/azure/get-started/deploy-changes/ --- -Now that your storage account is provisioned, let's add an object to it. First, from within your project directory, create a new `index.html` file with some content in it. +## Make an update + +Now you will update your project to serve a static website out of your Azure storage account. You will change +your code and then re-run `pulumi up` which will update your infrastructure. + +### Add new resources + +Pulumi knows how to evolve your current infrastructure to your project's new desired state, both for +the first deployment as well as subsequent updates. + +To turn your storage account into a static website, you will add two new Azure resources: + +1. [`StorageAccountStaticWebsite`](/registry/packages/azure-native/api-docs/storage/storageaccountstaticwebsite/): + enables static website support on your storage account +2. [`Blob`](/registry/packages/azure-native/api-docs/storage/blob/): + uploads your website content to the storage container + +### Add an index.html + +First, from within your project directory, create a new `index.html` file with some content in it. {{< chooser os "macos,linux,windows" / >}} @@ -61,15 +82,13 @@ EOT {{% /choosable %}} -Now that you have your new `index.html` with some content, you can enable static website support, upload `index.html` to a storage container, and retrieve a public URL through the use of resource properties. These properties can be used to define dependencies between related resources or to retrieve property values for further processing. - -{{< chooser language "typescript,python,go,csharp,java,yaml" / >}} +Now open {{< langfile >}} in your editor and enable static website support by adding a [`StorageAccountStaticWebsite`](/registry/packages/azure-native/api-docs/storage/storageaccountstaticwebsite/) resource right after the storage account creation: {{% choosable language typescript %}} -To start, open `index.ts` and add the following right after the storage account creation: - ```typescript +// Storage account... + // Enable static website support const staticWebsite = new storage.StorageAccountStaticWebsite("staticWebsite", { accountName: storageAccount.name, @@ -81,9 +100,9 @@ const staticWebsite = new storage.StorageAccountStaticWebsite("staticWebsite", { {{% /choosable %}} {{% choosable language python %}} -To start, open `__main__.py` and add the following right after the storage account creation: - ```python +# Storage account... + # Enable static website support static_website = storage.StorageAccountStaticWebsite( "staticWebsite", @@ -96,9 +115,9 @@ static_website = storage.StorageAccountStaticWebsite( {{% /choosable %}} {{% choosable language go %}} -To start, open `main.go` and add the following right after the storage account creation: - ```go +// Storage account... + // Enable static website support staticWebsite, err := storage.NewStorageAccountStaticWebsite(ctx, "staticWebsite", &storage.StorageAccountStaticWebsiteArgs{ AccountName: account.Name, @@ -113,9 +132,9 @@ if err != nil { {{% /choosable %}} {{% choosable language csharp %}} -To start, open `Program.cs` and add the following right after the storage account creation: - ```csharp +// Storage account... + // Enable static website support var staticWebsite = new StorageAccountStaticWebsite("staticWebsite", new StorageAccountStaticWebsiteArgs { @@ -129,7 +148,7 @@ var staticWebsite = new StorageAccountStaticWebsite("staticWebsite", new Storage {{% choosable language java %}} -To start, open `App.java` and add the following imports: +First, add the following imports at the top of `App.java`: ```java import com.pulumi.azurenative.storage.StorageAccountStaticWebsite; @@ -140,9 +159,11 @@ import com.pulumi.azurenative.storage.outputs.EndpointsResponse; import com.pulumi.asset.FileAsset; ``` -Next, add the following right after the storage account creation: +Then add the following right after the storage account creation: ```java +// Storage account... + var staticWebsite = new StorageAccountStaticWebsite("staticWebsite", StorageAccountStaticWebsiteArgs.builder() .accountName(storageAccount.name()) @@ -155,8 +176,6 @@ var staticWebsite = new StorageAccountStaticWebsite("staticWebsite", {{% choosable language yaml %}} -To start, open `Pulumi.yaml` and add the following right after the storage account creation: - ```yaml resources: # ... @@ -170,9 +189,10 @@ resources: {{% /choosable %}} -The static website resource leverages the storage account and resource group names defined previously in your program. +Notice that resources can reference each other, which forms automatic dependencies between them. +Pulumi uses this information to parallelize deployments safely. -Now use all of these cloud resources and a local `FileAsset` resource to upload `index.html` into your storage container by adding the following at the end of the file (after enabling the static website support): +Now use all of these cloud resources and a local `FileAsset` resource to upload `index.html` into your storage container by adding a [`Blob`](/registry/packages/azure-native/api-docs/storage/blob/) at the end of the file (after enabling the static website support): {{% choosable language typescript %}} ```typescript @@ -272,9 +292,13 @@ resources: {{% /choosable %}} -{{% choosable language typescript %}} +This uploads the `index.html` file to your storage container using a Pulumi concept called an [asset](/docs/iac/concepts/assets-archives/#assets). + +### Export the website URL -Finally, at the end of `index.ts`, export the resulting storage container's endpoint URL to stdout for easy access: +Now to export the website's URL for easy access add this to the end of your program: + +{{% choosable language typescript %}} ```typescript // Web endpoint to the website @@ -285,8 +309,6 @@ export const staticEndpoint = storageAccount.primaryEndpoints.web; {{% choosable language python %}} -Finally, at the end of `__main__.py`, export the resulting storage container's endpoint URL to stdout for easy access: - ```python # Web endpoint to the website pulumi.export("staticEndpoint", account.primary_endpoints.web) @@ -296,8 +318,6 @@ pulumi.export("staticEndpoint", account.primary_endpoints.web) {{% choosable language go %}} -Finally, at the end of `main.go`, export the resulting storage container's endpoint URL to stdout for easy access: - ```go // Web endpoint to the website ctx.Export("staticEndpoint", account.PrimaryEndpoints.Web()) @@ -307,8 +327,6 @@ ctx.Export("staticEndpoint", account.PrimaryEndpoints.Web()) {{% choosable language csharp %}} -Finally, at the end of `Program.cs`, export the resulting storage container's endpoint URL to stdout for easy access: - ```csharp // Web endpoint to the website return new Dictionary @@ -322,8 +340,6 @@ return new Dictionary {{% choosable language java %}} -Finally, at the end of `App.java`, export the resulting storage container's endpoint URL to stdout for easy access: - ```java ctx.export("staticEndpoint", storageAccount.primaryEndpoints() .applyValue(EndpointsResponse::web)); @@ -333,8 +349,6 @@ ctx.export("staticEndpoint", storageAccount.primaryEndpoints() {{% choosable language yaml %}} -Finally, at the end of `Pulumi.yaml` in the `outputs`, export the resulting storage container's endpoint URL to stdout for easy access: - ```yaml outputs: # ... @@ -343,6 +357,103 @@ outputs: {{% /choosable %}} -Now that you have declared how you want your resources to be provisioned, it is time to deploy these remaining changes. +The storage account's endpoint is [an output property](/docs/iac/concepts/inputs-outputs/#outputs) +that Azure assigns at deployment time, not a raw string, meaning its value is not known in advance. + +### Deploy the changes + +To deploy the changes, run `pulumi up` again and it will figure out the deltas: + +{{% choosable "os" "macos,linux" %}} + +```bash +$ pulumi up +``` + +{{% /choosable %}} +{{% choosable "os" "windows" %}} + +```powershell +> pulumi up +``` + +{{% /choosable %}} + +Just like the first time you will see a preview of the changes before they happen: + +``` +Previewing update (dev): + + Type Name Plan + pulumi:pulumi:Stack quickstart-dev + + ├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite create + + └─ azure-native:storage:Blob index.html create + +Outputs: + + staticEndpoint : "https://sa8dd8af62.z22.web.core.windows.net/" + +Resources: + + 2 to create + 3 unchanged + +Do you want to perform this update? +> yes + no + details +``` + +Choose `yes` to perform the deployment: + +``` +Do you want to perform this update? yes +Updating (dev): + + Type Name Status + pulumi:pulumi:Stack quickstart-dev + + ├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite created + + └─ azure-native:storage:Blob index.html created + +Outputs: + primaryStorageKey: "" + + staticEndpoint : "https://sa8dd8af62.z22.web.core.windows.net/" + +Resources: + + 2 created + 3 unchanged + +Duration: 4s +``` + +In just a few seconds, your new website will be ready. Curl the endpoint to see it live: + +{{% choosable os "linux,macos" %}} + +```bash +$ curl $(pulumi stack output staticEndpoint) +``` + +{{% /choosable %}} + +{{% choosable os "windows" %}} + +```powershell +> curl (pulumi stack output staticEndpoint) +``` + +{{% /choosable %}} + +This will reveal your new website! + +``` + + +

Hello, Pulumi!

+ + +``` + +Feel free to experiment, such as changing the contents of `index.html` and redeploying. + +Next, let's wrap this website up into an infrastructure abstraction. {{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/azure/next-steps.md b/content/docs/iac/get-started/azure/next-steps.md index f7f6284b2b42..df25b94f43da 100644 --- a/content/docs/iac/get-started/azure/next-steps.md +++ b/content/docs/iac/get-started/azure/next-steps.md @@ -1,9 +1,10 @@ --- title_tag: Next Steps | Azure +title: Next steps +h1: Next Steps with Pulumi & Azure +stepper_link: "Congratulations!" meta_desc: This page provides a list of tutorials that take a deeper dive into Azure cloud resources. -title: Next steps -h1: "Pulumi & Azure: Next steps" weight: 9 menu: iac: @@ -16,7 +17,15 @@ aliases: - /docs/clouds/azure/get-started/next-steps/ --- -Congrats! You've deployed your first project on Microsoft Azure with Pulumi. Here are some next steps, depending on your learning style. +Congratulations! You've successfully provisioned some cloud resources using Pulumi. By completing this guide you have successfully: + +- Created a Pulumi new project. +- Provisioned a new Azure Storage account. +- Enabled the static website feature on the storage account. +- Created a website component for easy reuse. +- Destroyed all of the resources you've provisioned. + +Below are some recommended next steps, including examples and tutorials that you can explore or use them as a foundation for your own applications and infrastructure projects. Also be sure to [join the Community Slack](https://slack.pulumi.com/) to meet fellow IaC practitioners. ## Try Pulumi ESC (Environments, Secrets, and Configuration) diff --git a/content/docs/iac/get-started/azure/review-project.md b/content/docs/iac/get-started/azure/review-project.md deleted file mode 100644 index e950259f148a..000000000000 --- a/content/docs/iac/get-started/azure/review-project.md +++ /dev/null @@ -1,317 +0,0 @@ ---- -title_tag: Review the New Project | Azure -meta_desc: This page provides an overview on how to a review a new Azure project. -title: Review project -h1: "Pulumi & Azure: Review project" -weight: 4 -menu: - iac: - name: Review project - identifier: azure-get-started.review-project - parent: azure-get-started - weight: 4 - -aliases: - - /docs/quickstart/azure/review-project/ - - /docs/clouds/azure/get-started/review-project/ ---- - -Let's review some of the generated project files: - -{{% choosable language "typescript,python,go,csharp,java" %}} - -- `Pulumi.yaml` defines the [project](/docs/concepts/projects/). - -{{% /choosable %}} - -{{% choosable language yaml %}} - -- `Pulumi.yaml` defines both the [project](/docs/concepts/projects/) and the program that manages your stack resources. - -{{% /choosable %}} - -- `Pulumi.dev.yaml` contains [configuration](/docs/concepts/config/) values for the [stack](/docs/concepts/stack/) you initialized. - -{{% choosable language java %}} - -- `src/main/java/myproject` defines the project's Java package root. - -{{% /choosable %}} - -{{% choosable language python %}} - -- `__main__.py` is the Pulumi program that defines your stack resources. - -{{% /choosable %}} - -{{% choosable language "typescript,go,csharp,java" %}} - -- {{< langfile >}} is the Pulumi program that defines your stack resources. - -{{% /choosable %}} - -Let's examine {{< langfile >}}. - -{{< chooser language "typescript,python,go,csharp,java,yaml" / >}} - -{{% choosable language typescript %}} - -```typescript -import * as pulumi from "@pulumi/pulumi"; -import * as resources from "@pulumi/azure-native/resources"; -import * as storage from "@pulumi/azure-native/storage"; - -// Create an Azure Resource Group -const resourceGroup = new resources.ResourceGroup("resourceGroup"); - -// Create an Azure resource (Storage Account) -const storageAccount = new storage.StorageAccount("sa", { - resourceGroupName: resourceGroup.name, - sku: { - name: storage.SkuName.Standard_LRS, - }, - kind: storage.Kind.StorageV2, -}); - -// Export the primary key of the Storage Account -const storageAccountKeys = storage.listStorageAccountKeysOutput({ - resourceGroupName: resourceGroup.name, - accountName: storageAccount.name -}); - -export const primaryStorageKey = storageAccountKeys.keys[0].value; -``` - -{{% /choosable %}} -{{% choosable language python %}} - -```python -"""An Azure RM Python Pulumi program""" - -import pulumi -from pulumi_azure_native import storage -from pulumi_azure_native import resources - -# Create an Azure Resource Group -resource_group = resources.ResourceGroup("resource_group") - -# Create an Azure resource (Storage Account) -account = storage.StorageAccount( - "sa", - resource_group_name=resource_group.name, - sku={ - "name": storage.SkuName.STANDARD_LRS, - }, - kind=storage.Kind.STORAGE_V2, -) - -# Export the primary key of the Storage Account -primary_key = ( - pulumi.Output.all(resource_group.name, account.name) - .apply( - lambda args: storage.list_storage_account_keys( - resource_group_name=args[0], account_name=args[1] - ) - ) - .apply(lambda accountKeys: accountKeys.keys[0].value) -) - -pulumi.export("primary_storage_key", primary_key) -``` - -{{% /choosable %}} -{{% choosable language go %}} - -```go -package main - -import ( - "github.com/pulumi/pulumi-azure-native-sdk/resources/v2" - "github.com/pulumi/pulumi-azure-native-sdk/storage/v2" - "github.com/pulumi/pulumi/sdk/v3/go/pulumi" -) - -func main() { - pulumi.Run(func(ctx *pulumi.Context) error { - // Create an Azure Resource Group - resourceGroup, err := resources.NewResourceGroup(ctx, "resourceGroup", nil) - if err != nil { - return err - } - - // Create an Azure resource (Storage Account) - account, err := storage.NewStorageAccount(ctx, "sa", &storage.StorageAccountArgs{ - ResourceGroupName: resourceGroup.Name, - AccessTier: storage.AccessTierHot, - Sku: &storage.SkuArgs{ - Name: storage.SkuName_Standard_LRS, - }, - Kind: storage.KindStorageV2, - }) - if err != nil { - return err - } - - // Export the primary key of the Storage Account - ctx.Export("primaryStorageKey", pulumi.All(resourceGroup.Name, account.Name).ApplyT( - func(args []interface{}) (string, error) { - resourceGroupName := args[0].(string) - accountName := args[1].(string) - accountKeys, err := storage.ListStorageAccountKeys(ctx, &storage.ListStorageAccountKeysArgs{ - ResourceGroupName: resourceGroupName, - AccountName: accountName, - }) - if err != nil { - return "", err - } - - return accountKeys.Keys[0].Value, nil - }, - )) - - return nil - }) -} -``` - -{{% /choosable %}} -{{% choosable language csharp %}} - -```csharp -using Pulumi; -using Pulumi.AzureNative.Resources; -using Pulumi.AzureNative.Storage; -using Pulumi.AzureNative.Storage.Inputs; -using System.Collections.Generic; - -return await Pulumi.Deployment.RunAsync(() => -{ - // Create an Azure Resource Group - var resourceGroup = new ResourceGroup("resourceGroup"); - - // Create an Azure resource (Storage Account) - var storageAccount = new StorageAccount("sa", new StorageAccountArgs - { - ResourceGroupName = resourceGroup.Name, - Sku = new SkuArgs - { - Name = SkuName.Standard_LRS - }, - Kind = Kind.StorageV2 - }); - - var storageAccountKeys = ListStorageAccountKeys.Invoke(new ListStorageAccountKeysInvokeArgs - { - ResourceGroupName = resourceGroup.Name, - AccountName = storageAccount.Name - }); - - var primaryStorageKey = storageAccountKeys.Apply(accountKeys => - { - var firstKey = accountKeys.Keys[0].Value; - return Output.CreateSecret(firstKey); - }); - - // Export the primary key of the Storage Account - return new Dictionary - { - ["primaryStorageKey"] = primaryStorageKey - }; -}); -``` - -{{% /choosable %}} - -{{% choosable language java %}} - -```java -package myproject; - -import com.pulumi.Pulumi; -import com.pulumi.azurenative.resources.ResourceGroup; -import com.pulumi.azurenative.storage.StorageAccount; -import com.pulumi.azurenative.storage.StorageAccountArgs; -import com.pulumi.azurenative.storage.StorageFunctions; -import com.pulumi.azurenative.storage.enums.Kind; -import com.pulumi.azurenative.storage.enums.SkuName; -import com.pulumi.azurenative.storage.inputs.ListStorageAccountKeysArgs; -import com.pulumi.azurenative.storage.inputs.SkuArgs; -import com.pulumi.core.Either; -import com.pulumi.core.Output; -import com.pulumi.deployment.InvokeOptions; - -public class App { - public static void main(String[] args) { - Pulumi.run(ctx -> { - var resourceGroup = new ResourceGroup("resourceGroup"); - var storageAccount = new StorageAccount("sa", StorageAccountArgs.builder() - .resourceGroupName(resourceGroup.name()) - .sku(SkuArgs.builder() - .name(SkuName.Standard_LRS) - .build()) - .kind(Kind.StorageV2) - .build()); - - var primaryStorageKey = getStorageAccountPrimaryKey( - resourceGroup.name(), - storageAccount.name()); - - ctx.export("primaryStorageKey", primaryStorageKey); - }); - } - - private static Output getStorageAccountPrimaryKey(Output resourceGroupName, - Output accountName) { - return Output.tuple(resourceGroupName, accountName).apply(tuple -> { - var actualResourceGroupName = tuple.t1; - var actualAccountName = tuple.t2; - var invokeResult = StorageFunctions.listStorageAccountKeys(ListStorageAccountKeysArgs.builder() - .resourceGroupName(actualResourceGroupName) - .accountName(actualAccountName) - .build(), InvokeOptions.Empty); - return Output.of(invokeResult) - .applyValue(r -> r.keys().get(0).value()) - .asSecret(); - }); - } -} -``` - -{{% /choosable %}} - -{{% choosable language yaml %}} - -```yaml -name: quickstart -runtime: yaml -description: A minimal Azure Native Pulumi YAML program -resources: - resourceGroup: - type: azure-native:resources:ResourceGroup - sa: - type: azure-native:storage:StorageAccount - properties: - resourceGroupName: ${resourceGroup.name} - sku: - name: Standard_LRS - kind: StorageV2 -variables: - storageAccountKeys: - fn::azure-native:storage:listStorageAccountKeys: - resourceGroupName: ${resourceGroup.name} - accountName: ${sa.name} -outputs: - primaryStorageKey: ${storageAccountKeys.keys[0].value} -``` - -{{% /choosable %}} - -This Pulumi program creates an Azure resource group and storage account and then exports the storage account's primary key. - -{{% notes %}} -In this program, the location of the resource group is set in the configuration setting `azure-native:location` (check the `Pulumi.dev.yaml` file). This is an easy way to set a global location for your program so you don't have to specify the location for each resource manually. The location for the storage account is automatically derived from the location of the resource group. To override the location for a resource, set the location property to one of Azure's [supported locations](https://azure.microsoft.com/en-us/global-infrastructure/locations/). -{{% /notes %}} - -Next, you'll deploy your stack, which will provision a resource group and your storage account. - -{{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/gcp/begin.md b/content/docs/iac/get-started/gcp/begin.md index 07046fab58df..6766083268ee 100644 --- a/content/docs/iac/get-started/gcp/begin.md +++ b/content/docs/iac/get-started/gcp/begin.md @@ -1,8 +1,8 @@ --- -title_tag: Before You Begin | Google Cloud +title_tag: Install Pulumi | Google Cloud meta_desc: This page provides an overview on how to get started with Pulumi and Google Cloud. -title: Before you begin -h1: "Pulumi & Google Cloud: Before you begin" +title: Install Pulumi +h1: "Get started with Pulumi and Google Cloud" weight: 2 menu: iac: @@ -18,72 +18,6 @@ aliases: - /docs/clouds/gcp/get-started/begin/ --- -Before you get started using Pulumi, let's run through a few quick steps to ensure your environment is set up correctly. - -### Install Pulumi - -{{< install-pulumi >}} -{{% notes "info" %}} -All Windows examples in this tutorial assume you are running in PowerShell. -{{% /notes %}} -{{< /install-pulumi >}} - -Next, install the required language runtime, if you have not already. - -### Install Language Runtime - -#### Choose Your Language - -{{< chooser language "typescript,python,go,csharp,java,yaml" / >}} - -{{% choosable language "typescript" %}} -{{< install-node >}} -{{% /choosable %}} - -{{% choosable language python %}} -{{< install-python >}} -{{% /choosable %}} - -{{% choosable language go %}} -{{< install-go >}} -{{% /choosable %}} - -{{% choosable language "csharp,fsharp,visualbasic" %}} -{{< install-dotnet >}} -{{% /choosable %}} - -{{% choosable language java %}} -{{< install-java >}} -{{% /choosable %}} - -{{% choosable language yaml %}} -{{< install-yaml >}} -{{% /choosable %}} - -Finally, configure Pulumi with Google Cloud. - -### Configure Pulumi to access your Google Cloud account - -Pulumi requires cloud credentials to manage and provision resources. You must use an IAM user or service account that has **Programmatic access** with rights to deploy and manage your Google Cloud resources. - -In this guide, you will need an IAM user account with permissions that can create and populate a Cloud Storage bucket, such as those in the predefined Storage Admin (`roles/storage.admin`) or the Storage Legacy Bucket Owner (`roles/storage.legacyBucketOwner`) roles. - -When developing locally, we recommend that you install the [Google Cloud SDK](https://cloud.google.com/sdk/install) and then [authorize access with a user account](https://cloud.google.com/sdk/docs/authorizing#authorizing_with_a_user_account). - -If `gcloud` is not configured to interact with your Google Cloud project, set it with the `config` command using the project's ID: - -```bash -gcloud config set project -``` - -Next, Pulumi requires default application credentials to interact with your Google Cloud resources, so run `auth application-default login` command to obtain those credentials. - -```bash -gcloud auth application-default login -``` - -For additional information on setting and using Google Cloud credentials, see [Google Cloud Setup](/registry/packages/gcp/installation-configuration/). - -Next, you'll create a new Pulumi project. +{{< get-started-install-body >}} {{< get-started-stepper >}} diff --git a/content/docs/iac/get-started/kubernetes/begin.md b/content/docs/iac/get-started/kubernetes/begin.md index 4bb642b595f7..41ceb842dad1 100644 --- a/content/docs/iac/get-started/kubernetes/begin.md +++ b/content/docs/iac/get-started/kubernetes/begin.md @@ -1,8 +1,8 @@ --- -title_tag: Before You Begin | Kubernetes -meta_desc: This page provides an overview on how to get started with Pulumi when starting an Kubernetes project. -title: Before you begin -h1: "Pulumi & Kubernetes: Before you begin" +title_tag: Install Pulumi | Kubernetes +meta_desc: This page provides an overview on how to get started with Pulumi when starting a Kubernetes project. +title: Install Pulumi +h1: "Get started with Pulumi and Kubernetes" weight: 2 menu: iac: @@ -19,54 +19,6 @@ aliases: - /get-started/kubernetes/begin/ --- -Before we get started using Pulumi, let's run through a few quick steps to ensure our environment is setup correctly. - -### Install Pulumi - -{{< install-pulumi >}} -{{% notes "info" %}} -All Windows examples in this tutorial assume you are running in PowerShell. -{{% /notes %}} -{{< /install-pulumi >}} - -Next, we'll install the required language runtime. - -### Install Language Runtime - -#### Choose Your Language - -{{< chooser language "typescript,python,go,csharp,java,yaml" / >}} - -{{% choosable language "typescript" %}} -{{< install-node >}} -{{% /choosable %}} - -{{% choosable language python %}} -{{< install-python >}} -{{% /choosable %}} - -{{% choosable language go %}} -{{< install-go >}} -{{% /choosable %}} - -{{% choosable language "csharp,fsharp,visualbasic" %}} -{{< install-dotnet >}} -{{% /choosable %}} - -{{% choosable language java %}} -{{< install-java >}} -{{% /choosable %}} - -{{% choosable language yaml %}} -{{< install-yaml >}} -{{% /choosable %}} - -Next, we'll configure Kubernetes. - -### Configure Kubernetes - -Configure Kubernetes so the Pulumi CLI can connect to a Kubernetes cluster. If you have previously configured the kubectl CLI, `kubectl`, Pulumi will respect and use your configuration settings. Depending on the approach you choose, you may need to apply some of the configuration after creating your project and stack in the next step. - -Next, we'll create a new Pulumi project. +{{< get-started-install-body >}} {{< get-started-stepper >}} diff --git a/layouts/shortcodes/get-started-install-body.html b/layouts/shortcodes/get-started-install-body.html new file mode 100644 index 000000000000..11bff9d7ac37 --- /dev/null +++ b/layouts/shortcodes/get-started-install-body.html @@ -0,0 +1,5 @@ +

Install Pulumi

+ +

Download and install Pulumi for your platform:

+ +{{ .Page.RenderString "{{< install-pulumi >}}\n{{% notes info %}}\nAll Windows examples in this tutorial assume you are running in PowerShell.\n{{% /notes %}}\n{{< /install-pulumi >}}" }}