Search code examples
google-cloud-platformgoogle-cloud-buildgoogle-cloud-nodegoogle-devtools-cloudbuild

Requested entity was not found using google-devtools-cloudbuild


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.


Solution

  • 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
    );