Contoh respons kontrol biaya otomatis

Contoh arsitektur referensi

Diagram contoh menggunakan notifikasi terprogram pemberitahuan anggaran
            untuk mengotomatiskan respons kontrol biaya.
Gambar 1: Menggambarkan contoh penggunaan pemberitahuan anggaran untuk mengotomatiskan respons kontrol biaya menggunakan Pub/Sub untuk notifikasi terprogram dan Cloud Functions untuk mengotomatiskan respons.

Jika Anda sadar biaya dan perlu mengontrol lingkungan sesuai dengan anggaran, Anda dapat menggunakan notifikasi anggaran terprogram untuk mengotomatiskan respons kontrol biaya berdasarkan notifikasi anggaran.

Notifikasi anggaran menggunakan topik Pub/Sub untuk memberikan status real-time anggaran Penagihan Cloud menggunakan skalabilitas, fleksibilitas, dan keandalan middleware berorientasi pesan perusahaan untuk cloud.

Halaman ini berisi contoh dan petunjuk langkah demi langkah tentang cara menggunakan notifikasi anggaran dengan Cloud Functions untuk mengotomatiskan pengelolaan biaya.

Menyiapkan notifikasi anggaran

Langkah pertama adalah mengaktifkan topik Pub/Sub sesuai anggaran Anda. Hal ini dijelaskan secara detail dalam artikel Mengelola notifikasi pemberitahuan anggaran terprogram.

Setelah mengaktifkan notifikasi anggaran, perhatikan hal-hal berikut:

  • Topik Pub/Sub: Ini adalah endpoint notifikasi yang dikonfigurasi untuk anggaran.
  • ID Anggaran: Ini adalah ID unik untuk anggaran Anda yang disertakan di semua notifikasi. Anda dapat menemukan ID anggaran dalam anggaran di bagian Kelola notifikasi. ID ditampilkan setelah Anda memilih Hubungkan topik Pub/Sub ke anggaran ini.

Bagian Kelola notifikasi di konsol Google Cloud, tempat Anda dapat
         menghubungkan topik Pub/Sub ke anggaran. Ini mencakup
         ID Anggaran, nama project, dan topik Pub/Sub.

Mendengarkan notifikasi

Langkah selanjutnya adalah mendengarkan notifikasi dengan berlangganan topik Pub/Sub. Jika tidak memiliki pelanggan, Pub/Sub akan menghapus pesan yang dipublikasikan dan Anda tidak dapat mengambilnya nanti.

Meskipun ada banyak cara agar Anda dapat berlangganan topik, untuk contoh ini, kami akan menggunakan pemicu Cloud Function.

Buat Cloud Function

Untuk membuat Cloud Function baru:

  1. Di konsol Google Cloud, buka halaman Cloud Function.

    Buka halaman Cloud Functions

  2. Klik BUAT FUNGSI dan beri nama fungsi yang bermakna bagi anggaran Anda.

  3. Di bagian Pemicu, pilih Topik Pub/Sub.

  4. Pilih topik yang Anda konfigurasikan pada anggaran.

  5. Berikan kode sumber dan dependensi untuk fungsi yang akan dijalankan.

  6. Pastikan Anda menetapkan Fungsi untuk dieksekusi ke nama fungsi yang benar.

Halaman Buat fungsi di bagian Cloud Functions pada
         konsol Google Cloud. Ini mencakup nama fungsi, jumlah memori yang
         dialokasikan, jenis pemicu, dan topik Pub/Sub
         yang dikonfigurasi pada anggaran Anda.

Mendeskripsikan Cloud Function

Untuk memberi tahu Cloud Function hal yang ingin Anda lakukan dengan notifikasi, Anda dapat menulis kode menggunakan editor langsung atau mengupload file. Untuk detail tentang notifikasi yang akan diterima kode Anda, lihat Format Notifikasi.

