Pulumi Infrastructure as Code

Modern Infrastructure as Code examples using Pulumi with TypeScript, Python, and Go

Key Facts

Category
Infrastructure as Code
Items
4
Format Families
sample

Sample Overview

Modern Infrastructure as Code examples using Pulumi with TypeScript, Python, and Go This sample set belongs to Infrastructure as Code and can be used to test related workflows inside Elysia Tools.

💻 Pulumi with TypeScript for AWS typescript

🟢 simple ⭐⭐

Deploying AWS infrastructure using Pulumi and TypeScript

⏱️ 15 min 🏷️ pulumi, typescript, aws, serverless, iac
Prerequisites: Node.js, AWS account, Pulumi CLI
// Pulumi TypeScript for AWS
import * as pulumi from '@pulumi/pulumi';
import * as aws from '@pulumi/aws';

// Get AWS provider configuration
const config = new pulumi.Config();
const stackName = pulumi.getStack();
const environment = stackName === 'prod' ? 'production' : 'development';

// Create an AWS resource (S3 Bucket)
const bucket = new aws.s3.Bucket('my-app-bucket', {
    bucket: pulumi.interpolate`my-app-bucket-${stackName}-${Math.floor(Math.random() * 1000000)}`,
    acl: 'private',
    versioning: {
        enabled: true,
    },
    tags: {
        Name: pulumi.interpolate`my-app-bucket-${stackName}`,
        Environment: environment,
        Project: 'pulumi-demo',
        ManagedBy: 'pulumi'
    },
    website: {
        indexDocument: 'index.html',
        errorDocument: 'error.html'
    },
    forceDestroy: true
});

// Create IAM role for Lambda
const lambdaRole = new aws.iam.Role('app-lambda-role', {
    assumeRolePolicy: JSON.stringify({
        Version: '2012-10-17',
        Statement: [{
            Action: 'sts:AssumeRole',
            Effect: 'Allow',
            Principal: {
                Service: 'lambda.amazonaws.com'
            }
        }]
    }),
    tags: {
        Name: pulumi.interpolate`app-lambda-role-${stackName}`,
        Environment: environment
    }
});

// Attach basic execution policy
new aws.iam.RolePolicyAttachment('app-lambda-basic-execution', {
    role: lambdaRole.name,
    policyArn: aws.iam.ManagedPolicies.AWSLambdaBasicExecutionRole,
});

// Create Lambda function
const lambdaFunction = new aws.lambda.Function('app-api-function', {
    name: pulumi.interpolate`app-api-${stackName}`,
    runtime: 'nodejs18.x',
    handler: 'index.handler',
    role: lambdaRole.arn,
    s3Bucket: bucket.id,
    s3Key: 'api/function.zip',
    timeout: 30,
    memorySize: 256,
    environment: {
        variables: {
            NODE_ENV: environment,
            BUCKET_NAME: bucket.id
        }
    },
    tags: {
        Name: pulumi.interpolate`app-api-${stackName}`,
        Environment: environment
    }
});

// Create API Gateway
const api = new aws.apigateway.RestApi('app-api', {
    name: pulumi.interpolate`app-api-${stackName}`,
    description: pulumi.interpolate`API Gateway for Pulumi demo in ${environment}`,
    endpointConfiguration: {
        types: 'REGIONAL',
    }
});

// Create API resource
const apiResource = new aws.apigateway.Resource('app-api-resource', {
    restApi: api.id,
    parentId: api.rootResourceId,
    pathPart: '{proxy+}'
});

// Create API method
const apiMethod = new aws.apigateway.Method('app-api-method', {
    restApi: api.id,
    resourceId: apiResource.id,
    httpMethod: 'ANY',
    authorization: 'NONE'
});

// Create API integration
const apiIntegration = new aws.apigateway.Integration('app-api-integration', {
    restApi: api.id,
    resourceId: apiResource.id,
    httpMethod: apiMethod.httpMethod,
    integrationHttpMethod: 'POST',
    type: 'AWS_PROXY',
    uri: lambdaFunction.invokeArn
});

// Grant API Gateway permission to invoke Lambda
const lambdaPermission = new aws.lambda.Permission('app-api-lambda-permission', {
    statementId: 'AllowAPIGatewayInvoke',
    action: 'lambda:InvokeFunction',
    function: lambdaFunction.name,
    principal: 'apigateway.amazonaws.com',
    sourceArn: pulumi.interpolate`arn:aws:execute-api:${aws.getRegion()}:${aws.getAccountId()}:${api.id}/*/*`
});

