# `Kubereq`
[🔗](https://github.com/mruoss/kubereq/blob/v0.4.3/lib/kubereq.ex#L1)

A Kubernetes client for Elixir based on `Req`.

## Usage

First, attach `kubereq` to your `Req` request (see `attach/2` for options):

    Req.new() |> Kubereq.attach()

Now you can use plain Req functionality. However, the functions defined in
this module make it much easier to perform the most common operation.

### Kubereq API

While you can use this library with plain `Req` functions (see below), it is
easier to prepare a `Req` request for a specific resource and then use the
functions defined in the `Kubereq` module.

```
sa_req = Req.new() |> Kubereq.attach(api_version: "v1", kind: "ServiceAccount")

Kubereq.get(sa_req, "my-namespace", "default")
Kubereq.list(sa_req, "my-namespace")
```

Or use the functions right away, defining the resource through options:

```
req = Req.new() |> Kubereq.attach()

Kubereq.get(req, "my-namespace", "default", api_version: "v1", kind: "ServiceAccount")

# get the "status" subresource of the default namespace
Kubereq.get(req, "my-namespace", api_version: "v1", kind: "Namespace", subresource: "status")
```

For resources defined by Kubernetes, the `api_version` can be omitted:

```
Req.new()
|> Kubereq.attach(kind: "Namespace")
|> Kubereq.get("my-namespace")
```

### Usage with plain Req functionality

Inestead of using the function in `Kubereq`, you can use
`Kubereq.Kubeconfig.Default` to create connection to the cluster and then use
plain `Req.request()` to make the request.

```
req = Req.new() |> Kubereq.attach()

Req.request!(req,
  api_version: "v1",
  kind: "ServiceAccount",
  operation: :get,
  path_params: [namespace: "default", name: "default"]
)
```

You can pass your own Kubeconfigloader pipeline when attaching:

```
req = Req.new() |> Kubereq.attach(kubeconfig: {Kubereq.Kubeconfig.File, path: "/path/to/kubeconfig.yaml"})

Req.request!(req,
  api_version: "v1",
  kind: "ServiceAccount",
  operation: :get,
  path_params: [namespace: "default", name: "default"]
)
```

Prepare a `Req` struct for a specific resource:

```
sa_req = Req.new() |> Kubereq.attach(api_version: "v1", kind: "ServiceAccount")

Req.request!(sa_req,  operation: :get, path_params: [namespace: "default", name: "default"])
Req.request!(sa_req,  operation: :list, path_params: [namespace: "default"])
```

## Options

`kubereq` registeres the following options with `Req`:

  * `:kubeconfig` - A `%Kubereq.Kubeconfig{}` struct. The `attach/2` function also accepts a
    Kubeconf pipeline (e.g. `Kubereq.Kubeconfig.Default`)
  * `:api_version` - The group and version of the targeted resource (case sensitive)
  * `:kind` - The kind of the targeted resource (case sensitive)
  * `:resource_path` - Can be defined instead of `:api_version` and `:kind`. The path to the
    targeted resource with placeholders for `:namespace` and `:name`
    (e.g. `api/v1/namespaces/:namespace/configmaps/:name`)
  * `:field_selectors` - See `Kubereq.Step.FieldSelector`
  * `:label_selectors` - See `Kubereq.Step.LabelSelector`
  * `:operation` - The operation on the resource (one of `:create`, `:get` `:update`,
    `:delete`, `:delete_all`, `:apply`, `:json_patch`, `:merge_patch`, `:watch`)
  * `:subresource` - Some operations can be performed on subresources
    (e.g. `status` or `scale`)

# `namespace`

```elixir
@type namespace() :: String.t() | nil
```

# `response`

```elixir
@type response() :: {:ok, Req.Response.t()} | {:error, Exception.t()}
```

# `subresource`

```elixir
@type subresource() :: String.t() | nil
```

# `wait_until_callback`

```elixir
@type wait_until_callback() :: (map() | :deleted -&gt; boolean() | {:error, any()})
```

# `wait_until_response`

```elixir
@type wait_until_response() :: :ok | {:error, :watch_timeout}
```

# `apply`

```elixir
@spec apply(
  Req.Request.t(),
  resource :: map(),
  field_manager :: binary(),
  force :: boolean(),
  opts :: Keyword.t()
) :: response()
```

Applies the given `resource` using a Server-Side-Apply Patch. Returns a
response or an error.

See the [documentation](https://kubernetes.io/docs/reference/using-api/server-side-apply/)
for a documentation on `field_manager` and `force` arguments.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.apply(resource)

# `apply!`

```elixir
@spec apply!(
  Req.Request.t(),
  resource :: map(),
  field_manager :: binary(),
  force :: boolean(),
  opts :: Keyword.t()
) :: Req.Response.t()
```

Applies the given `resource` using a Server-Side-Apply Patch. Returns a
response or raises an error.

See the [documentation](https://kubernetes.io/docs/reference/using-api/server-side-apply/)
for a documentation on `field_manager` and `force` arguments.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.apply!(resource)

# `attach`

```elixir
@spec attach(req :: Req.Request.t(), opts :: Keyword.t()) :: Req.Request.t()
```

Attaches `kubereq` to a `Req.Request` struct for making HTTP requests to a
Kubernetes cluster. You can optionally pass a Kubernetes configuration or
pipeline via `kubeconfig` option. If it is omitted, the default config
`Kubereq.Kubeconfig.Default` is loaded.

### Examples

    Req.new() |> Kubereq.attach()

### Options

All options (see Options section in module doc) are accepted and merged with
the given req.

# `can_i?`

```elixir
@spec can_i?(Req.Request.t(), Keyword.t(), Keyword.t()) :: boolean()
```

Checks whether the authenticated user is authorized to perform a specific
action.

Creates a [SelfSubjectAccessReview][SelfSubjectAccessReview] resource with
the given `attributes` and sends it to the API Server. It returns
`.status.allowed` from the result (boolean). In case of an error, the
function returns `false`.

### Attributes

`attributes` is a Keyword list that allows the following keywords (See
attribute descriptions on the  [Kubernetes documentation][SelfSubjectAccessReview])

[SelfSubjectAccessReview]: https://kubernetes.io/docs/reference/kubernetes-api/authorization-resources/self-subject-access-review-v1/

### Examples

Check for a specific action (`GET`) on a specific resource (`pods` in namespace
`default`):

    Req.new()
    |> Kubereq.attach()
    |> Kubereq.can_i?(verb: "get", version: "v1", resource: "pods", namespace: "default")

Check for a specific path on the API Server:

    Req.new()
    |> Kubereq.attach()
    |> Kubereq.can_i?(verb: "get", path: "apis/apiregistration.k8s.io/v1")

# `create`

```elixir
@spec create(Req.Request.t(), resource :: map(), opts :: Keyword.t()) :: response()
```

Create the `resource` or its `subresource` on the cluster and returns a
response or an error.

### Example

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.create(resource)

# `create!`

```elixir
@spec create!(Req.Request.t(), resource :: map(), opts :: Keyword.t()) ::
  Req.Response.t()
```

Create the `resource` or its `subresource` on the cluster and returns a
response or raises an error.

### Example

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.create!(resource)

# `delete`

```elixir
@spec delete(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t()
) :: response()
```

Deletes the `resource` or its `subresource` from the cluster. Returns a
response or an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.delete("default", "foo")

# `delete!`

```elixir
@spec delete!(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t()
) :: Req.Response.t()
```

Deletes the `resource` or its `subresource` from the cluster. Returns a
response or raises an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.delete!("default", "foo")

# `delete_all`

```elixir
@spec delete_all(Req.Request.t(), namespace :: namespace(), opts :: keyword()) ::
  response()
```

Deletes all resources in the given namespace. Returns a response or an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.delete_all("default", label_selectors: [{"app", "my-app"}])

# `delete_all!`

```elixir
@spec delete_all!(Req.Request.t(), namespace :: namespace(), opts :: keyword()) ::
  Req.Response.t()
```

Deletes all resources in the given namespace. Returns a response or raises an
error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.delete_all!("default", label_selectors: [{"app", "my-app"}])

# `exec`

```elixir
@spec exec(
  req :: Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t() | nil
) :: response()
```

Opens a websocket to the given Pod and executes a command on it.
Returns a response or an error.

> #### Info {: .tip}
>
> This function blocks the process. It should be used to execute commands
> which terminate eventually. To implement a shell with a long running
> connection, use `Kubereq.PodExec` with `tty: true` instead.

## Examples
    {:ok, resp} =
      Kubereq.exec(req, "defaault", "my-pod",
        container: "main-container",
        command: "/bin/sh",
        command: "-c",
        command: "echo foobar",
        stdout: true,
        stderr: true
      )
    Enum.each(resp.body, &IO.inspect/1)
    # {:stdout, ""}
    # {:stdout, "foobar\n"}

## Options

* `:container` (optional) - The container to connect to. Defaults to only
  container if there is one container in the pod. Fails if not defined for
  pods with multiple pods.
* `:command` - Command is the remote command to execute. Not executed within a shell.
* `:stdin` (optional) - Redirect the standard input stream of the pod for this call. Defaults to `true`.
* `:stdin` (optional) - Redirect the standard output stream of the pod for this call. Defaults to `true`.
* `:stderr` (optional) - Redirect the standard error stream of the pod for this call. Defaults to `true`.
* `:tty` (optional) - If `true` indicates that a tty will be allocated for the exec call. Defaults to `false`.

# `exec!`

```elixir
@spec exec!(
  req :: Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t() | nil
) :: Req.Response.t()
```

Opens a websocket to the given Pod and executes a command on it.
Returns a response or raises an error.

> #### Info {: .tip}
>
> This function blocks the process. It should be used to execute commands
> which terminate eventually. To implement a shell with a long running
> connection, use `Kubereq.PodExec` with `tty: true` instead.

## Examples
    {:ok, resp} =
      Kubereq.exec!(req, "defaault", "my-pod",
        container: "main-container",
        command: "/bin/sh",
        command: "-c",
        command: "echo foobar",
        stdout: true,
        stderr: true
      )
    Enum.each(resp.body, &IO.inspect/1)
    # {:stdout, ""}
    # {:stdout, "foobar\n"}

## Options

* `:container` (optional) - The container to connect to. Defaults to only
  container if there is one container in the pod. Fails if not defined for
  pods with multiple pods.
* `:command` - Command is the remote command to execute. Not executed within a shell.
* `:stdin` (optional) - Redirect the standard input stream of the pod for this call. Defaults to `true`.
* `:stdin` (optional) - Redirect the standard output stream of the pod for this call. Defaults to `true`.
* `:stderr` (optional) - Redirect the standard error stream of the pod for this call. Defaults to `true`.
* `:tty` (optional) - If `true` indicates that a tty will be allocated for the exec call. Defaults to `false`.

# `get`

```elixir
@spec get(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t() | nil
) :: response()
```

Get the resource `name` in `namespace` or its `subresource`. and returns a
response or an error

Omit `namespace` to get cluster resources.

### Example

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.get("default", "foo")

# `get!`

```elixir
@spec get!(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t() | nil
) :: Req.Response.t()
```

Get the resource `name` in `namespace` or its `subresource`. and returns a
response or raises an error

Omit `namespace` to get cluster resources.

### Example

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.get!("default", "foo")

# `json_patch`

```elixir
@spec json_patch(
  Req.Request.t(),
  json_patch :: map(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t()
) :: response()
```

Patches the resource `name`in `namespace` or its `subresource` using the given
`json_patch`. Returns a response or an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.json_patch(%{...}, "default", "foo")

# `json_patch!`

```elixir
@spec json_patch!(
  Req.Request.t(),
  json_patch :: map(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t()
) :: Req.Response.t()
```

Patches the resource `name`in `namespace` or its `subresource` using the given
`json_patch`. Returns a response or raises an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.json_patch!(%{...}, "default", "foo")

# `list`

```elixir
@spec list(Req.Request.t(), namespace :: namespace(), opts :: keyword()) :: response()
```

Get a resource list. Returns a response or an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.list("default")

### Options

All options described in the moduledoc plus:

  * `:into` - Optional. When set to `:stream`, the underlying list request to
    Kubernetes is paginated using `:limit` and `:continue` query parameters.

  * `:limit` - Optional. Used with `into: :stream`; defines the limit query
    parameter used for pagination.

### Async Response through the `into: :stream`

With `into: :srteam`, the response's `:body` is a `Stream`

    {:ok, resp} =
      Req.new()
      |> Kubereq.attach(api_version: "v1", kind: "Pod")
      |> Kubereq.list(into: :stream)
    resp.body |> Stream.take(25) |> Enum.to_list()

# `list!`

```elixir
@spec list!(Req.Request.t(), namespace :: namespace(), opts :: keyword()) ::
  Req.Response.t()
```

Get a resource list. Returns a response or raises an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.list!("default")

### Options

All options described in the moduledoc plus:

  * `:into` - Optional. When set to `:stream`, the underlying list request to
    Kubernetes is paginated using `:limit` and `:continue` query parameters.

  * `:limit` - Optional. Used with `into: :stream`; defines the limit query
    parameter used for pagination.

### Async Response through the `into: :stream`

With `into: :srteam`, the response's `:body` is a `Stream`

    {:ok, resp} =
      Req.new()
      |> Kubereq.attach(api_version: "v1", kind: "Pod")
      |> Kubereq.list!(into: :stream)
    resp.body |> Stream.take(25) |> Enum.to_list()

# `logs`

```elixir
@spec logs(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t() | nil
) :: response()
```

Opens a websocket to the given container and streams logs from it.
Returns a response or an error.

> #### Info {: .tip}
>
> This function blocks the process. It should be used to retrieve a finite
> set of logs from a container. If you want to follow logs, use
> `Kubereq.PodLogs` combined with the `:follow` options instead.

## Examples

    req = Req.new() |> Kubereq.attach()
    {:ok, resp} =
      Kubereq.logs(req, "default", "my-pod",
        container: "main-container",
        tailLines: 5
      )
    Enum.each(resp.body, &IO.inspect/1)

## Options

* `:container` - The container for which to stream logs. Defaults to only
  container if there is one container in the pod. Fails if not defined for
  pods with multiple pods.
* `:follow` - Follow the log stream of the pod. If this is set to `true`,
  the connection is kept alive which blocks current the process. If you need
  this, you probably want to use `Kubereq.PodLogs` instead. Defaults to
  `false`.
* `:insecureSkipTLSVerifyBackend` - insecureSkipTLSVerifyBackend indicates
  that the apiserver should not confirm the validity of the serving
  certificate of the backend it is connecting to. This will make the HTTPS
  connection between the apiserver and the backend insecure. This means the
  apiserver cannot verify the log data it is receiving came from the real
  kubelet. If the kubelet is configured to verify the apiserver's TLS
  credentials, it does not mean the connection to the real kubelet is
  vulnerable to a man in the middle attack (e.g. an attacker could not
  intercept the actual log data coming from the real kubelet).
* `:limitBytes` - If set, the number of bytes to read from the server before
  terminating the log output. This may not display a complete final line of
  logging, and may return slightly more or slightly less than the specified
  limit.
* `:pretty` - If 'true', then the output is pretty printed.
* `:previous` - Return previous t  erminated container logs. Defaults to
  `false`.
* `:sinceSeconds` - A relative time in seconds before the current time from
  which to show logs. If this value precedes the time a pod was started,
  only logs since the pod start will be returned. If this value is in the
  future, no logs will be returned. Only one of sinceSeconds or sinceTime
  may be specified.
* `:tailLines` - If set, the number of lines from the end of the logs to
  show. If not specified, logs are shown from the creation of the container
  or sinceSeconds or sinceTime
* `:timestamps` - If true, add an RFC3339 or RFC3339Nano timestamp at the
  beginning of every line of log output. Defaults to `false`.

# `logs!`

```elixir
@spec logs!(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t() | nil
) :: Req.Response.t()
```

Opens a websocket to the given container and streams logs from it.
Returns a response or raises an error.

> #### Info {: .tip}
>
> This function blocks the process. It should be used to retrieve a finite
> set of logs from a container. If you want to follow logs, use
> `Kubereq.PodLogs` combined with the `:follow` options instead.

## Examples

    req = Req.new() |> Kubereq.attach()
    {:ok, resp} =
      Kubereq.logs!(req, "default", "my-pod",
        container: "main-container",
        tailLines: 5
      )
    Enum.each(resp.body, &IO.inspect/1)

## Options

* `:container` - The container for which to stream logs. Defaults to only
  container if there is one container in the pod. Fails if not defined for
  pods with multiple pods.
* `:follow` - Follow the log stream of the pod. If this is set to `true`,
  the connection is kept alive which blocks current the process. If you need
  this, you probably want to use `Kubereq.PodLogs` instead. Defaults to
  `false`.
* `:insecureSkipTLSVerifyBackend` - insecureSkipTLSVerifyBackend indicates
  that the apiserver should not confirm the validity of the serving
  certificate of the backend it is connecting to. This will make the HTTPS
  connection between the apiserver and the backend insecure. This means the
  apiserver cannot verify the log data it is receiving came from the real
  kubelet. If the kubelet is configured to verify the apiserver's TLS
  credentials, it does not mean the connection to the real kubelet is
  vulnerable to a man in the middle attack (e.g. an attacker could not
  intercept the actual log data coming from the real kubelet).
* `:limitBytes` - If set, the number of bytes to read from the server before
  terminating the log output. This may not display a complete final line of
  logging, and may return slightly more or slightly less than the specified
  limit.
* `:pretty` - If 'true', then the output is pretty printed.
* `:previous` - Return previous t  erminated container logs. Defaults to
  `false`.
* `:sinceSeconds` - A relative time in seconds before the current time from
  which to show logs. If this value precedes the time a pod was started,
  only logs since the pod start will be returned. If this value is in the
  future, no logs will be returned. Only one of sinceSeconds or sinceTime
  may be specified.
* `:tailLines` - If set, the number of lines from the end of the logs to
  show. If not specified, logs are shown from the creation of the container
  or sinceSeconds or sinceTime
* `:timestamps` - If true, add an RFC3339 or RFC3339Nano timestamp at the
  beginning of every line of log output. Defaults to `false`.

# `merge_patch`

```elixir
@spec merge_patch(
  Req.Request.t(),
  merge_patch :: String.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t()
) :: response()
```

Patches the resource `name`in `namespace` or its `subresource` using the given
`merge_patch`. Returns a response or an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.merge_patch(%{...}, "default", "foo")

# `merge_patch!`

```elixir
@spec merge_patch!(
  Req.Request.t(),
  merge_patch :: String.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: Keyword.t()
) :: Req.Response.t()
```

Patches the resource `name`in `namespace` or its `subresource` using the given
`merge_patch`. Returns a response or raises an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.merge_patch!(%{...}, "default", "foo")

# `new`

> This function is deprecated. Use Kubereq.attach/2.

```elixir
@spec new(kubeconfig :: Kubereq.Kubeconfig.t()) :: Req.Request.t()
```

# `new`

> This function is deprecated. Use Kubereq.attach/2.

```elixir
@spec new(kubeconfig :: Kubereq.Kubeconfig.t(), resource_path :: binary()) ::
  Req.Request.t()
```

# `update`

```elixir
@spec update(Req.Request.t(), resource :: map(), opts :: Keyword.t()) :: response()
```

Updates the given `resource`. Returns a response or an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.update(resource)

# `update!`

```elixir
@spec update!(Req.Request.t(), resource :: map(), opts :: Keyword.t()) ::
  Req.Response.t()
```

Updates the given `resource`. Returns a response or raises an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.update!(resource)

# `wait_until`

```elixir
@spec wait_until(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  callback :: wait_until_callback(),
  opts :: Keyword.t()
) :: wait_until_response()
```

GET a resource and wait until the given `callback` returns true or the given
`timeout` (ms) has expired.

### Options

All options described in the moduledoc plus:

* `:timeout` - Timeout in ms after function terminates with `{:error, :timeout}`

# `watch`

```elixir
@spec watch(
  Req.Request.t(),
  namespace :: namespace(),
  opts :: keyword()
) :: response()
```

Watch events of all resources in `namespace`. If `namespace` is `nil`, all
namespaces are watched. Returns a response or an error.

> #### Info {: .tip}
>
> The Enumerable returned via the response's body blocks the process when run.
> Use `Kubereq.Watcher` instead if you want to build a long running process
> handling all occurring events.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.watch("default")

Omit the `namespace` in order to watch events in all namespaces:

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.watch()

### Options

  All options described in the moduledoc plus:

    * `:resource_version` - Optional. Resource version to start watching from.
      Per default, the watcher starts watching from the current
      resource_version.

# `watch!`

```elixir
@spec watch!(
  Req.Request.t(),
  namespace :: namespace(),
  opts :: keyword()
) :: Req.Response.t()
```

Watch events of all resources in `namespace`. If `namespace` is `nil`, all
namespaces are watched. Returns a response or raises an error.

> #### Info {: .tip}
>
> The Enumerable returned via the response's body blocks the process when run.
> Use `Kubereq.Watcher` instead if you want to build a long running process
> handling all occurring events.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.watch!("default")

Omit the `namespace` in order to watch events in all namespaces:

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.watch!()

### Options

  All options described in the moduledoc plus:

    * `:resource_version` - Optional. Resource version to start watching from.
      Per default, the watcher starts watching from the current
      resource_version.

# `watch_single`

```elixir
@spec watch_single(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: keyword()
) :: response()
```

Watch events of a single resources `name`in `namespace`. Returns a response
or an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.watch_single("default")

Omit the second argument in order to watch events in all namespaces:

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.watch_single()

# `watch_single!`

```elixir
@spec watch_single!(
  Req.Request.t(),
  namespace :: namespace(),
  name :: String.t(),
  opts :: keyword()
) :: Req.Response.t()
```

Watch events of a single resources `name`in `namespace`. Returns a response
or raises an error.

### Examples

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.watch_single!("default")

Omit the second argument in order to watch events in all namespaces:

    Req.new()
    |> Kubereq.attach(api_version: "v1", kind: "ConfigMap")
    |> Kubereq.watch_single!()

---

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