From 2bede602c2113297e6a36ffd14f4f1b459920c87 Mon Sep 17 00:00:00 2001 From: Felipe Ripoll Date: Wed, 29 Aug 2018 08:05:59 -0600 Subject: [PATCH] [#59] improving documentation --- README.md | 41 +- config/config.exs | 8 + config/prod.exs | 2 +- doc/.build | 5 +- doc/404.html | 2 +- doc/POABackend.Auth.Guardian.Plug.html | 2 +- doc/POABackend.Auth.Models.Token.html | 2 +- doc/POABackend.Auth.Models.User.html | 2 +- doc/POABackend.Auth.REST.html | 2 +- doc/POABackend.Auth.html | 22 +- doc/POABackend.CustomHandler.REST.html | 2 +- doc/POABackend.CustomHandler.html | 2 +- doc/POABackend.Protocol.DataType.html | 2 +- doc/POABackend.Protocol.Message.html | 2 +- doc/POABackend.Protocol.MessageType.html | 2 +- doc/POABackend.Protocol.html | 2 +- doc/POABackend.Receiver.html | 2 +- doc/POABackend.Receivers.Dashboard.html | 2 +- doc/POABackend.Receivers.DynamoDB.html | 2 +- doc/POABackend.Receivers.Eth.Stats.html | 336 ++++ doc/POABackend.Receivers.Repo.html | 1852 ++++++++++++++++++++ doc/POABackend.Receivers.System.Stats.html | 336 ++++ doc/POABackend.html | 50 +- doc/api-reference.html | 22 +- doc/dist/sidebar_items-3739fd4c82.js | 1 - doc/dist/sidebar_items-3d14d8fe9b.js | 1 + doc/initial_architecture.html | 2 +- doc/search.html | 2 +- lib/poa_backend.ex | 41 +- lib/poa_backend/receivers/eth/stats.ex | 15 +- lib/poa_backend/receivers/system/stats.ex | 15 +- mix.exs | 4 +- 32 files changed, 2733 insertions(+), 50 deletions(-) create mode 100644 doc/POABackend.Receivers.Eth.Stats.html create mode 100644 doc/POABackend.Receivers.Repo.html create mode 100644 doc/POABackend.Receivers.System.Stats.html delete mode 100644 doc/dist/sidebar_items-3739fd4c82.js create mode 100644 doc/dist/sidebar_items-3d14d8fe9b.js diff --git a/README.md b/README.md index 6eb896d..8909cb8 100644 --- a/README.md +++ b/README.md @@ -19,23 +19,56 @@ mix docs That command will create a `doc/` folder with the actual Documentation. -## Run Tests +## Configuring Databases for first time -`POABackend` uses [Mnesia](http://erlang.org/doc/man/mnesia.html) as a local database with [Ecto](https://hexdocs.pm/ecto/Ecto.html). In order to have this running we have to create a folder where `Mnesia` will store our data. In order to do that we have to define it in the `config/test.exs` file like this: +`POABackend` uses many Databases. For Authentication we use [Mnesia](http://erlang.org/doc/man/mnesia.html) as a local database and for some receivers which require storage we use Postgres. All databases are managed on top of [Ecto](https://hexdocs.pm/ecto/Ecto.html) a widly used database wrapper for Elixir projects. + +For this reason we have to set the databases before running the `POABackend` for the first time. + +- Auth Database (Mnesia): Setting up Mnesia is easy since it is working localy and is built in the Erlang Virtual Machine. We only have to say "where" we are going to store the database's files. In order to do that we have to add the configuration to the config file (`prod.exs` or `test.exs` depending if you want to run tests or production) ``` config :mnesia, dir: 'your/local/path' # make sure this directory exists! ``` -once we have the path defined we have to create the database (those commands must be run only once if you are going to use always this same path for testing). In your root folder run: +- Receivers Database (Postgres): This is a little more complex than Mnesia. We need a Postgres instance running somewhere and we have to add the config to the config files + +``` +config :poa_backend, POABackend.Receivers.Repo, + priv: "priv/receivers", # this value is not changed + adapter: Ecto.Adapters.Postgres, + database: "poabackend_stats", + username: "postgres", + password: "postgres", + hostname: "localhost" +``` + +The important fields here are `database`, `username`, `password` and `hostname`. The rest of values must remain exactly as the example. + +Once we have set the database configuration we have to create and migrate the databases, in order to do that we should be in the root of the project and run: + +- for production + +``` +MIX_ENV=prod mix ecto.create +MIX_ENV=prod mix ecto.migrate +``` + +- for test ``` MIX_ENV=test mix ecto.create MIX_ENV=test mix ecto.migrate ``` -Now the environment is set. We can run the tests with: +Now the environment is ready for running `POABackend` + +## Run Tests + +The first time you run the tests you will need having the Database's environment set up. Check the previous section and set the configuration in the `config/test.exs` file. + +Once the environment is set. We can run the tests with: ``` mix test diff --git a/config/config.exs b/config/config.exs index fc116b8..1f27a30 100644 --- a/config/config.exs +++ b/config/config.exs @@ -23,4 +23,12 @@ config :poa_backend, POABackend.Auth.Repo, config :mnesia, dir: 'priv/data/mnesia' # make sure this directory exists! +config :poa_backend, POABackend.Receivers.Repo, + priv: "priv/receivers", # this value is not changed + adapter: Ecto.Adapters.Postgres, + database: "poabackend_stats", + username: "postgres", + password: "postgres", + hostname: "localhost" + import_config "#{Mix.env}.exs" diff --git a/config/prod.exs b/config/prod.exs index 48ec67f..f61b63c 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -85,7 +85,7 @@ config :mnesia, dir: 'priv/data/mnesia' # make sure this directory exists! config :poa_backend, POABackend.Receivers.Repo, - priv: "priv/receivers", + priv: "priv/receivers", # this value is not changed adapter: Ecto.Adapters.Postgres, database: "poabackend_stats", username: "postgres", diff --git a/doc/.build b/doc/.build index 20cb5e2..3f67fef 100644 --- a/doc/.build +++ b/doc/.build @@ -4,12 +4,13 @@ fonts/icomoon.eot fonts/icomoon.svg fonts/icomoon.ttf fonts/icomoon.woff -dist/sidebar_items-3739fd4c82.js +dist/sidebar_items-3d14d8fe9b.js api-reference.html initial_architecture.html search.html 404.html POABackend.html +POABackend.Receivers.Repo.html POABackend.Auth.html POABackend.Auth.Guardian.Plug.html POABackend.Auth.Models.Token.html @@ -24,4 +25,6 @@ POABackend.CustomHandler.REST.html POABackend.Receiver.html POABackend.Receivers.Dashboard.html POABackend.Receivers.DynamoDB.html +POABackend.Receivers.Eth.Stats.html +POABackend.Receivers.System.Stats.html index.html diff --git a/doc/404.html b/doc/404.html index 48ca53c..f0ca307 100644 --- a/doc/404.html +++ b/doc/404.html @@ -8,7 +8,7 @@ 404 – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Auth.Guardian.Plug.html b/doc/POABackend.Auth.Guardian.Plug.html index fdbacb4..24255c0 100644 --- a/doc/POABackend.Auth.Guardian.Plug.html +++ b/doc/POABackend.Auth.Guardian.Plug.html @@ -8,7 +8,7 @@ POABackend.Auth.Guardian.Plug – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Auth.Models.Token.html b/doc/POABackend.Auth.Models.Token.html index 7a8e395..bcd2e3c 100644 --- a/doc/POABackend.Auth.Models.Token.html +++ b/doc/POABackend.Auth.Models.Token.html @@ -8,7 +8,7 @@ POABackend.Auth.Models.Token – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Auth.Models.User.html b/doc/POABackend.Auth.Models.User.html index 3afa4ef..c84b08e 100644 --- a/doc/POABackend.Auth.Models.User.html +++ b/doc/POABackend.Auth.Models.User.html @@ -8,7 +8,7 @@ POABackend.Auth.Models.User – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Auth.REST.html b/doc/POABackend.Auth.REST.html index 56f8ebf..eb186a9 100644 --- a/doc/POABackend.Auth.REST.html +++ b/doc/POABackend.Auth.REST.html @@ -8,7 +8,7 @@ POABackend.Auth.REST – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Auth.html b/doc/POABackend.Auth.html index 656f55b..3db7c08 100644 --- a/doc/POABackend.Auth.html +++ b/doc/POABackend.Auth.html @@ -8,7 +8,7 @@ POABackend.Auth – poa_backend v0.1.0 - + @@ -318,7 +318,7 @@ with that name in the database already

authenticate_admin(admin_name, password) - + View Source @@ -378,7 +378,7 @@ with that name in the database already

create_banned_token(jwt_token) - + View Source @@ -409,7 +409,7 @@ This function will extract the expiration time from the claims and store them in create_banned_token(token, expires) - + View Source @@ -504,7 +504,7 @@ expiration time as Integer.

generate_password() - + View Source @@ -533,7 +533,7 @@ expiration time as Integer.

generate_user_name() - + View Source @@ -562,7 +562,7 @@ expiration time as Integer.

generate_user_name(user_name) - + View Source @@ -620,7 +620,7 @@ expiration time as Integer.

purge_banned_tokens() - + View Source @@ -678,7 +678,7 @@ expiration time as Integer.

token_banned?(token) - + View Source @@ -736,7 +736,7 @@ expiration time as Integer.

valid_token?(jwt_token) - + View Source @@ -765,7 +765,7 @@ expiration time as Integer.

valid_user_name?(user_name) - + View Source diff --git a/doc/POABackend.CustomHandler.REST.html b/doc/POABackend.CustomHandler.REST.html index 9a7d8a5..8288db7 100644 --- a/doc/POABackend.CustomHandler.REST.html +++ b/doc/POABackend.CustomHandler.REST.html @@ -8,7 +8,7 @@ POABackend.CustomHandler.REST – poa_backend v0.1.0 - + diff --git a/doc/POABackend.CustomHandler.html b/doc/POABackend.CustomHandler.html index 5c183ff..72bb231 100644 --- a/doc/POABackend.CustomHandler.html +++ b/doc/POABackend.CustomHandler.html @@ -8,7 +8,7 @@ POABackend.CustomHandler – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Protocol.DataType.html b/doc/POABackend.Protocol.DataType.html index 4eba283..cd7e666 100644 --- a/doc/POABackend.Protocol.DataType.html +++ b/doc/POABackend.Protocol.DataType.html @@ -8,7 +8,7 @@ POABackend.Protocol.DataType – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Protocol.Message.html b/doc/POABackend.Protocol.Message.html index b2dd061..f43cfb5 100644 --- a/doc/POABackend.Protocol.Message.html +++ b/doc/POABackend.Protocol.Message.html @@ -8,7 +8,7 @@ POABackend.Protocol.Message – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Protocol.MessageType.html b/doc/POABackend.Protocol.MessageType.html index db7eef2..24713f2 100644 --- a/doc/POABackend.Protocol.MessageType.html +++ b/doc/POABackend.Protocol.MessageType.html @@ -8,7 +8,7 @@ POABackend.Protocol.MessageType – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Protocol.html b/doc/POABackend.Protocol.html index b475403..8dec9ae 100644 --- a/doc/POABackend.Protocol.html +++ b/doc/POABackend.Protocol.html @@ -8,7 +8,7 @@ POABackend.Protocol – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Receiver.html b/doc/POABackend.Receiver.html index 44a1049..792b608 100644 --- a/doc/POABackend.Receiver.html +++ b/doc/POABackend.Receiver.html @@ -8,7 +8,7 @@ POABackend.Receiver – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Receivers.Dashboard.html b/doc/POABackend.Receivers.Dashboard.html index 22bbb83..80307ca 100644 --- a/doc/POABackend.Receivers.Dashboard.html +++ b/doc/POABackend.Receivers.Dashboard.html @@ -8,7 +8,7 @@ POABackend.Receivers.Dashboard – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Receivers.DynamoDB.html b/doc/POABackend.Receivers.DynamoDB.html index 3c2ab40..c036af4 100644 --- a/doc/POABackend.Receivers.DynamoDB.html +++ b/doc/POABackend.Receivers.DynamoDB.html @@ -8,7 +8,7 @@ POABackend.Receivers.DynamoDB – poa_backend v0.1.0 - + diff --git a/doc/POABackend.Receivers.Eth.Stats.html b/doc/POABackend.Receivers.Eth.Stats.html new file mode 100644 index 0000000..003e6b8 --- /dev/null +++ b/doc/POABackend.Receivers.Eth.Stats.html @@ -0,0 +1,336 @@ + + + + + + + + POABackend.Receivers.Eth.Stats – poa_backend v0.1.0 + + + + + + + + + + + +
+ + + + +
+
+
+ + +

+ poa_backend v0.1.0 + POABackend.Receivers.Eth.Stats + + + + View Source + + +

+ + +
+

This is a Receiver Plugin which is in charge of storing the Ethereum Statistics received from the Agents in a Postgres +database. If we want to use it we have to declare it in the Config file, inside the :receivers section, ie:

+
{:store_eth_stats, POABackend.Receivers.Eth.Stats, []}
+

This Plugin uses Postgres as a backend, specifically the eth_stats table. Make sure that table exists before using +this Plugin.

+

We also need to subscribe this plugin to :ethereum_metrics metrics in the config file. For that we have to add this line +to the list in the :subscriptions section:

+
{:store_eth_stats, [:ethereum_metrics]}
+ +
+ + + +
+

+ + + Link to this section + + Summary +

+ + + +
+

+ Functions +

+
+ + +

This function is called when a Custom Handler detects a client is inactive

+
+ +
+
+ + +

In this callback is called when the Receiver process receives an erlang message

+
+ +
+
+ + +

A callback executed when the Receiver Plugin starts. + The argument is retrieved from the configuration file when the Receiver is defined + It must return {:ok, state}, that state will be keept as in GenServer and can be + retrieved in the metrics_received/3 function

+
+ +
+
+ + +

This callback will be called every time a message to the subscribed metric type arrives. It must + return the tuple {:ok, state}

+
+ +
+
+ + +

This callback is called just before the Process goes down. This is a good place for closing connections

+
+ +
+ +
+ + + + +
+ + + + + +
+

+ + + Link to this section + + Functions +

+
+ + +
+ + + Link to this function + + handle_inactive(agent_id, state) + + + + View Source + + + + +
+
+

This function is called when a Custom Handler detects a client is inactive.

+

The Custom Handler must to call explicity to POABackend.CustomHandler.publish_inactive/1 and it will publish the + inactive message to all the metrics in the system (defined in the config file).

+

Callback implementation for POABackend.Receiver.handle_inactive/2.

+ +
+
+
+ + +
+ + + Link to this function + + handle_message(message, state) + + + + View Source + + + + +
+
+

In this callback is called when the Receiver process receives an erlang message.

+

It must return {:ok, state}.

+

Callback implementation for POABackend.Receiver.handle_message/2.

+ +
+
+
+ + +
+ + + Link to this function + + init_receiver(args) + + + + View Source + + + + +
+
+

A callback executed when the Receiver Plugin starts. + The argument is retrieved from the configuration file when the Receiver is defined + It must return {:ok, state}, that state will be keept as in GenServer and can be + retrieved in the metrics_received/3 function.

+

Callback implementation for POABackend.Receiver.init_receiver/1.

+ +
+
+
+ + +
+ + + Link to this function + + metrics_received(arg1, from, state) + + + + View Source + + + + +
+
+

This callback will be called every time a message to the subscribed metric type arrives. It must + return the tuple {:ok, state}

+

Callback implementation for POABackend.Receiver.metrics_received/3.

+ +
+
+
+ + +
+ + + Link to this function + + terminate(state) + + + + View Source + + + + +
+
+

This callback is called just before the Process goes down. This is a good place for closing connections.

+

Callback implementation for POABackend.Receiver.terminate/1.

+ +
+
+ +
+ + + + +
+
+
+
+ + + + + + + + diff --git a/doc/POABackend.Receivers.Repo.html b/doc/POABackend.Receivers.Repo.html new file mode 100644 index 0000000..8caf7cb --- /dev/null +++ b/doc/POABackend.Receivers.Repo.html @@ -0,0 +1,1852 @@ + + + + + + + + POABackend.Receivers.Repo – poa_backend v0.1.0 + + + + + + + + + + + +
+ + + + +
+
+
+ + +

+ poa_backend v0.1.0 + POABackend.Receivers.Repo + + + + View Source + + +

+ + + + +
+

+ + + Link to this section + + Summary +

+ + + +
+

+ Functions +

+
+ + +

Calculate the given aggregate over the given field

+
+ +
+
+ + +

Fetches all entries from the data store matching the given query

+
+ +
+
+
+ config() +
+ +

Returns the adapter configuration stored in the :otp_app environment

+
+ +
+
+ + +

Deletes a struct using its primary key

+
+ +
+
+ + +

Same as delete/2 but returns the struct or raises if the changeset is invalid

+
+ +
+
+ + +

Deletes all entries matching the given query

+
+ +
+
+ + +

Fetches a single struct from the data store where the primary key matches the +given id

+
+ +
+
+ + +

Similar to get/3 but raises Ecto.NoResultsError if no record was found

+
+ +
+
+ + +

Fetches a single result from the query

+
+ +
+
+ + +

Similar to get_by/3 but raises Ecto.NoResultsError if no record was found

+
+ +
+
+ + +

Returns true if the current process is inside a transaction

+
+ +
+
+ + +

Inserts a struct or a changeset

+
+ +
+
+ + +

Same as insert/2 but returns the struct or raises if the changeset is invalid

+
+ +
+
+ + +

Inserts all entries into the repository

+
+ +
+
+ + +

Inserts or updates a changeset depending on whether the struct is persisted +or not

+
+ +
+
+ + +

Same as insert_or_update/2 but returns the struct or raises if the changeset +is invalid

+
+ +
+
+ + +

Loads data into a struct or a map

+
+ +
+
+ + +

Fetches a single result from the query

+
+ +
+
+ + +

Similar to one/2 but raises Ecto.NoResultsError if no record was found

+
+ +
+
+ + +

Preloads all associations on the given struct or structs

+
+ +
+
+ + +

A convenience function for SQL-based repositories that executes the given query

+
+ +
+
+ + +

A convenience function for SQL-based repositories that executes the given query

+
+ +
+
+ + +

Rolls back the current transaction

+
+ +
+
+ + +

Starts any connection pooling or supervision and return {:ok, pid} +or just :ok if nothing needs to be done

+
+ +
+
+ + +

Shuts down the repository represented by the given pid

+
+ +
+
+ + +

Returns a lazy enumerable that emits all entries from the data store +matching the given query. SQL adapters, such as Postgres and MySQL, can only +enumerate a stream inside a transaction

+
+ +
+
+ + +

Runs the given function or Ecto.Multi inside a transaction

+
+ +
+
+ + +

Updates a changeset using its primary key

+
+ +
+
+ + +

Same as update/2 but returns the struct or raises if the changeset is invalid

+
+ +
+
+ + +

Updates all entries matching the given query with the given values

+
+ +
+ +
+ + + + +
+ + + + + +
+

+ + + Link to this section + + Functions +

+
+ + + + +
+ + + Link to this function + + aggregate(queryable, aggregate, field, opts \\ []) + + + + View Source + + + + +
+
+

Calculate the given aggregate over the given field.

+

If the query has a limit, offset or distinct set, it will be +automatically wrapped in a subquery in order to return the +proper result.

+

Any preload or select in the query will be ignored in favor of +the column being aggregated.

+

The aggregation will fail if any group_by field is set.

+

+ + Options +

+ +

See the “Shared options” section at the module documentation.

+

+ + Examples +

+ +
# Returns the number of visits per blog post
+Repo.aggregate(Post, :count, :visits)
+
+# Returns the average number of visits for the top 10
+query = from Post, limit: 10
+Repo.aggregate(query, :avg, :visits)
+

Callback implementation for Ecto.Repo.aggregate/4.

+ +
+
+
+ + + + +
+ + + Link to this function + + all(queryable, opts \\ []) + + + + View Source + + + + +
+
+

Fetches all entries from the data store matching the given query.

+

May raise Ecto.QueryError if query validation fails.

+

+ + Options +

+ +
    +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). This overrides the prefix set +in the query. +
  • +
