# `Bonny.Server.Scheduler`
[🔗](https://github.com/coryodaniel/bonny/blob/v1.5.0/lib/bonny/server/scheduler.ex#L1)

Kubernetes custom scheduler interface. Built on top of `Reconciler`.

The only function that needs to be implemented is `select_node_for_pod/2`. All others defined by behaviour have default implementations.

## Examples
  Will schedule each unschedule pod with `spec.schedulerName=cheap-node` to a node with a label `cheap=true`.
  `nodes` is a stream that can be lazily filtered:

    defmodule CheapNodeScheduler do
      use Bonny.Server.Scheduler, name: "cheap-node"

      @impl Bonny.Server.Scheduler
      def select_node_for_pod(_pod, nodes) do
        nodes
        |> Stream.filter(fn(node) ->
          is_cheap = K8s.Resource.label(node, "cheap")
          is_cheap == "true"
        end)
        |> Enum.take(1)
        |> List.first
      end
    end

    CheapNodeScheduler.start_link()

  Will schedule each unschedule pod with `spec.schedulerName=random-node` to a random node:

    defmodule RandomNodeScheduler do
      use Bonny.Server.Scheduler, name: "random-node"

      @impl Bonny.Server.Scheduler
      def select_node_for_pod(_pod, nodes) do
        Enum.random(nodes)
      end
    end

    RandomNodeScheduler.start_link()

  Override `nodes/0` default implementation (`pods/0` can be overridden too).
  Schedules pod on a random GPU node:

    defmodule GpuScheduler do
      use Bonny.Server.Scheduler, name: "gpu-node"

      @impl Bonny.Server.Scheduler
      def select_node_for_pod(_pod, nodes) do
        Enum.random(nodes)
      end

      @impl Bonny.Server.Scheduler
      def nodes() do
        label = "my.label.on.gpu.instances"
        conn = Bonny.Config.conn()

        op = K8s.Client.list("v1", :nodes)
        K8s.Client.stream(conn, op, params: %{labelSelector: label})
      end
    end

    GpuScheduler.start_link()

# `conn`

```elixir
@callback conn() :: K8s.Conn.t()
```

# `field_selector`

```elixir
@callback field_selector() :: binary()
```

Field selector for selecting unscheduled pods waiting to be scheduled by this scheduler.

Default implementation is all unscheduled pods assigned to this scheduler.

# `name`

```elixir
@callback name() :: binary()
```

Name of the scheduler.

# `nodes`

```elixir
@callback nodes(K8s.Conn.t()) :: {:ok, Enumerable.t()} | {:error, any()}
```

List of nodes available to this scheduler.

Default implementation is all nodes in cluster.

# `select_node_for_pod`

```elixir
@callback select_node_for_pod(map(), [map()]) :: map()
```

Selects the best node for the current `pod`.

Takes the current unscheduled pod and a `Stream` of nodes. `pod` is provided in the event that `taints` or `affinities` would need to be respected by the scheduler.

Returns the node to schedule on.

# `bind`

```elixir
@spec bind(K8s.Conn.t(), map(), map()) :: {:ok, map()} | {:error, atom()}
```

Binds a pod to a node

# `field_selector`

```elixir
@spec field_selector(binary()) :: binary()
```

Kubernetes API `fieldSelector` value for unbound pods waiting on the given scheduler.

# `nodes`

```elixir
@spec nodes(K8s.Conn.t()) :: {:ok, [map()]} | {:error, any()}
```

Returns a list of all nodes in the cluster.

# `reconcile`

```elixir
@spec reconcile(module(), map()) :: :ok
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
