Requested entity was not found using google-devtools-cloudbuild

713 views Asked by At

I took this sample code right out of google-cloud-node.

I have my ADC set up and working with Owner permissions and every cloud build permission available. The same account can create a build with gcloud submit build.

I took the trigger UUID out of the url at /cloud-build/triggers.

I ran the build manually from the GCP console and confirmed the EXACT same payload was being sent.

Can anyone tell me why I am getting this unholy error message when I run the following code:


export default async function cloudBuild(
  projectId = "myprojectId", // Your Google Cloud Platform project ID
  triggerId = "75aaeefc-0b11-4ce8-b285-cc066ceffc77", // UUID for build trigger.
  commitSha = "c13a9a2d500bec8680d3bb5a064c7dc72db31a90" // Commit to run build against.
) {
  // Imports the Google Cloud client library

  // Creates a client
  const cb = new CloudBuildClient();

  // Starts a build against the branch provided.
  const [resp] = await cb.runBuildTrigger({
    projectId,
    triggerId,
    source: {
      commitSha,
    },
  });

  console.info(`triggered build for ${triggerId}`);
  const [build] = await resp.promise();
}

Error:

Error: 5 NOT_FOUND: Requested entity was not found.
    at callErrorFromStatus (/Users/jambrose/Apps/deploy_server/node_modules/@grpc/grpc-js/src/call.ts:81:17)
    at Object.onReceiveStatus (/Users/jambrose/Apps/deploy_server/node_modules/@grpc/grpc-js/src/client.ts:356:55)
    at Object.onReceiveStatus (/Users/jambrose/Apps/deploy_server/node_modules/@grpc/grpc-js/src/client-interceptors.ts:455:34)
    at Object.onReceiveStatus (/Users/jambrose/Apps/deploy_server/node_modules/@grpc/grpc-js/src/client-interceptors.ts:417:48)
    at /Users/jambrose/Apps/deploy_server/node_modules/@grpc/grpc-js/src/resolving-call.ts:111:24
    at processTicksAndRejections (node:internal/process/task_queues:78:11)
for call at
 {
  code: 5,
  details: 'Requested entity was not found.',
  metadata: Metadata {
    internalRepr: Map(2) {
      'endpoint-load-metrics-bin' => [Array],
      'grpc-server-stats-bin' => [Array]
    },
    options: {}
  }
}

Update:

Since the error can be caused by an authentication issue, I tested another service: Storage.listBuckets({ keyFilename: "key-file.json" }) which was successful. This illustrates that the key-file is valid and the service account is activated.

Update:

Looking closer at the sample specifically for runCloudBuild. In the comments, it says:

/**
   *  The name of the `Trigger` to run.
   *  Format: `projects/{project}/locations/{location}/triggers/{trigger}`
   */
  // const name = 'abc123'
  /**
   *  Required. ID of the project.
   */
  // const projectId = 'abc123'
  /**
   *  Required. ID of the trigger.
   */
  // const triggerId = 'abc123'
  /**
   *  Source to build against this trigger.
   */
  // const source = {}

And the code sample regarding the resource:

async function callRunBuildTrigger() {
    // Construct request
    const request = {
      projectId,
      triggerId,
    };

Note, there is no "name" in the sample payload.

1

There are 1 answers

1
jambrose On BEST ANSWER

Solved. The samples are incomplete. I combined several samples and also looked at the REST API Explorer.

This typescript code works for my purpose:

// cloudBuild.ts
import { CloudBuildClient } from "@google-cloud/cloudbuild";
import types from "@google-cloud/cloudbuild/build/protos/protos";

const STATUS_LOOKUP = [
  "UNKNOWN",
  "Queued",
  "Working",
  "Success",
  "Failure",
  "Error",
  "Timeout",
  "Cancelled",
];

export default async function cloudBuild(
  projectId: string,
  region: string,
  triggerId: string,
  commitSha: string,
  onBuildStart: (buildId: string, logUrl: string) => void,
  onBuildComplete: (buildId: string) => void,
  onBuildFailed: (buildId: string, logUrl: string) => void
) {
  const cb = new CloudBuildClient();
  // Or, use this if you are local and have a service account key-file
  //const cb = new CloudBuildClient({ keyFilename: "key-file.json" });

  const request = {
    name: `projects/${projectId}/locations/${region}/triggers/${triggerId}`,
    source: {
      dir: "./api",
      commitSha: commitSha,
    },
  };

  const [operation] = await cb.runBuildTrigger(request);

  console.info(`Triggered build for ${triggerId}, commitSha: ${commitSha}`);

  // Check that the build has started
  const operationInfo = getOperationInfo(
    operation.metadata as types.google.devtools.cloudbuild.v1.IBuildOperationMetadata
  );

  // If the build has any valid status, it has started
  if (operationInfo.status) {
    onBuildStart(operationInfo.id, operationInfo.logUrl);
  }

  const [build] = await operation.promise();

  const buildInfo = getBuildInfo(build);

  // If the build status is successful, notify that the build is complete
  if (buildInfo.status === "Success") {
    onBuildComplete(buildInfo.id);
  }

  // If the build status is successful, notify that the build is complete
  if (["Failure", "Error", "Timeout", "Cancelled"].includes(buildInfo.status)) {
    onBuildFailed(buildInfo.id, buildInfo.logUrl);
  }

  // Otherwise, there was something else that went wrong

  return buildInfo;
}

function getOperationInfo(
  metadata: types.google.devtools.cloudbuild.v1.IBuildOperationMetadata
) {
  if (!metadata) {
    throw new Error("Metadata not found");
  }

  const build = metadata.build as types.google.devtools.cloudbuild.v1.IBuild;

  const buildInfo = getBuildInfo(build);

  return buildInfo;
}

function getBuildInfo(build: types.google.devtools.cloudbuild.v1.IBuild) {
  const buildInfo = {
    id: "",
    status: "",
    logUrl: "",
  };

  // Check that build.id is defined
  if (build && build.id !== undefined && build.id !== null) {
    // Make sure we have a logUrl string
    if (!build.logUrl) {
      build.logUrl = "";
    }
    const buildStatusNumber = build.status as number;
    // Make sure the build status is within the bounds of the lookup array
    if (buildStatusNumber >= 0 && buildStatusNumber < STATUS_LOOKUP.length) {
      const buildStatus = STATUS_LOOKUP[buildStatusNumber];
      buildInfo.id = build.id;
      buildInfo.status = buildStatus;
      buildInfo.logUrl = build.logUrl;
      return buildInfo;
    } else {
      throw new Error("Build status out of bounds");
    }
  } else {
    throw new Error("Build id not found");
  }
}

You can call it from something like this:

// pleaseDoThisBuild.ts

import cloudBuild from ("./cloudBuild")

const onBuildStart = (buildId: string, logUrl: string) => {
  console.log(`Build ${buildId} started.  Log Url: ${logUrl}`);
  // Do other things here
};

const onBuildComplete = (buildId: string) => {
  console.log(`Build ${buildId} complete`);
  // Do other things here
};

const onBuildFailed = (buildId: string, logUrl: string) => {
  console.log(`Build ${buildId} failed.  Log Url: ${logUrl}`);
  // Do other things here
};

const result = await cloudBuild(
  "myProjectId", // Your project id
  "us-central1", // Your region
  "75aaeefc-0b11-4ce8-b285-cc066ceffc77", // Your trigger id
  "c13a9a2d500bec8680d3bb5a064c7dc72db31a90", // Your commit sha
  onBuildStart,
  onBuildComplete,
  onBuildFailed
);