# Configuring Machines

`GcpCompute.Instance.spec/1` turns a friendly keyword list into the (verbose)
Compute `instances.insert` JSON body, with cheap **Spot VM** defaults. You pass
that keyword list straight to `GcpCompute.Instances.insert/3` /
`insert_and_wait/3`, which build and validate it for you.

## Options

| Option              | Default                                              | Notes |
| ------------------- | --------------------------------------------------- | ----- |
| `:name`             | — (required)                                        | Instance name (RFC1035). |
| `:zone`             | the config's `:zone`                                | Injected automatically; override per call. |
| `:machine_type`     | `"e2-micro"`                                         | Short name, or a full `zones/.../machineTypes/...` URL. |
| `:source_image`     | `projects/debian-cloud/global/images/family/debian-12` | Boot disk image. |
| `:disk_size_gb`     | `10`                                                | Boot disk size. |
| `:spot`             | `true`                                              | `true` → `SPOT`, no auto-restart, `DELETE` on termination. |
| `:max_run_duration` | `nil`                                               | Seconds. Hard **server-side TTL** (`scheduling.maxRunDuration`). |
| `:external_ip`      | `true`                                              | Attach an ephemeral external IP (`ONE_TO_ONE_NAT`). |
| `:startup_script`   | `nil`                                               | Shell script injected as `startup-script` metadata. |
| `:metadata`         | `%{}`                                               | Extra metadata key/values. |
| `:labels`           | `%{}`                                               | Resource labels (great for ownership/cost attribution). |
| `:tags`             | `[]`                                                | Network tags (firewall targeting). |
| `:network`          | `"global/networks/default"`                         | Network URL. |
| `:subnetwork`       | `nil`                                               | Subnetwork URL. |
| `:service_account`  | `nil`                                               | Service-account email to attach. |
| `:scopes`           | `["https://www.googleapis.com/auth/cloud-platform"]` | Scopes for the service account. |

## A cheap, self-deleting Spot VM (the default)

```elixir
GcpCompute.insert_instance_and_wait(config,
  name: "worker-1",
  machine_type: "e2-micro",
  max_run_duration: 3600
)
```

produces scheduling equivalent to:

```json
{
  "provisioningModel": "SPOT",
  "automaticRestart": false,
  "instanceTerminationAction": "DELETE",
  "maxRunDuration": { "seconds": 3600 }
}
```

## A standard, internal-only VM

```elixir
GcpCompute.insert_instance(config,
  name: "db-1",
  machine_type: "n2-standard-4",
  spot: false,
  external_ip: false,
  disk_size_gb: 100
)
```

## Injecting tooling via startup script

```elixir
startup = """
#!/bin/bash
apt-get update && apt-get install -y docker.io
docker run -d --restart=always ghcr.io/me/scenario:latest
"""

GcpCompute.insert_instance(config,
  name: "scenario-1",
  machine_type: "e2-standard-2",
  startup_script: startup,
  labels: %{"scenario" => "web-101"},
  tags: ["scenario"]
)
```

## Attaching a service account

```elixir
GcpCompute.insert_instance(config,
  name: "uploader-1",
  machine_type: "e2-small",
  service_account: "uploader@my-project.iam.gserviceaccount.com",
  scopes: ["https://www.googleapis.com/auth/devstorage.read_write"]
)
```

## Building the body separately

`spec/1` returns the body so you can inspect or tweak it:

```elixir
{:ok, body} = GcpCompute.Instance.spec(name: "w", zone: "us-central1-a", machine_type: "e2-micro")
```

## Escape hatch: a raw body

Need a field `spec/1` doesn't model (GPUs, multiple disks, confidential compute)?
Pass a raw Compute API body map straight to `insert/3` — it's used verbatim:

```elixir
GcpCompute.Instances.insert(config, %{
  "name" => "gpu-1",
  "machineType" => "zones/us-central1-a/machineTypes/a2-highgpu-1g",
  "guestAccelerators" => [%{"acceleratorType" => "...", "acceleratorCount" => 1}],
  "disks" => [%{"boot" => true, "initializeParams" => %{"sourceImage" => "..."}}],
  "networkInterfaces" => [%{"network" => "global/networks/default"}]
})
```
