Criar uma VM a partir de um modelo de instância

Nesta página, explicamos como usar um modelo de instância para criar uma instância de VM. Um modelo de instância é um recurso de API que define as propriedades das instâncias de VM. Defina as propriedades, como tipo de máquina, imagem do SO, configurações de disco permanente, metadados, scripts de inicialização e outras, em um modelo de instância. Depois, use o modelo para criar instâncias de VM individuais ou grupos de instâncias gerenciadas.

Por padrão, uma instância de VM criada a partir de um modelo de instância terá propriedades idênticas àquelas especificadas no modelo, com exceção do nome e da zona em que a instância residirá. No entanto, você também tem a opção de modificar determinados campos durante a criação da instância, se quiser alterar algumas propriedades definidas no modelo para casos de uso específicos.

Neste documento, pressupomos que você já tem um modelo de instância pronto para usar. Se você ainda não tem um, siga as instruções para criar um novo modelo de instância.

Antes de começar

Crie uma instância de VM a partir de um modelo de instância.

Para criar uma instância exatamente como descrito no modelo de instância, siga as instruções abaixo.

Console

  1. No console do Google Cloud, acesse a página Criar uma instância.

    Acesse "Criar uma instância"

  2. Clique em Nova instância de VM com base em modelo.

  3. Selecione o modelo e clique em Continuar.

  4. Especifique um nome para a VM e faça outras personalizações conforme necessário.

  5. Clique em Criar.

    Para mais detalhes sobre configuração, consulte Criar uma instância de VM a partir de uma imagem.

gcloud

Para criar uma nova VM a partir de um modelo de instância, use o mesmo comando gcloud compute instances create que você usaria para criar uma instância normal, mas adicione o --source-instance-template:

 gcloud compute instances create VM_NAME
 --source-instance-template INSTANCE_TEMPLATE_NAME
 

Substitua:

  • VM_NAME: o nome da instância.
  • INSTANCE_TEMPLATE_NAME: o nome do modelo de instância a ser usado.

Exemplo:

gcloud compute instances create example-instance --source-instance-template
my-instance-template

API

Na API, gere uma solicitação normal para criar uma instância, mas inclua o parâmetro de consulta sourceInstanceTemplate seguido de um caminho qualificado para um modelo de instância.

POST https://compute.googleapis.com/compute/v1/projects/
PROJECT_ID/zones/ZONE/
instances?sourceInstanceTemplate=INSTANCE_TEMPLATE_NAME

No corpo da solicitação, forneça um name para a instância de VM:

{ "name": "example-instance" }

Por exemplo, no snippet a seguir, é incluído um caminho totalmente qualificado para o modelo: https://compute.googleapis.com/compute/v1/projects/myproject/global/instanceTemplates/example-instance-template.

POST https://compute.googleapis.com/
compute/v1/projects/myproject/zones/us-central1-a/instances?sourceInstanceTemplate=
https://compute.googleapis.com/compute/v1/projects/myproject/global/
instanceTemplates/example-instance-template
{ "name": "example-instance" }

Go

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
	"google.golang.org/protobuf/proto"
)

// createInstanceFromTemplate creates a Compute Engine VM instance from an instance template.
func createInstanceFromTemplate(w io.Writer, projectID, zone, instanceName, instanceTemplateUrl string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// instanceTemplateUrl := "global/instanceTemplates/your_instance_template"

	ctx := context.Background()
	instancesClient, err := compute.NewInstancesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewInstancesRESTClient: %v", err)
	}
	defer instancesClient.Close()

	req := &computepb.InsertInstanceRequest{
		Project: projectID,
		Zone:    zone,
		InstanceResource: &computepb.Instance{
			Name: proto.String(instanceName),
		},
		SourceInstanceTemplate: &instanceTemplateUrl,
	}

	op, err := instancesClient.Insert(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to create instance: %v", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %v", err)
	}

	fmt.Fprintf(w, "Instance created\n")

	return nil
}

Java


