https://pulumi.com logo
#automation-api
Title
# automation-api
f

few-electrician-82432

12/08/2023, 5:32 PM
Hey everyone! We use Pulumi extensively here, but all in the CLI. We are just getting started with the automation api. We configured a starter project based on the pulumi over http example, and used the same pulumi.yaml as our cli projects. When we run it, it says it succesfully creates resources, but nothing is created in our project. Has anyone run into this before? I am using GCP and TS.
s

salmon-account-74572

12/08/2023, 8:49 PM
Are you able to share any of your code? Also, how do you have your code organized? Anecdotally I've seen issues if the Automation API code is a parent of the Pulumi program; moving folders around so they are siblings (peers in the same parent folder) usually fixes that.
f

few-electrician-82432

12/08/2023, 8:54 PM
client platform is a working cli program, server is where we are trying out the automation api.
Copy code
├── client-platform
│   ├── Pulumi.summa-development.yaml
│   ├── Pulumi.yaml
│   ├── database.ts
│   ├── index.ts
│   ├── package.json
│   ├── tsconfig.json
│   └── yarn.lock
└── server
    ├── Pulumi.yaml
    ├── index.ts
    ├── package.json
    └── yarn.lock

8 directories, 42 files
Copy code
import {
  LocalWorkspace,
  ConcurrentUpdateError,
  StackAlreadyExistsError,
  StackNotFoundError, InlineProgramArgs, ProjectSettings
} from '@pulumi/pulumi/automation'
import express from "express";
import { DB } from '../client-platform/database'
const projectName = 'summa-development'

const workDir = './'; // Path to your server directory


const createPulumiProgram = (content: string) => async () => {
  const DatabaseParameters = {
    name: 'summa-test-primary',
    region: 'us-east1',
    environment: 'production',
    diskSize: 25,
    tier: 'db-f1-micro',
    replica: true,
    secondaryRegion: 'us-central1',
    secondaryName: 'summa-test-secondary',
  }
  const db = new DB(DatabaseParameters)
  return db;
}

const createHandler: express.RequestHandler = async (req, res) => {
  const stackName = 'automation-api'
  const content = req.body.content as string
  const db = createPulumiProgram(content)
  const args: InlineProgramArgs = {
    stackName: stackName,
    projectName: projectName,
    program: db,
  };

  const projectSettings: ProjectSettings = {
    name: projectName,
    runtime: "nodejs",
    backend: {
      url: '<gs://client-platform-pulumi-state>',
    },
  };
  try {

    const stack = await LocalWorkspace.createOrSelectStack(args, {
      projectSettings,
      secretsProvider,
      stackSettings: {
        [stackName]: {
          secretsProvider,
        },
      },
    })

    const upRes = await stack.up({ onOutput: console.info })
    res.json({ id: stackName })
  } catch (e) {
    if (e instanceof StackAlreadyExistsError) {
      res.status(409).send(`stack "${stackName}" already exists`)
    } else {
      res.status(500).send(e)
    }
  }
}

// deletes a site
const deleteHandler: express.RequestHandler = async (req, res) => {
  const stackName = req.params.id
  try {
    // select the existing stack
    const stack = await LocalWorkspace.selectStack({
      stackName,
      projectName,
      // don't need a program for destroy
      program: async () => { },
    })
    // deploy the stack, tailing the logs to console
    await stack.destroy({ onOutput: console.info })
    await stack.workspace.removeStack(stackName)
    res.status(200).end()
  } catch (e) {
    if (e instanceof StackNotFoundError) {
      res.status(404).send(`stack "${stackName}" does not exist`)
    } else if (e instanceof ConcurrentUpdateError) {
      res
        .status(409)
        .send(`stack "${stackName}" already has update in progress`)
    } else {
      res.status(500).send(e)
    }
  }
}
const ensurePlugins = async () => {
  const ws = await LocalWorkspace.create({
    workDir: workDir,
  })
  await ws.installPlugin('gcp', '6.0.0')
}

// install necessary plugins once upon boot
// ensurePlugins()

const app = express()
app.use(express.json())

app.post('/', createHandler)
app.delete('/:id', deleteHandler)