+

See the “Shared options” section at the module documentation.

+

+ + Example +

+ +
# Fetch all post titles
+query = from p in Post,
+     select: p.title
+MyRepo.all(query)
+

Callback implementation for Ecto.Repo.all/2.

+ +
+
+
+ + + +
+

Returns the adapter configuration stored in the :otp_app environment.

+

Dynamic configuration is not reflected on this value.

+

Callback implementation for Ecto.Repo.config/0.

+ +
+
+
+ + + + +
+ + + Link to this function + + delete(struct, opts \\ []) + + + + View Source + + + + +
+
+

Deletes a struct using its primary key.

+

If the struct has no primary key, Ecto.NoPrimaryKeyFieldError +will be raised.

+

It returns {:ok, struct} if the struct has been successfully +deleted or {:error, changeset} if there was a validation +or a known constraint error.

+

+ + Options +

+ +
    +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). This overrides the prefix set +in the struct. +
  • +
+

See the “Shared options” section at the module documentation.

+

+ + Example +

+ +
post = MyRepo.get!(Post, 42)
+case MyRepo.delete post do
+  {:ok, struct}       -> # Deleted with success
+  {:error, changeset} -> # Something went wrong
+end
+

Callback implementation for Ecto.Repo.delete/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + delete!(struct, opts \\ []) + + + + View Source + + + + +
+
+