import com.google.cloud.compute.v1.InsertInstanceRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateInstanceFromTemplate {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    /*  TODO(developer): Replace these variables before running the sample.
        projectId - ID or number of the project you want to use.
        zone - Name of the zone you want to check, for example: us-west3-b
        instanceName - Name of the new instance.
        instanceTemplateURL - URL of the instance template using for creating the new instance.
        It can be a full or partial URL.
        Examples:
        - https://www.googleapis.com/compute/v1/projects/project/global/instanceTemplates/example-instance-template
        - projects/project/global/instanceTemplates/example-instance-template
        - global/instanceTemplates/example-instance-template
     */
    String projectId = "your-project-id";
    String zone = "zone-name";
    String instanceName = "instance-name";
    String instanceTemplateUrl = "instance-template-url";
    createInstanceFromTemplate(projectId, zone, instanceName, instanceTemplateUrl);
  }

  // Create a new instance from template in the specified project and zone.
  public static void createInstanceFromTemplate(String projectId, String zone, String instanceName,
      String instanceTemplateUrl)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {

    try (InstancesClient instancesClient = InstancesClient.create()) {

      InsertInstanceRequest insertInstanceRequest = InsertInstanceRequest.newBuilder()
          .setProject(projectId)
          .setZone(zone)
          .setInstanceResource(Instance.newBuilder().setName(instanceName).build())
          .setSourceInstanceTemplate(instanceTemplateUrl).build();

      Operation response = instancesClient.insertAsync(insertInstanceRequest)
          .get(3, TimeUnit.MINUTES);

      if (response.hasError()) {
        System.out.println("Instance creation from template failed ! ! " + response);
        return;
      }
      System.out
          .printf("Instance creation from template: Operation Status %s: %s ", instanceName,
              response.getStatus());
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const zone = 'europe-central2-b'
// const instanceName = 'YOUR_INSTANCE_NAME'
// const instanceTemplateUrl = 'YOUR_INSTANCE_TEMPLATE_URL'

const compute = require('@google-cloud/compute');

// Create a new instance from template in the specified project and zone.
async function createInstanceFromTemplate() {
  const instancesClient = new compute.InstancesClient();

  console.log(
    `Creating the ${instanceName} instance in ${zone} from template ${instanceTemplateUrl}...`
  );

  const [response] = await instancesClient.insert({
    project: projectId,
    zone,
    instanceResource: {
      name: instanceName,
    },
    sourceInstanceTemplate: instanceTemplateUrl,
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

  // Wait for the create operation to complete.
  while (operation.status !== 'DONE') {
    [operation] = await operationsClient.wait({
      operation: operation.name,
      project: projectId,
      zone: operation.zone.split('/').pop(),
    });
  }

  console.log('Instance created.');
}

createInstanceFromTemplate();

Python

import sys
from typing import Any

from google.api_core.extended_operation import ExtendedOperation
from google.cloud import compute_v1

def wait_for_extended_operation(
    operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
) -> Any:
    """
    This method will wait for the extended (long-running) operation to
    complete. If the operation is successful, it will return its result.
    If the operation ends with an error, an exception will be raised.
    If there were any warnings during the execution of the operation
    they will be printed to sys.stderr.

    Args:
        operation: a long-running operation you want to wait on.
        verbose_name: (optional) a more verbose name of the operation,
            used only during error and warning reporting.
        timeout: how long (in seconds) to wait for operation to finish.
            If None, wait indefinitely.

    Returns:
        Whatever the operation.result() returns.

    Raises:
        This method will raise the exception received from `operation.exception()`
        or RuntimeError if there is no exception set, but there is an `error_code`
        set for the `operation`.

        In case of an operation taking longer than `timeout` seconds to complete,
        a `concurrent.futures.TimeoutError` will be raised.
    """
    result = operation.result(timeout=timeout)

    if operation.error_code:
        print(
            f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
            file=sys.stderr,
            flush=True,
        )
        print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
        raise operation.exception() or RuntimeError(operation.error_message)

    if operation.warnings:
        print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
        for warning in operation.warnings:
            print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)

    return result

def create_instance_from_template(
    project_id: str, zone: str, instance_name: str, instance_template_url: str
) -> compute_v1.Instance:
    """
    Creates a Compute Engine VM instance from an instance template.

    Args:
        project_id: ID or number of the project you want to use.
        zone: Name of the zone you want to check, for example: us-west3-b
        instance_name: Name of the new instance.
        instance_template_url: URL of the instance template used for creating the new instance.
            It can be a full or partial URL.
            Examples:
            - https://www.googleapis.com/compute/v1/projects/project/global/instanceTemplates/example-instance-template
            - projects/project/global/instanceTemplates/example-instance-template
            - global/instanceTemplates/example-instance-template

    Returns:
        Instance object.
    """
    instance_client = compute_v1.InstancesClient()

    instance_insert_request = compute_v1.InsertInstanceRequest()
    instance_insert_request.project = project_id
    instance_insert_request.zone = zone
    instance_insert_request.source_instance_template = instance_template_url
    instance_insert_request.instance_resource.name = instance_name

    operation = instance_client.insert(instance_insert_request)
    wait_for_extended_operation(operation, "instance creation")

    return instance_client.get(project=project_id, zone=zone, instance=instance_name)

Como criar uma instância de VM a partir de um modelo de instância com modificações

Por padrão, uma instância de VM iniciada a partir de um modelo de instância será exatamente como descrito no modelo, com exceção do nome e da zona.

Se você quiser criar uma instância baseada em um modelo, mas com algumas alterações, use o comportamento de modificação. Para tanto, informe os atributos para modificar o modelo de instância existente durante a criação da instância.

gcloud

Usando a CLI gcloud, faça uma solicitação para criar uma instância com a sinalização --source-instance-template e substituir qualquer propriedade que você queira com a sinalização gcloud adequada. Para uma lista de sinalizações aplicáveis, consulte a referência gcloud.

Por exemplo, para modificar as propriedades de tipo de máquina, metadados, sistema operacional, disco permanente de inicialização e disco secundário de um modelo de instância, forneça as sinalizações a seguir:

gcloud compute instances create example-instance --source-instance-template
example-instance --machine-type e2-standard-2 --image-family debian-8 \
--image-project debian-cloud --metadata bread=butter \
--disk=boot=no,name=my-override-disk

API

Na API, use o parâmetro de consulta sourceInstanceTemplate e forneça os campos que você quer substituir no corpo da solicitação ao construir uma solicitação normal para criar uma instância.

O comportamento de modificação na API segue as regras de patch de mesclagem JSON descritas em RFC 7396 (em inglês).

Especificamente:

  • Se você modificar um campo básico, o campo básico correspondente no modelo de instância será substituído pelo valor de campo básico na solicitação. Os campos básicos incluem machineType, sourceImage, name e assim por diante.
  • Se você modificar um campo repetido, todos os valores repetidos dessa propriedade serão substituídos pelos valores correspondentes fornecidos na solicitação. Geralmente, campos repetidos são propriedades do tipo list. Por exemplo, disks e networkInterfaces são campos repetidos.
  • Se você modificar um nested object, o objeto no modelo de instância será mesclado com a especificação de objeto correspondente na solicitação. Observe que, se um objeto aninhado residir dentro de um campo repetido, esse campo será tratado segundo as regras para campos repetidos. Os rótulos são uma exceção a essa regra e são tratados como um campo repetido, mesmo sendo do tipo object.

Por exemplo, imagine que você tem um modelo de instância com dois discos que não sejam de inicialização, mas quer substituir um deles. Você precisa informar toda a especificação disks na sua solicitação, incluindo os discos que quer manter.

O URL dessa solicitação:

POST https://compute.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances?
sourceInstanceTemplate=https://compute.googleapis.com/compute/v1/projects/myproject/global/instanceTemplates/example-instance-template

O corpo da solicitação:

    {
      "disks": [
        {
          # Since you are overriding the repeated disk property, you must
          # specify a boot disk in the request, even if it is already
          # specified in the instance template
          "autoDelete": true,
          "boot": true,
          "initializeParams": {
            "sourceImage": "projects/debian-cloud/global/images/family/debian-8"
          },
          "mode": "READ_WRITE",
          "type": "PERSISTENT"
        },
        {
          # New disk you want to use
          "autoDelete": false,
          "boot": false,
          "mode": "READ_WRITE",
          "source": "zones/us-central1-f/disks/my-override-disk",
          "type": "PERSISTENT"
        },
        {
           # Assume this disk is already specified in instance template, but
           # you must specify it again since you are overriding the disks
           # property
          "autoDelete": false,
          "boot": false,
          "mode": "READ_WRITE",

          "source": "zones/us-central1-f/disks/my-other-disk-to-keep",
          "type": "PERSISTENT"
        }
      ],
      "machineType": "zones/us-central1-f/machineTypes/e2-standard-2",
      "name": "example-instance"
    }
    

Go

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
	"google.golang.org/protobuf/proto"
)

// createInstanceFromTemplate creates a Compute Engine VM instance from an instance template, but overrides the disk and machine type options in the template.
func createInstanceFromTemplateWithOverrides(w io.Writer, projectID, zone, instanceName, instanceTemplateName, machineType, newDiskSourceImage string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// instanceTemplateName := "your_instance_template_name"
	// machineType := "n1-standard-2"
	// newDiskSourceImage := "projects/debian-cloud/global/images/family/debian-10"

	ctx := context.Background()
	instancesClient, err := compute.NewInstancesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewInstancesRESTClient: %v", err)
	}
	defer instancesClient.Close()

	intanceTemplatesClient, err := compute.NewInstanceTemplatesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewInstanceTemplatesRESTClient: %v", err)
	}
	defer instancesClient.Close()

	// Retrieve an instance template by name.
	reqGetTemplate := &computepb.GetInstanceTemplateRequest{
		Project:          projectID,
		InstanceTemplate: instanceTemplateName,
	}

	instanceTemplate, err := intanceTemplatesClient.Get(ctx, reqGetTemplate)
	if err != nil {
		return fmt.Errorf("unable to get intance template: %v", err)
	}

	fmt.Printf("%s", "asdfadf")

	for _, disk := range instanceTemplate.Properties.Disks {
		diskType := disk.InitializeParams.GetDiskType()
		if diskType != "" {
			disk.InitializeParams.DiskType = proto.String(fmt.Sprintf(`zones/%s/diskTypes/%s`, zone, diskType))
		}
	}

	reqInsertInstance := &computepb.InsertInstanceRequest{
		Project: projectID,
		Zone:    zone,
		InstanceResource: &computepb.Instance{
			Name:        proto.String(instanceName),
			MachineType: proto.String(fmt.Sprintf(`zones/%s/machineTypes/%s`, zone, machineType)),
			Disks: append(
				// If you override a repeated field, all repeated values
				// for that property are replaced with the
				// corresponding values provided in the request.
				// When adding a new disk to existing disks,
				// insert all existing disks as well.
				instanceTemplate.Properties.Disks,
				&computepb.AttachedDisk{
					InitializeParams: &computepb.AttachedDiskInitializeParams{
						DiskSizeGb:  proto.Int64(10),
						SourceImage: &newDiskSourceImage,
					},
					AutoDelete: proto.Bool(true),
					Boot:       proto.Bool(false),
					Type:       proto.String(computepb.AttachedDisk_PERSISTENT.String()),
				},
			),
		},
		SourceInstanceTemplate: instanceTemplate.SelfLink,
	}

	op, err := instancesClient.Insert(ctx, reqInsertInstance)
	if err != nil {
		return fmt.Errorf("unable to create instance: %v", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %v", err)
	}

	fmt.Fprintf(w, "Instance created\n")

	return nil
}

Java


import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.InsertInstanceRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstanceTemplate;
import com.google.cloud.compute.v1.InstanceTemplatesClient;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateInstanceFromTemplateWithOverrides {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    /* TODO(developer): Replace these variables before running the sample.
     * projectId - ID or number of the project you want to use.
     * zone - Name of the zone you want to check, for example: us-west3-b
     * instanceName - Name of the new instance.
     * instanceTemplateName - Name of the instance template to use when creating the new instance.
     * machineType - Machine type you want to set in following format:
     *    "zones/{zone}/machineTypes/{type_name}". For example:
     *    "zones/europe-west3-c/machineTypes/f1-micro"
     *    You can find the list of available machine types using:
     *    https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list
     * newDiskSourceImage - Path the the disk image you want to use for your new
     *    disk. This can be one of the public images
     *    (like "projects/debian-cloud/global/images/family/debian-10")
     *    or a private image you have access to.
     *    You can check the list of available public images using the doc:
     *    http://cloud.google.com/compute/docs/images
     */
    String projectId = "your-project-id";
    String zone = "zone-name";
    String instanceName = "instance-name";
    String instanceTemplateName = "instance-template-name";

    createInstanceFromTemplateWithOverrides(projectId, zone, instanceName, instanceTemplateName);
  }

  // Creates a Compute Engine VM instance from an instance template,
  // but overrides the disk and machine type options in the template.
  public static void createInstanceFromTemplateWithOverrides(String projectId, String zone,
      String instanceName, String instanceTemplateName)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {

    try (InstancesClient instancesClient = InstancesClient.create();
        InstanceTemplatesClient instanceTemplatesClient = InstanceTemplatesClient.create()) {

      String machineType = "n1-standard-1";
      String newDiskSourceImage = "projects/debian-cloud/global/images/family/debian-10";

      // Retrieve an instance template.
      InstanceTemplate instanceTemplate = instanceTemplatesClient
          .get(projectId, instanceTemplateName);

      AttachedDisk newdisk = AttachedDisk.newBuilder()
          .setInitializeParams(AttachedDiskInitializeParams.newBuilder()
              .setDiskSizeGb(10)
              .setSourceImage(newDiskSourceImage).build())
          .setAutoDelete(true)
          .setBoot(false)
          .setType(AttachedDisk.Type.PERSISTENT.toString()).build();

      Instance instance = Instance.newBuilder()
          .setName(instanceName)
          .setMachineType(String.format("zones/%s/machineTypes/%s", zone, machineType))
          // If you override a repeated field, all repeated values
          // for that property are replaced with the
          // corresponding values provided in the request.
          // When adding a new disk to existing disks,
          // insert all existing disks as well.
          .addAllDisks(instanceTemplate.getProperties().getDisksList())
          .addDisks(newdisk)
          .build();

      InsertInstanceRequest insertInstanceRequest = InsertInstanceRequest.newBuilder()
          .setProject(projectId)
          .setZone(zone)
          .setInstanceResource(instance)
          .setSourceInstanceTemplate(instanceTemplate.getSelfLink()).build();

      Operation response = instancesClient.insertAsync(insertInstanceRequest)
          .get(3, TimeUnit.MINUTES);

      if (response.hasError()) {
        System.out.println("Instance creation from template with overrides failed ! ! " + response);
        return;
      }
      System.out
          .printf("Instance creation from template with overrides: Operation Status %s: %s ",
              instanceName, response.getStatus());
    }

  }
}