Misalnya, fungsi dapat mencatat log notifikasi, atribut, dan data Pub/Sub yang diterima saat dipicu oleh notifikasi anggaran. Untuk mempelajari lebih lanjut, lihat Pemicu Pub/Sub.

Melihat peristiwa Cloud Function

Setelah menyimpan Cloud Function, Anda dapat mengklik LIHAT LOG untuk melihat notifikasi anggaran yang dicatat dalam log. Ini menunjukkan log dari pemanggilan fungsi Anda.

Menunjukkan tempat Anda dapat menemukan log tampilan di layar dan daftar
         peristiwa Cloud Function di konsol Google Cloud.

Menguji Cloud Function Anda

Notifikasi dikirim ke Pub/Sub dan pelanggan menerima pesan tersebut. Untuk menguji contoh notifikasi guna memastikan fungsi Anda berfungsi seperti yang diharapkan, publikasikan pesan di Pub/Sub menggunakan objek ini sebagai isi pesan:

{
    "budgetDisplayName": "name-of-budget",
    "alertThresholdExceeded": 1.0,
    "costAmount": 100.01,
    "costIntervalStart": "2019-01-01T00:00:00Z",
    "budgetAmount": 100.00,
    "budgetAmountType": "SPECIFIED_AMOUNT",
    "currencyCode": "USD"
}

Anda juga dapat menambahkan atribut pesan seperti ID akun penagihan. Lihat dokumentasi format notifikasi lengkap untuk informasi selengkapnya.

Mengirim notifikasi ke Slack

Email tidak selalu menjadi cara terbaik untuk mendapatkan informasi terbaru tentang biaya cloud Anda, terutama jika anggaran Anda sangat penting dan sensitif terhadap waktu. Dengan notifikasi, Anda dapat meneruskan pesan anggaran ke media lain.

Dalam contoh ini, kami menjelaskan cara meneruskan notifikasi anggaran ke Slack. Dengan cara ini, setiap kali Penagihan Cloud memublikasikan notifikasi anggaran, Cloud Function menggunakan bot untuk memposting pesan ke saluran Slack dari ruang kerja bot.

Menyiapkan saluran dan izin Slack

Langkah pertama adalah membuat ruang kerja Slack Anda dan token pengguna bot yang digunakan untuk memanggil Slack API. Token API dapat dikelola di https://api.slack.com/apps. Untuk petunjuk detailnya, lihat Pengguna Bot di situs Slack.

Mengonfigurasi notifikasi Slack.

Menulis Cloud Function

  1. Buat fungsi baru dengan mengikuti langkah-langkah di Membuat Cloud Function. Pastikan pemicu ditetapkan ke topik Pub/Sub yang sama dengan yang ditetapkan untuk digunakan oleh anggaran Anda.

  2. Tambahkan dependensi:

    Node.js

    Salin kode berikut ke package.json Anda:

    {
      "name": "cloud-functions-billing",
      "private": "true",
      "version": "0.0.1",
      "description": "Examples of integrating Cloud Functions with billing",
      "main": "index.js",
      "engines": {
        "node": ">=16.0.0"
      },
      "scripts": {
        "compute-test": "c8 mocha -p -j 2 test/periodic.test.js --timeout=600000",
        "test": "c8 mocha -p -j 2 test/index.test.js --timeout=5000 --exit"
      },
      "author": "Ace Nassri <anassri@google.com>",
      "license": "Apache-2.0",
      "dependencies": {
        "@google-cloud/billing": "^4.0.0",
        "@google-cloud/compute": "^4.0.0",
        "google-auth-library": "^9.0.0",
        "googleapis": "^126.0.0",
        "slack": "^11.0.1"
      },
      "devDependencies": {
        "@google-cloud/functions-framework": "^3.0.0",
        "c8": "^8.0.0",
        "gaxios": "^6.0.0",
        "mocha": "^10.0.0",
        "promise-retry": "^2.0.0",
        "proxyquire": "^2.1.0",
        "sinon": "^16.0.0",
        "wait-port": "^1.0.4"
      }
    }
    

    Python

    Salin kode berikut ke requirements.txt Anda:

    slackclient==2.9.4
    google-api-python-client==2.87.0
    

  3. Tulis kode atau gunakan contoh di bawah ini untuk memposting notifikasi anggaran ke saluran chat Slack menggunakan Slack API.

  4. Pastikan parameter postMessage Slack API berikut disetel dengan benar:

    • Token akses OAuth Pengguna Bot
    • Nama saluran

