README.adoc

:icons: font
:encoding: utf-8

= NodePing Elixir

An Elixir package for managing checks, schedules, contacts, etc. on your NodePing account.

== Installation

The package can be installed by adding `nodeping` to your list of dependencies in `mix.exs`:

[source,elixir]
----
def deps do
  [
    {:nodeping, "~> 1.4"}
  ]
end
----

NOTE: If you want to use this package with Elixir version 1.9, instead set your dep to `{:nodeping, "~> 1.1"}`

And run `mix deps.get`.

== Usage

You will need to create an account at https://nodeping.com[NodePing] and fetch your API token under Account `Settings -> API`.
This will be your API `token` that you provide to authenticate with the service and manage things such as checks.
If you want to manage `SubAccounts`, you can get the ID for that subaccount under `Account Settings -> SubAccounts`,
and the ID is next to the name.

This document does not contain all the capabilities provided by this package.

=== Verify API Token

Verify if your API token is valid. Returns `true` or `false`.

[source,elixir]
----
token = System.fetch_env!("TOKEN")
NodePing.token_valid?(token)
----

== Checks

=== Get Checks

Get checks on your NodePing account via the `NodePing.Checks.get_checks` module.

[source,elixir]
----
token = System.fetch_env!("TOKEN")
{:ok, result} = NodePing.Checks.get_checks(token)
----

You can also get checks that meet certain conditions such as:

* passing - `NodePing.Checks.get_passing_checks`
* failing - `NodePing.Checks.get_failing_checks`
* disabled - `NodePing.Checks.get_disabled_checks`
* last result - `NodePing.Checks.get_last_result`

==== Get By ID

Get a single check by providing its ID

[source,elixir]
----
token = System.fetch_env!("TOKEN")
id = "201205050153W2Q4C-0J2HSIRF"
{:ok, result} = NodePing.Checks.get_by_id(token, id)
----

=== Find Checks

There are functions in the `NodePing.Checks` module called `find_by_id` and `find_by_state` which
accepts a result from `NodePing.Checks.get_checks` and lets you search by ID in the result or for
passing/failing checks. Each time you use these functions, they do not make a call to the API.


=== Create a Check

Create checks on your NodePing account via `NodePing.Checks.create_check`.

In this example a PING check is created and pointed at 8.8.8.8

[source,elixir]
----
token = System.fetch_env!("TOKEN")
checktype = NodePing.Checktypes.Ping
target = "8.8.8.8"
args = %{label: "my label", target: target, interval: 1, enabled: true}
{:ok, result} = NodePing.Checks.create_check(token, checktype, args)
----

==== PUSH Check Fields

When creating a variable for the fields for the PUSH check, the value should be formatted as such:

[source,elixir]
----
fields = %{
  :apcupsd => %{
    :name => "apcupsd",
    :min => 1,
    :max => 1
  },
  :load1min => %{
    :name => "load1min",
    :min => 1,
    :max => 1
  }
}
----

== Contacts

Creating contacts are done with the `NodePing.Contacts` module. You can find the structure of a
contact defined in the `NodePing.Contacts.Contact` module.

=== Create a Contact

How to create a contact with both an email and sms address:

[source,elixir]
----
token = System.fetch_env!("TOKEN")
name = testcontact
addresses = [
  %{address: "1234567890", type: "sms", name: "cellphone"},
  %{address: "me@example.com", type: "email", name: "workemail"}
]
role = "owner"
args = %{name: name, newaddresses: addresses, custrole: role}
{:ok, result} = NodePing.Contacts.create_contact(token, args)
----

=== Update a Contact

Updating a contact requires having all the information of the existing conact. If a contact
has contact methods "A", "B", and "C" and you only provide "A", and "B", then you won't have
contact method "C" anymore. This means it's probably best to get existing contact information
to modify it. The below example gets contacts containing email addresses "me@example.com"
and replacing them with "email@example.com"

[source,elixir]
----
token = System.fetch_env!("TOKEN")
contact_id = "201205050153W2Q4C-BKPGH"
old_email = "me@example.com"
new_email = "email@example.com"
{:ok, contact} = NodePing.Contacts.get_by_id(token, contact_id)

{id, opts}
Map.get(contact, "addresses")
|> Enum.find(fn {_, val} -> val["address"] == old_email end)

new_opts =
  opts
  |> Map.replace("address", new_email)
  |> Map.drop(["_id", "customer_id", "sdomain", "type"])

{_, new_contact} = get_and_update_in(contact, ["addresses", id, "address"], &{&1, "email@example.com"})
updated_addresses = Map.get(new_contact, "addresses")

{:ok, updated} = NodePing.Contacts.update_contact(token, contact_id, %{addresses: updated_addresses})
----

=== Mute a Contact

Muting a contact is going to be almost identical to the Update a Contact section, except instead of
replacing a value, we are going to have to update the map. It's possible the `mute` key might not exist
in the contact, so using `Map.update/4` is going to be necessary to set a default value in case the
key does not exist. Muting a contact is usually done with a timestamp of when you want the muting to _STOP_
with a millisecond Unix timestamp

[source,elixir]
----
token = System.fetch_env!("TOKEN")
parent_contact_id = "201205050153W2Q4C-BKPGH"
contact_id = "IRAB6O5W"
{:ok, contact} = NodePing.Contacts.get_by_id(token, parent_contact_id)

five_min_later =
  DateTime.utc_now()
  |> DateTime.add(300, :second)
  |> DateTime.to_unix(:millisecond)

muted =
  contact
  |> get_in(["addresses", contact_id])
  |> Map.update("mute", five_min_later, fn _x -> five_min_later end)

new_addresses =
  contact
  |> Map.get("addresses")
  |> Map.replace(contact_id, muted)

{:ok, updated} = NodePing.Contacts.update_contact(token, parent_contact_id, %{addresses: new_addresses})
----