Node.js

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const zone = 'europe-central2-b';
// const instanceName = 'YOUR_INSTANCE_NAME';
// const instanceTemplateName = 'YOUR_INSTANCE_TEMPLATE_NAME';
// const machineType = 'n1-standard-1';
// const newDiskSourceImage = 'projects/debian-cloud/global/images/family/debian-10';

const compute = require('@google-cloud/compute');

// Creates a new instance in the specified project and zone using a selected template,
// but overrides the disk and machine type options in the template.
async function createInstanceFromTemplateWithOverrides() {
  const instancesClient = new compute.InstancesClient();
  const instanceTemplatesClient = new compute.InstanceTemplatesClient();

  console.log(
    `Creating the ${instanceName} instance in ${zone} from template ${instanceTemplateName}...`
  );

  // Retrieve an instance template by name.
  const [instanceTemplate] = await instanceTemplatesClient.get({
    project: projectId,
    instanceTemplate: instanceTemplateName,
  });

  // Adjust diskType field of the instance template to use the URL formatting required by instances.insert.diskType
  // For instance template, there is only a name, not URL.
  for (const disk of instanceTemplate.properties.disks) {
    if (disk.initializeParams.diskType) {
      disk.initializeParams.diskType = `zones/${zone}/diskTypes/${disk.initializeParams.diskType}`;
    }
  }

  const [response] = await instancesClient.insert({
    project: projectId,
    zone,
    instanceResource: {
      name: instanceName,
      machineType: `zones/${zone}/machineTypes/${machineType}`,
      disks: [
        // If you override a repeated field, all repeated values
        // for that property are replaced with the
        // corresponding values provided in the request.
        // When adding a new disk to existing disks,
        // insert all existing disks as well.
        ...instanceTemplate.properties.disks,
        {
          initializeParams: {
            diskSizeGb: '10',
            sourceImage: newDiskSourceImage,
          },
          autoDelete: true,
          boot: false,
          type: 'PERSISTENT',
        },
      ],
    },
    sourceInstanceTemplate: instanceTemplate.selfLink,
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

  // Wait for the create operation to complete.
  while (operation.status !== 'DONE') {
    [operation] = await operationsClient.wait({
      operation: operation.name,
      project: projectId,
      zone: operation.zone.split('/').pop(),
    });
  }

  console.log('Instance created.');
}

createInstanceFromTemplateWithOverrides();

Python

import sys
from typing import Any

from google.api_core.extended_operation import ExtendedOperation
from google.cloud import compute_v1

def wait_for_extended_operation(
    operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
) -> Any:
    """
    This method will wait for the extended (long-running) operation to
    complete. If the operation is successful, it will return its result.
    If the operation ends with an error, an exception will be raised.
    If there were any warnings during the execution of the operation
    they will be printed to sys.stderr.

    Args:
        operation: a long-running operation you want to wait on.
        verbose_name: (optional) a more verbose name of the operation,
            used only during error and warning reporting.
        timeout: how long (in seconds) to wait for operation to finish.
            If None, wait indefinitely.

    Returns:
        Whatever the operation.result() returns.

    Raises:
        This method will raise the exception received from `operation.exception()`
        or RuntimeError if there is no exception set, but there is an `error_code`
        set for the `operation`.

        In case of an operation taking longer than `timeout` seconds to complete,
        a `concurrent.futures.TimeoutError` will be raised.
    """
    result = operation.result(timeout=timeout)

    if operation.error_code:
        print(
            f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
            file=sys.stderr,
            flush=True,
        )
        print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
        raise operation.exception() or RuntimeError(operation.error_message)

    if operation.warnings:
        print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
        for warning in operation.warnings:
            print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)

    return result

def create_instance_from_template_with_overrides(
    project_id: str,
    zone: str,
    instance_name: str,
    instance_template_name: str,
    machine_type: str,
    new_disk_source_image: str,
) -> compute_v1.Instance:
    """
    Creates a Compute Engine VM instance from an instance template, changing the machine type and
    adding a new disk created from a source image.

    Args:
        project_id: ID or number of the project you want to use.
        zone: Name of the zone you want to check, for example: us-west3-b
        instance_name: Name of the new instance.
        instance_template_name: Name of the instance template used for creating the new instance.
        machine_type: Machine type you want to set in following format:
            "zones/{zone}/machineTypes/{type_name}". For example:
            - "zones/europe-west3-c/machineTypes/f1-micro"
            - You can find the list of available machine types using:
              https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list
        new_disk_source_image: Path the the disk image you want to use for your new
            disk. This can be one of the public images
            (like "projects/debian-cloud/global/images/family/debian-10")
            or a private image you have access to.
            For a list of available public images, see the documentation:
            http://cloud.google.com/compute/docs/images

    Returns:
        Instance object.
    """
    instance_client = compute_v1.InstancesClient()
    instance_template_client = compute_v1.InstanceTemplatesClient()

    # Retrieve an instance template by name.
    instance_template = instance_template_client.get(
        project=project_id, instance_template=instance_template_name
    )

    # Adjust diskType field of the instance template to use the URL formatting required by instances.insert.diskType
    # For instance template, there is only a name, not URL.
    for disk in instance_template.properties.disks:
        if disk.initialize_params.disk_type:
            disk.initialize_params.disk_type = (
                f"zones/{zone}/diskTypes/{disk.initialize_params.disk_type}"
            )

    instance = compute_v1.Instance()
    instance.name = instance_name
    instance.machine_type = machine_type
    instance.disks = list(instance_template.properties.disks)

    new_disk = compute_v1.AttachedDisk()
    new_disk.initialize_params.disk_size_gb = 50
    new_disk.initialize_params.source_image = new_disk_source_image
    new_disk.auto_delete = True
    new_disk.boot = False
    new_disk.type_ = "PERSISTENT"

    instance.disks.append(new_disk)

    instance_insert_request = compute_v1.InsertInstanceRequest()
    instance_insert_request.project = project_id
    instance_insert_request.zone = zone
    instance_insert_request.instance_resource = instance
    instance_insert_request.source_instance_template = instance_template.self_link

    operation = instance_client.insert(instance_insert_request)
    wait_for_extended_operation(operation, "instance creation")

    return instance_client.get(project=project_id, zone=zone, instance=instance_name)

A seguir