Contoh kode:

Node.js

const slack = require('slack');

// TODO(developer) replace these with your own values
const BOT_ACCESS_TOKEN =
  process.env.BOT_ACCESS_TOKEN || 'xxxx-111111111111-abcdefghidklmnopq';
const CHANNEL = process.env.SLACK_CHANNEL || 'general';

exports.notifySlack = async pubsubEvent => {
  const pubsubAttrs = pubsubEvent.attributes;
  const pubsubData = Buffer.from(pubsubEvent.data, 'base64').toString();
  const budgetNotificationText = `${JSON.stringify(
    pubsubAttrs
  )}, ${pubsubData}`;

  await slack.chat.postMessage({
    token: BOT_ACCESS_TOKEN,
    channel: CHANNEL,
    text: budgetNotificationText,
  });

  return 'Slack notification sent successfully';
};

Python

import base64
import json
import os

import slack
from slack.errors import SlackApiError

# See https://api.slack.com/docs/token-types#bot for more info
BOT_ACCESS_TOKEN = "xxxx-111111111111-abcdefghidklmnopq"
CHANNEL = "C0XXXXXX"

slack_client = slack.WebClient(token=BOT_ACCESS_TOKEN)

def notify_slack(data, context):
    pubsub_message = data

    # For more information, see
    # https://cloud.google.com/billing/docs/how-to/budgets-programmatic-notifications#notification_format
    try:
        notification_attr = json.dumps(pubsub_message["attributes"])
    except KeyError:
        notification_attr = "No attributes passed in"

    try:
        notification_data = base64.b64decode(data["data"]).decode("utf-8")
    except KeyError:
        notification_data = "No data passed in"

    # This is just a quick dump of the budget data (or an empty string)
    # You can modify and format the message to meet your needs
    budget_notification_text = f"{notification_attr}, {notification_data}"

    try:
        slack_client.api_call(
            "chat.postMessage",
            json={"channel": CHANNEL, "text": budget_notification_text},
        )
    except SlackApiError:
        print("Error posting to Slack")

Sekarang Anda dapat Menguji Cloud Function untuk melihat pesan yang muncul di Slack.

Membatasi (menonaktifkan) penagihan untuk menghentikan penggunaan

Contoh ini menunjukkan cara membatasi biaya dan menghentikan penggunaan untuk suatu project dengan menonaktifkan Penagihan Cloud. Menonaktifkan penagihan pada project akan menyebabkan semua layanan Google Cloud dalam project dihentikan, termasuk layanan paket gratis.

Mengapa menonaktifkan penagihan?

Anda mungkin membatasi biaya karena Anda memiliki batas jumlah uang yang dapat dibelanjakan di Google Cloud. Hal ini biasa terjadi pada siswa, peneliti, atau developer yang bekerja di lingkungan sandbox. Dalam kasus ini, Anda ingin menghentikan pengeluaran dan mungkin bersedia menonaktifkan semua layanan dan penggunaan Google Cloud saat batas anggaran tercapai.

Sebagai contoh, kami menggunakan acme-backend-dev sebagai project non-produksi yang Penagihan Cloud-nya dapat dinonaktifkan dengan aman.

Konfigurasikan batas anggaran di konsol Google Cloud.

