# Getting Started

This guide takes you from zero to a running (and self-deleting) VM.

## 1. Add the dependencies

```elixir
def deps do
  [
    {:gcp_compute, "~> 0.3.0"},
    {:goth, "~> 1.4"}   # recommended token provider (optional dependency)
  ]
end
```

## 2. Authenticate

`GcpCompute` needs an OAuth2 access token for every request. In production that
comes from [Goth](https://hexdocs.pm/goth), which picks up Application Default
Credentials (a service-account key via `GOOGLE_APPLICATION_CREDENTIALS`, the GCE
metadata server, or `gcloud auth application-default login` in dev).

Start a Goth server in your supervision tree:

```elixir
# lib/my_app/application.ex
children = [
  {Goth, name: MyApp.Goth}
  # ...
]
```

Auth is pluggable — see `GcpCompute.TokenProvider` to use workload identity, the
metadata server, Vault, etc. instead of Goth.

## 3. Build a config

A `GcpCompute.Config` is a cheap, immutable handle you build once and pass to
every call. There is **no process to supervise** — `Req` handles connection
pooling internally.

```elixir
{:ok, config} =
  GcpCompute.Config.production(
    project: "my-project",
    zone: "us-central1-a",
    goth: MyApp.Goth
  )
```

Or load it from application env with `GcpCompute.Config.from_env/2`.

## 4. Spawn a VM and wait for it

`insert_instance_and_wait/3` inserts the instance, polls the resulting operation
to completion, and returns the live `GcpCompute.Instance`:

```elixir
{:ok, instance} =
  GcpCompute.insert_instance_and_wait(config,
    name: "worker-1",
    machine_type: "e2-micro",
    spot: true,                       # cheap, preemptible, deletes on termination
    max_run_duration: 3600,           # hard server-side TTL (seconds)
    startup_script: "#!/bin/bash\necho ready > /tmp/ready",
    labels: %{"owner" => "platform"}
  )

GcpCompute.Instance.external_ip(instance)   #=> "34.x.x.x"
```

See [Configuring machines](configuring-machines.md) for every `spec/1` option.

## 5. Drive the lifecycle yourself (optional)

Every mutating call returns an `GcpCompute.Operation` you can poll explicitly:

```elixir
{:ok, op}   = GcpCompute.insert_instance(config, name: "worker-1", machine_type: "e2-micro")
{:ok, _done} = GcpCompute.wait_for_operation(config, op, timeout: :timer.minutes(3))
{:ok, vm}   = GcpCompute.get_instance(config, "worker-1")
```

## 6. Tear it down

```elixir
{:ok, _op} = GcpCompute.delete_instance_and_wait(config, "worker-1")
```

(Spot VMs with `max_run_duration` also delete themselves server-side — belt and
suspenders.)

## Error handling

Every function returns `{:ok, _}` or `{:error, %GcpCompute.Error{}}`. The error
carries a coarse `:reason` you can match on:

```elixir
case GcpCompute.insert_instance(config, name: "w", machine_type: "e2-micro") do
  {:ok, op} -> op
  {:error, %GcpCompute.Error{reason: :api_error, status: 403, message: msg}} -> {:denied, msg}
  {:error, %GcpCompute.Error{reason: :operation_failed} = err} -> {:failed, err}
  {:error, %GcpCompute.Error{reason: :timeout}} -> :timed_out
  {:error, %GcpCompute.Error{reason: :transport}} -> :network
end
```

## Observability

Attach a quick logger during development, or wire the spans into
`Telemetry.Metrics`:

```elixir
GcpCompute.Telemetry.attach_default_logger()
```

See `GcpCompute.Telemetry` for the full event list.