app.listen(1337, () => console.info('server running on :1337'))
Sorry for the long code file. That is our server. I omitted the secret configuration.
s

salmon-account-74572

12/08/2023, 8:57 PM
Your server program (with the Automation API code) generally doesn't need a
Pulumi.yaml
. Try removing that and see if it helps.
f

few-electrician-82432

12/08/2023, 8:57 PM
ok running
s

salmon-account-74572

12/08/2023, 8:58 PM
A quick perusal of the server/Automation API code seems reasonable, but most of the Automation API code I've written has been in Go.
f

few-electrician-82432

12/08/2023, 8:59 PM
I would prefer Go as well, unfortunately when we started using pulumi the Go SDK was not as good as the TS one, and now all our IaC is in TS.
s

salmon-account-74572

12/08/2023, 9:00 PM
You can write your Automation API code in Go even if the IaC program is in TS. That's a supported configuration/use case.
f

few-electrician-82432

12/08/2023, 9:00 PM
Oh interesting, ill have to take a look at that
the thing that is weird to us, is the output of this is:
Copy code
Updating (automation-api):
    pulumi:pulumi:Stack summa-development-automation-api running

    pulumi:pulumi:Stack summa-development-automation-api
Resources:
    + 1 created

Duration: 3s
which we cannot find in our cloud project anywhere
s

salmon-account-74572

12/08/2023, 9:02 PM
Looks like you're using GCS for your backend, you don't see anything created there?
f

few-electrician-82432

12/08/2023, 9:03 PM
No, the stack isnt even in our bucket. Could it be something to do with the
workdir
? if I log the stack, I get this output
Copy code
Stack {
  name: 'automation-api',
  workspace: LocalWorkspace {
    pulumiHome: undefined,
    program: [AsyncFunction (anonymous)],
    secretsProvider: undefined,
    remote: undefined,
    remoteGitProgramArgs: undefined,
    remotePreRunCommands: undefined,
    remoteEnvVars: {},
    remoteSkipInstallDependencies: undefined,
    workDir: '/var/folders/89/x36p7wgx681f21zfzv45h_gh0000gn/T/automation-2zfOxa',
    envVars: {},
    ready: Promise { [Array] },
    _pulumiVersion: SemVer {
      options: {},
      loose: false,
      includePrerelease: false,
      raw: 'v3.94.2',
      major: 3,
      minor: 94,
      patch: 2,
      prerelease: [],
      build: [],
      version: '3.94.2'
    }
  },
  ready: Promise { undefined }
}
s

salmon-account-74572

12/08/2023, 9:32 PM
Hmm...I would think you should see something. Let me make some inquiries internally and see what I'm missing here. Given that it's the end of the week, it may be a few days before I can get back to you.
f

few-electrician-82432

12/08/2023, 9:32 PM
Thanks scott, I appreciate it. No worries!
r

red-match-15116

12/09/2023, 2:41 AM
Hey! Is
DB
a pulumi component where the resources are defined? It seems like we are creating a stack,
f

few-electrician-82432

12/11/2023, 3:02 PM
Yeah, and in some of the examples the stack has a program, and thats what we are passing in
l

limited-rainbow-51650

01/04/2024, 9:02 AM
@few-electrician-82432 not sure if you solved it already, but my guess is you are mixing up an inline program and a local program. If
./client-platform/database.ts
only contains a function or a component class setting up the database, but the instantiation happens in
./client-platform/index.ts
, then nothing will be created in your current setup. Rather than using an inline program (
InlineProgramArgs
), try to use a local program (
LocalProgramArgs
) and pass a relative path from the automation api workdir to the the Pulumi CLI program:
Copy code
const args: LocalProgramArgs = {
    stackName: "automation-api",
    workDir: upath.joinSafe(__dirname, "..", "client-platform"),
};
So the gist is to point to the full working Pulumi program and as Scott mentioned, at that moment the language you use for the infrastructure code and your automation program may differ. Example: https://github.com/pulumi/automation-api-examples/blob/main/nodejs/localProgram-tsnode/automation/index.ts#L17-L20 If you want to use an inline program, you only have a single program and programming language, containing both. Here is an example of an inline program in TS: https://github.com/pulumi/automation-api-examples/tree/main/nodejs/inlineProgram-ts