Sebelum mulai menggunakan contoh ini, pastikan Anda telah melakukan hal berikut:

  • Aktifkan Cloud Billing API. Cloud Function Anda perlu memanggil Cloud Billing API untuk menonaktifkan Penagihan Cloud untuk sebuah project.

  • Siapkan anggaran untuk memantau biaya project dan aktifkan notifikasi anggaran.

Menampilkan daftar pemberitahuan Penagihan Cloud di
         konsol Google Cloud.

Menulis Cloud Function

Selanjutnya, Anda perlu mengonfigurasi Cloud Function untuk memanggil Cloud Billing API. Tindakan ini memungkinkan Cloud Function menonaktifkan Penagihan Cloud untuk project contoh acme-backend-dev.

  1. Buat fungsi baru dengan mengikuti langkah-langkah di Membuat Cloud Function. Pastikan pemicu ditetapkan ke topik Pub/Sub yang sama dengan yang ditetapkan untuk digunakan oleh anggaran Anda.

  2. Tambahkan dependensi berikut:

    Node.js

    Salin kode berikut ke package.json Anda:

    {
      "name": "cloud-functions-billing",
      "private": "true",
      "version": "0.0.1",
      "description": "Examples of integrating Cloud Functions with billing",
      "main": "index.js",
      "engines": {
        "node": ">=16.0.0"
      },
      "scripts": {
        "compute-test": "c8 mocha -p -j 2 test/periodic.test.js --timeout=600000",
        "test": "c8 mocha -p -j 2 test/index.test.js --timeout=5000 --exit"
      },
      "author": "Ace Nassri <anassri@google.com>",
      "license": "Apache-2.0",
      "dependencies": {
        "@google-cloud/billing": "^4.0.0",
        "@google-cloud/compute": "^4.0.0",
        "google-auth-library": "^9.0.0",
        "googleapis": "^126.0.0",
        "slack": "^11.0.1"
      },
      "devDependencies": {
        "@google-cloud/functions-framework": "^3.0.0",
        "c8": "^8.0.0",
        "gaxios": "^6.0.0",
        "mocha": "^10.0.0",
        "promise-retry": "^2.0.0",
        "proxyquire": "^2.1.0",
        "sinon": "^16.0.0",
        "wait-port": "^1.0.4"
      }
    }
    

    Python

    Salin kode berikut ke requirements.txt Anda:

    slackclient==2.9.4
    google-api-python-client==2.87.0
    

  3. Salin kode di bawah ke dalam Cloud Function.

  4. Tetapkan fungsi yang akan dieksekusi ke "stopBilling" (Node) atau "stop_billing" (Python).

  5. Bergantung pada runtime Anda, variabel lingkungan GOOGLE_CLOUD_PROJECT mungkin ditetapkan secara otomatis. Tinjau daftar variabel lingkungan yang ditetapkan secara otomatis dan tentukan apakah Anda perlu menetapkan variabel GOOGLE_CLOUD_PROJECT secara manual ke project yang Penagihan Cloud-nya ingin Anda batasi (nonaktifkan).

Node.js

const {CloudBillingClient} = require('@google-cloud/billing');
const {InstancesClient} = require('@google-cloud/compute');

const PROJECT_ID = process.env.GOOGLE_CLOUD_PROJECT;
const PROJECT_NAME = `projects/${PROJECT_ID}`;
const billing = new CloudBillingClient();

exports.stopBilling = async pubsubEvent => {
  const pubsubData = JSON.parse(
    Buffer.from(pubsubEvent.data, 'base64').toString()
  );
  if (pubsubData.costAmount <= pubsubData.budgetAmount) {
    return `No action necessary. (Current cost: ${pubsubData.costAmount})`;
  }

  if (!PROJECT_ID) {
    return 'No project specified';
  }

  const billingEnabled = await _isBillingEnabled(PROJECT_NAME);
  if (billingEnabled) {
    return _disableBillingForProject(PROJECT_NAME);
  } else {
    return 'Billing already disabled';
  }
};