Same as delete/2 but returns the struct or raises if the changeset is invalid.

+

Callback implementation for Ecto.Repo.delete!/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + delete_all(queryable, opts \\ []) + + + + View Source + + + + +
+
+

Deletes all entries matching the given query.

+

It returns a tuple containing the number of entries +and any returned result as second element. If the database +does not support RETURNING in DELETE statements or no +return result was selected, the second element will be nil.

+

+ + Options +

+ +
    +
  • :returning - selects which fields to return. When true, +returns all fields in the given struct. May be a list of +fields, where a struct is still returned but only with the +given fields. Or false, where nothing is returned (the default). +This option is not supported by all databases. +
  • +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). This overrides the prefix set +in the query. +
  • +
+

See the “Shared options” section at the module documentation for +remaining options.

+

+ + Examples +

+ +
MyRepo.delete_all(Post)
+
+from(p in Post, where: p.id < 10) |> MyRepo.delete_all
+

Callback implementation for Ecto.Repo.delete_all/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + get(queryable, id, opts \\ []) + + + + View Source + + + + +
+
+

Fetches a single struct from the data store where the primary key matches the +given id.

+

Returns nil if no result was found. If the struct in the queryable +has no or more than one primary key, it will raise an argument error.

+

+ + Options +

+ +

See the “Shared options” section at the module documentation.

+

+ + Example +

+ +
MyRepo.get(Post, 42)
+

Callback implementation for Ecto.Repo.get/3.

+ +
+
+
+ + + + +
+ + + Link to this function + + get!(queryable, id, opts \\ []) + + + + View Source + + + + +
+
+

Similar to get/3 but raises Ecto.NoResultsError if no record was found.

+

+ + Options +

+ +

See the “Shared options” section at the module documentation.

+

+ + Example +

+ +
MyRepo.get!(Post, 42)
+

Callback implementation for Ecto.Repo.get!/3.

+ +
+
+
+ + + + +
+ + + Link to this function + + get_by(queryable, clauses, opts \\ []) + + + + View Source + + + + +
+
+

Fetches a single result from the query.

+

Returns nil if no result was found.

+

+ + Options +

+ +

See the “Shared options” section at the module documentation.

+

+ + Example +

+ +
MyRepo.get_by(Post, title: "My post")
+

Callback implementation for Ecto.Repo.get_by/3.

+ +
+
+
+ + + + +
+ + + Link to this function + + get_by!(queryable, clauses, opts \\ []) + + + + View Source + + + + +
+
+

Similar to get_by/3 but raises Ecto.NoResultsError if no record was found.

+

+ + Options +

+ +

See the “Shared options” section at the module documentation.

+

+ + Example +

+ +
MyRepo.get_by!(Post, title: "My post")
+

Callback implementation for Ecto.Repo.get_by!/3.

+ +
+
+
+ + +
+ + + Link to this function + + in_transaction?() + + + + View Source + + + + +
+
+

Returns true if the current process is inside a transaction.

+

+ + Examples +

+ +
MyRepo.in_transaction?
+#=> false
+
+MyRepo.transaction(fn ->
+  MyRepo.in_transaction? #=> true
+end)
+

Callback implementation for Ecto.Repo.in_transaction?/0.

+ +
+
+
+ + + + +
+ + + Link to this function + + insert(struct, opts \\ []) + + + + View Source + + + + +
+
+

Inserts a struct or a changeset.

+

In case a struct is given, the struct is converted into a changeset +with all non-nil fields as part of the changeset.

+

In case a changeset is given, the changes in the changeset are +merged with the struct fields, and all of them are sent to the +database.

+

It returns {:ok, struct} if the struct has been successfully +inserted or {:error, changeset} if there was a validation +or a known constraint error.

+

+ + Options +

+ +
    +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). This overrides the prefix set +in the struct. +
  • +
  • :on_conflict - It may be one of :raise (the default), :nothing, +:replace_all, a keyword list of update instructions or an Ecto.Query +query for updates. See the “Upserts” section for more information. +
  • +
  • :conflict_target - Which columns to verify for conflicts. If +none is specified, the conflict target is left up to the database +and is usually made of primary keys and/or unique/exclusion constraints. +
  • +
+

See the “Shared options” section at the module documentation.

+

+ + Examples +

+ +

A typical example is calling MyRepo.insert/1 with a struct +and acting on the return value:

+
case MyRepo.insert %Post{title: "Ecto is great"} do
+  {:ok, struct}       -> # Inserted with success
+  {:error, changeset} -> # Something went wrong
+end
+

+ + Upserts +

+ +

insert_all provides upserts (update or inserts) via the :on_conflict +option. The :on_conflict option supports the following values:

