'gcloud run deploy as an http request

I typically deploy new updates to my cloud run instances on GCP using the CLI:

gcloud run deploy CLOUD_RUN_INSTANCE --image gcr.io/ORGANIZATION/IMAGE --region us-east1 --platform managed --allow-unauthenticated --quiet

How would I run this same command as an http request using [axios][1] from my firebase functions?



Solution 1:[1]

The answers above solves the task of deploying Cloud Run by using a call to Cloud Build and then Cloud Build deploys the new revision, nevertheless the question is very specific:

gcloud run deploy CLOUD_RUN_INSTANCE --image gcr.io/ORGANIZATION/IMAGE --region us-east1 --platform managed --allow-unauthenticated --quiet

How would I run this same command as an http request using axios from my firebase functions?

So we need to use the replaceService method. The following code will do this by purely using axios and HTTP request. It's worth to mention that this is an snippet but can be adapted to different approaches like Firebase Functions, etc:

const {GoogleAuth} = require('google-auth-library');
const axios = require('axios');


const create_revision = async () => {
  const auth = new GoogleAuth({
    scopes: 'https://www.googleapis.com/auth/cloud-platform'
  });
  
  const token = await auth.getAccessToken();

  //TODO: Replace as needed

  region = 'REGION';
  project_id = 'PROJECT_ID';
  service_name = 'SERVICE_NAME';
  image = 'gcr.io/PROJECT_ID/IMAGE';

  //Get the current details of the service
  try {
    resp = await axios.get(
      `https://${region}-run.googleapis.com/apis/serving.knative.dev/v1/namespaces/${project_id}/services/${service_name}`,
      {headers: {'Authorization': `Bearer ${token}`}}
    );
    
    service = resp.data;

    //Create the body to create a new revision
    body = {
      "apiVersion": service.apiVersion,
      "kind": service.kind,
      "metadata": {
        "annotations": {
          "client.knative.dev/user-image": image,
          'run.googleapis.com/ingress': service.metadata.annotations['run.googleapis.com/ingress'],
          'run.googleapis.com/ingress-status': service.metadata.annotations['run.googleapis.com/ingress-status']
        },
        "generation": service.metadata.generation,
        "labels": (service.metadata.labels === undefined)? {} : service.metadata.labels,
        "name": service.metadata.name,
      },
      "spec": {
        "template": {
          "metadata": {
            "annotations": {
              "autoscaling.knative.dev/maxScale": service.spec.template.metadata.annotations['autoscaling.knative.dev/maxScale'],
              "client.knative.dev/user-image": image,
            },
            "labels": (service.spec.template.metadata.labels === undefined) ? {} : service.spec.template.metadata.labels,
          },
          "spec": {
            "containerConcurrency": service.spec.template.spec.containerConcurrency,
            "containers": [{
              "image": image,
              "ports": service.spec.template.spec.containers[0].ports,
              "resources": {
                "limits": service.spec.template.spec.containers[0].resources.limits
              }
            }],
            "serviceAccountName": service.spec.template.spec.serviceAccountName,
            "timeoutSeconds": service.spec.template.spec.timeoutSeconds
          }
        },
        "traffic": service.spec.traffic[0]
      }
    }

    //Make the request
    create_service_response = await axios.put(
      `https://${region}-run.googleapis.com/apis/serving.knative.dev/v1/namespaces/${project_id}/services/${service_name}`,
      body,
      {headers: {'Authorization': `Bearer ${token}`}}
    );

    console.log(create_service_response.status)

  }catch (err) {
    console.error(err.response.data);
  }
};

This is the minimum body needed to create a new revision without modifying any previous configurations. As well to make any more customizations, the API docs can be helpful. The code was created by analyzing the output of the command by adding the --log-http flag.

Of course this is a little more complicated than using the Cloud Build approach, but this answers the question and can be helpful for others.

Solution 2:[2]

Got it working using the following

try {
async function updateTheme() {
  let token: any
  const jwtClient = new google.auth.JWT(firebaseClientEmail, '', firebaseKey, [
    'https://www.googleapis.com/auth/cloud-platform',
  ])

  await jwtClient.authorize(async function (err: any, _token: any) {
    if (err) {
      console.log('JWT ERROR: ', err)
      return err
    } else {
      token = _token.access_token.split('.')
      token = token[0] + '.' + token[1] + '.' + token[2]

      const deploySteps = [
        {
          name: 'gcr.io/cloud-builders/gcloud',
          args: [
            'run',
            'deploy',
            `${name}`,
            '--image',
            `gcr.io/${googleCloudProject}/theme-${theme}`,
            '--region',
            'us-east1',
            '--allow-unauthenticated',
            '--platform',
            'managed',
            '--quiet',
          ],
        },
      ]

      const deployRevisions = async () => {
        await axios({
          method: 'post',
          url: `https://cloudbuild.googleapis.com/v1/projects/${googleCloudProject}/builds`,
          headers: {
            Authorization: `Bearer ${token}`,
          },
          data: {
            steps: deploySteps,
            timeout: '1200s',
          },
        })
          .catch(function (error: any) {
            console.log('ERROR UPDATING THEME: ', error)
            return
          })
          .then(function (response: any) {
            console.log('SUCCESSFULLY DEPLOYED THEME UPDATE')
          })
      }

      if (token) {
        deployRevisions()
      } else {
        console.log('MISSING TOKEN')
      }
    }
  })
}

await updateTheme()

} catch (e) {
    console.log('tried updating theme but something went wrong')
    return
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ferregina Pelona
Solution 2 cormacncheese