/**
 * Determine whether billing is enabled for a project
 * @param {string} projectName Name of project to check if billing is enabled
 * @return {bool} Whether project has billing enabled or not
 */
const _isBillingEnabled = async projectName => {
  try {
    const [res] = await billing.getProjectBillingInfo({name: projectName});
    return res.billingEnabled;
  } catch (e) {
    console.log(
      'Unable to determine if billing is enabled on specified project, assuming billing is enabled'
    );
    return true;
  }
};

/**
 * Disable billing for a project by removing its billing account
 * @param {string} projectName Name of project disable billing on
 * @return {string} Text containing response from disabling billing
 */
const _disableBillingForProject = async projectName => {
  const [res] = await billing.updateProjectBillingInfo({
    name: projectName,
    resource: {billingAccountName: ''}, // Disable billing
  });
  return `Billing disabled: ${JSON.stringify(res)}`;
};

Python

import base64
import json
import os

from googleapiclient import discovery

PROJECT_ID = os.getenv("GCP_PROJECT")
PROJECT_NAME = f"projects/{PROJECT_ID}"
def stop_billing(data, context):
    pubsub_data = base64.b64decode(data["data"]).decode("utf-8")
    pubsub_json = json.loads(pubsub_data)
    cost_amount = pubsub_json["costAmount"]
    budget_amount = pubsub_json["budgetAmount"]
    if cost_amount <= budget_amount:
        print(f"No action necessary. (Current cost: {cost_amount})")
        return

    if PROJECT_ID is None:
        print("No project specified with environment variable")
        return

    billing = discovery.build(
        "cloudbilling",
        "v1",
        cache_discovery=False,
    )

    projects = billing.projects()

    billing_enabled = __is_billing_enabled(PROJECT_NAME, projects)

    if billing_enabled:
        __disable_billing_for_project(PROJECT_NAME, projects)
    else:
        print("Billing already disabled")

def __is_billing_enabled(project_name, projects):
    """
    Determine whether billing is enabled for a project
    @param {string} project_name Name of project to check if billing is enabled
    @return {bool} Whether project has billing enabled or not
    """
    try:
        res = projects.getBillingInfo(name=project_name).execute()
        return res["billingEnabled"]
    except KeyError:
        # If billingEnabled isn't part of the return, billing is not enabled
        return False
    except Exception:
        print(
            "Unable to determine if billing is enabled on specified project, assuming billing is enabled"
        )
        return True

def __disable_billing_for_project(project_name, projects):
    """
    Disable billing for a project by removing its billing account
    @param {string} project_name Name of project disable billing on
    """
    body = {"billingAccountName": ""}  # Disable billing
    try:
        res = projects.updateBillingInfo(name=project_name, body=body).execute()
        print(f"Billing disabled: {json.dumps(res)}")
    except Exception:
        print("Failed to disable billing, possibly check permissions")

Mengonfigurasi izin akun layanan

Cloud Function Anda dijalankan sebagai akun layanan yang dibuat otomatis. Agar akun layanan dapat menonaktifkan penagihan, Anda harus memberikan izin yang benar, seperti Billing Admin.

Untuk mengidentifikasi akun layanan yang benar, lihat detail Cloud Function Anda. Akun layanan tercantum di bagian bawah halaman.

Menunjukkan tempat informasi akun layanan dapat ditemukan di
         bagian Cloud Function pada konsol Google Cloud.

Anda dapat mengelola izin Admin Penagihan di halaman Penagihan di konsol Google Cloud.

Untuk memberikan hak istimewa Billing Account Administrator ke akun layanan, pilih nama akun layanan.

Menunjukkan tempat untuk memilih nama akun layanan dan peran Billing
         Account Administrator di bagian Izin pada
         konsol Google Cloud.

Memvalidasi bahwa Penagihan Cloud dinonaktifkan