+
    +
  • :raise - raises if there is a conflicting primary key or unique index +
  • +
  • :nothing - ignores the error in case of conflicts +
  • +
  • :replace_all - replace all entries in the database by the one being +currently attempted +
  • +
  • a keyword list of update instructions - such as the one given to +c:update_all/3, for example: [set: [title: "new title"]] +
  • +
  • an Ecto.Query that will act as an UPDATE statement, such as the +one given to c:update_all/3 +
  • +
+

Upserts map to “ON CONFLICT” on databases like Postgres and “ON DUPLICATE KEY” +on databases such as MySQL.

+

As an example, imagine :title is marked as a unique column in +the database:

+
# Insert it once
+{:ok, inserted} = MyRepo.insert(%Post{title: "this is unique"})
+
+# Insert with the same title but do nothing on conflicts.
+# Keep in mind that, although this returns :ok, the returned
+# struct does not reflect the data in the database. For instance,
+# in case of "on_conflict: :nothing", the returned post has no ID.
+{:ok, ignored} = MyRepo.insert(%Post{title: "this is unique"}, on_conflict: :nothing)
+assert ignored.id == nil
+
+# Now let's insert with the same title but use a query to update
+# a column on conflicts. Although this returns :ok and a struct with
+# the existing ID for successful operations, the other columns may
+# not necessarily reflect the data in the database. In fact, any
+# operation done on `:on_conflict` won't be automatically mapped to
+# the struct.
+
+# In Postgres (it requires the conflict target for updates):
+on_conflict = [set: [body: "updated"]]
+{:ok, updated} = MyRepo.insert(%Post{title: "this is unique"},
+                               on_conflict: on_conflict, conflict_target: :title)
+
+# In MySQL (conflict target is not supported):
+on_conflict = [set: [title: "updated"]]
+{:ok, updated} = MyRepo.insert(%Post{id: inserted.id, title: "updated"},
+                               on_conflict: on_conflict)
+

Callback implementation for Ecto.Repo.insert/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + insert!(struct, opts \\ []) + + + + View Source + + + + +
+
+

Same as insert/2 but returns the struct or raises if the changeset is invalid.

+

Callback implementation for Ecto.Repo.insert!/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + insert_all(schema_or_source, entries, opts \\ []) + + + + View Source + + + + +
+
+

Inserts all entries into the repository.

+

It expects a schema (MyApp.User) or a source ("users") or +both ({"users", MyApp.User}) as the first argument. The second +argument is a list of entries to be inserted, either as keyword +lists or as maps.

+

It returns a tuple containing the number of entries +and any returned result as second element. If the database +does not support RETURNING in UPDATE statements or no +return result was selected, the second element will be nil.

+

When a schema is given, the values given will be properly dumped +before being sent to the database. If the schema contains an +autogenerated ID field, it will be handled either at the adapter +or the storage layer. However any other autogenerated value, like +timestamps, won’t be autogenerated when using c:insert_all/3. +This is by design as this function aims to be a more direct way +to insert data into the database without the conveniences of +c:insert/2. This is also consistent with c:update_all/3 that +does not handle timestamps as well.

+

If a source is given, without a schema, the given fields are passed +as is to the adapter.

+

+ + Options +

+ +
    +
  • :returning - selects which fields to return. When true, +returns all fields in the given struct. May be a list of +fields, where a struct is still returned but only with the +given fields. Or false, where nothing is returned (the default). +This option is not supported by all databases. +
  • +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). +
  • +
  • :on_conflict - It may be one of :raise (the default), :nothing, +:replace_all, a keyword list of update instructions or an Ecto.Query +query for updates. See the “Upserts” section for more information. +
  • +
  • :conflict_target - Which columns to verify for conflicts. If +none is specified, the conflict target is left up to the database +and is usually made of primary keys and/or unique/exclusion constraints. +
  • +
+

See the “Shared options” section at the module documentation for +remaining options.

+

+ + Examples +

+ +
MyRepo.insert_all(Post, [[title: "My first post"], [title: "My second post"]])
+MyRepo.insert_all(Post, [%{title: "My first post"}, %{title: "My second post"}])
+

+ + Upserts +

+ +

insert_all provides upserts (update or inserts) via the :on_conflict +option. The :on_conflict option supports the following values:

+
    +
  • :raise - raises if there is a conflicting primary key or unique index +
  • +
  • :nothing - ignores the error in case of conflicts +
  • +
  • :replace_all - replace all entries in the database by the one being +currently attempted +
  • +
  • a keyword list of update instructions - such as the one given to +c:update_all/3, for example: [set: [title: "new title"]] +
  • +
  • an Ecto.Query that will act as an UPDATE statement, such as the +one given to c:update_all/3 +
  • +
+

Upserts map to “ON CONFLICT” on databases like Postgres and “ON DUPLICATE KEY” +on databases such as MySQL.

+

+ + Return values +

+ +

By default, both Postgres and MySQL return the amount of entries +inserted on insert_all. However, when the :on_conflict option +is specified, Postgres will only return a row if it was affected +while MySQL returns at least the number of entries attempted.

+

For example, if :on_conflict is set to :nothing, Postgres will +return 0 if no new entry was added while MySQL will still return +the amount of entries attempted to be inserted, even if no entry +was added. Even worse, if :on_conflict is query, MySQL will return +the number of attempted entries plus the number of entries modified +by the UPDATE query.

+

Callback implementation for Ecto.Repo.insert_all/3.

+ +
+
+
+ + + + +
+ + + Link to this function + + insert_or_update(changeset, opts \\ []) + + + + View Source + + + + +
+
+

Inserts or updates a changeset depending on whether the struct is persisted +or not.

+

The distinction whether to insert or update will be made on the +Ecto.Schema.Metadata field :state. The :state is automatically set by +Ecto when loading or building a schema.

+

Please note that for this to work, you will have to load existing structs from +the database. So even if the struct exists, this won’t work:

+
struct = %Post{id: 'existing_id', ...}
+MyRepo.insert_or_update changeset
+# => {:error, "id already exists"}
+

+ + Options +

+ +
    +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). This overrides the prefix set +in the struct. +
  • +
+

See the “Shared options” section at the module documentation.

+

+ + Example +

+ +
result =
+  case MyRepo.get(Post, id) do
+    nil  -> %Post{id: id} # Post not found, we build one
+    post -> post          # Post exists, let's use it
+  end
+  |> Post.changeset(changes)
+  |> MyRepo.insert_or_update
+
+case result do
+  {:ok, struct}       -> # Inserted or updated with success
+  {:error, changeset} -> # Something went wrong
+end
+

Callback implementation for Ecto.Repo.insert_or_update/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + insert_or_update!(changeset, opts \\ []) + + + + View Source + + + + +
+
+

Same as insert_or_update/2 but returns the struct or raises if the changeset +is invalid.

+

Callback implementation for Ecto.Repo.insert_or_update!/2.

+ +
+
+
+ + +
+ + + Link to this function + + load(schema_or_types, data) + + + + View Source + + + + +
+
+

Loads data into a struct or a map.

+

The first argument can be a schema, or a map (of types) and determines the return value: +a struct or a map, respectively.

+

The second argument data specifies fields and values that are to be loaded. +It can be a map, a keyword list, or a {fields, values} tuple. +Fields can be atoms or strings.

+

Fields that are not present in the schema (or types map) are ignored. +If any of the values has invalid type, an error is raised.

+

+ + Examples +

+ +
iex> MyRepo.load(User, %{name: "Alice", age: 25})
+%User{name: "Alice", age: 25}
+
+iex> MyRepo.load(User, [name: "Alice", age: 25])
+%User{name: "Alice", age: 25}
+

data can also take form of {fields, values}:

+
iex> MyRepo.load(User, {[:name, :age], ["Alice", 25]})
+%User{name: "Alice", age: 25, ...}
+

The first argument can also be a types map:

+
iex> types = %{name: :string, age: :integer}
+iex> MyRepo.load(types, %{name: "Alice", age: 25})
+%{name: "Alice", age: 25}
+

This function is especially useful when parsing raw query results:

+
iex> result = Ecto.Adapters.SQL.query!(MyRepo, "SELECT * FROM users", [])
+iex> Enum.map(result.rows, &MyRepo.load(User, {result.columns, &1}))
+[%User{...}, ...]
+

Callback implementation for Ecto.Repo.load/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + one(queryable, opts \\ []) + + + + View Source + + + + +
+
+

Fetches a single result from the query.

+

Returns nil if no result was found. Raises if more than one entry.

+

+ + Options +

+ +

See the “Shared options” section at the module documentation.

+

Callback implementation for Ecto.Repo.one/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + one!(queryable, opts \\ []) + + + + View Source + + + + +
+
+

Similar to one/2 but raises Ecto.NoResultsError if no record was found.

+

Raises if more than one entry.

+

+ + Options +

+ +

See the “Shared options” section at the module documentation.

+

Callback implementation for Ecto.Repo.one!/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + preload(struct_or_structs, preloads, opts \\ []) + + + + View Source + + + + +
+
+

Preloads all associations on the given struct or structs.

+