// Create CloudWatch Log Group for Lambda
const logGroup = new aws.cloudwatch.LogGroup('app-lambda-logs', {
    name: pulumi.interpolate`/aws/lambda/${lambdaFunction.name}`,
    retentionInDays: 14,
    tags: {
        Name: pulumi.interpolate`${lambdaFunction.name}-logs`,
        Environment: environment
    }
});

// Output values
export const bucketName = bucket.id;
export const bucketArn = bucket.arn;
export const apiEndpoint = pulumi.interpolate`https://${api.id}.execute-api.${aws.getRegion()}.amazonaws.com/prod`;
export const lambdaFunctionName = lambdaFunction.name;
export const logGroupName = logGroup.name;

// Cross-stack references example (optional)
if (environment === 'production') {
    const prodStackRef = new pulumi.StackReference('organization/project/prod');
    const prodApiStackRef = new pulumi.StackReference('organization/project/prod-api');

    prodStackRef.getOutput('bucket_name').apply(name => {
        console.log('Referenced prod bucket:', name);
    });
    prodApiStackRef.getOutput('api_endpoint').apply(endpoint => {
        console.log('Referenced prod API endpoint:', endpoint);
    });
}

💻 Pulumi with Python for Google Cloud python

🟡 intermediate ⭐⭐⭐

Deploying GCP infrastructure using Pulumi and Python

⏱️ 25 min 🏷️ pulumi, python, gcp, cloud run, cloud sql
Prerequisites: Python, GCP project, Pulumi CLI
# Pulumi Python for Google Cloud Platform
import pulumi
import pulumi_gcp as gcp

# Get configuration
config = pulumi.Config()
stack_name = pulumi.get_stack()
environment = 'production' if stack_name == 'prod' else 'development'
project_id = config.require('project_id')
region = config.get('region', 'us-central1')

# Create GCP provider
gcp_provider = gcp.provider.Provider('gcp',
    project=project_id,
    region=region
)