Saat anggaran mengirimkan notifikasi, project yang ditentukan tidak akan lagi memiliki akun Penagihan Cloud. Jika Anda ingin menguji fungsi, publikasikan contoh pesan yang berisi pesan pengujian di atas. Project tidak akan terlihat lagi di akun Penagihan Cloud dan resource dalam project dinonaktifkan, termasuk Cloud Function jika berada dalam project yang sama.

Menunjukkan bahwa project contoh tidak lagi terlihat dalam daftar
         project yang ditautkan ke akun Penagihan Cloud. Tindakan ini akan memvalidasi
         bahwa Penagihan Cloud dinonaktifkan untuk project tersebut.

Anda dapat mengaktifkan kembali Penagihan Cloud secara manual untuk project Anda di konsol Google Cloud.

Mengontrol penggunaan secara selektif

Membatasi (menonaktifkan) Penagihan Cloud seperti yang dijelaskan pada contoh sebelumnya adalah biner dan terminal. Project Anda akan diaktifkan atau dinonaktifkan. Jika dinonaktifkan, semua layanan akan dihentikan dan semua resource pada akhirnya dihapus.

Jika memerlukan respons yang lebih terperinci, Anda dapat mengontrol resource secara selektif. Misalnya, jika ingin menghentikan beberapa resource Compute Engine tetapi membiarkan Cloud Storage tetap utuh, Anda dapat mengontrol penggunaan secara selektif. Cara ini akan mengurangi biaya per jam tanpa menonaktifkan lingkungan Anda sepenuhnya.

Anda dapat menulis kebijakan dengan nuansa yang Anda inginkan. Namun, sebagai contoh, project kami menjalankan riset dengan sejumlah virtual machine Compute Engine, dan menyimpan hasilnya di Cloud Storage. Contoh Cloud Function ini akan menonaktifkan semua instance Compute Engine, tetapi tidak akan memengaruhi hasil yang tersimpan setelah anggaran terlampaui.

Menulis Cloud Function

  1. Buat fungsi baru dengan mengikuti langkah-langkah di Membuat Cloud Function. Pastikan pemicu ditetapkan ke topik Pub/Sub yang sama dengan yang ditetapkan untuk digunakan oleh anggaran Anda.

  2. Pastikan Anda telah menambahkan dependensi yang dijelaskan dalam Membatasi (menonaktifkan) penagihan untuk menghentikan penggunaan.

  3. Salin kode di bawah ke dalam Cloud Function.

  4. Tetapkan fungsi yang akan dieksekusi ke "limitUse" (Node) atau "limit_use" (Python).

  5. Bergantung pada runtime Anda, variabel lingkungan GCP_PROJECT mungkin ditetapkan secara otomatis. Tinjau daftar variabel lingkungan yang ditetapkan secara otomatis dan tentukan apakah Anda perlu menetapkan variabel GCP_PROJECT secara manual ke project yang menjalankan virtual machine.

  6. Tetapkan parameter ZONE. Ini adalah zona tempat instance akan dihentikan untuk contoh ini.

Node.js

const {CloudBillingClient} = require('@google-cloud/billing');
const {InstancesClient} = require('@google-cloud/compute');

const PROJECT_ID = process.env.GOOGLE_CLOUD_PROJECT;
const PROJECT_NAME = `projects/${PROJECT_ID}`;
const instancesClient = new InstancesClient();
const ZONE = 'us-central1-a';

exports.limitUse = async pubsubEvent => {
  const pubsubData = JSON.parse(
    Buffer.from(pubsubEvent.data, 'base64').toString()
  );
  if (pubsubData.costAmount <= pubsubData.budgetAmount) {
    return `No action necessary. (Current cost: ${pubsubData.costAmount})`;
  }

  const instanceNames = await _listRunningInstances(PROJECT_ID, ZONE);
  if (!instanceNames.length) {
    return 'No running instances were found.';
  }

  await _stopInstances(PROJECT_ID, ZONE, instanceNames);
  return `${instanceNames.length} instance(s) stopped successfully.`;
};