This is similar to Ecto.Query.preload/3 except it allows +you to preload structs after they have been fetched from the +database.

+

In case the association was already loaded, preload won’t attempt +to reload it.

+

+ + Options +

+ +

Besides the “Shared options” section at the module documentation, +it accepts:

+
    +
  • :force - By default, Ecto won’t preload associations that +are already loaded. By setting this option to true, any existing +association will be discarded and reloaded. +
  • +
  • :in_parallel - If the preloads must be done in parallel. It can +only be performed when we have more than one preload and the +repository is not in a transaction. Defaults to true. +
  • +
  • :prefix - the prefix to fetch preloads from. By default, queries +will use the same prefix as the one in the given collection. This +option allows the prefix to be changed. +
  • +
+

+ + Examples +

+ +
posts = Repo.preload posts, :comments
+posts = Repo.preload posts, comments: :permalinks
+posts = Repo.preload posts, comments: from(c in Comment, order_by: c.published_at)
+

Callback implementation for Ecto.Repo.preload/3.

+ +
+
+
+ + + + + + +
+ + + Link to this function + + query(sql, params \\ [], opts \\ []) + + + + View Source + + + + +
+
+

A convenience function for SQL-based repositories that executes the given query.

+

See Ecto.Adapters.SQL.query/3 for more information.

+ +
+
+
+ + + + + + +
+ + + Link to this function + + query!(sql, params \\ [], opts \\ []) + + + + View Source + + + + +
+
+

A convenience function for SQL-based repositories that executes the given query.

+

See Ecto.Adapters.SQL.query/3 for more information.

+ +
+
+
+ + +
+ + + Link to this function + + rollback(value) + + + + View Source + + + + +
+ +
rollback(term()) :: no_return()
+ +
+ +
+
+

Rolls back the current transaction.

+

The transaction will return the value given as {:error, value}.

+

Callback implementation for Ecto.Repo.rollback/1.

+ +
+
+
+ + + + +
+ + + Link to this function + + start_link(opts \\ []) + + + + View Source + + + + +
+
+

Starts any connection pooling or supervision and return {:ok, pid} +or just :ok if nothing needs to be done.

+

Returns {:error, {:already_started, pid}} if the repo is already +started or {:error, term} in case anything else goes wrong.

+

+ + Options +

+ +

See the configuration in the moduledoc for options shared between adapters, +for adapter-specific configuration see the adapter’s documentation.

+

Callback implementation for Ecto.Repo.start_link/1.

+ +
+
+
+ + + + +
+ + + Link to this function + + stop(pid, timeout \\ 5000) + + + + View Source + + + + +
+
+

Shuts down the repository represented by the given pid.

+

Callback implementation for Ecto.Repo.stop/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + stream(queryable, opts \\ []) + + + + View Source + + + + +
+
+

Returns a lazy enumerable that emits all entries from the data store +matching the given query. SQL adapters, such as Postgres and MySQL, can only +enumerate a stream inside a transaction.

+

May raise Ecto.QueryError if query validation fails.

+

+ + Options +

+ +
    +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). This overrides the prefix set +in the query

    +
  • +
  • :max_rows - The number of rows to load from the database as we stream. +It is supported at least by Postgres and MySQL and defaults to 500.

    +
  • +
+

See the “Shared options” section at the module documentation.

+

+ + Example +

+ +
# Fetch all post titles
+query = from p in Post,
+     select: p.title
+stream = MyRepo.stream(query)
+MyRepo.transaction(fn() ->
+  Enum.to_list(stream)
+end)
+

Callback implementation for Ecto.Repo.stream/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + transaction(fun_or_multi, opts \\ []) + + + + View Source + + + + +
+
+

Runs the given function or Ecto.Multi inside a transaction.

+

+ + Use with function +

+ +

If an unhandled error occurs the transaction will be rolled back +and the error will bubble up from the transaction function. +If no error occurred the transaction will be committed when the +function returns. A transaction can be explicitly rolled back +by calling rollback/1, this will immediately leave the function +and return the value given to rollback as {:error, value}.

+

A successful transaction returns the value returned by the function +wrapped in a tuple as {:ok, value}.

+

If transaction/2 is called inside another transaction, the function +is simply executed, without wrapping the new transaction call in any +way. If there is an error in the inner transaction and the error is +rescued, or the inner transaction is rolled back, the whole outer +transaction is marked as tainted, guaranteeing nothing will be committed.

+

+ + Use with Ecto.Multi +

+ +

Besides functions transaction can be used with an Ecto.Multi struct. +Transaction will be started, all operations applied and in case of +success committed returning {:ok, changes}. In case of any errors +the transaction will be rolled back and +{:error, failed_operation, failed_value, changes_so_far} will be +returned.

+

You can read more about using transactions with Ecto.Multi as well as +see some examples in the Ecto.Multi documentation.

+

+ + Options +

+ +

See the “Shared options” section at the module documentation.

+

+ + Examples +

+ +
MyRepo.transaction(fn ->
+  MyRepo.update!(%{alice | balance: alice.balance - 10})
+  MyRepo.update!(%{bob | balance: bob.balance + 10})
+end)
+
+# Roll back a transaction explicitly
+MyRepo.transaction(fn ->
+  p = MyRepo.insert!(%Post{})
+  if not Editor.post_allowed?(p) do
+    MyRepo.rollback(:posting_not_allowed)
+  end
+end)
+
+# With Ecto.Multi
+Ecto.Multi.new
+|> Ecto.Multi.insert(:post, %Post{})
+|> MyRepo.transaction
+

Callback implementation for Ecto.Repo.transaction/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + update(struct, opts \\ []) + + + + View Source + + + + +
+
+

Updates a changeset using its primary key.

+

A changeset is required as it is the only mechanism for +tracking dirty changes. Only the fields present in the changes part +of the changeset are sent to the database. Any other, in-memory +changes done to the schema are ignored.

+

If the struct has no primary key, Ecto.NoPrimaryKeyFieldError +will be raised.

+

It returns {:ok, struct} if the struct has been successfully +updated or {:error, changeset} if there was a validation +or a known constraint error.

+

+ + Options +

+ +

Besides the “Shared options” section at the module documentation, +it accepts:

+
    +
  • :force - By default, if there are no changes in the changeset, +update!/2 is a no-op. By setting this option to true, update +callbacks will always be executed, even if there are no changes +(including timestamps). +
  • +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). This overrides the prefix set +in the struct. +
  • +
+

+ + Example +

+ +
post = MyRepo.get!(Post, 42)
+post = Ecto.Changeset.change post, title: "New title"
+case MyRepo.update post do
+  {:ok, struct}       -> # Updated with success
+  {:error, changeset} -> # Something went wrong
+end
+

Callback implementation for Ecto.Repo.update/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + update!(struct, opts \\ []) + + + + View Source + + + + +
+
+

Same as update/2 but returns the struct or raises if the changeset is invalid.

+

Callback implementation for Ecto.Repo.update!/2.

+ +
+
+
+ + + + +
+ + + Link to this function + + update_all(queryable, updates, opts \\ []) + + + + View Source + + + + +
+
+

Updates all entries matching the given query with the given values.

+

It returns a tuple containing the number of entries +and any returned result as second element. If the database +does not support RETURNING in UPDATE statements or no +return result was selected, the second element will be nil.

+

Keep in mind this update_all will not update autogenerated +fields like the updated_at columns.

+

See Ecto.Query.update/3 for update operations that can be +performed on fields.

+

+ + Options +

+ +
    +
  • :returning - selects which fields to return. When true, +returns all fields in the given struct. May be a list of +fields, where a struct is still returned but only with the +given fields. Or false, where nothing is returned (the default). +This option is not supported by all databases. +
  • +
  • :prefix - The prefix to run the query on (such as the schema path +in Postgres or the database in MySQL). This overrides the prefix set +in the query. +
  • +
+

See the “Shared options” section at the module documentation for +remaining options.

+

+ + Examples +

+ +
MyRepo.update_all(Post, set: [title: "New title"])
+
+MyRepo.update_all(Post, inc: [visits: 1])
+
+from(p in Post, where: p.id < 10)
+|> MyRepo.update_all(set: [title: "New title"])
+
+from(p in Post, where: p.id < 10, update: [set: [title: "New title"]])
+|> MyRepo.update_all([])
+
+from(p in Post, where: p.id < 10, update: [set: [title: fragment("?", new_title)]])
+|> MyRepo.update_all([])
+

Callback implementation for Ecto.Repo.update_all/3.

+ +
+
+ +
+ + + + +
+
+
+
+ + + + + + + + diff --git a/doc/POABackend.Receivers.System.Stats.html b/doc/POABackend.Receivers.System.Stats.html new file mode 100644 index 0000000..3398ffe --- /dev/null +++ b/doc/POABackend.Receivers.System.Stats.html @@ -0,0 +1,336 @@ + + + + + + + + POABackend.Receivers.System.Stats – poa_backend v0.1.0 + + + + + + + + + + + +
+ + + + +
+
+
+ + +

