Hello, I've written a vpc module that outputs a f...
# automation-api
w
Hello, I've written a vpc module that outputs a few pieces of information as Pulumi OutputString. I'm now hoping to pass this information to an instance of an eks module. I am also hoping to do this twice, once for a non-prod enivronment, once for a prod. Here's my current work in progress:
Copy code
#!/usr/bin/node
import * as vpcModule from "./components/vpc"
import * as eksModule from "./components/eks"
import * as automation from "@pulumi/pulumi/automation";

/**
 * Non-prod configuration
 */
export const nonprodDemoVpcArgs: vpcModule.VpcArgs = {
    description: "Typescript pulumi vpc module non-prod",
    
    instanceTenancy: "default",

    availabilityZones: ["ca-central-1a", "ca-central-1b", "ca-central-1d"],

    vpcCidr: "10.0.0.0/16",
    publicSubnetsCidrs: ["10.0.1.0/24", "10.0.2.0/24"],
    privateSubnetsCidrs: ["10.0.3.0/24", "10.0.4.0/24"],   

    vpcSecurityGroupName: "sg-non-prod",
    
    enableDnsHostnames: true,
    enableDnsSupport: true,

    tags: { "Name": "non-prod-vpc" }
};

export const nonProdEksArgs: eksModule.AsgArgs = {
    // Ec2 Description
    description: "Helloworld non-prod eks cluster",

    vpcId: "",
    publicSubnets: ["subnet-12345678", "subnet-23456789"],
    privateSubnets: ["subnet-34567890", "subnet-45678901"]
}


/**
 * Prod configuration
 */

export const prodDemoVpcArgs: vpcModule.VpcArgs = {
    description: "Typescript pulumi vpc module prod",

    instanceTenancy: "default",

    availabilityZones: ["ca-central-1a", "ca-central-1b", "ca-central-1d"],

    vpcCidr: "192.168.0.0/16",
    publicSubnetsCidrs: ["192.168.1.0/24", "192.168.2.0/24"],
    privateSubnetsCidrs: ["192.168.3.0/24", "192.168.4.0/24"],

    vpcSecurityGroupName: "sg-prod",
    
    enableDnsHostnames: true,
    enableDnsSupport: true,
    
    tags: { "Name": "demo-vpc" }
};

export async function buildNonProd() {
    // Initialize a new workspace
    const projectName = "ts-modular-eks-iac"
    const stackName = "non-prod";
    
    // Create or select non-prod stack
    const nonProdVpc = await automation.LocalWorkspace.createOrSelectStack({
        stackName: stackName,
        projectName: projectName,
        program: async () => {
            // Component resource definition goes here
            new vpcModule.AwsWebVpc("non-prod", nonprodDemoVpcArgs);
        }
    });

    // Up the VPC stack
    await nonProdVpc.up({});

    // Get outputs from VPC stack
    const nonProdVpcOutputs = await nonProdVpc.outputs();

    const nonProdEks = await automation.LocalWorkspace.createOrSelectStack({
        stackName: stackName,
         projectName: projectName,

         program: async () => {
        // Component resource definition goes here
             new eksModule.AwsWebEc2("non-prod", nonProdEksArgs);
             config: vpcId: nonProdVpcOutputs.vpcId
         },
//        config: {
//             "vpcId": { value: nonProdVpcOutputs.vpcId }
//         }
    })

    await nonProdEks.up({});
    
    const nonProdEksOutputs = await nonProdEks.outputs();

//     const nonProdEks = await automation.LocalWorkspace.createOrSelectStack({
//         stackName: stackName,
//         projectName: projectName,

//         program: async () => {
//         // Component resource definition goes here
//             new eksModule.AwsWebEc2("non-prod", nonProdEksArgs);
//         },
//         config: {
//             "vpcId": { value: nonProdVpcOutputs.vpcId }
//         }
// });

    // // Create or select prod stack
    // const prodStack = await automation.LocalWorkspace.createOrSelectStack({
    //     stackName: stackNameProd,
    //     projectName: projectName,
    //     program: async () => {
    //         // Your component resource definition goes here
    //         // Example:
    //         new vpcModule.AwsWebVpc("prod", prodDemoVpcArgs);;
    //     }
    // });
    console.log("Stacks have been updated.");
}

buildNonProd().then(() => console.log("Done!"));
//main().catch(err => console.error(err));
I'm still in the early stages of looking at pulumi so any advice on how to achieve this pattern is most welcome.
l
The point (for me) of separate projects is to enable you to have different schedules for deploying different groups of resources. So you might want to deploy your VPC resources only once every few months or even years, as they're very stable; and you might want to deploy your EKS module every month or so, if it's under more regular development. Sticking the two projects together into a single automation-api program means that you're deploying them on the same schedule. This might be what you need, but it might also just be adding extra code and complexity for no benefit.
The point of separate stacks is so that you can run the same code against different sets of infrastructure. But your automation-api program has a very precise use of non-prod, and you'd need to duplicate all that code for prod.. which defeats the point of one project -- two stacks.
Unless you have a very clear reason to use automation-api, I recommend not using it. Work with vanilla Pulumi programs, designed in the simplest manner feasible. Once you've got those working, you'll have a great knowledge of Pulumi and the sorts of scenarios where automation-api, projects and stacks can be used in different ways for different purposes.
w
Thankyou 🙂 That's great advice... My requirements are: 1. Deploy a non-prod vpc stack 2. Deploy a non-prod eks stack 3. Deploy a prod vpc stack 4. Deploy a prod eks stack I want stack references between the non-prod-vpc stack and the non-prod-eks stack. The same goes for prod. I want to write the modules so that an application developer, in a different part of the business and unfamilliar to IaC can just consume them by passing infra Could you advise on how this could be best achieved with pulumi?
l
First, imagine it's a few months from now and the code is working perfectly. Are you likely to want to deploy the EKS stuff much more often than the VPC stuff? If you are, then develop two projects, each with two stacks. Otherwise, develop one project with two stacks.
It is easier to use Component Resources than separate projects. So unless your projects are very large and unwieldly, or have very different deployment schedules, I would prefer fewer projects and more Component Resources.
w
yes, the vpc and eks configuration are component resources
l
Then you don't need multiple projects.
w
which i'm passing interfaces
projects as in stacks?
l
And since this it Typescript, you don't need interfaces 🙂
JavaBeans are dead 🙂
Not stacks. Projects.
Projects are your index.ts files, or your "programs" in automation-api. Stacks are the instances of them: the combination of source code + config.
w
so, one project with 4 stacks? 2 nonprod and 2 prod?
l
This is one of the reasons to leave automation-api until after you understand Pulumi well. So you know about projects and stacks.
No, it's looking to me like it should be one project with two stacks, nonprod and prod.
You do not seem to need separate projects.
You may have two ComponentResource files, and a single project which might be as simple as:
Copy code
import { MyVpc } from "./myvpc";
import { MyEks } from "./myeks";
const provider = new aws.Provider(/* params from config */);
const vpc = new MyVpc("vpc", {}, provider);
const eks = new MyEks("eks", { vpc: vpc }, provider);
export const vpcId = vpc.id;
export const eksId = eks.id;
There's no reference to prod and nonprod in the project (code). Instead, you have a Pulumi.nonprod.yaml and a Pulumi.prod.yaml, which contain the configuration for your stacks.
You will need to get that config via
new pulumi.Config()
, but in your project code, you don't care about prod or nonprod. That matters only to the config files.
w
That's cool
thanks a lot
Will allow me to complete this project
l
Good luck. Looking forward to your next question 🙂
w
haha yes no doubt i'll have some 🙂