/**
 * @return {Promise} Array of names of running instances
 */
const _listRunningInstances = async (projectId, zone) => {
  const [instances] = await instancesClient.list({
    project: projectId,
    zone: zone,
  });
  return instances
    .filter(item => item.status === 'RUNNING')
    .map(item => item.name);
};

/**
 * @param {Array} instanceNames Names of instance to stop
 * @return {Promise} Response from stopping instances
 */
const _stopInstances = async (projectId, zone, instanceNames) => {
  await Promise.all(
    instanceNames.map(instanceName => {
      return instancesClient
        .stop({
          project: projectId,
          zone: zone,
          instance: instanceName,
        })
        .then(() => {
          console.log(`Instance stopped successfully: ${instanceName}`);
        });
    })
  );
};

Python

import base64
import json
import os

from googleapiclient import discovery

PROJECT_ID = os.getenv("GCP_PROJECT")
PROJECT_NAME = f"projects/{PROJECT_ID}"
ZONE = "us-west1-b"

def limit_use(data, context):
    pubsub_data = base64.b64decode(data["data"]).decode("utf-8")
    pubsub_json = json.loads(pubsub_data)
    cost_amount = pubsub_json["costAmount"]
    budget_amount = pubsub_json["budgetAmount"]
    if cost_amount <= budget_amount:
        print(f"No action necessary. (Current cost: {cost_amount})")
        return

    compute = discovery.build(
        "compute",
        "v1",
        cache_discovery=False,
    )
    instances = compute.instances()

    instance_names = __list_running_instances(PROJECT_ID, ZONE, instances)
    __stop_instances(PROJECT_ID, ZONE, instance_names, instances)

def __list_running_instances(project_id, zone, instances):
    """
    @param {string} project_id ID of project that contains instances to stop
    @param {string} zone Zone that contains instances to stop
    @return {Promise} Array of names of running instances
    """
    res = instances.list(project=project_id, zone=zone).execute()

    if "items" not in res:
        return []

    items = res["items"]
    running_names = [i["name"] for i in items if i["status"] == "RUNNING"]
    return running_names

def __stop_instances(project_id, zone, instance_names, instances):
    """
    @param {string} project_id ID of project that contains instances to stop
    @param {string} zone Zone that contains instances to stop
    @param {Array} instance_names Names of instance to stop
    @return {Promise} Response from stopping instances
    """
    if not len(instance_names):
        print("No running instances were found.")
        return

    for name in instance_names:
        instances.stop(project=project_id, zone=zone, instance=name).execute()
        print(f"Instance stopped successfully: {name}")

Mengonfigurasi izin akun layanan

  1. Cloud Function Anda dijalankan sebagai akun layanan yang dibuat secara otomatis. Untuk mengontrol penggunaan, Anda perlu memberikan izin akun layanan ke layanan apa pun di project yang perlu diubahnya.
  2. Untuk mengidentifikasi akun layanan yang benar, lihat detail Cloud Function Anda. Akun layanan tercantum di bagian bawah halaman.
  3. Di konsol Google Cloud, buka halaman IAM untuk menetapkan izin yang sesuai.
    Buka halaman IAM
     
    Menampilkan layar IAM di konsol Google Cloud,
         tempat Anda dapat menetapkan izin yang sesuai untuk akun layanan
         yang menjalankan Cloud Function.

Memvalidasi bahwa instance dihentikan

Saat anggaran mengirimkan notifikasi, virtual machine Compute Engine akan dihentikan.

Untuk menguji fungsi, publikasikan contoh pesan dengan pesan pengujian di atas. Untuk memvalidasi bahwa fungsi tersebut berhasil dijalankan, periksa virtual machine Compute Engine Anda di konsol Google Cloud.