# Create VPC network
vpc_network = gcp.compute.Network('app-vpc',
    name=f'app-vpc-{stack_name}',
    auto_create_subnetworks=False,
    description=f'VPC for application in {environment}',
    routing_mode='REGIONAL',
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Create subnets
public_subnet = gcp.compute.Subnetwork('app-public-subnet',
    name=f'app-public-subnet-{stack_name}',
    ip_cidr_range='10.0.1.0/24',
    region=region,
    network=vpc_network.id,
    private_ip_google_access=False,
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

private_subnet = gcp.compute.Subnetwork('app-private-subnet',
    name=f'app-private-subnet-{stack_name}',
    ip_cidr_range='10.0.2.0/24',
    region=region,
    network=vpc_network.id,
    private_ip_google_access=True,
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Create Cloud Storage bucket
bucket_suffix = pulumi.random.RandomString('bucket-suffix',
    length=8,
    special=False,
    upper=False
).result

storage_bucket = gcp.storage.Bucket('app-storage-bucket',
    name=bucket_suffix.apply(lambda suffix: f'app-storage-bucket-{stack_name}-{suffix}'),
    location=region,
    storage_class='STANDARD',
    uniform_bucket_level_access=True,
    versioning= {
        'enabled': True
    },
    labels={
        'environment': environment,
        'managed-by': 'pulumi'
    },
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Create Cloud SQL instance
sql_instance = gcp.sql.DatabaseInstance('app-sql-instance',
    name=f'app-sql-instance-{stack_name}',
    database_version='POSTGRES_14',
    region=region,
    settings={
        'tier': 'db-g1-small',
        'disk_size': 20,
        'disk_type': 'PD_SSD',
        'ip_configuration': {
            'ipv4_enabled': False,
            'private_network': vpc_network.id,
            'authorized_networks': []
        },
        'backup_configuration': {
            'enabled': True,
            'binary_log_enabled': True
        }
    },
    deletion_protection=False,
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Create SQL database
sql_database = gcp.sql.Database('app-sql-database',
    name='app_database',
    instance=sql_instance.name,
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Create Cloud Run service
cloud_run_service = gcp.cloudrun.Service('app-cloudrun-service',
    name=f'app-service-{stack_name}',
    location=region,
    template={
        'spec': {
            'containers': [{
                'image': 'gcr.io/cloudrun/hello:latest',
                'ports': [{
                    'name': 'http1',
                    'containerPort': 8080
                }],
                'envs': [
                    {
                        'name': 'DATABASE_HOST',
                        'value': sql_instance.private_ip_address.apply(lambda ip: f'{ip}:5432')
                    },
                    {
                        'name': 'DATABASE_NAME',
                        'value': sql_database.name
                    },
                    {
                        'name': 'STORAGE_BUCKET',
                        'value': storage_bucket.name
                    },
                    {
                        'name': 'ENVIRONMENT',
                        'value': environment
                    }
                ]
            }],
            'container_concurrency': 80,
            'timeout_seconds': 30
        }
    },
    traffic=[{
        'percent': 100,
        'latest_revision': True
    }],
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Create IAM policy for Cloud Run
cloud_run_iam = gcp.cloudrun.IamPolicy('app-cloudrun-iam',
    location=region,
    project=project_id,
    bindings=[{
        'role': 'roles/run.invoker',
        'members': ['allUsers']
    }],
    cloudrun=cloud_run_service.name,
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Create Cloud Scheduler job
scheduler_job = gcp.cloudscheduler.Job('app-scheduler-job',
    name=f'app-scheduler-{stack_name}',
    description='Scheduled job for data processing',
    schedule='0 2 * * *',  # Daily at 2 AM
    time_zone='America/Los_Angeles',
    pubsub_target={
        'topic_name': gcp.pubsub.Topic('app-topic',
            name=f'app-topic-{stack_name}',
            opts=pulumi.ResourceOptions(provider=gcp_provider)
        ).id.apply(lambda id: f'projects/{project_id}/topics/{id}'),
        'data': '{"task": "daily_cleanup"}'
    },
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Create Cloud Function for background processing
cloud_function = gcp.cloudfunctions.Function('app-background-function',
    name=f'app-background-func-{stack_name}',
    description='Background processing function',
    runtime='python39',
    available_memory_mb=256,
    source_archive_bucket=storage_bucket.name,
    source_archive_object=gcp.storage.BucketObject('function-source',
        name='background-function.zip',
        bucket=storage_bucket.name,
        source=pulumi.FileArchive('./function-source'),
        opts=pulumi.ResourceOptions(provider=gcp_provider)
    ).name,
    entry_point='handler',
    event_trigger={
        'event_type': 'google.pubsub.topic.publish',
        'resource': scheduler_job.pubsub_target.topic_name
    },
    opts=pulumi.ResourceOptions(provider=gcp_provider)
)

# Export values
pulumi.export('project_id', project_id)
pulumi.export('vpc_network_name', vpc_network.name)
pulumi.export('public_subnet_name', public_subnet.name)
pulumi.export('private_subnet_name', private_subnet.name)
pulumi.export('storage_bucket_name', storage_bucket.name)
pulumi.export('sql_instance_name', sql_instance.name)
pulumi.export('sql_database_name', sql_database.name)
pulumi.export('sql_instance_ip', sql_instance.private_ip_address)
pulumi.export('cloud_run_service_url', cloud_run_service.statuses[0].url)
pulumi.export('scheduler_job_name', scheduler_job.name)
pulumi.export('cloud_function_name', cloud_function.name)

💻 Pulumi with Go for Kubernetes go

🟡 intermediate ⭐⭐⭐⭐

Deploying Kubernetes resources using Pulumi and Go

⏱️ 30 min 🏷️ pulumi, go, kubernetes, helm, deployment
Prerequisites: Go programming, Kubernetes, Helm
// Pulumi Go for Kubernetes
package main

import (
	"context"
	"fmt"

	"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
	"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apps/v1"
	"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
	"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/networking/v1"
	"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/rbac/v1"
	"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/helm/v3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		// Get configuration
		config := ctx.NewConfig()
		stackName := ctx.Stack()
		environment := "development"
		if stackName == "prod" {
			environment = "production"
		}

		namespaceName := fmt.Sprintf("app-%s", stackName)

		// Create Kubernetes provider
		k8sProvider, err := kubernetes.NewProvider(ctx, "k8s", &kubernetes.ProviderArgs{
			Kubeconfig: config.Get("kubeconfig"),
		})
		if err != nil {
			return err
		}

		// Create namespace
		namespace, err := v1.NewNamespace(ctx, "app-namespace", &v1.NamespaceArgs{
			Metadata: &v1.ObjectMetaArgs{
				Name: pulumi.String(namespaceName),
				Labels: pulumi.StringMap{
					"name":       pulumi.String(namespaceName),
					"environment": pulumi.String(environment),
					"managed-by": pulumi.String("pulumi"),
				},
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Create ConfigMap for application configuration
		appConfigMap, err := v1.NewConfigMap(ctx, "app-config", &v1.ConfigMapArgs{
			Metadata: &v1.ObjectMetaArgs{
				Name:      pulumi.String("app-config"),
				Namespace: namespace.Name,
			},
			Data: pulumi.StringMap{
				"API_URL":         pulumi.String("https://api.example.com"),
				"LOG_LEVEL":       pulumi.String("info"),
				"REDIS_HOST":      pulumi.String("redis-service"),
				"REDIS_PORT":      pulumi.String("6379"),
				"DB_HOST":         pulumi.String("postgres-service"),
				"DB_PORT":         pulumi.String("5432"),
				"ENVIRONMENT":     pulumi.String(environment),
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Create Secret for sensitive data
		appSecret, err := v1.NewSecret(ctx, "app-secret", &v1.SecretArgs{
			Metadata: &v1.ObjectMetaArgs{
				Name:      pulumi.String("app-secret"),
				Namespace: namespace.Name,
			},
			StringData: pulumi.StringMap{
				"DB_PASSWORD":   pulumi.String("changeme123!"),
				"API_KEY":       pulumi.String("secret-api-key"),
				"JWT_SECRET":    pulumi.String("jwt-secret-key"),
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Create Redis deployment
		redisDeployment, err := v1.NewDeployment(ctx, "redis-deployment", &v1.DeploymentArgs{
			Metadata: &v1.ObjectMetaArgs{
				Name:      pulumi.String("redis"),
				Namespace: namespace.Name,
				Labels: pulumi.StringMap{
					"app":  pulumi.String("redis"),
					"tier": pulumi.String("cache"),
				},
			},
			Spec: &v1.DeploymentSpecArgs{
				Replicas: pulumi.Int(1),
				Selector: &v1.LabelSelectorArgs{
					MatchLabels: pulumi.StringMap{
						"app": pulumi.String("redis"),
					},
				},
				Template: &v1.PodTemplateSpecArgs{
					Metadata: &v1.ObjectMetaArgs{
						Labels: pulumi.StringMap{
							"app": pulumi.String("redis"),
						},
					},
					Spec: &v1.PodSpecArgs{
						Containers: v1.ContainerArray{
							&v1.ContainerArgs{
								Name:  pulumi.String("redis"),
								Image: pulumi.String("redis:7-alpine"),
								Ports: v1.ContainerPortArray{
									&v1.ContainerPortArgs{
										ContainerPort: pulumi.Int(6379),
									},
								},
								Resources: &v1.ResourceRequirementsArgs{
									Requests: pulumi.StringMap{
										"memory": pulumi.String("64Mi"),
										"cpu":    pulumi.String("250m"),
									},
									Limits: pulumi.StringMap{
										"memory": pulumi.String("128Mi"),
										"cpu":    pulumi.String("500m"),
									},
								},
							},
						},
					},
				},
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Create Redis service
		redisService, err := v1.NewService(ctx, "redis-service", &v1.ServiceArgs{
			Metadata: &v1.ObjectMetaArgs{
				Name:      pulumi.String("redis-service"),
				Namespace: namespace.Name,
			},
			Spec: &v1.ServiceSpecArgs{
				Selector: pulumi.StringMap{
					"app": pulumi.String("redis"),
				},
				Ports: v1.ServicePortArray{
					&v1.ServicePortArgs{
						Port:       pulumi.Int(6379),
						TargetPort: pulumi.Int(6379),
					},
				},
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Create application deployment
		appDeployment, err := v1.NewDeployment(ctx, "app-deployment", &v1.DeploymentArgs{
			Metadata: &v1.ObjectMetaArgs{
				Name:      pulumi.String("app"),
				Namespace: namespace.Name,
				Labels: pulumi.StringMap{
					"app":  pulumi.String("my-app"),
					"tier": pulumi.String("frontend"),
				},
			},
			Spec: &v1.DeploymentSpecArgs{
				Replicas: pulumi.IntPtr(3),
				Selector: &v1.LabelSelectorArgs{
					MatchLabels: pulumi.StringMap{
						"app": pulumi.String("my-app"),
					},
				},
				Template: &v1.PodTemplateSpecArgs{
					Metadata: &v1.ObjectMetaArgs{
						Labels: pulumi.StringMap{
							"app": pulumi.String("my-app"),
						},
					},
					Spec: &v1.PodSpecArgs{
						Containers: v1.ContainerArray{
							&v1.ContainerArgs{
								Name:  pulumi.String("app"),
								Image: pulumi.String("nginx:alpine"),
								Ports: v1.ContainerPortArray{
									&v1.ContainerPortArgs{
										ContainerPort: pulumi.Int(80),
									},
								},
								Env: v1.EnvVarArray{
									&v1.EnvVarArgs{
										Name:  pulumi.String("ENVIRONMENT"),
										Value: pulumi.String(environment),
									},
								},
								Resources: &v1.ResourceRequirementsArgs{
									Requests: pulumi.StringMap{
										"memory": pulumi.String("64Mi"),
										"cpu":    pulumi.String("250m"),
									},
									Limits: pulumi.StringMap{
										"memory": pulumi.String("128Mi"),
										"cpu":    pulumi.String("500m"),
									},
								},
								ReadinessProbe: &v1.ProbeArgs{
									HttpGet: &v1.HTTPGetActionArgs{
										Path: pulumi.String("/"),
										Port: pulumi.Int(80),
									},
									InitialDelaySeconds: pulumi.Int(5),
									PeriodSeconds:       pulumi.Int(10),
								},
							},
						},
					},
				},
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Create application service
		appService, err := v1.NewService(ctx, "app-service", &v1.ServiceArgs{
			Metadata: &v1.ObjectMetaArgs{
				Name:      pulumi.String("app-service"),
				Namespace: namespace.Name,
			},
			Spec: &v1.ServiceSpecArgs{
				Type:     pulumi.String("LoadBalancer"),
				Selector: pulumi.StringMap{
					"app": pulumi.String("my-app"),
				},
				Ports: v1.ServicePortArray{
					&v1.ServicePortArgs{
						Port:       pulumi.Int(80),
						TargetPort: pulumi.Int(80),
					},
				},
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Create Ingress for HTTP routing
		appIngress, err := networkingv1.NewIngress(ctx, "app-ingress", &networkingv1.IngressArgs{
			Metadata: &v1.ObjectMetaArgs{
				Name:      pulumi.String("app-ingress"),
				Namespace: namespace.Name,
				Annotations: pulumi.StringMap{
					"kubernetes.io/ingress.class": pulumi.String("nginx"),
					"cert-manager.io/cluster-issuer": pulumi.String("letsencrypt-prod"),
				},
			},
			Spec: &networkingv1.IngressSpecArgs{
				Tls: networkingv1.IngressTLSArray{
					&networkingv1.IngressTLSArgs{
						Hosts: pulumi.StringArray{
							pulumi.String("app.example.com"),
						},
						SecretName: pulumi.String("app-tls"),
					},
				},
				Rules: networkingv1.IngressRuleArray{
					&networkingv1.IngressRuleArgs{
						Host: pulumi.String("app.example.com"),
						Http: &networkingv1.HTTPIngressRuleValueArgs{
							Paths: networkingv1.HTTPIngressPathArray{
								&networkingv1.HTTPIngressPathArgs{
									Path:     pulumi.String("/"),
									PathType: pulumi.String("Prefix"),
									Backend: &networkingv1.IngressBackendArgs{
										Service: &networkingv1.IngressServiceBackendArgs{
											Name: appService.Name,
											Port: &networkingv1.ServiceBackendPortArgs{
												Number: pulumi.Int(80),
											},
										},
									},
								},
							},
						},
					},
				},
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Deploy Helm chart for monitoring (Prometheus)
		prometheusChart, err := helmv3.NewRelease(ctx, "prometheus", &helmv3.ReleaseArgs{
			Chart:     pulumi.String("prometheus"),
			Version:   pulumi.String("25.8.0"),
			Namespace: namespace.Name,
			RepositoryOpts: &helmv3.RepositoryOptsArgs{
				Repo: pulumi.String("https://prometheus-community.github.io/helm-charts"),
			},
			Values: pulumi.Map{
				"server": pulumi.Map{
					"persistentVolume": pulumi.Map{
						"enabled": pulumi.Bool(false),
					},
				},
				"alertmanager": pulumi.Map{
					"enabled": pulumi.Bool(false),
				},
			},
		}, pulumi.Provider(k8sProvider))
		if err != nil {
			return err
		}

		// Export outputs
		ctx.Export("namespace_name", namespace.Name)
		ctx.Export("redis_deployment_name", redisDeployment.Name)
		ctx.Export("redis_service_name", redisService.Name)
		ctx.Export("app_deployment_name", appDeployment.Name)
		ctx.Export("app_service_name", appService.Name)
		ctx.Export("app_load_balancer_ip", appService.Status.Apply(func(status *v1.ServiceStatus) *string {
			if status.LoadBalancer != nil && len(status.LoadBalancer.Ingress) > 0 {
				return status.LoadBalancer.Ingress[0].Ip
			}
			return pulumi.String("")
		}))
		ctx.Export("ingress_host", appIngress.Spec.Apply(func(spec *networkingv1.IngressSpec) string {
			if len(spec.Rules) > 0 {
				return *spec.Rules[0].Host
			}
			return ""
		}))
		ctx.Export("prometheus_release_name", prometheusChart.Name)

		return nil
	})
}

💻 Multi-Cloud Infrastructure with Pulumi typescript

🔴 complex ⭐⭐⭐⭐⭐

Deploying infrastructure across multiple cloud providers with Pulumi

⏱️ 45 min 🏷️ pulumi, multi-cloud, aws, azure, gcp, hybrid
Prerequisites: Advanced Pulumi, Multiple cloud accounts, Cross-cloud networking
// Multi-Cloud Infrastructure with Pulumi
import * as pulumi from '@pulumi/pulumi';
import * as aws from '@pulumi/aws';
import * as azure from '@pulumi/azure-native';
import * as gcp from '@pulumi/gcp';

// Configuration
const config = new pulumi.Config();
const stackName = pulumi.getStack();
const environment = stackName === 'prod' ? 'production' : 'development';

// AWS Configuration
const awsRegion = config.get('awsRegion', 'us-west-2');
const awsProvider = new aws.Provider('aws', {
    region: awsRegion,
});

// Azure Configuration
const azureLocation = config.get('azureLocation', 'East US');
const azureResourceGroupName = pulumi.interpolate `rg-pulumi-multi-${stackName}`;
const azureResourceGroup = new azure.resources.ResourceGroup('azure-rg', {
    resourceGroupName: azureResourceGroupName,
    location: azureLocation,
    tags: {
        environment,
        managedBy: 'pulumi'
    }
});

// GCP Configuration
const gcpConfig = new gcp.Provider('gcp', {
    project: config.require('gcpProjectId'),
    region: config.get('gcpRegion', 'us-central1'),
});

// AWS Infrastructure
const awsVpc = new aws.ec2.Vpc('aws-vpc', {
    cidrBlock: '10.0.0.0/16',
    enableDnsHostnames: true,
    enableDnsSupport: true,
    tags: {
        Name: pulumi.interpolate `pulumi-multi-${stackName}`,
        Environment: environment
    }
}, { provider: awsProvider });

const awsSubnet = new aws.ec2.Subnet('aws-subnet', {
    vpcId: awsVpc.id,
    cidrBlock: '10.0.1.0/24',
    availabilityZone: pulumi.interpolate `${awsRegion}a`,
    mapPublicIpOnLaunch: true,
    tags: {
        Name: pulumi.interpolate `pulumi-multi-${stackName}-subnet`,
        Environment: environment
    }
}, { provider: awsProvider });

const awsSecurityGroup = new aws.ec2.SecurityGroup('aws-sg', {
    vpcId: awsVpc.id,
    ingress: [
        {
            protocol: 'tcp',
            fromPort: 22,
            toPort: 22,
            cidrBlocks: ['0.0.0.0/0'],
            description: 'SSH'
        },
        {
            protocol: 'tcp',
            fromPort: 80,
            toPort: 80,
            cidrBlocks: ['0.0.0.0/0'],
            description: 'HTTP'
        }
    ],
    egress: [{
        protocol: '-1',
        fromPort: 0,
        toPort: 0,
        cidrBlocks: ['0.0.0.0/0']
    }],
    tags: {
        Name: pulumi.interpolate `pulumi-multi-${stackName}-sg`,
        Environment: environment
    }
}, { provider: awsProvider });

// AWS Lambda function
const awsLambda = new aws.lambda.Function('aws-lambda', {
    name: pulumi.interpolate `pulumi-multi-${stackName}-function`,
    runtime: 'nodejs18.x',
    handler: 'index.handler',
    role: aws.iam.getRoleDocument('lambda-role-doc', {
        assumeRolePolicy: JSON.stringify({
            Version: '2012-10-17',
            Statement: [{
                Action: 'sts:AssumeRole',
                Effect: 'Allow',
                Principal: { Service: 'lambda.amazonaws.com' }
            }]
        })
    }).then(doc => new aws.iam.Role('aws-lambda-role', {
        assumeRolePolicy: doc.json,
        name: pulumi.interpolate `pulumi-multi-${stackName}-lambda-role`
    }, { provider: awsProvider }).arn),
    code: new pulumi.asset.AssetArchive({
        'index.js': new pulumi.asset.StringAsset(`
            exports.handler = async (event) => {
                return {
                    statusCode: 200,
                    body: JSON.stringify({
                        message: 'Hello from AWS Lambda!',
                        cloud: 'AWS',
                        region: process.env.AWS_REGION,
                        timestamp: new Date().toISOString()
                    })
                };
            };
        `)
    }),
    environment: {
        variables: {
            ENVIRONMENT: environment
        }
    },
    tags: {
        Name: pulumi.interpolate `pulumi-multi-${stackName}-lambda`,
        Environment: environment
    }
}, { provider: awsProvider });

// Azure Infrastructure
const azureVirtualNetwork = new azure.network.VirtualNetwork('azure-vnet', {
    virtualNetworkName: pulumi.interpolate `pulumi-multi-${stackName}-vnet`,
    resourceGroupName: azureResourceGroup.name,
    location: azureLocation,
    addressSpace: {
        addressPrefixes: ['10.1.0.0/16']
    },
    tags: {
        environment,
        managedBy: 'pulumi'
    }
});

const azureSubnet = new azure.network.Subnet('azure-subnet', {
    subnetName: pulumi.interpolate `pulumi-multi-${stackName}-subnet`,
    resourceGroupName: azureResourceGroup.name,
    virtualNetworkName: azureVirtualNetwork.name,
    addressPrefix: '10.1.1.0/24',
    privateEndpointNetworkPolicies: 'Disabled',
    privateLinkServiceNetworkPolicies: 'Enabled'
});

const azureNetworkSecurityGroup = new azure.network.NetworkSecurityGroup('azure-nsg', {
    networkSecurityGroupName: pulumi.interpolate `pulumi-multi-${stackName}-nsg`,
    resourceGroupName: azureResourceGroup.name,
    location: azureLocation,
    securityRules: [
        {
            name: 'AllowSSH',
            priority: 1000,
            direction: 'Inbound',
            access: 'Allow',
            protocol: 'Tcp',
            sourcePortRange: '*',
            destinationPortRange: '22',
            sourceAddressPrefix: '*',
            destinationAddressPrefix: '*'
        },
        {
            name: 'AllowHTTP',
            priority: 1001,
            direction: 'Inbound',
            access: 'Allow',
            protocol: 'Tcp',
            sourcePortRange: '*',
            destinationPortRange: '80',
            sourceAddressPrefix: '*',
            destinationAddressPrefix: '*'
        }
    ]
});

// Azure Function App
const azureStorageAccount = new azure.storage.StorageAccount('azure-storage', {
    accountName: pulumi.random.RandomString('storage-suffix', {
        length: 8,
        special: false,
        upper: false
    }).result.apply(suffix => `pulumi${suffix}`),
    resourceGroupName: azureResourceGroup.name,
    location: azureLocation,
    kind: 'StorageV2',
    sku: {
        name: azure.storage.SkuName.Standard_LRS
    },
    tags: {
        environment,
        managedBy: 'pulumi'
    }
});

const azureFunctionApp = new azure.web.WebApp('azure-function', {
    name: pulumi.interpolate `pulumi-multi-${stackName}-function`,
    resourceGroupName: azureResourceGroup.name,
    location: azureLocation,
    kind: 'functionapp',
    serverFarmId: new azure.web.AppServicePlan('azure-app-service-plan', {
        name: pulumi.interpolate `pulumi-multi-${stackName}-asp`,
        resourceGroupName: azureResourceGroup.name,
        location: azureLocation,
        sku: {
            name: azure.web.SkuName.Basic,
            tier: azure.web.SkuTier.Basic,
            size: 'B1'
        },
        kind: 'linux',
        reserved: true
    }).id,
    siteConfig: {
        linuxFxVersion: 'NODE|18-lts',
        appSettings: [
            {
                name: 'WEBSITE_RUN_FROM_PACKAGE',
                value: '1'
            },
            {
                name: 'FUNCTIONS_WORKER_RUNTIME',
                value: 'node'
            },
            {
                name: 'ENVIRONMENT',
                value: environment
            },
            {
                name: 'AzureWebJobsStorage',
                value: azureStorageAccount.primaryConnectionString
            }
        ]
    },
    tags: {
        environment,
        managedBy: 'pulumi'
    }
});

// GCP Infrastructure
const gcpVpcNetwork = new gcp.compute.Network('gcp-vpc', {
    name: pulumi.interpolate `pulumi-multi-${stackName}-vnet`,
    autoCreateSubnetworks: false,
    description: pulumi.interpolate `VPC for Pulumi multi-cloud demo in ${environment}`,
    routingMode: 'REGIONAL',
    tags: {
        environment,
        managedBy: 'pulumi'
    }
}, { provider: gcpConfig });

const gcpSubnet = new gcp.compute.Subnetwork('gcp-subnet', {
    name: pulumi.interpolate `pulumi-multi-${stackName}-subnet`,
    ipCidrRange: '10.2.1.0/24',
    region: config.get('gcpRegion', 'us-central1'),
    network: gcpVpcNetwork.id,
    privateIpGoogleAccess: false,
    tags: {
        environment,
        managedBy: 'pulumi'
    }
}, { provider: gcpConfig });

const gcpFirewall = new gcp.compute.Firewall('gcp-firewall', {
    name: pulumi.interpolate `pulumi-multi-${stackName}-fw`,
    network: gcpVpcNetwork.id,
    allow: [{
        protocol: 'tcp',
        ports: ['22', '80']
    }],
    sourceRanges: ['0.0.0.0/0'],
    description: 'Allow SSH and HTTP traffic',
    tags: {
        environment,
        managedBy: 'pulumi'
    }
}, { provider: gcpConfig });

// GCP Cloud Function
const gcpBucketSuffix = pulumi.random.RandomString('gcp-bucket-suffix', {
    length: 8,
    special: false,
    upper: false
}).result;

const gcpBucket = new gcp.storage.Bucket('gcp-function-bucket', {
    name: gcpBucketSuffix.apply(suffix => `pulumi-multi-${stackName}-bucket-${suffix}`),
    location: config.get('gcpRegion', 'US-CENTRAL1'),
    forceDestroy: true,
    uniformBucketLevelAccess: true,
    tags: {
        environment,
        managedBy: 'pulumi'
    }
}, { provider: gcpConfig });

const gcpFunctionArchive = new gcp.storage.BucketObject('gcp-function-zip', {
    name: 'function.zip',
    bucket: gcpBucket.name,
    source: new pulumi.asset.AssetArchive({
        'index.js': new pulumi.asset.StringAsset(`
            exports.handler = async (req, res) => {
                res.status(200).json({
                    message: 'Hello from GCP Cloud Function!',
                    cloud: 'GCP',
                    region: process.env.FUNCTION_REGION,
                    timestamp: new Date().toISOString()
                });
            };
        `)
    })
}, { provider: gcpConfig });

const gcpFunction = new gcp.cloudfunctions.Function('gcp-function', {
    name: pulumi.interpolate `pulumi-multi-${stackName}-function`,
    description: pulumi.interpolate `Pulumi multi-cloud demo function in ${environment}`,
    runtime: 'nodejs18',
    entryPoint: 'handler',
    sourceArchiveBucket: gcpBucket.name,
    sourceArchiveObject: gcpFunctionArchive.name,
    triggerHttp: true,
    availableMemoryMb: 256,
    timeout: 60,
    environmentVariables: {
        ENVIRONMENT: environment
    },
    tags: {
        environment,
        managedBy: 'pulumi'
    }
}, { provider: gcpConfig });

// Enable Cloud Function invocations
const gcpFunctionIAM = new gcp.cloudfunctions.FunctionIamPolicy('gcp-function-iam', {
    region: gcpFunction.region,
    cloudFunction: gcpFunction.name,
    bindings: [{
        role: 'roles/cloudfunctions.invoker',
        members: ['allUsers']
    }]
}, { provider: gcpConfig });

// Cross-Cloud Networking (VPN connections would go here)
// This is a simplified example - in production you'd set up VPN tunnels or Direct Connect

// Monitoring Integration (using a centralized monitoring solution)
const monitoringConfig = {
    aws: {
        lambdaName: awsLambda.name,
        region: awsRegion
    },
    azure: {
        functionName: azureFunctionApp.name,
        resourceGroup: azureResourceGroup.name
    },
    gcp: {
        functionName: gcpFunction.name,
        region: config.get('gcpRegion', 'us-central1')
    }
};

// Export outputs
export const awsInfrastructure = {
    vpcId: awsVpc.id,
    subnetId: awsSubnet.id,
    lambdaFunctionName: awsLambda.name,
    lambdaArn: awsLambda.arn
};

export const azureInfrastructure = {
    resourceGroupName: azureResourceGroup.name,
    vnetName: azureVirtualNetwork.name,
    subnetName: azureSubnet.name,
    functionName: azureFunctionApp.name,
    functionUrl: azureFunctionApp.defaultHostName
};

export const gcpInfrastructure = {
    vpcName: gcpVpcNetwork.name,
    subnetName: gcpSubnet.name,
    functionName: gcpFunction.name,
    functionUrl: gcpFunction.httpsTriggerUrl
};

export const monitoringSetup = monitoringConfig;

// Additional exports for easy access
pulumi.export('aws_lambda_name', awsLambda.name);
pulumi.export('azure_function_name', azureFunctionApp.name);
pulumi.export('gcp_function_name', gcpFunction.name);
pulumi.export('gcp_function_url', gcpFunction.httpsTriggerUrl);

// Stack outputs for monitoring dashboard
pulumi.export('dashboard_config', pulumi.all([
    awsLambda.name,
    azureFunctionApp.name,
    gcpFunction.name
]).apply(([awsName, azureName, gcpName]) => JSON.stringify({
    environment,
    services: {
        aws: awsName,
        azure: azureName,
        gcp: gcpName
    },
    monitoring: {
        enabled: true,
        providers: ['cloudwatch', 'azure-monitor', 'cloud-monitoring']
    }
})));