+ poa_backend v0.1.0 + POABackend.Receivers.System.Stats + + + + View Source + + +

+ + +
+

This is a Receiver Plugin which is in charge of storing the System Metrics received from the Agents in a Postgres +database. If we want to use it we have to declare it in the Config file, inside the :receivers section, ie:

+
{:store_system_stats, POABackend.Receivers.System.Stats, []}
+

This Plugin uses Postgres as a backend, specifically the system_stats table. Make sure that table exists before using +this Plugin.

+

We also need to subscribe this plugin to :system_metrics metrics in the config file. For that we have to add this line +to the list in the :subscriptions section:

+
{:store_system_stats, [:system_metrics]}
+ +
+ + + +
+

+ + + Link to this section + + Summary +

+ + + +
+

+ Functions +

+
+ + +

This function is called when a Custom Handler detects a client is inactive

+
+ +
+
+ + +

In this callback is called when the Receiver process receives an erlang message

+
+ +
+
+ + +

A callback executed when the Receiver Plugin starts. + The argument is retrieved from the configuration file when the Receiver is defined + It must return {:ok, state}, that state will be keept as in GenServer and can be + retrieved in the metrics_received/3 function

+
+ +
+
+ + +

This callback will be called every time a message to the subscribed metric type arrives. It must + return the tuple {:ok, state}

+
+ +
+
+ + +

This callback is called just before the Process goes down. This is a good place for closing connections

+
+ +
+ +
+ + + + +
+ + + + + +
+

+ + + Link to this section + + Functions +

+
+ + +
+ + + Link to this function + + handle_inactive(agent_id, state) + + + + View Source + + + + +
+
+

This function is called when a Custom Handler detects a client is inactive.

+

The Custom Handler must to call explicity to POABackend.CustomHandler.publish_inactive/1 and it will publish the + inactive message to all the metrics in the system (defined in the config file).

+

Callback implementation for POABackend.Receiver.handle_inactive/2.

+ +
+
+
+ + +
+ + + Link to this function + + handle_message(message, state) + + + + View Source + + + + +
+
+

In this callback is called when the Receiver process receives an erlang message.

+

It must return {:ok, state}.

+

Callback implementation for POABackend.Receiver.handle_message/2.

+ +
+
+
+ + +
+ + + Link to this function + + init_receiver(args) + + + + View Source + + + + +
+
+

A callback executed when the Receiver Plugin starts. + The argument is retrieved from the configuration file when the Receiver is defined + It must return {:ok, state}, that state will be keept as in GenServer and can be + retrieved in the metrics_received/3 function.

+

Callback implementation for POABackend.Receiver.init_receiver/1.

+ +
+
+
+ + +
+ + + Link to this function + + metrics_received(arg1, from, state) + + + + View Source + + + + +
+
+

This callback will be called every time a message to the subscribed metric type arrives. It must + return the tuple {:ok, state}

+

Callback implementation for POABackend.Receiver.metrics_received/3.

+ +
+
+
+ + +
+ + + Link to this function + + terminate(state) + + + + View Source + + + + +
+
+

This callback is called just before the Process goes down. This is a good place for closing connections.

+

Callback implementation for POABackend.Receiver.terminate/1.

+ +
+
+ +
+ + + + +
+
+
+
+ + + + + + + + diff --git a/doc/POABackend.html b/doc/POABackend.html index eaee582..4ec9fc5 100644 --- a/doc/POABackend.html +++ b/doc/POABackend.html @@ -8,7 +8,7 @@ POABackend – poa_backend v0.1.0 - + @@ -100,18 +100,52 @@
mix deps.get
 mix docs

That command will create a doc/ folder with the actual Documentation.

+

+ + Configuring Databases for first time +

+ +

POABackend uses many Databases. For Authentication we use Mnesia as a local database and for some receivers which require storage we use Postgres. All databases are managed on top of Ecto a widly used database wrapper for Elixir projects.

+

For this reason we have to set the databases before running the POABackend for the first time.

+ +
config :mnesia,
+  dir: 'your/local/path' # make sure this directory exists!
+ +
config :poa_backend, POABackend.Receivers.Repo,
+  priv: "priv/receivers", # this value is not changed
+  adapter: Ecto.Adapters.Postgres,
+  database: "poabackend_stats",
+  username: "postgres",
+  password: "postgres",
+  hostname: "localhost"
+

The important fields here are database, username, password and hostname. The rest of values must remain exactly as the example.

+

Once we have set the database configuration we have to create and migrate the databases, in order to do that we should be in the root of the project and run:

+ +
MIX_ENV=prod mix ecto.create
+MIX_ENV=prod mix ecto.migrate
+ +
MIX_ENV=test mix ecto.create
+MIX_ENV=test mix ecto.migrate
+

Now the environment is ready for running POABackend

Run Tests

-

POABackend uses Mnesia as a local database with Ecto. In order to have this running we have to create a folder where Mnesia will store our data. In order to do that we have to define it in the config/test.exs file like this:

-
config :mnesia,
-  dir: 'your/local/path' # make sure this directory exists!
-

once we have the path defined we have to create the database (those commands must be run only once if you are going to use always this same path for testing). In your root folder run:

-
MIX_ENV=test mix ecto.create
-MIX_ENV=test mix ecto.migrate
-

Now the environment is set. We can run the tests with:

+

The first time you run the tests you will need having the Database’s environment set up. Check the previous section and set the configuration in the config/test.exs file.

+

Once the environment is set. We can run the tests with:

mix test

POABackend comes also with a code analysis tool Credo and a types checker tool Dialyxir. In order to run them we have to run

mix credo
diff --git a/doc/api-reference.html b/doc/api-reference.html
index 8029746..aa1a3be 100644
--- a/doc/api-reference.html
+++ b/doc/api-reference.html
@@ -8,7 +8,7 @@
     API Reference – poa_backend v0.1.0
     
     
-    
+    
     
     
     
@@ -195,6 +195,26 @@ Those Admins are defined in the Config (ie prod.exs)
     

This is a Receiver Plugin which stores the received Ethereum Blocks in DynamoDB

+ +
+ + +

This is a Receiver Plugin which is in charge of storing the Ethereum Statistics received from the Agents in a Postgres +database. If we want to use it we have to declare it in the Config file, inside the :receivers section, ie

+
+ +
+ +
+ + +

This is a Receiver Plugin which is in charge of storing the System Metrics received from the Agents in a Postgres +database. If we want to use it we have to declare it in the Config file, inside the :receivers section, ie

+
+
diff --git a/doc/dist/sidebar_items-3739fd4c82.js b/doc/dist/sidebar_items-3739fd4c82.js deleted file mode 100644 index f9f2f9a..0000000 --- a/doc/dist/sidebar_items-3739fd4c82.js +++ /dev/null @@ -1 +0,0 @@ -sidebarNodes={"extras":[{"id":"api-reference","title":"API Reference","group":"","headers":[{"id":"Modules","anchor":"modules"},{"id":"POA Protocol","anchor":"poa-protocol"}]},{"id":"initial_architecture","title":"Initial Architecture","group":"","headers":[]}],"exceptions":[],"modules":[{"id":"POABackend","title":"POABackend","group":""},{"id":"POABackend.Auth","title":"POABackend.Auth","group":"POA Auth","functions":[{"id":"activate_user/1","anchor":"activate_user/1"},{"id":"authenticate_admin/2","anchor":"authenticate_admin/2"},{"id":"authenticate_user/2","anchor":"authenticate_user/2"},{"id":"create_banned_token/1","anchor":"create_banned_token/1"},{"id":"create_banned_token/2","anchor":"create_banned_token/2"},{"id":"create_user/3","anchor":"create_user/3"},{"id":"deactivate_user/1","anchor":"deactivate_user/1"},{"id":"generate_password/0","anchor":"generate_password/0"},{"id":"generate_user_name/0","anchor":"generate_user_name/0"},{"id":"generate_user_name/1","anchor":"generate_user_name/1"},{"id":"get_user/1","anchor":"get_user/1"},{"id":"purge_banned_tokens/0","anchor":"purge_banned_tokens/0"},{"id":"remove_user/1","anchor":"remove_user/1"},{"id":"token_banned?/1","anchor":"token_banned?/1"},{"id":"user_active?/1","anchor":"user_active?/1"},{"id":"valid_token?/1","anchor":"valid_token?/1"},{"id":"valid_user_name?/1","anchor":"valid_user_name?/1"}]},{"id":"POABackend.Auth.Guardian.Plug","title":"POABackend.Auth.Guardian.Plug","group":"POA Auth","functions":[{"id":"authenticated?/2","anchor":"authenticated?/2"},{"id":"current_claims/2","anchor":"current_claims/2"},{"id":"current_resource/2","anchor":"current_resource/2"},{"id":"current_token/2","anchor":"current_token/2"},{"id":"implementation/0","anchor":"implementation/0"},{"id":"put_current_claims/3","anchor":"put_current_claims/3"},{"id":"put_current_resource/3","anchor":"put_current_resource/3"},{"id":"put_current_token/3","anchor":"put_current_token/3"},{"id":"remember_me/4","anchor":"remember_me/4"},{"id":"remember_me_from_token/4","anchor":"remember_me_from_token/4"},{"id":"sign_in/4","anchor":"sign_in/4"},{"id":"sign_out/2","anchor":"sign_out/2"}]},{"id":"POABackend.Auth.Models.Token","title":"POABackend.Auth.Models.Token","group":"POA Auth","functions":[{"id":"new/2","anchor":"new/2"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.Auth.Models.User","title":"POABackend.Auth.Models.User","group":"POA Auth","functions":[{"id":"changeset/2","anchor":"changeset/2"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.Auth.REST","title":"POABackend.Auth.REST","group":"POA Auth"},{"id":"POABackend.Protocol","title":"POABackend.Protocol","group":"POA Protocol"},{"id":"POABackend.Protocol.DataType","title":"POABackend.Protocol.DataType","group":"POA Protocol","types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.Protocol.Message","title":"POABackend.Protocol.Message","group":"POA Protocol","functions":[{"id":"assign/3","anchor":"assign/3"},{"id":"new/0","anchor":"new/0"},{"id":"new/4","anchor":"new/4"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.Protocol.MessageType","title":"POABackend.Protocol.MessageType","group":"POA Protocol","types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.CustomHandler","title":"POABackend.CustomHandler","group":"Custom Handler","callbacks":[{"id":"child_spec/1","anchor":"c:child_spec/1"}],"functions":[{"id":"publish_inactive/1","anchor":"publish_inactive/1"},{"id":"send_to_receivers/1","anchor":"send_to_receivers/1"}]},{"id":"POABackend.CustomHandler.REST","title":"POABackend.CustomHandler.REST","group":"Custom Handler","functions":[{"id":"ping_monitor/1","anchor":"ping_monitor/1"}]},{"id":"POABackend.Receiver","title":"POABackend.Receiver","group":"Receivers","callbacks":[{"id":"handle_inactive/2","anchor":"c:handle_inactive/2"},{"id":"handle_message/2","anchor":"c:handle_message/2"},{"id":"init_receiver/1","anchor":"c:init_receiver/1"},{"id":"metrics_received/3","anchor":"c:metrics_received/3"},{"id":"terminate/1","anchor":"c:terminate/1"}]},{"id":"POABackend.Receivers.Dashboard","title":"POABackend.Receivers.Dashboard","group":"Receivers","functions":[{"id":"handle_inactive/2","anchor":"handle_inactive/2"},{"id":"handle_message/2","anchor":"handle_message/2"},{"id":"init_receiver/1","anchor":"init_receiver/1"},{"id":"metrics_received/3","anchor":"metrics_received/3"},{"id":"terminate/1","anchor":"terminate/1"}]},{"id":"POABackend.Receivers.DynamoDB","title":"POABackend.Receivers.DynamoDB","group":"Receivers","functions":[{"id":"handle_inactive/2","anchor":"handle_inactive/2"},{"id":"handle_message/2","anchor":"handle_message/2"},{"id":"init_receiver/1","anchor":"init_receiver/1"},{"id":"metrics_received/3","anchor":"metrics_received/3"},{"id":"terminate/1","anchor":"terminate/1"}]}],"tasks":[]} \ No newline at end of file diff --git a/doc/dist/sidebar_items-3d14d8fe9b.js b/doc/dist/sidebar_items-3d14d8fe9b.js new file mode 100644 index 0000000..dc3a95b --- /dev/null +++ b/doc/dist/sidebar_items-3d14d8fe9b.js @@ -0,0 +1 @@ +sidebarNodes={"extras":[{"id":"api-reference","title":"API Reference","group":"","headers":[{"id":"Modules","anchor":"modules"},{"id":"POA Protocol","anchor":"poa-protocol"}]},{"id":"initial_architecture","title":"Initial Architecture","group":"","headers":[]}],"exceptions":[],"modules":[{"id":"POABackend","title":"POABackend","group":""},{"id":"POABackend.Receivers.Repo","title":"POABackend.Receivers.Repo","group":"","functions":[{"id":"aggregate/4","anchor":"aggregate/4"},{"id":"all/2","anchor":"all/2"},{"id":"config/0","anchor":"config/0"},{"id":"delete/2","anchor":"delete/2"},{"id":"delete!/2","anchor":"delete!/2"},{"id":"delete_all/2","anchor":"delete_all/2"},{"id":"get/3","anchor":"get/3"},{"id":"get!/3","anchor":"get!/3"},{"id":"get_by/3","anchor":"get_by/3"},{"id":"get_by!/3","anchor":"get_by!/3"},{"id":"in_transaction?/0","anchor":"in_transaction?/0"},{"id":"insert/2","anchor":"insert/2"},{"id":"insert!/2","anchor":"insert!/2"},{"id":"insert_all/3","anchor":"insert_all/3"},{"id":"insert_or_update/2","anchor":"insert_or_update/2"},{"id":"insert_or_update!/2","anchor":"insert_or_update!/2"},{"id":"load/2","anchor":"load/2"},{"id":"one/2","anchor":"one/2"},{"id":"one!/2","anchor":"one!/2"},{"id":"preload/3","anchor":"preload/3"},{"id":"query/3","anchor":"query/3"},{"id":"query!/3","anchor":"query!/3"},{"id":"rollback/1","anchor":"rollback/1"},{"id":"start_link/1","anchor":"start_link/1"},{"id":"stop/2","anchor":"stop/2"},{"id":"stream/2","anchor":"stream/2"},{"id":"transaction/2","anchor":"transaction/2"},{"id":"update/2","anchor":"update/2"},{"id":"update!/2","anchor":"update!/2"},{"id":"update_all/3","anchor":"update_all/3"}]},{"id":"POABackend.Auth","title":"POABackend.Auth","group":"POA Auth","functions":[{"id":"activate_user/1","anchor":"activate_user/1"},{"id":"authenticate_admin/2","anchor":"authenticate_admin/2"},{"id":"authenticate_user/2","anchor":"authenticate_user/2"},{"id":"create_banned_token/1","anchor":"create_banned_token/1"},{"id":"create_banned_token/2","anchor":"create_banned_token/2"},{"id":"create_user/3","anchor":"create_user/3"},{"id":"deactivate_user/1","anchor":"deactivate_user/1"},{"id":"generate_password/0","anchor":"generate_password/0"},{"id":"generate_user_name/0","anchor":"generate_user_name/0"},{"id":"generate_user_name/1","anchor":"generate_user_name/1"},{"id":"get_user/1","anchor":"get_user/1"},{"id":"purge_banned_tokens/0","anchor":"purge_banned_tokens/0"},{"id":"remove_user/1","anchor":"remove_user/1"},{"id":"token_banned?/1","anchor":"token_banned?/1"},{"id":"user_active?/1","anchor":"user_active?/1"},{"id":"valid_token?/1","anchor":"valid_token?/1"},{"id":"valid_user_name?/1","anchor":"valid_user_name?/1"}]},{"id":"POABackend.Auth.Guardian.Plug","title":"POABackend.Auth.Guardian.Plug","group":"POA Auth","functions":[{"id":"authenticated?/2","anchor":"authenticated?/2"},{"id":"current_claims/2","anchor":"current_claims/2"},{"id":"current_resource/2","anchor":"current_resource/2"},{"id":"current_token/2","anchor":"current_token/2"},{"id":"implementation/0","anchor":"implementation/0"},{"id":"put_current_claims/3","anchor":"put_current_claims/3"},{"id":"put_current_resource/3","anchor":"put_current_resource/3"},{"id":"put_current_token/3","anchor":"put_current_token/3"},{"id":"remember_me/4","anchor":"remember_me/4"},{"id":"remember_me_from_token/4","anchor":"remember_me_from_token/4"},{"id":"sign_in/4","anchor":"sign_in/4"},{"id":"sign_out/2","anchor":"sign_out/2"}]},{"id":"POABackend.Auth.Models.Token","title":"POABackend.Auth.Models.Token","group":"POA Auth","functions":[{"id":"new/2","anchor":"new/2"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.Auth.Models.User","title":"POABackend.Auth.Models.User","group":"POA Auth","functions":[{"id":"changeset/2","anchor":"changeset/2"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.Auth.REST","title":"POABackend.Auth.REST","group":"POA Auth"},{"id":"POABackend.Protocol","title":"POABackend.Protocol","group":"POA Protocol"},{"id":"POABackend.Protocol.DataType","title":"POABackend.Protocol.DataType","group":"POA Protocol","types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.Protocol.Message","title":"POABackend.Protocol.Message","group":"POA Protocol","functions":[{"id":"assign/3","anchor":"assign/3"},{"id":"new/0","anchor":"new/0"},{"id":"new/4","anchor":"new/4"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.Protocol.MessageType","title":"POABackend.Protocol.MessageType","group":"POA Protocol","types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"POABackend.CustomHandler","title":"POABackend.CustomHandler","group":"Custom Handler","callbacks":[{"id":"child_spec/1","anchor":"c:child_spec/1"}],"functions":[{"id":"publish_inactive/1","anchor":"publish_inactive/1"},{"id":"send_to_receivers/1","anchor":"send_to_receivers/1"}]},{"id":"POABackend.CustomHandler.REST","title":"POABackend.CustomHandler.REST","group":"Custom Handler","functions":[{"id":"ping_monitor/1","anchor":"ping_monitor/1"}]},{"id":"POABackend.Receiver","title":"POABackend.Receiver","group":"Receivers","callbacks":[{"id":"handle_inactive/2","anchor":"c:handle_inactive/2"},{"id":"handle_message/2","anchor":"c:handle_message/2"},{"id":"init_receiver/1","anchor":"c:init_receiver/1"},{"id":"metrics_received/3","anchor":"c:metrics_received/3"},{"id":"terminate/1","anchor":"c:terminate/1"}]},{"id":"POABackend.Receivers.Dashboard","title":"POABackend.Receivers.Dashboard","group":"Receivers","functions":[{"id":"handle_inactive/2","anchor":"handle_inactive/2"},{"id":"handle_message/2","anchor":"handle_message/2"},{"id":"init_receiver/1","anchor":"init_receiver/1"},{"id":"metrics_received/3","anchor":"metrics_received/3"},{"id":"terminate/1","anchor":"terminate/1"}]},{"id":"POABackend.Receivers.DynamoDB","title":"POABackend.Receivers.DynamoDB","group":"Receivers","functions":[{"id":"handle_inactive/2","anchor":"handle_inactive/2"},{"id":"handle_message/2","anchor":"handle_message/2"},{"id":"init_receiver/1","anchor":"init_receiver/1"},{"id":"metrics_received/3","anchor":"metrics_received/3"},{"id":"terminate/1","anchor":"terminate/1"}]},{"id":"POABackend.Receivers.Eth.Stats","title":"POABackend.Receivers.Eth.Stats","group":"Receivers","functions":[{"id":"handle_inactive/2","anchor":"handle_inactive/2"},{"id":"handle_message/2","anchor":"handle_message/2"},{"id":"init_receiver/1","anchor":"init_receiver/1"},{"id":"metrics_received/3","anchor":"metrics_received/3"},{"id":"terminate/1","anchor":"terminate/1"}]},{"id":"POABackend.Receivers.System.Stats","title":"POABackend.Receivers.System.Stats","group":"Receivers","functions":[{"id":"handle_inactive/2","anchor":"handle_inactive/2"},{"id":"handle_message/2","anchor":"handle_message/2"},{"id":"init_receiver/1","anchor":"init_receiver/1"},{"id":"metrics_received/3","anchor":"metrics_received/3"},{"id":"terminate/1","anchor":"terminate/1"}]}],"tasks":[]} \ No newline at end of file diff --git a/doc/initial_architecture.html b/doc/initial_architecture.html index 2381c92..56786bf 100644 --- a/doc/initial_architecture.html +++ b/doc/initial_architecture.html @@ -8,7 +8,7 @@ Initial Architecture – poa_backend v0.1.0 - + diff --git a/doc/search.html b/doc/search.html index 1c12f43..ade5563 100644 --- a/doc/search.html +++ b/doc/search.html @@ -8,7 +8,7 @@ Search – poa_backend v0.1.0 - + diff --git a/lib/poa_backend.ex b/lib/poa_backend.ex index eb7f434..8ed5844 100644 --- a/lib/poa_backend.ex +++ b/lib/poa_backend.ex @@ -21,23 +21,56 @@ defmodule POABackend do That command will create a `doc/` folder with the actual Documentation. - ## Run Tests + ## Configuring Databases for first time - `POABackend` uses [Mnesia](http://erlang.org/doc/man/mnesia.html) as a local database with [Ecto](https://hexdocs.pm/ecto/Ecto.html). In order to have this running we have to create a folder where `Mnesia` will store our data. In order to do that we have to define it in the `config/test.exs` file like this: + `POABackend` uses many Databases. For Authentication we use [Mnesia](http://erlang.org/doc/man/mnesia.html) as a local database and for some receivers which require storage we use Postgres. All databases are managed on top of [Ecto](https://hexdocs.pm/ecto/Ecto.html) a widly used database wrapper for Elixir projects. + + For this reason we have to set the databases before running the `POABackend` for the first time. + + - Auth Database (Mnesia): Setting up Mnesia is easy since it is working localy and is built in the Erlang Virtual Machine. We only have to say "where" we are going to store the database's files. In order to do that we have to add the configuration to the config file (`prod.exs` or `test.exs` depending if you want to run tests or production) ``` config :mnesia, dir: 'your/local/path' # make sure this directory exists! ``` - once we have the path defined we have to create the database (those commands must be run only once if you are going to use always this same path for testing). In your root folder run: + - Receivers Database (Postgres): This is a little more complex than Mnesia. We need a Postgres instance running somewhere and we have to add the config to the config files + + ``` + config :poa_backend, POABackend.Receivers.Repo, + priv: "priv/receivers", # this value is not changed + adapter: Ecto.Adapters.Postgres, + database: "poabackend_stats", + username: "postgres", + password: "postgres", + hostname: "localhost" + ``` + + The important fields here are `database`, `username`, `password` and `hostname`. The rest of values must remain exactly as the example. + + Once we have set the database configuration we have to create and migrate the databases, in order to do that we should be in the root of the project and run: + + - for production + + ``` + MIX_ENV=prod mix ecto.create + MIX_ENV=prod mix ecto.migrate + ``` + + - for test ``` MIX_ENV=test mix ecto.create MIX_ENV=test mix ecto.migrate ``` - Now the environment is set. We can run the tests with: + Now the environment is ready for running `POABackend` + + ## Run Tests + + The first time you run the tests you will need having the Database's environment set up. Check the previous section and set the configuration in the `config/test.exs` file. + + Once the environment is set. We can run the tests with: ``` mix test diff --git a/lib/poa_backend/receivers/eth/stats.ex b/lib/poa_backend/receivers/eth/stats.ex index b2e23bf..c2407da 100644 --- a/lib/poa_backend/receivers/eth/stats.ex +++ b/lib/poa_backend/receivers/eth/stats.ex @@ -1,7 +1,20 @@ defmodule POABackend.Receivers.Eth.Stats do use POABackend.Receiver - @moduledoc false + @moduledoc """ + This is a Receiver Plugin which is in charge of storing the Ethereum Statistics received from the Agents in a Postgres + database. If we want to use it we have to declare it in the Config file, inside the `:receivers` section, ie: + + {:store_eth_stats, POABackend.Receivers.Eth.Stats, []} + + This Plugin uses Postgres as a backend, specifically the `eth_stats` table. Make sure that table exists before using + this Plugin. + + We also need to subscribe this plugin to `:ethereum_metrics` metrics in the config file. For that we have to add this line + to the list in the `:subscriptions` section: + + {:store_eth_stats, [:ethereum_metrics]} + """ alias POABackend.Protocol.Message alias POABackend.Receivers.Models.EthStats diff --git a/lib/poa_backend/receivers/system/stats.ex b/lib/poa_backend/receivers/system/stats.ex index 29e1638..826e37d 100644 --- a/lib/poa_backend/receivers/system/stats.ex +++ b/lib/poa_backend/receivers/system/stats.ex @@ -1,7 +1,20 @@ defmodule POABackend.Receivers.System.Stats do use POABackend.Receiver - @moduledoc false + @moduledoc """ + This is a Receiver Plugin which is in charge of storing the System Metrics received from the Agents in a Postgres + database. If we want to use it we have to declare it in the Config file, inside the `:receivers` section, ie: + + {:store_system_stats, POABackend.Receivers.System.Stats, []} + + This Plugin uses Postgres as a backend, specifically the `system_stats` table. Make sure that table exists before using + this Plugin. + + We also need to subscribe this plugin to `:system_metrics` metrics in the config file. For that we have to add this line + to the list in the `:subscriptions` section: + + {:store_system_stats, [:system_metrics]} + """ alias POABackend.Protocol.Message alias POABackend.Receivers.Models.SystemStats diff --git a/mix.exs b/mix.exs index 137fa58..9fb6c22 100644 --- a/mix.exs +++ b/mix.exs @@ -88,7 +88,9 @@ defmodule POABackend.MixProject do "Receivers": [ POABackend.Receiver, POABackend.Receivers.DynamoDB, - POABackend.Receivers.Dashboard + POABackend.Receivers.Dashboard, + POABackend.Receivers.System.Stats, + POABackend.Receivers.Eth.Stats ] ] ]