diff --git a/.gitignore b/.gitignore
index 7249abc..6a5c62d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,5 +14,4 @@ erl_crash.dump
*.secret.exs
dev.exs
.env
-mix.lock
todo.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd073b7..388dd6f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,22 +1,124 @@
# Changelog
+
+## v0.4.0
+
+- Bump dependencies and remove many deprecations for elixir 1.5+
+
+## v0.3.6
+
+[changes]
+- Remove `mod: []` as this caused some release warnings. No Module Supervisor
+is started by default.
+- bump version of `:httpipe_adapters_hackney`
+
+## v0.3.5
+
+[changes]
+- Added `:floki` to list of applications to remove
+warnings when making a release.
+
+## v0.3.4
+
+[bug fix]
+- Added `:poison` to list of applications to remove
+warnings when making a release.
+
+## v0.3.3
+
+[bug fix]
+- Fix error `function :hackney.execute_request/5 is undefined or private` when
+running `mix ovh` task by setting the adapter correctly
+
+
+## v0.3.2
+
+[security fix]
+- Remove dependency on `Og`. A potential security issue existed for `og` versions below `1.0.0`. See
+[Code.eval_string/3](https://github.com/elixir-lang/elixir/commit/f1daca5be78e6a466745ba2cdc66d9787c3cf47f#diff-da151e1c1d9b535259a2385407272c9eR107).
+As `Og` was removed anyways as a dependency in `v0.3.2` of `ex_ovh`, this issue is resolved.
+
+[changes]
+- Add default adapter `hackney` to the mix tasks.
+
+[bug fix]
+- Fix setting the query string bug (typo) - `url.encode_query(qs_map)` -> `URI.encode_query(qs_map)`
+- Problem with `Body.apply()` being called in the wrong place
+- Fix `get_prices` in the `Cloud` Request build functions
+
+[enhancements]
+- Add `prepare_request/2` function - prepares the request without sending it. Applies standard transformations.
+
+## v0.3.1
+
+***Security Warning: Versions of `ex_ovh` less than `0.3.2` are deprecated and should not be used
+due to the inclusion of older releases of the dependency `Og` Use versions `0.3.2` or above of `ex_ovh` instead***
+
+[changes]
+- Update some dependencies
+- Relax versioning of some dependencies
+- Include `mix.lock` in version control
+- Add new file `docs/usage.md` with examples on using the api
+- Remove dependency on `morph` - use `Macro.underscore` instead.
+- Reduce depency base - use `:hackney` only
+- remove `Cloud.Cloudstorage` module and place all functions in `Cloud` module ***(breaking change)***
+- change naming of various modules to reduce length ***(breaking change)***
+- change the docs to reflect the move to [httpipe](https://hex.pm/packages/httpipe)
+- with the use of [httpipe](https://hex.pm/packages/httpipe), the abstraction changes from `Query` to `Request` -
+this is essentially a name change only.
+
+[enhancements]
+- Use [httpipe](https://hex.pm/packages/httpipe) and the corresponding hackney adapter.
+- Remove the abstractions based on `Query` and `HTTPQuery` and in it's place use a similar abstraction
+in the third party library [httpipe](https://hex.pm/packages/httpipe)
+
+
+## v0.2
+
+***Security Warning: Versions of `ex_ovh` less than `0.3.2` are deprecated and should not be used
+due to the inclusion of older releases of the dependency `Og` Use versions `0.3.2` or above of `ex_ovh` instead***
+
+[enhancements]
+- Update some dependencies
+- Update mix task so that it will handle activated 2FA on OVH accounts
+- Simplify the readme documentation
+
+[bug fixes]
+- Fix bug in mix task causing it to fail
+- Fix bug in ex_ovh config file where list could not be printed inside "#{}" - causing application to crash
+
+[neutral changes]
+- Merge docs back into the original module files
+
## v0.1.3
+***Security Warning: Versions of `ex_ovh` less than `0.3.2` are deprecated and should not be used
+due to the inclusion of older releases of the dependency `Og` Use versions `0.3.2` or above of `ex_ovh` instead***
+
- Improve the `mix ovh` docs to better illustrate how to create an application and setup access rules.
## v0.1.2
+***Security Warning: Versions of `ex_ovh` less than `0.3.2` are deprecated and should not be used
+due to the inclusion of older releases of the dependency `Og` Use versions `0.3.2` or above of `ex_ovh` instead***
+
- Fix `mix ovh` task.
- Fix some of the `/cloud` queries (binary key was missing due to missed earlier change)
## v0.1.1
+***Security Warning: Versions of `ex_ovh` less than `0.3.2` are deprecated and should not be used
+due to the inclusion of older releases of the dependency `Og` Use versions `0.3.2` or above of `ex_ovh` instead***
+
- No changes to source code. Only documentation changes.
## v0.1.0
+***Security Warning: Versions of `ex_ovh` less than `0.3.2` are deprecated and should not be used
+due to the inclusion of older releases of the dependency `Og` Use versions `0.3.2` or above of `ex_ovh` instead***
+
- Decouple the `Openstack` component into the `Openstex` repository.
Only requests to the `ExOvh` API can be made with `ExOvh`.
- Add documentation.
@@ -25,4 +127,7 @@ Only requests to the `ExOvh` API can be made with `ExOvh`.
## v0.0.1
+***Security Warning: Versions of `ex_ovh` less than `0.3.2` are deprecated and should not be used
+due to the inclusion of older releases of the dependency `Og` Use versions `0.3.2` only of `ex_ovh`***
+
- Initial release.
\ No newline at end of file
diff --git a/LICENCE.md b/LICENCE.md
index b962b24..5fa45c0 100644
--- a/LICENCE.md
+++ b/LICENCE.md
@@ -1,6 +1,6 @@
# MIT License
-Copyright (c) 2016 Stephen Moloney
+Copyright (c) 2016 - 2017 Stephen Moloney
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/README.md b/README.md
index dd1ada0..5481dc9 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,24 @@
# ExOvh [](https://travis-ci.org/stephenmoloney/ex_ovh) [](https://hex.pm/packages/ex_ovh) [](https://hexdocs.pm/ex_ovh) [](https://beta.hexfaktor.org/github/stephenmoloney/ex_ovh)
-
ExOvh is an helper library for the [elixir language](http://elixir-lang.org/) for the [Ovh Api](https://api.ovh.com/).
To use the Openstack components of the OVH API, see [Openstex](https://github.com/stephenmoloney/openstex)
#### Project Features
-- Config supervised agent running in the background which stores frequently accessed authentication information.
-- Query modules for making building requests to the [Ovh Api](https://api.ovh.com/).
-- Request functions to send Queries to the [Ovh Api](https://api.ovh.com/).
-
-
+- ***A Supervised agent*** running in the background which stores frequently accessed authentication information.
+- ***Helper*** modules for making building requests to the [Ovh Api](https://api.ovh.com/).
+- ***Request*** functions to send requests to the [Ovh Api](https://api.ovh.com/).
#### Getting started - Step 1: Generating the OVH `application key`, `application secret` and `consumer key`.
-- This may be done manually by going to `https://eu.api.ovh.com/createApp/` and following the directions outlined by `OVH` ath
+- This may be done manually by going to `https://eu.api.ovh.com/createApp/` and following the directions outlined by `OVH` at
[their first steps guide](https://api.ovh.com/g934.first_step_with_api).
- Alternatively, this may be achieved by running a mix task. This saves me a lot of time when generating a new application.
- [Documentation here](https://github.com/stephenmoloney/ex_ovh/blob/master/docs/mix_task.md)
+
+- [Documentation here](https://github.com/stephenmoloney/ex_ovh/blob/master/docs/mix_task.md)
#### Getting Started - Step 2: Generating the OVH client module for your elixir application
@@ -33,12 +31,45 @@ functions of the ***ex_ovh*** `API`.
#### Usage
-- Basic examples to be added to readme.
+#### Examples - Method 1 - Building the queries manually and send the request (my preferred way)
+
+
+- `GET /me/api/application/#{app_id}`
+```
+app_id = "0"
+req = %HTTPipe.Request{
+ method: :get,
+ url: "/me/api/application/#{app_id}"
+}
+MyApp.OvhClient.request!(req)
+```
-[See Hex Docs](https://hexdocs.pm/ex_ovh/0.2/api-reference.html)
+- `GET /cloud/project/{serviceName}/storage`
+```
+service_name = "service_name"
+req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/storage"
+}
+|> MyApp.OvhClient.request!()
+```
+
+
+#### Examples - Method 2 - Build the request using provided helper functions and send the request
+
+***Note:*** Helper functions are only available currently for the `/Cloud` portion of the OVH API.
+*Eventually, I would like to write a macro to create the queries.*
+
+- `GET /cloud/project/{serviceName}/storage`
+```
+ExOvh.V1.Cloud.get_containers(service_name) |> ExOvh.request!()
+```
+
+- For more information [See Hex Docs](https://hexdocs.pm/ex_ovh/0.2/api-reference.html)
#### Contributing
+
- Pull requests welcome.
@@ -51,9 +82,10 @@ functions of the ***ex_ovh*** `API`.
- [ ] Tests for OVH portion of library
- [ ] Option to set the application ttl when running ovh mix task.
-- [ ] Add queries for the remainder of the OVH API. (Webstorage CDN and Cloud are the only ones covered so far)
-- [ ] Basic examples to be added to readme of usage of the api.
+- [x] Basic examples to be added to readme of usage of the api.
- [ ] Add macro for building queries.
+- [ ] Write the usage guide - more examples of using the API.
+- [ ] Remove dependency on `:calendar` if tz info is not required.
#### Note
diff --git a/config/config.exs b/config/config.exs
index a8c4e27..ddf2fe8 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -15,5 +15,4 @@ end
unless Mix.env == :test do
import_config "#{Mix.env}.exs"
-end
-
+end
\ No newline at end of file
diff --git a/config/dev.exs b/config/dev.exs
index d0bfc00..11a9d6a 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -10,7 +10,10 @@ config :ex_ovh,
application_secret: System.get_env("EX_OVH_APPLICATION_SECRET"),
consumer_key: System.get_env("EX_OVH_CONSUMER_KEY")
],
- httpoison: [
+ hackney: [
connect_timeout: 20000,
- receive_timeout: 180000
- ]
\ No newline at end of file
+ recv_timeout: 180000
+ ]
+
+config :httpipe,
+ :adapter, HTTPipe.Adapters.Hackney
diff --git a/docs/getting_started.md b/docs/getting_started.md
index 765043d..4049dab 100644
--- a/docs/getting_started.md
+++ b/docs/getting_started.md
@@ -10,7 +10,7 @@ then substitute `Awesome` for `MyApp` and `AWESOME_OVH_CLIENT_` for `MY_APP_OVH_
```elixir
defp deps() do
- [{:ex_ovh, "~> 0.2"}]
+ [{:ex_ovh, "~> 0.4"}]
end
```
@@ -32,6 +32,7 @@ environment variables should be set:
echo '.env' >> .gitignore` for the git repository to ensure it doesn't get added to source control.
The `.env` file will be similar to as follows:
+
```
#!/usr/bin/env bash
@@ -50,6 +51,7 @@ export MY_APP_OVH_CLIENT_CONSUMER_KEY="<application_consumer_key>"
***NOTE:*** Matching naming between `MyApp.OvhClient` and `MY_APP_OVH_CLIENT_APPLICATION_KEY` variables is expected.
- Basic settings
+
```elixir
config :my_app, MyApp.OvhClient,
ovh: [
@@ -60,6 +62,7 @@ export MY_APP_OVH_CLIENT_CONSUMER_KEY="<application_consumer_key>"
```
- More elaborate settings
+
```elixir
config :my_app, MyApp.OvhClient,
ovh: [
@@ -69,9 +72,9 @@ export MY_APP_OVH_CLIENT_CONSUMER_KEY="<application_consumer_key>"
endpoint: "ovh-eu",
api_version: "1.0"
],
- httpoison: [ # optional
+ hackney: [ # optional
connect_timeout: 20000,
- receive_timeout: 100000
+ recv_timeout: 100000
]
```
@@ -117,13 +120,78 @@ end
#### Example usages
-- First start the application `iex -S mix`
+- First start the application with the system environment variables available `source .env && iex -S mix`
- Then try running some requests against the `API`
+#### Examples - Method 1 - Building the queries manually and sending the request (my preferred way)
+
+
+- `GET /me`
+
+```
+req = %HTTPipe.Request{
+ method: :get,
+ url: "/me"
+}
+|> MyApp.OvhClient.request!()
+```
+
+- `GET /me/api/application`
+
+```
+req = %HTTPipe.Request{
+ method: :get,
+ url: "/me/api/application"
+}
+|> MyApp.OvhClient.request!()
+```
+
+- `GET /me/api/application/#{app_id}`
+
+```
+app_id = "0"
+req = %HTTPipe.Request{
+ method: :get,
+ url: "/me/api/application/#{app_id}"
+}
+|> MyApp.OvhClient.request!()
+```
+
+- `GET /cloud/project/{serviceName}/storage`
+
+```
+service_name = "service_name"
+req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/storage"
+}
+|> MyApp.OvhClient.request!()
+```
+
+
+#### Examples - Method 2 - Build the request using provided helper functions and sending the request
+
+***Note:*** Helper functions are only available currently for the `/Cloud` portion of the OVH API.
+*Eventually, I would like to write a macro to create the queries.*
+
+- `GET /cloud/project`
+
+```
+ExOvh.V1.Cloud.list_services() |> ExOvh.request!()
+```
+
+- `GET /cloud/project/{serviceName}/storage`
+
+```
+resp1 = ExOvh.V1.Cloud.list_services() |> ExOvh.request!() |> Map.get(:response)
+service = Map.get(resp1, :body) |> List.last()
+resp2 = ExOvh.V1.Cloud.get_containers(service) |> ExOvh.request!() |> Map.get(:response)
+containers = Map.get(resp2, :body)
+```
+
-#### Some useful requests in the `OVH console` to see applications
+#### Usage guide
-- `GET /me/api/application` -- returns a list of application ids.
-- `GET /me/api/application/{applicationId}` -- returns json with application key.
\ No newline at end of file
+- For more usage examples see the usage guide or the [hex documentation](https://hexdocs.pm/ex_ovh/ExOvh.html)
\ No newline at end of file
diff --git a/docs/mix_task.md b/docs/mix_task.md
index d9ede9f..cf94673 100644
--- a/docs/mix_task.md
+++ b/docs/mix_task.md
@@ -21,10 +21,7 @@ version control.
**Shell input:**
```shell
-mix ovh \
---login=<username-ovh> \
---password=<password> \
---appname='ex_ovh'
+mix ovh --login=<username-ovh> --password=<password> --appname='my_app_name'
```
- `login`: username/nic_handle for logging into OVH services. *Note*: must include `-ovh` at the end of the string.
diff --git a/docs/usage.md b/docs/usage.md
new file mode 100644
index 0000000..df95b22
--- /dev/null
+++ b/docs/usage.md
@@ -0,0 +1,10 @@
+## Examples using the OVH api
+
+## TODO
+
+
+#### Examples (1) - Building queries manually
+
+
+#### Examples (2) - Building queries with the helper modules
+
diff --git a/lib/ex_ovh/client.ex b/lib/ex_ovh/client.ex
index 446f5a3..3e010a6 100644
--- a/lib/ex_ovh/client.ex
+++ b/lib/ex_ovh/client.ex
@@ -1,11 +1,75 @@
defmodule ExOvh.Client do
- @moduledoc Module.concat(__MODULE__, Docs).moduledoc()
- alias ExOvh.{HttpQuery, Query, Response, Transformation}
+ @moduledoc ~s"""
+ A behaviour for setting up an OVH client.
+
+ ## Example setting up the `ExOvh` Client
+
+ Defining a client:
+
+ defmodule ExOvh do
+ @moduledoc :false
+ use ExOvh.Client, otp_app: :ex_ovh, client: __MODULE__
+ end
+
+ Configuring a client:
+
+ config :ex_ovh,
+ ovh: [
+ application_key: System.get_env("EX_OVH_APPLICATION_KEY"),
+ application_secret: System.get_env("EX_OVH_APPLICATION_SECRET"),
+ consumer_key: System.get_env("EX_OVH_CONSUMER_KEY"),
+ endpoint: "ovh-eu",
+ api_version: "1.0"
+ ],
+ # default hackney options to each request (optional)
+ hackney: [
+ connect_timeout: 20000,
+ recv_timeout: 100000
+ ]
+
+ ## Example using the `ExOvh` client
+
+ %HTTPipe.Request{ method: :get, url: "/me", params: %{}} |> ExOvh.request!()
+ %HTTPipe.Request{ method: :get, url: "/cloud/project", params: %{}} |> ExOvh.request!()
+
+ ## Example (2): Setting up an additional `MyApp.MyClient` client.
+
+ Defining the `MyApp.MyClient`
+
+ defmodule MyApp.MyClient do
+ @moduledoc :false
+ use ExOvh.Client, otp_app: :my_app
+ end
+
+ Configuring the `MyApp.MyClient`
+
+ config :my_app, MyApp.MyClient,
+ ovh: [
+ application_key: System.get_env("MY_APP_MY_CLIENT_APPLICATION_KEY"),
+ application_secret: System.get_env("MY_APP_MY_CLIENT_APPLICATION_SECRET"),
+ consumer_key: System.get_env("MY_APP_MY_CLIENT_CONSUMER_KEY")
+ ],
+ # default hackney options to each request (optional)
+ hackney: [
+ connect_timeout: 20000,
+ recv_timeout: 100000
+ ]
+
+ ## Example using the `MyApp.MyClient` client
+
+ %HTTPipe.Request{ method: :get, url: "/me", params: %{}} |> MyApp.MyClient.request!()
+ %ExOvh.Query{ method: :get, url: "/cloud/project", params: %{}} |> MyApp.MyClient.request!()
+ """
defmacro __using__(opts) do
quote bind_quoted: [opts: opts] do
- @moduledoc Module.concat(ExOvh.Client, Docs).ovh_client_docs()
- alias ExOvh.{Defaults, HttpQuery, Query, Request, Response, ResponseError}
+
+ @moduledoc ~s"""
+ A default client for sending requests to the [OVH API](https://api.ovh.com/console/).
+
+ `ExOvh` is the default client. Additional clients such as `MyApp.MyClient.Ovh` can be created - see `PAGES`.
+ """
+ alias ExOvh.{Defaults, ResponseError}
@behaviour ExOvh.Client
# public callback functions
@@ -29,30 +93,30 @@ defmodule ExOvh.Client do
@spec ovh_config() :: Keyword.t
def ovh_config(), do: config() |> Keyword.fetch!(:ovh)
- @doc "Gets all the `:httpoison` configuration settings"
- @spec httpoison_config() :: Keyword.t
- def httpoison_config(), do: config() |> Keyword.fetch!(:httpoison)
+ @doc "Gets all the default `:hackney` options to be sent with each request"
+ @spec hackney_opts() :: Keyword.t
+ def hackney_opts(), do: config() |> Keyword.fetch!(:hackney)
- @doc "Prepares a request prior to sending by adding metadata such as authorization headers."
- @spec prepare_request(Query.t, Keyword.t) :: {:ok, Response.t} | {:error, Response.t}
- def prepare_request(query, httpoison_opts \\ []) do
+ @doc "Prepares a request prior to sending by applying standard transformations to the request"
+ @spec prepare_request(HTTPipe.Conn.t | HTTPipe.Request.t) :: HTTPipe.Conn.t
+ def prepare_request(conn) do
client = unquote(opts) |> Keyword.fetch!(:client)
- Transformation.prepare_request(query, httpoison_opts, client)
+ ExOvh.Request.apply_transformations(conn, client)
end
- @doc "Sends a request to the ovh api using [httpoison](https://hex.pm/packages/httpoison)."
- @spec request(Query.t | HttpQuery.t, Keyword.t) :: {:ok, Response.t} | {:error, Response.t}
- def request(query, httpoison_opts \\ []) do
+ @doc "Sends a request to the ovh api using [httpipe](https://hex.pm/packages/httpipe)."
+ @spec request(HTTPipe.Conn.t) :: {:ok, HTTPipe.Conn.t} | {:error, HTTPipe.Conn.t}
+ def request(conn) do
client = unquote(opts) |> Keyword.fetch!(:client)
- Request.request(query, httpoison_opts, client)
+ ExOvh.Request.request(conn, client)
end
- @doc "Sends a request to the ovh api using [httpoison](https://hex.pm/packages/httpoison)."
- @spec request!(Query.t | HttpQuery.t, Keyword.t) :: Response.t | no_return
- def request!(query, httpoison_opts \\ []) do
- case request(query) do
- {:ok, resp} -> resp
- {:error, resp} -> raise(ResponseError, response: resp, query: query)
+ @doc "Sends a request to the ovh api using [httpipe](https://hex.pm/packages/httpipe)."
+ @spec request!(HTTPipe.Conn.t) :: HTTPipe.Conn.t | no_return
+ def request!(conn) do
+ case request(conn) do
+ {:ok, conn} -> conn
+ {:error, conn} -> raise(ResponseError, conn: conn)
end
end
@@ -70,9 +134,9 @@ defmodule ExOvh.Client do
@callback start_link(sup_opts :: list) :: {:ok, pid} | {:error, atom}
@callback config() :: Keyword.t
@callback ovh_config() :: Keyword.t
- @callback httpoison_config() :: Keyword.t
- @callback prepare_request(query :: Query.t, httpoison_opts :: Keyword.t) :: Query.t | no_return
- @callback request(query :: Query.t | HttpQuery.t, httpoison_opts :: Keyword.t) :: {:ok, Response.t} | {:error, Response.t}
- @callback request!(query :: Query.t | HttpQuery.t, httpoison_opts :: Keyword.t) :: {:ok, Response.t} | no_return
+ @callback hackney_opts() :: Keyword.t
+ @callback prepare_request(HTTPipe.Conn.t | HTTPipe.Request.t) :: HTTPipe.Conn.t
+ @callback request(conn :: HTTPipe.Conn.t) :: {:ok, HTTPipe.Conn.t} | {:error, HTTPipe.Conn.t}
+ @callback request!(conn :: HTTPipe.Conn.t) :: HTTPipe.Conn.t | no_return
end
\ No newline at end of file
diff --git a/lib/ex_ovh/config.ex b/lib/ex_ovh/config.ex
index 36e9701..abff747 100644
--- a/lib/ex_ovh/config.ex
+++ b/lib/ex_ovh/config.ex
@@ -1,12 +1,11 @@
defmodule ExOvh.Config do
@moduledoc :false
- @default_httpoison_opts [connect_timeout: 20000, receive_timeout: 180000]
+ @default_hackney_opts [connect_timeout: 8000, recv_timeout: 5000]
alias ExOvh.Defaults
@doc "Starts an agent for the storage of credentials in memory"
def start_agent(client, opts) do
- Og.context(__ENV__, :debug)
- otp_app = Keyword.get(opts, :otp_app, :false) || Og.log_return(__ENV__, :error) |> raise()
+ otp_app = Keyword.get(opts, :otp_app, :false) || raise("otp_app not specified")
Agent.start_link(fn -> config(client, otp_app) end, name: agent_name(client))
end
@@ -26,7 +25,7 @@ defmodule ExOvh.Config do
end
end
- @doc "Gets the httpoison config.exs environment variables"
+ @doc "Gets the hackney config.exs environment variables"
def get_ovh_config_from_env(client, otp_app) do
try do
get_config_from_env(client, otp_app) |> Keyword.fetch!(:ovh)
@@ -38,19 +37,18 @@ defmodule ExOvh.Config do
end
end)
rescue
- _error -> Og.log_return("No ovh_config was found. ", __ENV__, :warn) |> raise()
+ _error -> raise("No ovh_config was found. ")
end
end
- @doc "Gets the httpoison config.exs environment variables"
- def get_httpoison_config_from_env(client, otp_app) do
+ @doc "Gets the hackney config.exs environment variables"
+ def get_hackney_opts_from_env(client, otp_app) do
try do
- get_config_from_env(client, otp_app) |> Keyword.fetch!(:httpoison)
+ get_config_from_env(client, otp_app) |> Keyword.fetch!(:hackney)
rescue
_error ->
- Og.log_return("No httpoison_config was found. " <>
- "Falling back to default httpoison settings #{inspect(@default_httpoison_opts)}", __ENV__, :warn)
- @default_httpoison_opts
+ _msg = "No hackney_opts was found. Falling back to default hackney settings #{inspect(@default_hackney_opts)}"
+ @default_hackney_opts
end
end
@@ -64,9 +62,9 @@ defmodule ExOvh.Config do
Agent.get(agent_name(client), fn(config) -> config[:ovh] end)
end
- @doc "Gets the httpoison_config related config variables from a supervised Agent"
- def httpoison_config(client) do
- Agent.get(agent_name(client), fn(config) -> config[:httpoison] end)
+ @doc "Gets the hackney_opts related config variables from a supervised Agent"
+ def hackney_opts(client) do
+ Agent.get(agent_name(client), fn(config) -> config[:hackney] end)
end
@doc "Gets the diff"
@@ -79,16 +77,16 @@ defmodule ExOvh.Config do
ovh_config = get_ovh_config_from_env(client, otp_app)
|> Keyword.put(:diff, diff)
- httpoison_config = get_httpoison_config_from_env(client, otp_app)
- connect_timeout = httpoison_config[:connect_timeout] || 30000 # 30 seconds
- receive_timeout = httpoison_config[:receive_timeout] || (60000 * 30) # 30 minutes
+ hackney_opts = get_hackney_opts_from_env(client, otp_app)
+ connect_timeout = hackney_opts[:connect_timeout] || 30000 # 30 seconds
+ recv_timeout = hackney_opts[:recv_timeout] || (60000 * 30) # 30 minutes
[
ovh: ovh_config,
- httpoison:
+ hackney:
[
timeout: connect_timeout,
- recv_timeout: receive_timeout,
+ recv_timeout: recv_timeout,
]
]
end
@@ -106,12 +104,21 @@ defmodule ExOvh.Config do
defp api_time_request(client, otp_app) do
ovh_config = get_ovh_config_from_env(client, otp_app)
method = :get
- uri = ovh_config[:endpoint] <> ovh_config[:api_version] <> "/auth/time"
+ url = ovh_config[:endpoint] <> ovh_config[:api_version] <> "/auth/time"
body = ""
headers = [{"Content-Type", "application/json; charset=utf-8"}]
- options = get_httpoison_config_from_env(client, otp_app)
- resp = HTTPoison.request!(method, uri, body, headers, options)
- Poison.decode!(resp.body)
+ options = get_hackney_opts_from_env(client, otp_app)
+ conn = %HTTPipe.Conn{
+ request: %HTTPipe.Request{
+ method: method,
+ url: url,
+ body: body,
+ headers: headers,
+ },
+ adapter_options: options
+ }
+ {:ok, conn} = HTTPipe.Conn.execute(conn)
+ Poison.decode!(conn.response.body)
end
end
diff --git a/lib/ex_ovh/docs/client.ex b/lib/ex_ovh/docs/client.ex
deleted file mode 100644
index 5514b25..0000000
--- a/lib/ex_ovh/docs/client.ex
+++ /dev/null
@@ -1,79 +0,0 @@
-defmodule ExOvh.Client.Docs do
- @moduledoc :false
-
- @doc :false
- def moduledoc() do
- ~s"""
- A behaviour for setting up an OVH client.
-
- ## Example (1): Setting up the `ExOvh` Client
-
- Defining a client:
-
- defmodule ExOvh do
- @moduledoc :false
- use ExOvh.Client, otp_app: :ex_ovh, client: __MODULE__
- end
-
- Configuring a client:
-
- config :ex_ovh,
- ovh: [
- application_key: System.get_env("EX_OVH_APPLICATION_KEY"),
- application_secret: System.get_env("EX_OVH_APPLICATION_SECRET"),
- consumer_key: System.get_env("EX_OVH_CONSUMER_KEY"),
- endpoint: "ovh-eu",
- api_version: "1.0"
- ],
- httpoison: [ # optional
- connect_timeout: 20000,
- receive_timeout: 100000
- ]
-
- ## Example using the `ExOvh` client
-
- %ExOvh.Query{ method: :get, uri: "/me", params: %{}} |> ExOvh.request!()
- %ExOvh.Query{ method: :get, uri: "/cloud/project", params: %{}} |> ExOvh.request!()
-
- ## Example (2): Setting up an additional `MyApp.MyClient` client.
-
- Defining the `MyApp.MyClient`
-
- defmodule MyApp.MyClient do
- @moduledoc :false
- use ExOvh.Client, otp_app: :my_app
- end
-
- Configuring the `MyApp.MyClient`
-
- config :my_app, MyApp.MyClient,
- ovh: [
- application_key: System.get_env("MY_APP_MY_CLIENT_APPLICATION_KEY"),
- application_secret: System.get_env("MY_APP_MY_CLIENT_APPLICATION_SECRET"),
- consumer_key: System.get_env("MY_APP_MY_CLIENT_CONSUMER_KEY")
- # if left out, :endpoint will default to "ovh-eu"
- # if left out, :api_version will default to "1.0"
- ],
- httpoison: [ # optional
- connect_timeout: 20000,
- receive_timeout: 100000
- ]
-
- ## Example using the `MyApp.MyClient` client
-
- %ExOvh.Query{ method: :get, uri: "/me", params: %{}} |> MyApp.MyClient.request!()
- %ExOvh.Query{ method: :get, uri: "/cloud/project", params: %{}} |> MyApp.MyClient.request!()
- """
- end
-
-
- @doc :false
- def ovh_client_docs() do
- ~s"""
- A default client for sending requests to the [OVH API](https://api.ovh.com/console/).
-
- `ExOvh` is the default client. Additional clients such as `MyApp.MyClient.Ovh` can be created - see `PAGES`.
- """
- end
-
-end
\ No newline at end of file
diff --git a/lib/ex_ovh/docs/cloud_query.ex b/lib/ex_ovh/docs/cloud_query.ex
deleted file mode 100644
index 9cf4ecd..0000000
--- a/lib/ex_ovh/docs/cloud_query.ex
+++ /dev/null
@@ -1,57 +0,0 @@
-defmodule ExOvh.Services.V1.Cloud.Query.Docs do
- @moduledoc :false
-
- @doc :false
- def moduledoc() do
- ~s"""
- Helper functions for building queries directed at the `/cloud` part of the [OVH API](https://api.ovh.com/console/).
-
- ## Functions Summary
-
- | Function | Description | OVH API call |
- |---|---|---|
- | `list_services/0` | <small>List available services or list available cloud projects. A returned project id in OVH terms is similar to a tenant id in swift terms</small> | <sub><sup>GET /cloud/project</sup></sub> |
- | `get_users/1` | <small>Get all users</small> | <sub><sup>GET /cloud/project/{serviceName}/user</sup></sub> |
- | `create_user/2` | <small>Create user</small> | <sub><sup>POST /ctsloud/project/{serviceName}/user</sup></sub> |
- | `get_user_details/2` | <small>Get user details. Returns the user_id and username and other details.</small> | <sub><sup>GET /cloud/project/{serviceName}/user/{userId}</sup></sub> |
- | `delete_user/2` | <small>Delete user</small> | <sub><sup>DELETE /cloud/project/{serviceName}/user/{userId}</sup></sub> |
- | `download_openrc_script/3` | <small>Get RC file of OpenStack</small> | <sub><sup>GET /cloud/project/{serviceName}/user/{userId}/openrc</sup></sub> |
- | `regenerate_credentials/2` | <small>Regenerate user credentials including password</small> | <sub><sup>POST /cloud/project/{serviceName}/user/{userId}/regeneratePassword</sup></sub> |
- | `swift_identity/3` | <small>Gets a json object similar to that returned by Keystone Identity. Includes the 'X-Auth-Token'</small> | <sub><sup>POST /cloud/project/{serviceName}/user/{userId}/token</sup></sub> |
- | `create_project/2` | <small>Start a new cloud project in the OVH cloud. Corresponds to creating a new Swift stack with a new tenant_id.</small> | <sub><sup>POST /cloud/createProject</sup></sub> |
- | `get_prices/2` | <small>Get Prices for OVH cloud services.</small> | <sub><sup>GET /cloud/price</sup></sub> |
- | `project_info/1` | <small>Get information about a project with the project_id (tenant_id)</small> | <sub><sup>GET /cloud/project/{serviceName}</sup></sub> |
- | `modify_project/2` | <small>Modify a project properties. Change the project description.</small> | <sub><sup>PUT /cloud/project/{serviceName}</sup></sub> |
- | `project_administrative_info/1` | <small>Get administration information about the project.</small> | <sub><sup>GET /cloud/project/{serviceName}/serviceInfos</sup></sub> |
- | `project_quotas/1` | <small>Get project quotas.</small> | <sub><sup>GET /cloud/project/{serviceName}/quota</sup></sub> |
- | `project_regions/1` | <small>Get project regions.</small> | <sub><sup>GET /cloud/project/{serviceName}/region</sup></sub> |
- | `project_region_info/2` | <small>Get details about a project region.</small> | <sub><sup>GET /cloud/project/{serviceName}/region/{regionName}</sup></sub> |
- | `project_consumption/3` | <small>Get details about a project consumption for a given `date_from` and `date_to`.</small> | <sub><sup>GET /cloud/project/{serviceName}/consumption</sup></sub> |
- | `project_bills/3` | <small>Get details about a project billing for a given `date_from` and `date_to`..</small> | <sub><sup>GET /cloud/project/{serviceName}/bill</sup></sub> |
- | `create_project_alert/4` | <small>Add a new project alert</small> | <sub><sup>POST /cloud/project/{serviceName}/alerting</sup></sub> |
- | `get_project_alert_info/2` | <small>Get detailed information about a project alert.</small> | <sub><sup>GET /cloud/project/{serviceName}/alerting/{id}</sup></sub> |
- | `modify_project_alert/5` | <small>Modify an existing project alert.</small> | <sub><sup>PUT /cloud/project/{serviceName}/alerting/{id}</sup></sub> |
- | `delete_project_alert/2` | <small>Delete an existing project alert.</small> | <sub><sup>DELETE /cloud/project/{serviceName}/alerting/{id}</sup></sub> |
- | `terminate_service/2` | <small>Terminate a cloud project.</small> | <sub><sup>POST /cloud/project/{serviceName}/terminate</sup></sub> |
-
-
- ## TO BE ADDED
-
- GET /cloud/project/{serviceName}/acl
- POST /cloud/project/{serviceName}/acl
- GET /cloud/project/{serviceName}/acl/{accountId}
- DELETE /cloud/project/{serviceName}/acl/{accountId}
-
- ## Notes
-
- - `service_name` or `serviceName` corresponds to the Openstack `tenant_id`
-
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.get_containers(service_name) |> ExOvh.request!()
- """
- end
-
-
-end
\ No newline at end of file
diff --git a/lib/ex_ovh/docs/cloudstorage_query.ex b/lib/ex_ovh/docs/cloudstorage_query.ex
deleted file mode 100644
index 7acfaf8..0000000
--- a/lib/ex_ovh/docs/cloudstorage_query.ex
+++ /dev/null
@@ -1,34 +0,0 @@
-defmodule ExOvh.Services.V1.Cloud.Cloudstorage.Query.Docs do
- @moduledoc :false
-
- @doc :false
- def moduledoc() do
- ~s"""
- Helper functions for building queries directed at the cloudstorage related parts of the `/cloud` part of the [OVH API](https://api.ovh.com/console/).
-
- See `ExOvh.Services.V1.Cloud.Query` for generic cloud requests.
-
- ## Functions Summary
-
- | Function | Description | OVH API call |
- |---|---|---|
- | `get_containers/1` | <small>Get containers for a given swift tenant id (project id or ovh service name)</small> | <sub><sup>GET /cloud/project/{serviceName}/storage </sup></sub> |
- | `create_container/3` | <small>Create a container for a given tenant_id (ovh service_name), a container and a region.</small> | <sub><sup>POST /cloud/project/{serviceName}/storage</sup></sub> |
- | `get_access/1` | <small>Get access details for the Swift API for a given swift tenant_id (ovh service_name)</small> | <sub><sup>GET /cloud/project/{serviceName}/storage/access</sup></sub> |
- | `container_info/2` | <small>Gets details about a container such as objects, size, region, public or not, static_url, name, ...</small> | <sub><sup>GET /cloud/project/{serviceName}/storage/{containerId}</sup></sub> |
- | `delete_container/2` | <small>Deletes a given container.</small> | <sub><sup>DELETE /cloud/project/{serviceName}/storage/{containerId}</sup></sub> |
- | `modify_container_cors/3` | <small>Modify the CORS settings for a container. See [swift docs](http://docs.openstack.org/developer/swift/cors.html)</small> | <sub><sup>POST /cloud/project/{serviceName}/storage/{containerId}/cors Add CORS support on your container</sup></sub> |
- | `deploy_container_as_static_website/2` | <small>Deploy the container files as a static web site.</small> | <sub><sup>POST /cloud/project/{serviceName}/storage/{containerId}/static</sup></sub> |
-
- ## Notes
-
- - `service_name` or `serviceName` corresponds to the Openstack `tenant_id`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.get_containers(service_name) |> ExOvh.request!()
- """
- end
-
-
-end
\ No newline at end of file
diff --git a/lib/ex_ovh/docs/mix_task.ex b/lib/ex_ovh/docs/mix_task.ex
deleted file mode 100644
index 3ef0483..0000000
--- a/lib/ex_ovh/docs/mix_task.ex
+++ /dev/null
@@ -1,39 +0,0 @@
-defmodule Mix.Tasks.Ovh.Docs do
- @moduledoc :false
-
- @doc :false
- def moduledoc() do
- ~s"""
- A mix task that generates the ex_ovh application secrets on the user's behalf.
-
- ## Steps
-
- - The user needs to set up an ovh account at https://www.ovh.co.uk/ and retrieve a username (nic-handle) and password.
-
- - Then the user is prompted to do some activations.
-
- - Upon completion of activations, the user needs to create an application in the ovh website.
-
- - Then the user can create an application at `https://eu.api.ovh.com/createApp/` or
- alternatively the user can use this mix task to generate the application:
-
- ## Example
-
- Create an app with access to all apis:
-
- mix ovh --login=<username-ovh> --password=<password> --appname='ex_ovh'
-
- Output:
-
- config :ex_ovh,
- ovh: [
- application_key: System.get_env("EX_OVH_APPLICATION_KEY"),
- application_secret: System.get_env("EX_OVH_APPLICATION_SECRET"),
- consumer_key: System.get_env("EX_OVH_CONSUMER_KEY")
- ]
-
- See the [mix task documentation]((https://github.com/stephenmoloney/ex_ovh/blob/master/docs/mix_task.md).
- """
- end
-
-end
\ No newline at end of file
diff --git a/lib/ex_ovh/docs/webstorage_query.ex b/lib/ex_ovh/docs/webstorage_query.ex
deleted file mode 100644
index cfdb118..0000000
--- a/lib/ex_ovh/docs/webstorage_query.ex
+++ /dev/null
@@ -1,27 +0,0 @@
-defmodule ExOvh.Services.V1.Webstorage.Query.Docs do
- @moduledoc :false
-
- @doc :false
- def moduledoc() do
- ~s"""
- Helper functions for building queries directed at the `/cdn/webstorage` part of the [OVH API](https://api.ovh.com/console/).
-
- ## Functions Summary
-
- | Function | Description | OVH API call |
- |---|---|---|
- | `get_services/0` | <small>Get a list of all webstorage cdn services.</small> | <sub><sup>GET /v1/cdn/webstorage</sup></sub> |
- | `get_service/1` | <small>Get the domain, server and storage limits for a specific webstorage cdn service</small> | <sub><sup>GET /v1/cdn/webstorage/{serviceName}</sup></sub> |
- | `get_service_info/1` | <small>Get a administrative details for a specific webstorage cdn service</small> | <sub><sup>GET /v1/cdn/webstorage/{serviceName}/serviceInfos</sup></sub> |
- | `get_service_stats/2` | <small>Get statistics for a specific webstorage cdn service</small> | <sub><sup>GET /v1/cdn/webstorage/{serviceName}/statistics</sup></sub> |
- | `get_credentials/1` | <small>Get credentials for using the swift compliant api</small> | <sub><sup>GET /v1/cdn/webstorage/{serviceName}/statistics</sup></sub> |
-
-
- ## Example
-
- ExOvh.Services.V1.Webstorage.Query.get_services() |> ExOvh.request()
- """
- end
-
-
-end
\ No newline at end of file
diff --git a/lib/ex_ovh/query.ex b/lib/ex_ovh/query.ex
deleted file mode 100644
index 1238631..0000000
--- a/lib/ex_ovh/query.ex
+++ /dev/null
@@ -1,18 +0,0 @@
-defmodule ExOvh.Query do
- @moduledoc false
- defstruct [:method, :uri, :params, headers: [], service: :ovh]
- @type t :: %__MODULE__{method: atom, uri: String.t, params: any, headers: list, service: :ovh}
-end
-
-defmodule ExOvh.HttpQuery do
- @moduledoc false
- defstruct [method: :nil, uri: :nil, body: "", headers: [], options: [], service: :ovh]
- @type t :: %__MODULE__{
- method: atom,
- uri: String.t,
- body: :binary | {:file, :binary},
- headers: [{binary, binary}],
- options: Keyword.t,
- service: atom
- }
-end
diff --git a/lib/ex_ovh/request.ex b/lib/ex_ovh/request.ex
index 4fb465e..9f4c095 100644
--- a/lib/ex_ovh/request.ex
+++ b/lib/ex_ovh/request.ex
@@ -1,35 +1,54 @@
defmodule ExOvh.Request do
@moduledoc :false
- alias ExOvh.{Transformation, Query, Response}
# Public
-
-
- @spec request(Query.t, Keyword.t, atom) :: {:ok, Response.t} | {:error, Response.t}
- def request(%Query{} = query, httpoison_opts, client) do
- Og.context(__ENV__, :debug)
- q = Transformation.prepare_request(query, httpoison_opts, client) |> Map.from_struct()
- options = Keyword.merge(q.options, httpoison_opts)
- case HTTPoison.request(q.method, q.uri, q.body, q.headers, options) do
- {:ok, resp} ->
- body = parse_body(resp)
- resp = %Response{ body: body, headers: resp.headers |> Enum.into(%{}), status_code: resp.status_code }
+ @spec request(HTTPipe.Conn.t | HTTPipe.Request.t, atom) :: {:ok, HTTPipe.Conn.t} | {:error, HTTPipe.Conn.t}
+ def request(%HTTPipe.Request{} = request, client) do
+ Map.put(HTTPipe.Conn.new(), :request, request)
+ |> request(client)
+ end
+ def request(%HTTPipe.Conn{} = conn, client) do
+ conn = apply_transformations(conn, client)
+
+ case HTTPipe.Conn.execute(conn) do
+ {:ok, conn} ->
+ body = parse_body(conn.response)
+ resp = Map.put(conn.response, :body, body)
+ conn = Map.put(conn, :response, resp)
if resp.status_code >= 100 and resp.status_code < 400 do
- {:ok, resp}
+ {:ok, conn}
else
- {:error, resp}
+ {:error, conn}
end
- {:error, resp} ->
- {:error, %HTTPoison.Error{reason: resp.reason}}
+ {:error, conn} -> {:error, conn}
end
+ end
+ @doc :false
+ def apply_transformations(conn, client) do
+ conn =
+ unless (:url in Map.get(conn, :completed_transformations, [])) do
+ ExOvh.Transformation.Url.apply(conn, client)
+ else
+ conn
+ end
+ conn =
+ unless (:hackney_options in Map.get(conn, :completed_transformations, [])) do
+ ExOvh.Transformation.HackneyOptions.apply(conn, client)
+ else
+ conn
+ end
+ unless (:auth in Map.get(conn, :completed_transformations, [])) do
+ ExOvh.Transformation.Auth.apply(conn, client)
+ else
+ conn
+ end
end
# private
-
defp parse_body(resp) do
try do
resp.body |> Poison.decode!()
@@ -39,7 +58,4 @@ defmodule ExOvh.Request do
end
end
-
end
-
-
diff --git a/lib/ex_ovh/response.ex b/lib/ex_ovh/response.ex
deleted file mode 100644
index db0ed78..0000000
--- a/lib/ex_ovh/response.ex
+++ /dev/null
@@ -1,5 +0,0 @@
-defmodule ExOvh.Response do
- @moduledoc false
- defstruct [:body, :headers, :status_code]
- @type t :: %__MODULE__{body: any, headers: list, status_code: integer}
-end
\ No newline at end of file
diff --git a/lib/ex_ovh/response_error.ex b/lib/ex_ovh/response_error.ex
index 341d7d0..26b5686 100644
--- a/lib/ex_ovh/response_error.ex
+++ b/lib/ex_ovh/response_error.ex
@@ -1,27 +1,51 @@
defmodule ExOvh.ResponseError do
@moduledoc :false
- defexception [:response, :query]
+ defexception [:conn]
- def message(%{query: query, response: resp}) do
+ def exception([conn: %HTTPipe.Conn{} = conn]) do
+ %ExOvh.ResponseError{conn: conn}
+ end
+
+ def message(%ExOvh.ResponseError{conn: conn}) do
~s"""
- The following http query was unsuccessful, unexpected or erroneous in some way:
+ The following http connection execution was unsuccessful, unexpected or erroneous in some way:
- #{Kernel.inspect(query)} was unsuccessful.
+ Request Details:
"""
<>
- message(%{response: resp})
+ request_output(conn)
+ <>
+ "\nResponse Details:\n"
+ <>
+ response_output(conn)
+ end
+
+ def request_output(conn) do
+ ~s"""
+ ** Request Method **
+ #{Kernel.inspect(conn.request.method)}
+
+ ** Request Body **
+ #{Kernel.inspect conn.request.body}
+
+ ** Request Headers **
+ #{Kernel.inspect(conn.request.headers)}
+
+ ** Request Url **
+ #{Kernel.inspect(conn.request.url)}
+ """
end
- def message(%{response: resp}) do
+ def response_output(conn) do
~s"""
** Reponse Status Code **
- #{inspect resp.status_code}
+ #{Kernel.inspect conn.response.status_code}
** Response Body **
- #{Kernel.inspect(resp.body)}
+ #{Kernel.inspect(conn.response.body)}
** Response Headers **
- #{Kernel.inspect(resp.headers)}
+ #{Kernel.inspect(conn.response.headers)}
"""
end
end
\ No newline at end of file
diff --git a/lib/ex_ovh/services/v1/cloud/cloudstorage/query.ex b/lib/ex_ovh/services/v1/cloud/cloudstorage/query.ex
deleted file mode 100644
index d588cd4..0000000
--- a/lib/ex_ovh/services/v1/cloud/cloudstorage/query.ex
+++ /dev/null
@@ -1,248 +0,0 @@
-defmodule ExOvh.Services.V1.Cloud.Cloudstorage.Query do
- @moduledoc Module.concat(__MODULE__, Docs).moduledoc()
- alias ExOvh.Query
-
-
- @doc ~s"""
- Get storage containers
-
- ## Api call
-
- GET /cloud/project/{serviceName}/storage
-
- ## Arguments
-
- - `service_name`: service name for the ovh cloud service
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.get_containers(service_name) |> ExOvh.request!()
- """
- @spec get_containers(String.t) :: Query.t
- def get_containers(service_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/storage",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Create container
-
- ## Api call
-
- POST /cloud/project/{serviceName}/storage
-
- ## Arguments
-
- - `service_name`: service name for the ovh cloud service
- - `container_name`: name for the new container
- - `region`: region for the new container, defaults to "SBG1". See regions by running:
- Currently can choose from "GRA1", "BHS1", "SBG1".
-
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.create_container(service_name, "test_container") |> ExOvh.request!()
- """
- @spec create_container(String.t, String.t, String.t) :: Query.t
- def create_container(service_name, container_name, region \\ "SBG1") do
- # POST /cloud/project/{serviceName}/storage Create container
- %Query{
- method: :post,
- uri: "/cloud/project/#{service_name}/storage",
- params: %{
- binary: %{
- "containerName" => container_name,
- "region" => region
- } |> Poison.encode!()
- }
- }
- end
-
-
- @doc ~s"""
- Gets the x_auth_token and the swift endpoints for a given tenant_id (ovh service_name). A different endpoint is returned
- depending on the region. Examples of regions include "BHS1", "SBG1", "GRA1". With these details, requests can be made through
- the Swift api.
-
- ## Api call
-
- GET /cloud/project/{serviceName}/storage/access
-
- ## Arguments
-
- - `service_name`: service name for the ovh cloud service
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.get_access(service_name) |> ExOvh.request!()
- """
- @spec get_access(String.t) :: Query.t
- def get_access(service_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/storage/access",
- params: %{}
- }
- end
-
-
-
- @doc ~s"""
- Gets the details for a given container.
-
- Returns information such as a list of objects in the container, size of the container, whether the container is public
- or not, the region of the container, the name of the container, the number of stored objects for the container and the
- static url for the container.
-
- ## Api call
-
- GET /cloud/project/{serviceName}/storage/{containerId}
-
- ## Arguments
-
- - `service_name`: service name for the ovh cloud service
- - `container_id`: container_id for a given container. *Note*: this is not the same as the container_name.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.container_info(service_name, container_id) |> ExOvh.request!()
- """
- @spec container_info(String.t, String.t) :: Query.t
- def container_info(service_name, container_id) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/storage/#{container_id}",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Deletes a given container.
-
- *Note:* container_d is not the same as container_name.
-
- ## Api call
-
- DELETE /cloud/project/{serviceName}/storage/{containerId}
-
- ## Arguments
-
- - `service_name`: service name for the ovh cloud service
- - `container_id`: container_id for a given container. *Note*: this is not the same as the container_name.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.delete_container(service_name, container_id) |> ExOvh.request!()
- """
- @spec delete_container(String.t, String.t) :: Query.t
- def delete_container(service_name, container_id) do
- %Query{
- method: :delete,
- uri: "/cloud/project/#{service_name}/storage/#{container_id}",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Modify CORS settings for a container.
-
- Modifies the container metadata such that cross origin requests can be permitted.
- See [CORS section of swift docs](http://docs.openstack.org/developer/swift/cors.html) for more info. Ans see here for more
- on [CORS in general](http://enable-cors.org/resources.html)
-
- | Metadata | Use |
- | --- | --- |
- | X-Container-Meta-Access-Control-Allow-Origin | Origins to be allowed to make Cross Origin Requests, space separated. |
-
-
- *Note:* container_d is not the same as container_name.
-
- ## Api call
-
- DELETE /cloud/project/{serviceName}/storage/{containerId}
-
- ## Arguments
-
- - `service_name`: service name for the ovh cloud service
- - `container_id`: container_id for a given container. *Note*: this is not the same as the container_name.
- - `origin`: an origin that may make cross origin requests to the container. Defaults to `{}` (none) if left absent.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.modify_container_cors(service_name, container_id, "http://localhost:4001/") |> ExOvh.Ovh.prepare_request() |> ExOvh.request!()
-
- ## Notes
-
- To get a full overview of the container details with all metadata, the Swift client should be used. To see the changes, try running the following
- command for the `container_name` associated with this `container_id`. In fact, the OVH functions are not really required, most changes can be made directly
- using queries sent via the `Swift.Cloudstorage` client.
-
- account = ExOvh.Swift.Cloudstorage.account()
- container = "test_container"
- Openstex.Swift.V1.Query.container_info(container, account) |> ExOvh.Swift.Cloudstorage.request!() |> Map.get(:headers) |> Map.get("X-Container-Meta-Access-Control-Allow-Origin")
- """
- @spec modify_container_cors(String.t, String.t, String.t) :: Query.t
- def modify_container_cors(service_name, container_id, origin \\ {}) do
- %Query{
- method: :post,
- uri: "/cloud/project/#{service_name}/storage/#{container_id}/cors",
- params: %{
- binary: %{
- "origin" => origin
- } |> Poison.encode!()
- }
- }
- end
-
-
-
- @doc ~s"""
- Deploy a container as a static website.
-
- Modifies the ACL settings for a container on the "X-Container-Read" header and also other container metadata.
- See [swift auth docs](http://docs.openstack.org/developer/swift/overview_auth.html),
- [swift acl middleware](http://docs.openstack.org/developer/swift/misc.html#module-swift.common.middleware.acl)
- and [swift account middleware](http://docs.openstack.org/developer/swift/middleware.html#module-swift.common.middleware.tempauth)
- for more information.
-
- ## Api call
-
- POST /cloud/project/{serviceName}/storage/{containerId}/static
-
- ## Arguments
-
- - `service_name`: service name for the ovh cloud service
- - `container_id`: container_id for a given container. *Note*: this is not the same as the container_name.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Cloudstorage.Query.modify_container_cors(service_name, container_id, "http://localhost:4001/") |> ExOvh.Ovh.prepare_request() |> ExOvh.request!()
-
- ## Notes
-
- To get a full overview of the container details with all metadata, the Swift client should be used. To see the changes, try running the following
- command for the `container_name` associated with this `container_id`. In fact, the OVH functions are not really required, most changes can be made directly
- using queries sent via the `Swift.Cloudstorage` client.
-
- account = ExOvh.Swift.Cloudstorage.account()
- container = "test_container"
- Openstex.Swift.V1.Query.container_info(container, account) |> ExOvh.Swift.Cloudstorage.request!() |> Map.get(:headers)
- """
- @spec deploy_container_as_static_website(String.t, String.t) :: Query.t
- def deploy_container_as_static_website(service_name, container_id) do
- %Query{
- method: :post,
- uri: "/cloud/project/#{service_name}/storage/#{container_id}/static",
- params: %{}
- }
- end
-
-
-
-end
diff --git a/lib/ex_ovh/services/v1/cloud/query.ex b/lib/ex_ovh/services/v1/cloud/query.ex
deleted file mode 100644
index 5d4a727..0000000
--- a/lib/ex_ovh/services/v1/cloud/query.ex
+++ /dev/null
@@ -1,689 +0,0 @@
-defmodule ExOvh.Services.V1.Cloud.Query do
- @moduledoc Module.concat(__MODULE__, Docs).moduledoc()
- alias ExOvh.Query
-
-
- @doc ~s"""
- List available services
-
- ## Api Call
-
- GET /cloud/project
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.list_services() |> ExOvh.request!()
- """
- @spec list_services() :: Query.t
- def list_services() do
- %Query{
- method: :get,
- uri: "/cloud/project",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Get all users
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/user
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.get_users(service_name) |> ExOvh.request!()
- """
- @spec get_users(String.t) :: Query.t
- def get_users(service_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/user",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Create user
-
- ## Api Call
-
- POST /cloud/project/{serviceName}/user
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `description`: description ascribed to the new user.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.create_user(service_name, "ex_ovh") |> ExOvh.request!()
- """
- @spec create_user(String.t, String.t) :: Query.t
- def create_user(service_name, description) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/user",
- params: %{
- binary: %{
- "description" => description
- } |> Poison.encode!()
- }
- }
- end
-
-
- @doc ~s"""
- Get user details. Returns the user_id and username and other details.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/user/{userId}
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `user_id`: corresponds to user_id. See `get_users/1`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.get_user_details(service_name, user_id) |> ExOvh.request!()
- """
- @spec get_user_details(String.t, String.t) :: Query.t
- def get_user_details(service_name, user_id) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/user/#{user_id}",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Delete a specific user.
-
- ## Api Call
-
- DELETE /cloud/project/{serviceName}/user/{userId}
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `user_id`: The user_id. See `get_users/1`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.delete_user(service_name, user_id) |> ExOvh.request!()
- """
- @spec delete_user(String.t, String.t) :: Query.t
- def delete_user(service_name, user_id) do
- %Query{
- method: :delete,
- uri: "/cloud/project/#{service_name}/user/#{user_id}",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Get RC file of OpenStack. This file is a bash script with much of the openstack credentials. Makes it easier for
- setting up a swift client from the terminal.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/user/{userId}/openrc
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `user_id`: user_id for user accessing the service.
- - `region`: region for which the rc file will be created. Defaults to "SBG1" if left absent.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.download_openrc_script(service_name, user_id, "SBG1") |> ExOvh.request!()
- """
- @spec download_openrc_script(String.t, String.t, String.t) :: Query.t
- def download_openrc_script(service_name, user_id, region \\ "SBG1") do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/user/#{user_id}/openrc",
- params: %{
- query_string: %{region: region}
- }
- }
- end
-
-
- @doc ~s"""
- Regenerate user password and other credentials.
-
- ## Api Call
-
- POST /cloud/project/{serviceName}/user/{userId}/regeneratePassword
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `user_id`: user_id for accessing the project. See `get_users/1`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.regenerate_credentials(service_name, user_id) |> ExOvh.request!()
- """
- @spec regenerate_credentials(String.t, String.t) :: Query.t
- def regenerate_credentials(service_name, user_id) do
- %Query{
- method: :post,
- uri: "/cloud/project/#{service_name}/user/#{user_id}/regeneratePassword",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Get the token for the user (very similar to keystone identity)
-
- ## Api Call
-
- POST /cloud/project/{serviceName}/user/{userId}/token
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `user_id`: The swift user_id to login with. See `get_users/1`.
- - `password`: The swift password to login with. See `regenerate_credentials/2`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.swift_identity(service_name, user_id) |> ExOvh.request!()
- """
- @spec swift_identity(String.t, String.t, String.t) :: Query.t
- def swift_identity(service_name, user_id, password) do
- %Query{
- method: :post,
- uri: "/cloud/project/#{service_name}/user/#{user_id}/token",
- params: %{
- binary: %{
- "password" => password
- } |> Poison.encode!()
- }
- }
- end
-
-
- @doc ~s"""
- Create a new Cloud Project.
-
- ## Api Call
-
- POST /cloud/createProject
-
- ## Arguments
-
- - `description`: project description
- - `voucher`: ovh voucher code
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.create_project(description, voucher) |> ExOvh.request!()
- """
- @spec create_project(String.t, String.t) :: Query.t
- def create_project(description, voucher) do
- %Query{
- method: :post,
- uri: "/cloud/createProject",
- params: %{
- binary: %{
- "description" => description,
- "voucher" => voucher
- } |> Poison.encode!()
- }
- }
- end
-
-
- @doc ~s"""
- Get services prices for the OVH public cloud.
-
- ## Api Call
-
- GET /cloud/price
-
- ## Arguments
-
- - `region`: prices for a particular region (optional)
- - `flavor_id`: ovh voucher code (optional)
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.get_prices() |> ExOvh.request!()
- """
- @spec get_prices(String.t | :nil, String.t | :nil) :: Query.t
- def get_prices(region \\ :nil, flavor_id \\ :nil) do
- params =
- cond do
- region == :nil and flavor_id == :nil -> %{}
- region != :nil and flavor_id == :nil -> %{"region" => region}
- region == :nil and flavor_id != :nil -> %{"flavorId" => flavor_id}
- region != :nil and flavor_id != :nil -> %{ "region" => region, "flavorId" => flavor_id }
- end
- %Query{
- method: :get,
- uri: "/cloud/createProject",
- params: %{
- binary: params |> Poison.encode!()
- }
- }
- end
-
-
- @doc ~s"""
- Get details for a given project.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.project_info(service_name) |> ExOvh.request!()
- """
- @spec project_info(String.t) :: Query.t
- def project_info(service_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Modify the project description for a project.
-
- ## Api Call
-
- PUT /cloud/project/{serviceName}
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.modify_project(service_name, new_description) |> ExOvh.request!()
- """
- @spec modify_project(String.t, String.t) :: Query.t
- def modify_project(service_name, new_description) do
- %Query{
- method: :put,
- uri: "/cloud/project/#{service_name}",
- params: %{
- binary: %{
- "description" => new_description
- } |> Poison.encode!()
- }
- }
- end
-
-
- @doc ~s"""
- Get administration information about the project
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/serviceInfos
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.project_administrative_info(service_name) |> ExOvh.request!()
- """
- @spec project_administrative_info(String.t) :: Query.t
- def project_administrative_info(service_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/serviceInfos",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Get project quotas.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/quota
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.project_quotas(service_name) |> ExOvh.request!()
- """
- @spec project_quotas(String.t) :: Query.t
- def project_quotas(service_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/quota",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Get project regions.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/region
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.project_regions(service_name) |> ExOvh.request!()
- """
- @spec project_regions(String.t) :: Query.t
- def project_regions(service_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/region",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Get project details about a project region.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/region/{regionName}
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.project_region_info(service_name) |> ExOvh.request!()
- """
- @spec project_region_info(String.t, String.t) :: Query.t
- def project_region_info(service_name, region_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/region/#{region_name}",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Get project details about a project consumption.
-
- *Note:* Will only allow for up to one month of data to be returned.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/consumption
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `date_from`: starting date in `ISO 8601` format. defaults to 4 weeks/28 days ago (UTC time) if left absent.
- - `date_to`: end date in `ISO 8601` format. defaults to now (UTC time) if left absent.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.project_consumption(service_name) |> ExOvh.request!()
- """
- @spec project_consumption(String.t, String.t, String.t) :: Query.t
- def project_consumption(service_name, date_from \\ :nil, date_to \\ :nil) do
- date_from = if date_from == :nil, do: Calendar.DateTime.now!("Etc/UTC") |> Calendar.DateTime.add!(-(60*60*24*28)) |> Calendar.DateTime.Format.rfc3339(), else: date_from
- date_to = if date_to == :nil, do: Calendar.DateTime.now!("Etc/UTC") |> Calendar.DateTime.Format.rfc3339(), else: date_to
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/consumption",
- params: %{
- query_string: %{
- from: date_from,
- to: date_to
- }
- }
- }
- end
-
-
- @doc ~s"""
- Get project details about a project bills.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/bill
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `date_from`: starting date in `ISO 8601` format. defaults to 4 weeks/28 days ago (UTC time) if left absent.
- - `date_to`: end date in `ISO 8601` format. defaults to now (UTC time) if left absent.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.project_bills(service_name) |> ExOvh.request!()
- """
- @spec project_bills(String.t, String.t, String.t) :: Query.t
- def project_bills(service_name, date_from \\ :nil, date_to \\ :nil) do
- date_from = if date_from == :nil, do: Calendar.DateTime.now!("Etc/UTC") |> Calendar.DateTime.add!(-(60*60*24*28)) |> Calendar.DateTime.Format.rfc3339(), else: date_from
- date_to = if date_to == :nil, do: Calendar.DateTime.now!("Etc/UTC") |> Calendar.DateTime.Format.rfc3339(), else: date_to
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/bill",
- params: %{
- query_string: %{
- from: date_from,
- to: date_to
- }
- }
- }
- end
-
-
- @doc ~s"""
- Get a list of project alert ids. These project alert ids can then be looked up in a separate query for more information.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/alerting
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.get_project_alerts(service_name) |> ExOvh.request!()
- """
- @spec get_project_alerts(String.t) :: Query.t
- def get_project_alerts(service_name) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/alerting",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Create a new project alert.
-
- *Notes:*
- It seems only one alert is allowed per project. To create a new one alter the old one or delete the old one and add a new one.
- Once the monthly threshold in the given currency is exceeded, then the alert email is sent.
-
- ## Api Call
-
- POST /cloud/project/{serviceName}/alerting
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `delay`: The delay between each alert in seconds. This has to be selected from an enumerable (a list). 3600 is the lowest. defaults to 3600. (1 hour)
- - `email`: The email to send the alert to.
- - `monthlyThreshold`: The maximum monetary (cash) usage allowed in one month. This is an integer value. Ask OVH about how the currency is chosen.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.create_project_alert(service_name, "email_address@email.email", 5) |> ExOvh.request!()
- """
- @spec create_project_alert(String.t, String.t, integer, String.t) :: Query.t | no_return
- def create_project_alert(service_name, email, monthly_threshold, delay \\ "3600") do
- unless is_integer(monthly_threshold), do: Og.log_return("monthly_threshold should be an integer!", __ENV__, :error) |> raise()
- %Query{
- method: :post,
- uri: "/cloud/project/#{service_name}/alerting",
- params: %{
- binary: %{
- "delay" => delay,
- "email" => email,
- "monthlyThreshold" => monthly_threshold
- } |> Poison.encode!()
- }
- }
- end
-
-
- @doc ~s"""
- Get detailed information about a project alert.
-
- ## Api Call
-
- GET /cloud/project/{serviceName}/alerting/{id}
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `alert_id`: The id of the project alert. See `get_project_alerts/1`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.get_project_alert_info(service_name, alert_id) |> ExOvh.request!()
- """
- @spec get_project_alert_info(String.t, String.t) :: Query.t
- def get_project_alert_info(service_name, alert_id) do
- %Query{
- method: :get,
- uri: "/cloud/project/#{service_name}/alerting/#{alert_id}",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Modify an existing project alert.
-
- ## Api Call
-
- PUT /cloud/project/{serviceName}/alerting/{id}
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `alert_id`: The alert to be modified.
- - `delay`: The delay between each alert in seconds. This has to be selected from an enumerable (a list). 3600 is the lowest. defaults to 3600. (1 hour)
- - `email`: The email to send the alert to.
- - `monthlyThreshold`: The maximum monetary (cash) usage allowed in one month. This is an integer value. Ask OVH about how the currency is chosen.
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.modify_project_alert(service_name, alert_id, "email_address@email.email", 5) |> ExOvh.request!()
- """
- @spec modify_project_alert(String.t, String.t, String.t, integer, String.t) :: Query.t
- def modify_project_alert(service_name, alert_id, email, monthly_threshold, delay \\ "3600") do
- unless is_integer(monthly_threshold), do: Og.log_return("monthly_threshold should be an integer!", __ENV__, :error) |> raise()
- %Query{
- method: :put,
- uri: "/cloud/project/#{service_name}/alerting/#{alert_id}",
- params: %{
- binary: %{
- "delay" => delay,
- "email" => email,
- "monthlyThreshold" => monthly_threshold
- } |> Poison.encode!()
- }
- }
- end
-
-
- @doc ~s"""
- Delete a project alert.
-
- ## Api Call
-
- DELETE /cloud/project/{serviceName}/alerting/{id}
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
- - `alert_id`: The id of the project alert. See `get_project_alerts/1`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.get_project_alert_info(service_name, alert_id) |> ExOvh.request!()
- """
- @spec delete_project_alert(String.t, String.t) :: Query.t
- def delete_project_alert(service_name, alert_id) do
- %Query{
- method: :delete,
- uri: "/cloud/project/#{service_name}/alerting/#{alert_id}",
- params: %{}
- }
- end
-
-
- @doc ~s"""
- Terminate a cloud project.
-
- ## Api Call
-
- POST /cloud/project/{serviceName}/terminate
-
- ## Arguments
-
- - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
-
- ## Example
-
- ExOvh.Services.V1.Cloud.Query.terminate_project(service_name) |> ExOvh.request!()
- """
- @spec terminate_project(String.t) :: Query.t
- def terminate_project(service_name) do
- %Query{
- method: :post,
- uri: "/cloud/project/#{service_name}/terminate",
- params: %{}
- }
- end
-
-
-
-end
\ No newline at end of file
diff --git a/lib/ex_ovh/services/v1/webstorage/query.ex b/lib/ex_ovh/services/v1/webstorage/query.ex
deleted file mode 100644
index 67999f2..0000000
--- a/lib/ex_ovh/services/v1/webstorage/query.ex
+++ /dev/null
@@ -1,158 +0,0 @@
-defmodule ExOvh.Services.V1.Webstorage.Query do
- @moduledoc Module.concat(__MODULE__, Docs).moduledoc()
- alias ExOvh.Query
-
-
-
- @doc ~s"""
- Get a list of all webstorage cdn services available for the client account
-
- ## Api call
-
- GET /v1/cdn/webstorage
-
- ## Example
-
- ExOvh.Services.V1.Webstorage.Query.get_services() |> ExOvh.request()
- """
- @spec get_services() :: Query.t
- def get_services() do
- %Query{
- method: :get,
- uri: "/cdn/webstorage",
- params: %{}
- }
- end
-
-
-
- @doc ~s"""
- Get the domain, server and storage limits for a specific webstorage cdn service
-
- ## Api call
-
- GET /v1/cdn/webstorage/{serviceName}
-
- ## Arguments
-
- - `service_name`: Name of the Webstorage CDN service - assigned by OVH.
-
- ## Example
-
- alias ExOvh.Services.V1.Webstorage.Query
- service_name = "cdnwebstorage-????"
- query = Query.get_service(service_name)
- {:ok, resp} = ExOvh.Ovh.request(query)
- %{
- "domain" => domain,
- "storageLimit => storage_limit,
- "server" => server
- } = resp.body
- """
- @spec get_service(String.t) :: Query.t
- def get_service(service_name) do
- %Query{
- method: :get,
- uri: "/cdn/webstorage/#{service_name}",
- params: %{}
- }
- end
-
-
-
- @doc ~s"""
- Get a administrative details for a specific webstorage cdn service
-
- ## Api call
-
- GET /v1/cdn/webstorage/{serviceName}/serviceInfos
-
- ## Arguments
-
- - `service_name`: Name of the Webstorage CDN service - assigned by OVH.
-
- ## Example
-
- alias ExOvh.Services.V1.Webstorage.Query
- service_name = "cdnwebstorage-????"
- Query.get_service_info(service_name)
- {:ok, resp} = ExOvh.Ovh.request(query)
- """
- @spec get_service_info(String.t) :: Query.t
- def get_service_info(service_name) do
- %Query{
- method: :get,
- uri: "/cdn/webstorage/#{service_name}/serviceInfos",
- params: %{}
- }
- end
-
-
-
- @doc ~s"""
- Get statistics for a specific webstorage cdn service
-
- ## Api call
-
- GET /v1/cdn/webstorage/{serviceName}/statistics
-
- ## Arguments
-
- - `service_name`: Name of the Webstorage CDN service - assigned by OVH.
- - `options`:
- - `period can be "month", "week" or "day"`
- - `type can be "backend", "quota" or "cdn"`
-
- ## Example
-
- alias ExOvh.Services.V1.Webstorage.Query
- service_name = "cdnwebstorage-????"
- query = Query.get_service_stats(service_name, [period: "month", type: "backend"])
- {:ok, resp} = ExOvh.Ovh.request(query)
- """
- @spec get_service_stats(String.t, Keyword.t) :: Query.t
- def get_service_stats(service_name, opts \\ []) do
- period = Keyword.get(opts, "period", "month")
- type = Keyword.get(opts, "type", "cdn")
- %Query{
- method: :get,
- uri: "/cdn/webstorage/#{service_name}/statistics",
- params: %{
- query_string: %{
- "period" => period,
- "type" => type
- }
- }
- }
- end
-
-
-
- @doc ~s"""
- Get credentials for using the swift compliant api
-
- ## Api call
-
- GET /v1/cdn/webstorage/{serviceName}/credentials
-
- ## Arguments
-
- - `service_name`: Name of the Webstorage CDN service - assigned by OVH.
-
- ## Example
-
- alias ExOvh.Services.V1.Webstorage.Query
- service_name = "cdnwebstorage-????"
- query = Query.get_webstorage_credentials(service_name)
- {:ok, resp} = ExOvh.Ovh.request(query)
- """
- @spec get_credentials(String.t) :: ExOvh.Query.Ovh.t
- def get_credentials(service_name) do
- %Query{
- method: :get,
- uri: "/cdn/webstorage/#{service_name}/credentials",
- params: %{}
- }
- end
-
-end
diff --git a/lib/ex_ovh/supervisor.ex b/lib/ex_ovh/supervisor.ex
index 6ec6be5..1df4abd 100644
--- a/lib/ex_ovh/supervisor.ex
+++ b/lib/ex_ovh/supervisor.ex
@@ -7,7 +7,6 @@ defmodule ExOvh.Supervisor do
def start_link(client, opts \\ []) do
- Og.context(__ENV__, :debug)
Supervisor.start_link(__MODULE__, {client, opts})
end
@@ -16,7 +15,6 @@ defmodule ExOvh.Supervisor do
def init({client, opts}) do
- Og.context(__ENV__, :debug)
sup_tree =
[
{client, {ExOvh.Config, :start_agent, [client, opts]}, :permanent, 10_000, :worker, [ExOvh.Config]}
diff --git a/lib/ex_ovh/transformation.ex b/lib/ex_ovh/transformation.ex
deleted file mode 100644
index dbe52c8..0000000
--- a/lib/ex_ovh/transformation.ex
+++ /dev/null
@@ -1,58 +0,0 @@
-defmodule ExOvh.Transformation do
- @moduledoc :false
- alias ExOvh.{Config, HttpQuery, Query}
- @default_headers [{"Content-Type", "application/json; charset=utf-8"}]
-
-
- # Public
-
-
- @spec prepare_request(Query.t, Keyword.t, atom) :: HttpQuery.t
- def prepare_request(%Query{method: method, uri: uri, params: params, headers: headers}, httpoison_opts, client) do
- ovh_config = client.ovh_config()
- uri = ovh_config[:endpoint] <> ovh_config[:api_version] <> uri
- uri =
- cond do
- params == %{} -> uri
- Map.get(params, :query_string, :nil) != :nil -> uri <> "?" <> (Map.fetch!(params, :query_string) |> URI.encode_query())
- :true -> uri
- end
- body = if Map.has_key?(params, :binary), do: Map.get(params, :binary), else: ""
- headers = headers ++ headers([ovh_config[:application_secret], ovh_config[:application_key], ovh_config[:consumer_key], Atom.to_string(method), uri, ""], client)
- default_httpoison_opts = client.httpoison_config()
- options = merge_options(default_httpoison_opts, httpoison_opts)
- %HttpQuery{method: method, uri: uri, body: body, headers: headers, options: options, service: :ovh}
- end
-
-
- # Private
-
-
- defp headers([app_secret, app_key, consumer_key, method, uri, body] = _opts, client) do
- time = :os.system_time(:seconds) + Config.get_diff(client)
- headers = [
- {"X-Ovh-Application", app_key},
- {"X-Ovh-Consumer", consumer_key},
- {"X-Ovh-Timestamp", time},
- {"X-Ovh-Signature", sign_request([app_secret, consumer_key, String.upcase(method), uri, body, time])}
- ]
- |> Enum.into(%{})
- Map.merge(Enum.into(@default_headers, %{}), headers) |> Enum.into([])
- end
-
-
- defp sign_request([_app_secret, _consumer_key, _method, _uri, _body, _time] = opts) do
- pre_hash = Enum.join(opts, "+")
- post_hash = :crypto.hash(:sha, pre_hash) |> Base.encode16(case: :lower)
- "$1$" <> post_hash
- end
-
- defp merge_options(opts1, opts2) do
- opts1 = Enum.into(opts1, %{})
- opts2 = Enum.into(opts2, %{})
- opts = Map.merge(opts1, opts2)
- Enum.into(opts, [])
- end
-
-
-end
diff --git a/lib/ex_ovh/transformation/auth.ex b/lib/ex_ovh/transformation/auth.ex
new file mode 100644
index 0000000..3787c97
--- /dev/null
+++ b/lib/ex_ovh/transformation/auth.ex
@@ -0,0 +1,41 @@
+defmodule ExOvh.Transformation.Auth do
+ @moduledoc :false
+ @default_headers [{"Content-Type", "application/json; charset=utf-8"}]
+
+
+ # Public
+
+ @spec apply(HTTPipe.Conn.t, atom) :: HTTPipe.Conn.t
+ def apply(%HTTPipe.Conn{request: %HTTPipe.Request{method: method, body: body, headers: headers, url: url}} = conn, client) do
+ trans = Map.get(conn, :completed_transformations, [])
+ unless (Enum.member?(trans, :url)), do: raise ":url must be added to the transformations before applying the :auth step"
+ ovh_config = client.ovh_config()
+ headers = Map.merge(headers, headers([ovh_config[:application_secret], ovh_config[:application_key], ovh_config[:consumer_key], Atom.to_string(method), url, body], client))
+ request = Map.put(conn.request, :headers, headers)
+ Map.put(conn, :request, request)
+ |> Map.put(:completed_transformations, trans ++ [:auth])
+ end
+
+
+ # Private
+
+ defp headers([app_secret, app_key, consumer_key, method, url, body] = _opts, client) do
+ time = :os.system_time(:seconds) + ExOvh.Config.get_diff(client)
+ headers = [
+ {"X-Ovh-Application", app_key},
+ {"X-Ovh-Consumer", consumer_key},
+ {"X-Ovh-Timestamp", time},
+ {"X-Ovh-Signature", sign_request([app_secret, consumer_key, String.upcase(method), url, body, time])}
+ ]
+ |> Enum.into(%{})
+ Map.merge(Enum.into(@default_headers, %{}), headers)
+ end
+
+ defp sign_request([_app_secret, _consumer_key, _method, _uri, _body, _time] = opts) do
+ pre_hash = Enum.join(opts, "+")
+ post_hash = :crypto.hash(:sha, pre_hash) |> Base.encode16(case: :lower)
+ "$1$" <> post_hash
+ end
+
+
+end
diff --git a/lib/ex_ovh/transformation/body.ex b/lib/ex_ovh/transformation/body.ex
new file mode 100644
index 0000000..40bc7a3
--- /dev/null
+++ b/lib/ex_ovh/transformation/body.ex
@@ -0,0 +1,16 @@
+defmodule ExOvh.Transformation.Body do
+ @moduledoc :false
+
+
+ # Public
+
+ @spec apply(HTTPipe.Conn.t, binary) :: HTTPipe.Conn.t
+ def apply(%HTTPipe.Conn{request: %HTTPipe.Request{}} = conn, body) when is_binary(body) do
+ trans = Map.get(conn, :completed_transformations, [])
+ request = Map.put(conn.request, :body, body)
+ Map.put(conn, :request, request)
+ |> Map.put(:completed_transformations, trans ++ [:body])
+ end
+
+
+end
diff --git a/lib/ex_ovh/transformation/hackney_options.ex b/lib/ex_ovh/transformation/hackney_options.ex
new file mode 100644
index 0000000..c2f39a0
--- /dev/null
+++ b/lib/ex_ovh/transformation/hackney_options.ex
@@ -0,0 +1,26 @@
+defmodule ExOvh.Transformation.HackneyOptions do
+ @moduledoc :false
+
+
+ # Public
+
+ @spec apply(HTTPipe.Conn.t, atom) :: HTTPipe.Conn.t
+ def apply(%HTTPipe.Conn{request: %HTTPipe.Request{}} = conn, client) do
+ hackney_options = Map.get(conn, :adapter_options, [])
+ trans = Map.get(conn, :completed_transformations, [])
+ options = merge_options(client.hackney_opts(), hackney_options)
+ Map.put(conn, :adapter_options, options)
+ |> Map.put(:completed_transformations, trans ++ [:hackney_options])
+ end
+
+
+ # Private
+
+ defp merge_options(opts1, opts2) do
+ opts1 = Enum.into(opts1, %{})
+ opts2 = Enum.into(opts2, %{})
+ opts = Map.merge(opts1, opts2)
+ Enum.into(opts, [])
+ end
+
+end
diff --git a/lib/ex_ovh/transformation/url.ex b/lib/ex_ovh/transformation/url.ex
new file mode 100644
index 0000000..4d3ab3c
--- /dev/null
+++ b/lib/ex_ovh/transformation/url.ex
@@ -0,0 +1,58 @@
+defmodule ExOvh.Transformation.Url do
+ @moduledoc :false
+
+
+ # Public
+
+ @spec apply(HTTPipe.Conn.t, atom) :: HTTPipe.Conn.t
+ def apply(%HTTPipe.Conn{request: %HTTPipe.Request{url: url}} = conn, client) do
+ ovh_config = client.ovh_config()
+ trans = Map.get(conn, :completed_transformations, [])
+ url = ovh_config[:endpoint] <> ovh_config[:api_version] <> url
+ request = Map.put(conn.request, :url, url)
+ Map.put(conn, :request, request)
+ |> Map.put(:completed_transformations, trans ++ [:url])
+ end
+
+ @spec apply(HTTPipe.Conn.t, map, atom) :: HTTPipe.Conn.t
+ def apply(%HTTPipe.Conn{} = conn, query_string_map, client) when query_string_map == %{} do
+ __MODULE__.apply(conn, client)
+ end
+ def apply(%HTTPipe.Conn{request: %HTTPipe.Request{url: url}} = conn, query_string_map, client) do
+ ovh_config = client.ovh_config()
+ trans = Map.get(conn, :completed_transformations, [])
+ url = ovh_config[:endpoint] <> ovh_config[:api_version] <> url
+ request = Map.put(conn.request, :url, url)
+ |> add_query_string(query_string_map)
+ Map.put(conn, :request, request)
+ |> Map.put(:completed_transformations, trans ++ [:url])
+ end
+
+
+ @doc ~S"""
+ Add the request string to a request from a map of `name`=`value` elements. Use instead of
+ `ExOvh.Transformation.Url.apply/3` when the `client` is not available but the request should
+ be modified without marking it as fully `transformed` with :url.
+
+ To be used for GET requests.
+
+ ## Example
+
+ service_name="service_name"
+ %HTTPipe.Request{
+ method: :get,
+ url: "/cdn/webstorage/#{service_name}/statistics"
+ }
+ |> ExOvh.Transformation.Url.add_query_string(%{"containerName" => container_name, "region" => region})
+ |> ExOvh.Request!()
+
+ """
+ @spec add_query_string(HTTPipe.Request.t, map) :: HTTPipe.Request.t
+ def add_query_string(%HTTPipe.Request{} = request, qs_map) when qs_map == %{}, do: request
+ def add_query_string(%HTTPipe.Request{url: url} = request, qs_map) do
+ url = url <> "?" <> URI.encode_query(qs_map)
+ Map.put(request, :url, url)
+ end
+
+
+end
diff --git a/lib/ex_ovh/v1/cloud.ex b/lib/ex_ovh/v1/cloud.ex
new file mode 100644
index 0000000..b030dfb
--- /dev/null
+++ b/lib/ex_ovh/v1/cloud.ex
@@ -0,0 +1,976 @@
+defmodule ExOvh.V1.Cloud do
+ @moduledoc ~s"""
+ Helper functions for building requests directed at the cloudstorage related parts of the `/cloud` part of the [OVH API](https://api.ovh.com/console/).
+
+ See `ExOvh.V1.Cloud` for generic cloud requests.
+
+ ## Functions Summary
+
+ | Function | Description | OVH API call |
+ |---|---|---|
+ | `list_services/0` | <small>List available services or list available cloud projects. A returned project id in OVH terms is similar to a tenant id in swift terms</small> | <sub><sup>GET /cloud/project</sup></sub> |
+ | `get_users/1` | <small>Get all users</small> | <sub><sup>GET /cloud/project/{serviceName}/user</sup></sub> |
+ | `create_user/2` | <small>Create user</small> | <sub><sup>POST /ctsloud/project/{serviceName}/user</sup></sub> |
+ | `get_user_details/2` | <small>Get user details. Returns the user_id and username and other details.</small> | <sub><sup>GET /cloud/project/{serviceName}/user/{userId}</sup></sub> |
+ | `delete_user/2` | <small>Delete user</small> | <sub><sup>DELETE /cloud/project/{serviceName}/user/{userId}</sup></sub> |
+ | `download_openrc_script/3` | <small>Get RC file of OpenStack</small> | <sub><sup>GET /cloud/project/{serviceName}/user/{userId}/openrc</sup></sub> |
+ | `regenerate_credentials/2` | <small>Regenerate user credentials including password</small> | <sub><sup>POST /cloud/project/{serviceName}/user/{userId}/regeneratePassword</sup></sub> |
+ | `swift_identity/3` | <small>Gets a json object similar to that returned by Keystone Identity. Includes the 'X-Auth-Token'</small> | <sub><sup>POST /cloud/project/{serviceName}/user/{userId}/token</sup></sub> |
+ | `create_project/2` | <small>Start a new cloud project in the OVH cloud. Corresponds to creating a new Swift stack with a new tenant_id.</small> | <sub><sup>POST /cloud/createProject</sup></sub> |
+ | `get_prices/2` | <small>Get Prices for OVH cloud services.</small> | <sub><sup>GET /cloud/price</sup></sub> |
+ | `project_info/1` | <small>Get information about a project with the project_id (tenant_id)</small> | <sub><sup>GET /cloud/project/{serviceName}</sup></sub> |
+ | `modify_project/2` | <small>Modify a project properties. Change the project description.</small> | <sub><sup>PUT /cloud/project/{serviceName}</sup></sub> |
+ | `project_administrative_info/1` | <small>Get administration information about the project.</small> | <sub><sup>GET /cloud/project/{serviceName}/serviceInfos</sup></sub> |
+ | `project_quotas/1` | <small>Get project quotas.</small> | <sub><sup>GET /cloud/project/{serviceName}/quota</sup></sub> |
+ | `project_regions/1` | <small>Get project regions.</small> | <sub><sup>GET /cloud/project/{serviceName}/region</sup></sub> |
+ | `project_region_info/2` | <small>Get details about a project region.</small> | <sub><sup>GET /cloud/project/{serviceName}/region/{regionName}</sup></sub> |
+ | `project_consumption/3` | <small>Get details about a project consumption for a given `date_from` and `date_to`.</small> | <sub><sup>GET /cloud/project/{serviceName}/consumption</sup></sub> |
+ | `project_bills/3` | <small>Get details about a project billing for a given `date_from` and `date_to`..</small> | <sub><sup>GET /cloud/project/{serviceName}/bill</sup></sub> |
+ | `create_project_alert/4` | <small>Add a new project alert</small> | <sub><sup>POST /cloud/project/{serviceName}/alerting</sup></sub> |
+ | `get_project_alert_info/2` | <small>Get detailed information about a project alert.</small> | <sub><sup>GET /cloud/project/{serviceName}/alerting/{id}</sup></sub> |
+ | `modify_project_alert/5` | <small>Modify an existing project alert.</small> | <sub><sup>PUT /cloud/project/{serviceName}/alerting/{id}</sup></sub> |
+ | `delete_project_alert/2` | <small>Delete an existing project alert.</small> | <sub><sup>DELETE /cloud/project/{serviceName}/alerting/{id}</sup></sub> |
+ | `terminate_service/2` | <small>Terminate a cloud project.</small> | <sub><sup>POST /cloud/project/{serviceName}/terminate</sup></sub> |
+ | `get_containers/1` | <small>Get containers for a given swift tenant id (project id or ovh service name)</small> | <sub><sup>GET /cloud/project/{serviceName}/storage </sup></sub> |
+ | `create_container/3` | <small>Create a container for a given tenant_id (ovh service_name), a container and a region.</small> | <sub><sup>POST /cloud/project/{serviceName}/storage</sup></sub> |
+ | `get_access/1` | <small>Get access details for the Swift API for a given swift tenant_id (ovh service_name)</small> | <sub><sup>GET /cloud/project/{serviceName}/storage/access</sup></sub> |
+ | `container_info/2` | <small>Gets details about a container such as objects, size, region, public or not, static_url, name, ...</small> | <sub><sup>GET /cloud/project/{serviceName}/storage/{containerId}</sup></sub> |
+ | `delete_container/2` | <small>Deletes a given container.</small> | <sub><sup>DELETE /cloud/project/{serviceName}/storage/{containerId}</sup></sub> |
+ | `modify_container_cors/3` | <small>Modify the CORS settings for a container. See [swift docs](http://docs.openstack.org/developer/swift/cors.html)</small> | <sub><sup>POST /cloud/project/{serviceName}/storage/{containerId}/cors Add CORS support on your container</sup></sub> |
+ | `deploy_container_as_static_website/2` | <small>Deploy the container files as a static web site.</small> | <sub><sup>POST /cloud/project/{serviceName}/storage/{containerId}/static</sup></sub> |
+
+ ## Notes
+
+ - `service_name` or `serviceName` corresponds to the Openstack `tenant_id`
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_containers(service_name) |> ExOvh.request!()
+ """
+ alias ExOvh.Transformation.{Body, Url}
+
+
+ @doc ~s"""
+ Get storage containers
+
+ ## Api call
+
+ GET /cloud/project/{serviceName}/storage
+
+ ## Arguments
+
+ - `service_name`: service name for the ovh cloud service
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_containers(service_name) |> ExOvh.request!()
+ """
+ @spec get_containers(String.t) :: HTTPipe.Conn.t
+ def get_containers(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/storage",
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Create container
+
+ ## Api call
+
+ POST /cloud/project/{serviceName}/storage
+
+ ## Arguments
+
+ - `service_name`: service name for the ovh cloud service
+ - `container_name`: name for the new container
+ - `region`: region for the new container, defaults to "SBG1". See regions by running:
+ Currently can choose from "GRA1", "BHS1", "SBG1".
+
+
+ ## Example
+
+ ExOvh.V1.Cloud.create_container(service_name, "test_container") |> ExOvh.request!()
+ """
+ @spec create_container(String.t, String.t, String.t) :: HTTPipe.Conn.t
+ def create_container(service_name, container_name, region \\ "SBG1") do
+ # POST /cloud/project/{serviceName}/storage Create container
+ body =
+ %{
+ "containerName" => container_name,
+ "region" => region
+ }
+ |> Poison.encode!()
+ req = %HTTPipe.Request{
+ method: :post,
+ url: "/cloud/project/#{service_name}/storage"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+ @doc ~s"""
+ Gets the x_auth_token and the swift endpoints for a given tenant_id (ovh service_name). A different endpoint is returned
+ depending on the region. Examples of regions include "BHS1", "SBG1", "GRA1". With these details, requests can be made through
+ the Swift api.
+
+ ## Api call
+
+ GET /cloud/project/{serviceName}/storage/access
+
+ ## Arguments
+
+ - `service_name`: service name for the ovh cloud service
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_access(service_name) |> ExOvh.request!()
+ """
+ @spec get_access(String.t) :: HTTPipe.Conn.t
+ def get_access(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/storage/access"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+
+ @doc ~s"""
+ Gets the details for a given container.
+
+ Returns information such as a list of objects in the container, size of the container, whether the container is public
+ or not, the region of the container, the name of the container, the number of stored objects for the container and the
+ static url for the container.
+
+ ## Api call
+
+ GET /cloud/project/{serviceName}/storage/{containerId}
+
+ ## Arguments
+
+ - `service_name`: service name for the ovh cloud service
+ - `container_id`: container_id for a given container. *Note*: this is not the same as the container_name.
+
+ ## Example
+
+ ExOvh.V1.Cloud.container_info(service_name, container_id) |> ExOvh.request!()
+ """
+ @spec container_info(String.t, String.t) :: HTTPipe.Conn.t
+ def container_info(service_name, container_id) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/storage/#{container_id}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Deletes a given container.
+
+ *Note:* container_d is not the same as container_name.
+
+ ## Api call
+
+ DELETE /cloud/project/{serviceName}/storage/{containerId}
+
+ ## Arguments
+
+ - `service_name`: service name for the ovh cloud service
+ - `container_id`: container_id for a given container. *Note*: this is not the same as the container_name.
+
+ ## Example
+
+ ExOvh.V1.Cloud.delete_container(service_name, container_id) |> ExOvh.request!()
+ """
+ @spec delete_container(String.t, String.t) :: HTTPipe.Conn.t
+ def delete_container(service_name, container_id) do
+ req = %HTTPipe.Request{
+ method: :delete,
+ url: "/cloud/project/#{service_name}/storage/#{container_id}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Modify CORS settings for a container.
+
+ Modifies the container metadata such that cross origin requests can be permitted.
+ See [CORS section of swift docs](http://docs.openstack.org/developer/swift/cors.html) for more info. Ans see here for more
+ on [CORS in general](http://enable-cors.org/resources.html)
+
+ | Metadata | Use |
+ | --- | --- |
+ | X-Container-Meta-Access-Control-Allow-Origin | Origins to be allowed to make Cross Origin Requests, space separated. |
+
+
+ *Note:* container_d is not the same as container_name.
+
+ ## Api call
+
+ DELETE /cloud/project/{serviceName}/storage/{containerId}
+
+ ## Arguments
+
+ - `service_name`: service name for the ovh cloud service
+ - `container_id`: container_id for a given container. *Note*: this is not the same as the container_name.
+ - `origin`: an origin that may make cross origin requests to the container. Defaults to `{}` (none) if left absent.
+
+ ## Example
+
+ ExOvh.V1.Cloud.modify_container_cors(service_name, container_id, "http://localhost:4001/") |> ExOvh.request!()
+
+ ## Notes
+
+ To get a full overview of the container details with all metadata, the Swift client should be used. To see the changes, try running the following
+ command for the `container_name` associated with this `container_id`. In fact, the OVH functions are not really required, most changes can be made directly
+ using queries sent via the `Swift.Cloudstorage` client.
+
+ account = ExOvh.Swift.Cloudstorage.account()
+ container = "test_container"
+ Openstex.Swift.V1.container_info(container, account) |> ExOvh.Swift.Cloudstorage.request!() |> Map.get(:headers) |> Map.get("X-Container-Meta-Access-Control-Allow-Origin")
+ """
+ @spec modify_container_cors(String.t, String.t, String.t) :: HTTPipe.Conn.t
+ def modify_container_cors(service_name, container_id, origin \\ {}) do
+ body =
+ %{
+ "origin" => origin
+ }
+ |> Poison.encode!()
+ req = %HTTPipe.Request{
+ method: :post,
+ url: "/cloud/project/#{service_name}/storage/#{container_id}/cors"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+
+ @doc ~s"""
+ Deploy a container as a static website.
+
+ Modifies the ACL settings for a container on the "X-Container-Read" header and also other container metadata.
+ See [swift auth docs](http://docs.openstack.org/developer/swift/overview_auth.html),
+ [swift acl middleware](http://docs.openstack.org/developer/swift/misc.html#module-swift.common.middleware.acl)
+ and [swift account middleware](http://docs.openstack.org/developer/swift/middleware.html#module-swift.common.middleware.tempauth)
+ for more information.
+
+ ## Api call
+
+ POST /cloud/project/{serviceName}/storage/{containerId}/static
+
+ ## Arguments
+
+ - `service_name`: service name for the ovh cloud service
+ - `container_id`: container_id for a given container. *Note*: this is not the same as the container_name.
+
+ ## Example
+
+ ExOvh.V1.Cloud.modify_container_cors(service_name, container_id, "http://localhost:4001/") |> ExOvh.request!()
+
+ ## Notes
+
+ To get a full overview of the container details with all metadata, the Swift client should be used. To see the changes, try running the following
+ command for the `container_name` associated with this `container_id`. In fact, the OVH functions are not really required, most changes can be made directly
+ using queries sent via the `Swift.Cloudstorage` client.
+
+ account = ExOvh.Swift.Cloudstorage.account()
+ container = "test_container"
+ Openstex.Swift.V1.container_info(container, account) |> ExOvh.Swift.Cloudstorage.request!() |> Map.get(:headers)
+ """
+ @spec deploy_container_as_static_website(String.t, String.t) :: HTTPipe.Conn.t
+ def deploy_container_as_static_website(service_name, container_id) do
+ req = %HTTPipe.Request{
+ method: :post,
+ url: "/cloud/project/#{service_name}/storage/#{container_id}/static"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+
+ @doc ~s"""
+ List available services
+
+ ## Api Call
+
+ GET /cloud/project
+
+ ## Example
+
+ ExOvh.V1.Cloud.list_services() |> ExOvh.request!()
+ """
+ @spec list_services() :: HTTPipe.Conn.t
+ def list_services() do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get all users
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/user
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_users(service_name) |> ExOvh.request!()
+ """
+ @spec get_users(String.t) :: HTTPipe.Conn.t
+ def get_users(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/user"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Create user
+
+ ## Api Call
+
+ POST /cloud/project/{serviceName}/user
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `description`: description ascribed to the new user.
+
+ ## Example
+
+ ExOvh.V1.Cloud.create_user(service_name, "ex_ovh") |> ExOvh.request!()
+ """
+ @spec create_user(String.t, String.t) :: HTTPipe.Conn.t
+ def create_user(service_name, description) do
+ body =
+ %{
+ "description" => description
+ } |> Poison.encode!()
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/user"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+ @doc ~s"""
+ Get user details. Returns the user_id and username and other details.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/user/{userId}
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `user_id`: corresponds to user_id. See `get_users/1`
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_user_details(service_name, user_id) |> ExOvh.request!()
+ """
+ @spec get_user_details(String.t, String.t) :: HTTPipe.Conn.t
+ def get_user_details(service_name, user_id) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/user/#{user_id}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Delete a specific user.
+
+ ## Api Call
+
+ DELETE /cloud/project/{serviceName}/user/{userId}
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `user_id`: The user_id. See `get_users/1`
+
+ ## Example
+
+ ExOvh.V1.Cloud.delete_user(service_name, user_id) |> ExOvh.request!()
+ """
+ @spec delete_user(String.t, String.t) :: HTTPipe.Conn.t
+ def delete_user(service_name, user_id) do
+ req = %HTTPipe.Request{
+ method: :delete,
+ url: "/cloud/project/#{service_name}/user/#{user_id}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get RC file of OpenStack. This file is a bash script with much of the openstack credentials. Makes it easier for
+ setting up a swift client from the terminal.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/user/{userId}/openrc
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `user_id`: user_id for user accessing the service.
+ - `region`: region for which the rc file will be created. Defaults to "SBG1" if left absent.
+
+ ## Example
+
+ ExOvh.V1.Cloud.download_openrc_script(service_name, user_id, "SBG1") |> ExOvh.request!()
+ """
+ @spec download_openrc_script(String.t, String.t, String.t) :: HTTPipe.Conn.t
+ def download_openrc_script(service_name, user_id, region \\ "SBG1") do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/user/#{user_id}/openrc",
+ }
+ |> Url.add_query_string(%{region: region})
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Regenerate user password and other credentials.
+
+ ## Api Call
+
+ POST /cloud/project/{serviceName}/user/{userId}/regeneratePassword
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `user_id`: user_id for accessing the project. See `get_users/1`
+
+ ## Example
+
+ ExOvh.V1.Cloud.regenerate_credentials(service_name, user_id) |> ExOvh.request!()
+ """
+ @spec regenerate_credentials(String.t, String.t) :: HTTPipe.Conn.t
+ def regenerate_credentials(service_name, user_id) do
+ req = %HTTPipe.Request{
+ method: :post,
+ url: "/cloud/project/#{service_name}/user/#{user_id}/regeneratePassword"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get the token for the user (very similar to keystone identity)
+
+ ## Api Call
+
+ POST /cloud/project/{serviceName}/user/{userId}/token
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `user_id`: The swift user_id to login with. See `get_users/1`.
+ - `password`: The swift password to login with. See `regenerate_credentials/2`
+
+ ## Example
+
+ ExOvh.V1.Cloud.swift_identity(service_name, user_id) |> ExOvh.request!()
+ """
+ @spec swift_identity(String.t, String.t, String.t) :: HTTPipe.Conn.t
+ def swift_identity(service_name, user_id, password) do
+ body =
+ %{
+ "password" => password
+ } |> Poison.encode!()
+ req = %HTTPipe.Request{
+ method: :post,
+ url: "/cloud/project/#{service_name}/user/#{user_id}/token"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+ @doc ~s"""
+ Create a new Cloud Project.
+
+ ## Api Call
+
+ POST /cloud/createProject
+
+ ## Arguments
+
+ - `description`: project description
+ - `voucher`: ovh voucher code
+
+ ## Example
+
+ ExOvh.V1.Cloud.create_project(description, voucher) |> ExOvh.request!()
+ """
+ @spec create_project(String.t, String.t) :: HTTPipe.Conn.t
+ def create_project(description, voucher) do
+ body =
+ %{
+ "description" => description,
+ "voucher" => voucher
+ } |> Poison.encode!()
+ req = %HTTPipe.Request{
+ method: :post,
+ url: "/cloud/createProject"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+ @doc ~s"""
+ Get services prices for the OVH public cloud.
+
+ ## Api Call
+
+ GET /cloud/price
+
+ ## Arguments
+
+ - `region`: prices for a particular region (optional)
+ - `flavor_id`: ovh voucher code (optional)
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_prices() |> ExOvh.request!()
+ """
+ @spec get_prices(String.t | :nil, String.t | :nil) :: HTTPipe.Conn.t
+ def get_prices(region \\ :nil, flavor_id \\ :nil) do
+ params =
+ cond do
+ region == :nil and flavor_id == :nil -> %{}
+ region != :nil and flavor_id == :nil -> %{"region" => region}
+ region == :nil and flavor_id != :nil -> %{"flavorId" => flavor_id}
+ region != :nil and flavor_id != :nil -> %{ "region" => region, "flavorId" => flavor_id }
+ end
+ body = if params == %{}, do: "", else: Poison.encode!(params)
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/price"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+ @doc ~s"""
+ Get details for a given project.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.project_info(service_name) |> ExOvh.request!()
+ """
+ @spec project_info(String.t) :: HTTPipe.Conn.t
+ def project_info(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Modify the project description for a project.
+
+ ## Api Call
+
+ PUT /cloud/project/{serviceName}
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.modify_project(service_name, new_description) |> ExOvh.request!()
+ """
+ @spec modify_project(String.t, String.t) :: HTTPipe.Conn.t
+ def modify_project(service_name, new_description) do
+ body =
+ %{
+ "description" => new_description
+ } |> Poison.encode!()
+ req = %HTTPipe.Request{
+ method: :put,
+ url: "/cloud/project/#{service_name}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+ @doc ~s"""
+ Get administration information about the project
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/serviceInfos
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.project_administrative_info(service_name) |> ExOvh.request!()
+ """
+ @spec project_administrative_info(String.t) :: HTTPipe.Conn.t
+ def project_administrative_info(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/serviceInfos"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get project quotas.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/quota
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.project_quotas(service_name) |> ExOvh.request!()
+ """
+ @spec project_quotas(String.t) :: HTTPipe.Conn.t
+ def project_quotas(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/quota"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get project regions.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/region
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.project_regions(service_name) |> ExOvh.request!()
+ """
+ @spec project_regions(String.t) :: HTTPipe.Conn.t
+ def project_regions(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/region"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get project details about a project region.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/region/{regionName}
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.project_region_info(service_name) |> ExOvh.request!()
+ """
+ @spec project_region_info(String.t, String.t) :: HTTPipe.Conn.t
+ def project_region_info(service_name, region_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/region/#{region_name}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get project details about a project consumption.
+
+ *Note:* Will only allow for up to one month of data to be returned.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/consumption
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `date_from`: starting date in `ISO 8601` format. defaults to 4 weeks/28 days ago (UTC time) if left absent.
+ - `date_to`: end date in `ISO 8601` format. defaults to now (UTC time) if left absent.
+
+ ## Example
+
+ ExOvh.V1.Cloud.project_consumption(service_name) |> ExOvh.request!()
+ """
+ @spec project_consumption(String.t, String.t, String.t) :: HTTPipe.Conn.t
+ def project_consumption(service_name, date_from \\ :nil, date_to \\ :nil) do
+ date_from = if date_from == :nil, do: Calendar.DateTime.now!("Etc/UTC") |> Calendar.DateTime.add!(-(60*60*24*28)) |> Calendar.DateTime.Format.rfc3339(), else: date_from
+ date_to = if date_to == :nil, do: Calendar.DateTime.now!("Etc/UTC") |> Calendar.DateTime.Format.rfc3339(), else: date_to
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/consumption"
+ }
+ |> Url.add_query_string(%{from: date_from, to: date_to})
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get project details about a project bills.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/bill
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `date_from`: starting date in `ISO 8601` format. defaults to 4 weeks/28 days ago (UTC time) if left absent.
+ - `date_to`: end date in `ISO 8601` format. defaults to now (UTC time) if left absent.
+
+ ## Example
+
+ ExOvh.V1.Cloud.project_bills(service_name) |> ExOvh.request!()
+ """
+ @spec project_bills(String.t, String.t, String.t) :: HTTPipe.Conn.t
+ def project_bills(service_name, date_from \\ :nil, date_to \\ :nil) do
+ date_from = if date_from == :nil, do: Calendar.DateTime.now!("Etc/UTC") |> Calendar.DateTime.add!(-(60*60*24*28)) |> Calendar.DateTime.Format.rfc3339(), else: date_from
+ date_to = if date_to == :nil, do: Calendar.DateTime.now!("Etc/UTC") |> Calendar.DateTime.Format.rfc3339(), else: date_to
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/bill"
+ }
+ |> Url.add_query_string(%{from: date_from,to: date_to})
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get a list of project alert ids. These project alert ids can then be looked up in a separate request for more information.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/alerting
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_project_alerts(service_name) |> ExOvh.request!()
+ """
+ @spec get_project_alerts(String.t) :: HTTPipe.Conn.t
+ def get_project_alerts(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/alerting"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Create a new project alert.
+
+ *Notes:*
+ It seems only one alert is allowed per project. To create a new one alter the old one or delete the old one and add a new one.
+ Once the monthly threshold in the given currency is exceeded, then the alert email is sent.
+
+ ## Api Call
+
+ POST /cloud/project/{serviceName}/alerting
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `delay`: The delay between each alert in seconds. This has to be selected from an enumerable (a list). 3600 is the lowest. defaults to 3600. (1 hour)
+ - `email`: The email to send the alert to.
+ - `monthlyThreshold`: The maximum monetary (cash) usage allowed in one month. This is an integer value. Ask OVH about how the currency is chosen.
+
+ ## Example
+
+ ExOvh.V1.Cloud.create_project_alert(service_name, "email_address@email.email", 5) |> ExOvh.request!()
+ """
+ @spec create_project_alert(String.t, String.t, integer, String.t) :: HTTPipe.Conn.t | no_return
+ def create_project_alert(service_name, email, monthly_threshold, delay \\ "3600") do
+ unless is_integer(monthly_threshold), do: raise("monthly_threshold should be an integer!")
+ body =
+ %{
+ "delay" => delay,
+ "email" => email,
+ "monthlyThreshold" => monthly_threshold
+ } |> Poison.encode!()
+ req = %HTTPipe.Request{
+ method: :post,
+ url: "/cloud/project/#{service_name}/alerting"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+ @doc ~s"""
+ Get detailed information about a project alert.
+
+ ## Api Call
+
+ GET /cloud/project/{serviceName}/alerting/{id}
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `alert_id`: The id of the project alert. See `get_project_alerts/1`
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_project_alert_info(service_name, alert_id) |> ExOvh.request!()
+ """
+ @spec get_project_alert_info(String.t, String.t) :: HTTPipe.Conn.t
+ def get_project_alert_info(service_name, alert_id) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cloud/project/#{service_name}/alerting/#{alert_id}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Modify an existing project alert.
+
+ ## Api Call
+
+ PUT /cloud/project/{serviceName}/alerting/{id}
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `alert_id`: The alert to be modified.
+ - `delay`: The delay between each alert in seconds. This has to be selected from an enumerable (a list). 3600 is the lowest. defaults to 3600. (1 hour)
+ - `email`: The email to send the alert to.
+ - `monthlyThreshold`: The maximum monetary (cash) usage allowed in one month. This is an integer value. Ask OVH about how the currency is chosen.
+
+ ## Example
+
+ ExOvh.V1.Cloud.modify_project_alert(service_name, alert_id, "email_address@email.email", 5) |> ExOvh.request!()
+ """
+ @spec modify_project_alert(String.t, String.t, String.t, integer, String.t) :: HTTPipe.Conn.t
+ def modify_project_alert(service_name, alert_id, email, monthly_threshold, delay \\ "3600") do
+ unless is_integer(monthly_threshold), do: raise("monthly_threshold should be an integer!")
+ body = %{
+ "delay" => delay,
+ "email" => email,
+ "monthlyThreshold" => monthly_threshold
+ } |> Poison.encode!()
+ req = %HTTPipe.Request{
+ method: :put,
+ url: "/cloud/project/#{service_name}/alerting/#{alert_id}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ |> Body.apply(body)
+ end
+
+
+ @doc ~s"""
+ Delete a project alert.
+
+ ## Api Call
+
+ DELETE /cloud/project/{serviceName}/alerting/{id}
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+ - `alert_id`: The id of the project alert. See `get_project_alerts/1`
+
+ ## Example
+
+ ExOvh.V1.Cloud.get_project_alert_info(service_name, alert_id) |> ExOvh.request!()
+ """
+ @spec delete_project_alert(String.t, String.t) :: HTTPipe.Conn.t
+ def delete_project_alert(service_name, alert_id) do
+ req = %HTTPipe.Request{
+ method: :delete,
+ url: "/cloud/project/#{service_name}/alerting/#{alert_id}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Terminate a cloud project.
+
+ ## Api Call
+
+ POST /cloud/project/{serviceName}/terminate
+
+ ## Arguments
+
+ - `service_name`: corresponds to project_id or tenant_id. See `list_services/0`
+
+ ## Example
+
+ ExOvh.V1.Cloud.HTTPipe.Conn.terminate_project(service_name) |> ExOvh.request!()
+ """
+ @spec terminate_project(String.t) :: HTTPipe.Conn.t
+ def terminate_project(service_name) do
+ req = %HTTPipe.Request{
+ method: :post,
+ url: "/cloud/project/#{service_name}/terminate"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+end
diff --git a/lib/ex_ovh/v1/webstorage.ex b/lib/ex_ovh/v1/webstorage.ex
new file mode 100644
index 0000000..b8fe4ad
--- /dev/null
+++ b/lib/ex_ovh/v1/webstorage.ex
@@ -0,0 +1,174 @@
+defmodule ExOvh.V1.Webstorage do
+ @moduledoc ~s"""
+
+ ***NOTE:*** This is a deprecated service!!!
+
+ Helper functions for building queries directed at the `/cdn/webstorage` part of the [OVH API](https://api.ovh.com/console/).
+
+ ## Functions Summary
+
+ | Function | Description | OVH API call |
+ |---|---|---|
+ | `get_services/0` | <small>Get a list of all webstorage cdn services.</small> | <sub><sup>GET /v1/cdn/webstorage</sup></sub> |
+ | `get_service/1` | <small>Get the domain, server and storage limits for a specific webstorage cdn service</small> | <sub><sup>GET /v1/cdn/webstorage/{serviceName}</sup></sub> |
+ | `get_service_info/1` | <small>Get a administrative details for a specific webstorage cdn service</small> | <sub><sup>GET /v1/cdn/webstorage/{serviceName}/serviceInfos</sup></sub> |
+ | `get_service_stats/2` | <small>Get statistics for a specific webstorage cdn service</small> | <sub><sup>GET /v1/cdn/webstorage/{serviceName}/statistics</sup></sub> |
+ | `get_credentials/1` | <small>Get credentials for using the swift compliant api</small> | <sub><sup>GET /v1/cdn/webstorage/{serviceName}/statistics</sup></sub> |
+
+
+ ## Example
+
+ ExOvh.V1.Webstorage.get_services() |> ExOvh.request()
+ """
+ alias ExOvh.Transformation.Url
+
+
+
+ @doc ~s"""
+ Get a list of all webstorage cdn services available for the client account
+
+ ## Api call
+
+ GET /v1/cdn/webstorage
+
+ ## Example
+
+ ExOvh.V1.Webstorage.get_services() |> ExOvh.request()
+ """
+ @spec get_services() :: HTTPipe.Conn.t
+ def get_services() do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cdn/webstorage"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+
+ @doc ~s"""
+ Get the domain, server and storage limits for a specific webstorage cdn service
+
+ ## Api call
+
+ GET /v1/cdn/webstorage/{serviceName}
+
+ ## Arguments
+
+ - `service_name`: Name of the Webstorage CDN service - assigned by OVH.
+
+ ## Example
+
+ alias ExOvh.V1.Webstorage
+ service_name = "cdnwebstorage-????"
+ conn = Webstorage.get_service(service_name)
+ {:ok, conn} = ExOvh.Ovh.request(conn)
+ %{
+ "domain" => domain,
+ "storageLimit => storage_limit,
+ "server" => server
+ } = conn.response.body
+ """
+ @spec get_service(String.t) :: HTTPipe.Conn.t
+ def get_service(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cdn/webstorage/#{service_name}"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+
+ @doc ~s"""
+ Get a administrative details for a specific webstorage cdn service
+
+ ## Api call
+
+ GET /v1/cdn/webstorage/{serviceName}/serviceInfos
+
+ ## Arguments
+
+ - `service_name`: Name of the Webstorage CDN service - assigned by OVH.
+
+ ## Example
+
+ alias ExOvh.V1.Webstorage
+ service_name = "cdnwebstorage-????"
+ Webstorage.get_service_info(service_name)
+ {:ok, conn} = ExOvh.Ovh.request(conn)
+ """
+ @spec get_service_info(String.t) :: HTTPipe.Conn.t
+ def get_service_info(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cdn/webstorage/#{service_name}/serviceInfos"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+
+ @doc ~s"""
+ Get statistics for a specific webstorage cdn service
+
+ ## Api call
+
+ GET /v1/cdn/webstorage/{serviceName}/statistics
+
+ ## Arguments
+
+ - `service_name`: Name of the Webstorage CDN service - assigned by OVH.
+ - `options`:
+ - `period can be "month", "week" or "day"`
+ - `type can be "backend", "quota" or "cdn"`
+
+ ## Example
+
+ alias ExOvh.V1.Webstorage
+ service_name = "cdnwebstorage-????"
+ conn = Webstorage.get_service_stats(service_name, [period: "month", type: "backend"])
+ {:ok, conn} = ExOvh.Ovh.request(conn)
+ """
+ @spec get_service_stats(String.t, Keyword.t) :: HTTPipe.Conn.t
+ def get_service_stats(service_name, opts \\ []) do
+ period = Keyword.get(opts, "period", "month")
+ type = Keyword.get(opts, "type", "cdn")
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cdn/webstorage/#{service_name}/statistics"
+ }
+ |> Url.add_query_string(%{"period" => period,"type" => type})
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+ @doc ~s"""
+ Get credentials for using the swift compliant api
+
+ ## Api call
+
+ GET /v1/cdn/webstorage/{serviceName}/credentials
+
+ ## Arguments
+
+ - `service_name`: Name of the Webstorage CDN service - assigned by OVH.
+
+ ## Example
+
+ alias ExOvh.V1.Webstorage
+ service_name = "cdnwebstorage-????"
+ conn = Webstorage.get_webstorage_credentials(service_name)
+ {:ok, conn} = ExOvh.Ovh.request(conn)
+ """
+ @spec get_credentials(String.t) :: HTTPipe.Conn.t
+ def get_credentials(service_name) do
+ req = %HTTPipe.Request{
+ method: :get,
+ url: "/cdn/webstorage/#{service_name}/credentials"
+ }
+ Map.put(HTTPipe.Conn.new(), :request, req)
+ end
+
+
+end
diff --git a/lib/mix/tasks/ovh.ex b/lib/mix/tasks/ovh.ex
index 76dbe99..ed68498 100644
--- a/lib/mix/tasks/ovh.ex
+++ b/lib/mix/tasks/ovh.ex
@@ -1,10 +1,41 @@
defmodule Mix.Tasks.Ovh do
@shortdoc "Create a new application and new credentials for accessing ovh api"
- @moduledoc Module.concat(__MODULE__, Docs).moduledoc()
+ @moduledoc ~s"""
+ A mix task that generates the ex_ovh application secrets on the user's behalf.
+
+ ## Steps
+
+ - The user needs to set up an ovh account at https://www.ovh.co.uk/ and retrieve a username (nic-handle) and password.
+
+ - Then the user is prompted to do some activations.
+
+ - Upon completion of activations, the user needs to create an application in the ovh website.
+
+ - Then the user can create an application at `https://eu.api.ovh.com/createApp/` or
+ alternatively the user can use this mix task to generate the application:
+
+ ## Example
+
+ Create an app with access to all apis:
+
+ mix ovh --login=<username-ovh> --password=<password> --appname='ex_ovh'
+
+ Output:
+
+ config :ex_ovh,
+ ovh: [
+ application_key: System.get_env("EX_OVH_APPLICATION_KEY"),
+ application_secret: System.get_env("EX_OVH_APPLICATION_SECRET"),
+ consumer_key: System.get_env("EX_OVH_CONSUMER_KEY")
+ ]
+
+ See the [mix task documentation]((https://github.com/stephenmoloney/ex_ovh/blob/master/docs/mix_task.md).
+ """
use Mix.Task
alias ExOvh.Defaults
@default_headers [{"Content-Type", "application/json; charset=utf-8"}]
- @default_options [ timeout: 30000, recv_timeout: (60000 * 1) ]
+ @default_adapter HTTPipe.Adapters.Hackney
+ @default_hackney_options [timeout: 30000, recv_timeout: (60000 * 1)]
@default_name "ex_ovh"
@default_description "ex_ovh application"
@default_redirect_uri ""
@@ -21,8 +52,10 @@ defmodule Mix.Tasks.Ovh do
Mix.Shell.IO.info("")
Mix.Shell.IO.info("The details in the map above will be used to create the ovh application.")
Mix.Shell.IO.info("")
+
if Mix.Shell.IO.yes?("Proceed?") do
- HTTPoison.start
+ Application.ensure_all_started(:hackney)
+
opts_map = parse_args(args)
message = get_credentials(opts_map)
@@ -81,9 +114,9 @@ defmodule Mix.Tasks.Ovh do
end
- defp parsers_login({opts, acc}), do: {opts, Map.merge(acc, %{login: Keyword.fetch!(opts, :login)}) }
- defp parsers_password({opts, acc}), do: {opts, Map.merge(acc, %{ password: Keyword.fetch!(opts, :password)}) }
- # defp parsers_app_name({opts, acc}), do: {opts, Map.merge(acc, %{ application_name: Keyword.fetch!(opts, :appname)}) }
+ defp parsers_login({opts, acc}), do: {opts, Map.merge(acc, %{login: Keyword.fetch!(opts, :login)})}
+ defp parsers_password({opts, acc}), do: {opts, Map.merge(acc, %{password: Keyword.fetch!(opts, :password)})}
+ # defp parsers_app_name({opts, acc}), do: {opts, Map.merge(acc, %{application_name: Keyword.fetch!(opts, :appname)})}
defp parsers_endpoint({opts, acc}) do
endpoint = Keyword.get(opts, :endpoint, :nil)
endpoint =
@@ -91,7 +124,7 @@ defmodule Mix.Tasks.Ovh do
:nil -> "ovh-eu"
_ -> endpoint
end
- {opts, Map.merge(acc, %{ endpoint: endpoint }) }
+ {opts, Map.merge(acc, %{endpoint: endpoint})}
end
defp parsers_api_version({opts, acc}) do
api_version = Keyword.get(opts, :apiversion, :nil)
@@ -100,33 +133,26 @@ defmodule Mix.Tasks.Ovh do
:nil -> "1.0"
_ -> api_version
end
- {opts, Map.merge(acc, %{ api_version: api_version }) }
+ {opts, Map.merge(acc, %{api_version: api_version})}
end
defp parsers_redirect_uri({opts, acc}) do
redirect_uri = Keyword.get(opts, :redirecturi, @default_redirect_uri)
- {opts, Map.merge(acc, %{ redirect_uri: redirect_uri }) }
+ {opts, Map.merge(acc, %{redirect_uri: redirect_uri})}
end
defp parsers_client_name({opts, acc}) do
client_name = Keyword.get(opts, :clientname, :nil)
- {opts, Map.merge(acc, %{ client_name: client_name }) }
+ {opts, Map.merge(acc, %{client_name: client_name})}
end
defp parsers_app_name({opts, acc}) do
application_name = Keyword.get(opts, :appname, @default_name)
- application_name =
- case application_name do
- :nil -> "ex_ovh"
- _ -> application_name
- end
- {opts, Map.merge(acc, %{ application_name: application_name }) }
+ application_name = application_name && application_name || @default_name
+ {opts, Map.merge(acc, %{application_name: application_name})}
end
defp parsers_app_desc({opts, acc}) do
application_description = Keyword.get(opts, :appdescription, :nil)
- application_description =
- case application_description do
- :nil -> Keyword.get(opts, :appname, @default_description)
- _ -> application_description
- end
- {opts, Map.merge(acc, %{ application_description: application_description }) }
+ application_description = application_description && application_description ||
+ Keyword.get(opts, :appname, @default_description)
+ {opts, Map.merge(acc, %{application_description: application_description})}
end
defp parsers_access_rules({opts, acc}) do
access_rules = Keyword.get(opts, :accessrules, :nil)
@@ -141,41 +167,43 @@ defmodule Mix.Tasks.Ovh do
end)
|> Enum.reduce([], fn({method, concat_paths}, acc) ->
paths = concat_paths
- |> String.lstrip(?[)
- |> String.strip(?]) #rstrip has a bug but fixed in master (01/02/2016)
+ |> String.trim_leading(?[)
+ |> String.trim(?]) #rstrip has a bug but fixed in master (01/02/2016)
|> String.split(",")
- new_rules = Enum.filter_map(paths,
- fn(path) -> path !== "" end,
- fn(path) ->
- %{
- method: String.upcase(method),
- path: path
- }
- end)
+ new_rules = Enum.filter(paths, fn(path) -> path != "" end)
+ |> Enum.map(fn(path) -> %{method: String.upcase(method), path: path} end)
List.insert_at(acc, -1, new_rules)
end)
|> List.flatten()
end
- {opts, Map.merge(acc, %{access_rules: access_rules}) }
+ {opts, Map.merge(acc, %{access_rules: access_rules})}
end
defp get_app_create_page(opts_map) do
-# Og.context(__ENV__, :debug)
-
method = :get
- uri = Defaults.endpoints()[opts_map[:endpoint]] <> Defaults.create_app_uri_suffix()
+ url = Defaults.endpoints()[opts_map[:endpoint]] <> Defaults.create_app_uri_suffix()
body = ""
headers = []
- options = @default_options
- resp = HTTPoison.request!(method, uri, body, headers, options)
- Map.get(resp, :body)
+ options = @default_hackney_options
+
+ conn = %HTTPipe.Conn{
+ request: %HTTPipe.Request{
+ method: method,
+ url: url,
+ body: body,
+ headers: headers
+ },
+ adapter: @default_adapter,
+ adapter_options: options
+ }
+ {:ok, conn} = HTTPipe.Conn.execute(conn)
+
+ conn.response.body
end
defp get_create_app_inputs(resp_body) do
-# Og.context(__ENV__, :debug)
-
inputs = Floki.find(resp_body, "form input")
|> List.flatten()
if Enum.any?(inputs, fn(input) -> input == [] end), do: raise "Empty input found"
@@ -184,8 +212,6 @@ defmodule Mix.Tasks.Ovh do
defp build_app_request(inputs, %{login: login, password: password} = opts_map) do
-# Og.context(__ENV__, :debug)
-
{acc, _index, _max} =
Enum.reduce(inputs, {"", 1, Enum.count(inputs)}, fn({"input", input, _}, acc) ->
name = :proplists.get_value("name", input)
@@ -212,25 +238,33 @@ defmodule Mix.Tasks.Ovh do
defp send_app_request(req_body, opts_map) do
-# Og.context(__ENV__, :debug)
-
method = :post
- uri = Defaults.endpoints()[opts_map[:endpoint]] <> Defaults.create_app_uri_suffix()
+ url = Defaults.endpoints()[opts_map[:endpoint]] <> Defaults.create_app_uri_suffix()
body = req_body
headers = [{"Content-Type", "application/x-www-form-urlencoded"}]
- options = @default_options
- resp = HTTPoison.request!(method, uri, body, headers, options)
+ options = @default_hackney_options
+
+ conn = %HTTPipe.Conn{
+ request: %HTTPipe.Request{
+ method: method,
+ url: url,
+ body: body,
+ headers: headers
+ },
+ adapter: @default_adapter,
+ adapter_options: options
+ }
+ {:ok, conn} = HTTPipe.Conn.execute(conn)
+ body = conn.response.body
# Error checking
cond do
- String.contains?(resp.body, msg = "There is already an application with that name for that Account ID") ->
+ String.contains?(body, msg = "There is already an application with that name for that Account ID") ->
raise(msg <> ", try removing the old application first using the ovh api console or just create a new one.")
- String.contains?(resp.body, msg = "Invalid account/password") ->
+ String.contains?(body, msg = "Invalid account/password") ->
raise(msg <> ", try adding '-ovh' to the end of the login")
- String.contains?(resp.body, "Application created") ->
- resp.body
- true ->
- raise "unknown error"
+ String.contains?(body, "Application created") -> body
+ true -> raise "unknown error"
end
end
@@ -260,31 +294,49 @@ defmodule Mix.Tasks.Ovh do
defp get_consumer_key(%{access_rules: access_rules, redirect_uri: redirect_uri} = opts_map) do
-# Og.context(__ENV__, :debug)
-
method = :post
- uri = Defaults.endpoints()[opts_map[:endpoint]] <> opts_map[:api_version] <> Defaults.consumer_key_suffix()
- body = %{ accessRules: access_rules, redirection: redirect_uri } |> Poison.encode!()
+ url = Defaults.endpoints()[opts_map[:endpoint]] <> opts_map[:api_version] <> Defaults.consumer_key_suffix()
+ body = %{accessRules: access_rules, redirection: redirect_uri} |> Poison.encode!()
headers = Map.merge(Enum.into(@default_headers, %{}), Enum.into([{"X-Ovh-Application", opts_map[:application_key]}], %{})) |> Enum.into([])
- options = @default_options
- resp = HTTPoison.request!(method, uri, body, headers, options)
-
- body = Poison.decode!(Map.get(resp, :body))
+ options = @default_hackney_options
+
+ conn = %HTTPipe.Conn{
+ request: %HTTPipe.Request{
+ method: method,
+ url: url,
+ body: body,
+ headers: headers
+ },
+ adapter: @default_adapter,
+ adapter_options: options
+ }
+ {:ok, conn} = HTTPipe.Conn.execute(conn)
+
+ body = Poison.decode!(conn.response.body)
{Map.get(body, "consumerKey"), Map.get(body, "validationUrl")}
end
defp bind_consumer_key_to_app({ck, validation_url}, opts_map) do
-# Og.context(__ENV__, :debug)
-
method = :get
- uri = validation_url
+ url = validation_url
body = ""
headers = []
- options = @default_options
- resp = HTTPoison.request!(method, uri, body, headers, options)
-
- Map.get(resp, :body)
+ options = @default_hackney_options
+
+ conn = %HTTPipe.Conn{
+ request: %HTTPipe.Request{
+ method: method,
+ url: url,
+ body: body,
+ headers: headers
+ },
+ adapter: @default_adapter,
+ adapter_options: options
+ }
+ {:ok, conn} = HTTPipe.Conn.execute(conn)
+
+ conn.response.body
|> get_bind_ck_to_app_inputs()
|> build_ck_binding_request(opts_map)
|> send_ck_binding_request(validation_url, ck)
@@ -292,13 +344,11 @@ defmodule Mix.Tasks.Ovh do
defp get_bind_ck_to_app_inputs(resp_body) do
-# Og.context(__ENV__, :debug)
-
inputs = Floki.find(resp_body, "form input") ++
Floki.find(resp_body, "form select")
|> List.flatten()
|> Enum.filter(fn({_type, input, _options}) ->
- :proplists.get_value("name", input) !== "identifiant"
+ :proplists.get_value("name", input) != "identifiant"
end)
if Enum.any?(inputs, fn(input) -> input == [] end), do: raise "Inputs should not be empty"
inputs
@@ -306,8 +356,6 @@ defmodule Mix.Tasks.Ovh do
defp build_ck_binding_request(inputs, %{login: login, password: password} = _opts_map) do
-# Og.context(__ENV__, :debug)
-
Enum.reduce(inputs, "", fn({type, input, _options}, acc) ->
{name_val, value} =
cond do
@@ -329,7 +377,6 @@ defmodule Mix.Tasks.Ovh do
{name_val, value}
true ->
# raise "Unexpected input"
-# Og.log("Ignoring unexpected input " <> inspect(input), __ENV__, :warn)
{:no_name, :no_val}
end
case {name_val, value} do
@@ -342,25 +389,32 @@ defmodule Mix.Tasks.Ovh do
defp send_ck_binding_request(req_body, validation_url, ck) do
-# Og.context(__ENV__, :debug)
-
method = :post
- uri = validation_url
+ url = validation_url
body = req_body
headers = [{"Content-Type", "application/x-www-form-urlencoded"}]
- options = @default_options
- resp = HTTPoison.request!(method, uri, body, headers, options)
-
- case check_for_successful_binding(resp, validation_url, ck) do
- {:ok, :handle_2fa} -> handle_2fa(resp.body, validation_url, ck)
+ options = @default_hackney_options
+
+ conn = %HTTPipe.Conn{
+ request: %HTTPipe.Request{
+ method: method,
+ url: url,
+ body: body,
+ headers: headers
+ },
+ adapter: @default_adapter,
+ adapter_options: options
+ }
+ {:ok, conn} = HTTPipe.Conn.execute(conn)
+
+ case check_for_successful_binding(conn.response, validation_url, ck) do
+ {:ok, :handle_2fa} -> handle_2fa(conn.response.body, validation_url, ck)
{:ok, ck} -> ck
{:error, msg} -> raise msg
end
end
- def check_for_successful_binding(resp, validation_url, ck) do
-# Og.context(__ENV__, :debug)
-
+ defp check_for_successful_binding(resp, validation_url, ck) do
error_msg1 = "Failed to bind the consumer token to the application. Please try to validate the consumer token manually at #{validation_url}"
error_msg2 = "Invalid validity period entered for the consumer token. Please try to validate the consumer token manually at #{validation_url}"
cond do
@@ -369,7 +423,7 @@ defmodule Mix.Tasks.Ovh do
String.contains?(resp.body, "Your token is now valid, you can use it in your application") -> {:ok, ck}
String.contains?(resp.body, "token is now valid") -> {:ok, ck}
String.contains?(resp.body, "You have activated the double factor authentication") -> {:ok, :handle_2fa}
- # presume the validation was successful if redirected to redirect uri
+ # presume the validation was successful if redirected to redirect url
resp.status_code == 302 && (resp.headers |> Enum.into(%{}) |> Map.has_key?("Location")) -> {:ok, ck}
true -> {:error, "Unexpected error " <> error_msg1}
end
@@ -377,8 +431,6 @@ defmodule Mix.Tasks.Ovh do
defp build_2fa_request(resp_body) do
-# Og.context(__ENV__, :debug)
-
Mix.Shell.IO.info("You have activated 2FA on your OVH account, you need to verify your account via 2FA")
Floki.find(resp_body, "form input")
@@ -406,7 +458,6 @@ defmodule Mix.Tasks.Ovh do
{name_val, value}
true ->
# raise "Unexpected input"
-# Og.log("Ignoring unexpected input " <> inspect(input), __ENV__, :warn)
{:no_name, :no_val}
end
case {name_val, value} do
@@ -419,17 +470,26 @@ defmodule Mix.Tasks.Ovh do
defp handle_2fa(resp_body, validation_url, ck) do
-# Og.context(__ENV__, :debug)
-
method = :post
- uri = validation_url
+ url = validation_url
body = build_2fa_request(resp_body)
headers = [{"Content-Type", "application/x-www-form-urlencoded"}]
- options = @default_options
- resp = HTTPoison.request!(method, uri, body, headers, options)
+ options = @default_hackney_options
+
+ conn = %HTTPipe.Conn{
+ request: %HTTPipe.Request{
+ method: method,
+ url: url,
+ body: body,
+ headers: headers
+ },
+ adapter: @default_adapter,
+ adapter_options: options
+ }
+ {:ok, conn} = HTTPipe.Conn.execute(conn)
error_msg = "function check_for_successful_binding seems to be entering an error loop"
- case check_for_successful_binding(resp, validation_url, ck) do
+ case check_for_successful_binding(conn.response, validation_url, ck) do
{:ok, :handle_2fa} -> raise error_msg
{:ok, ck} -> ck
{:error, msg} -> raise "#{error_msg} - #{msg}"
@@ -438,17 +498,15 @@ defmodule Mix.Tasks.Ovh do
defp get_credentials(opts_map) do
-# Og.context(__ENV__, :debug)
-
create_app_body = get_app_create_page(opts_map) |> get_create_app_inputs() |> build_app_request(opts_map) |> send_app_request(opts_map)
opts_map = Map.merge(opts_map, %{
application_key: get_application_key(create_app_body),
application_secret: get_application_secret(create_app_body),
application_name: get_application_name(create_app_body),
application_description: get_application_description(create_app_body)
- })
+ })
ck = get_consumer_key(opts_map) |> bind_consumer_key_to_app(opts_map)
- Map.merge(opts_map, %{ consumer_key: ck })
+ Map.merge(opts_map, %{consumer_key: ck})
|> Map.delete(:login) |> Map.delete(:password)
end
@@ -462,25 +520,19 @@ defmodule Mix.Tasks.Ovh do
config_names(Atom.to_string(app_name), client_name)
end
defp config_names(app_name, client_name) do
-# Og.context(__ENV__, :debug)
-
{config_header, mod_client_name} =
case app_name do
"ex_ovh" ->
{
":" <> app_name,
"EX_OVH_"
- }
+ }
other ->
- client_name =
- case client_name do
- :nil -> "OvhClient"
- client_name -> client_name
- end
+ client_name = client_name && client_name || "OvhClient"
{
":" <> app_name <> ", " <> Macro.camelize(app_name) <> "." <> client_name,
- String.upcase(other) <> "_" <> Morph.to_snake_caps(client_name) <>"_"
- }
+ String.upcase(other) <> "_" <> String.upcase(Macro.underscore(client_name)) <>"_"
+ }
end
{config_header, mod_client_name}
end
@@ -513,8 +565,6 @@ defmodule Mix.Tasks.Ovh do
defp print_config(options, elixir_app_name) do
-# Og.context(__ENV__, :debug)
-
app_name = elixir_app_name || options.application_name
{config_header, mod_client_name} = config_names(app_name, options.client_name)
@@ -529,7 +579,7 @@ defmodule Mix.Tasks.Ovh do
consumer_key: System.get_env(\"#{mod_client_name <> "CONSUMER_KEY"}\"),
endpoint: \"#{options.endpoint}\",
api_version: \"#{options.api_version}\"
- ]
+ ]
"""
end
diff --git a/mix.exs b/mix.exs
index cb7143b..4bf3dc1 100644
--- a/mix.exs
+++ b/mix.exs
@@ -1,6 +1,7 @@
defmodule ExOvh.Mixfile do
use Mix.Project
- @version "0.2.0"
+ @version "0.4.0"
+ @elixir "~> 1.5"
def project do
[
@@ -8,7 +9,7 @@ defmodule ExOvh.Mixfile do
name: "ExOvh",
version: @version,
source_url: "https://github.com/stephenmoloney/ex_ovh",
- elixir: "~> 1.2",
+ elixir: @elixir,
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
description: description(),
@@ -20,21 +21,20 @@ defmodule ExOvh.Mixfile do
def application() do
[
- applications: [:calendar, :crypto, :httpoison, :logger]
+ applications: [:calendar, :crypto, :hackney, :floki, :logger, :poison]
]
end
defp deps() do
[
{:calendar, "~> 0.17"},
- {:og, "~> 0.1"},
- {:morph, "~> 0.1"},
- {:poison, "~> 1.5 or ~> 2.0"},
- {:httpoison, "~> 0.8.0"},
- {:floki, "~> 0.14.0"},
+ {:poison, "~> 1.5 or ~> 2.0 or ~> 3.0"},
+ {:httpipe_adapters_hackney, "~> 0.11"},
+ {:floki, "~> 0.18"},
+ # dev deps
{:markdown, github: "devinus/markdown", only: :dev},
- {:ex_doc, "~> 0.11", only: :dev}
+ {:ex_doc, "~> 0.18", only: :dev}
]
end
@@ -50,7 +50,7 @@ defmodule ExOvh.Mixfile do
licenses: ["MIT"],
maintainers: ["Stephen Moloney"],
links: %{ "GitHub" => "https://github.com/stephenmoloney/ex_ovh"},
- files: ~w(lib priv mix.exs README* LICENCE* CHANGELOG*)
+ files: ~w(lib mix.exs README* LICENCE* CHANGELOG*)
}
end
diff --git a/mix.lock b/mix.lock
new file mode 100644
index 0000000..5fdf36e
--- /dev/null
+++ b/mix.lock
@@ -0,0 +1,18 @@
+%{"calendar": {:hex, :calendar, "0.17.4", "22c5e8d98a4db9494396e5727108dffb820ee0d18fed4b0aa8ab76e4f5bc32f1", [], [{:tzdata, "~> 0.5.8 or ~> 0.1.201603", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
+ "certifi": {:hex, :certifi, "2.0.0", "a0c0e475107135f76b8c1d5bc7efb33cd3815cb3cf3dea7aefdd174dabead064", [], [], "hexpm"},
+ "earmark": {:hex, :earmark, "1.2.3", "206eb2e2ac1a794aa5256f3982de7a76bf4579ff91cb28d0e17ea2c9491e46a4", [], [], "hexpm"},
+ "ex_doc": {:hex, :ex_doc, "0.18.1", "37c69d2ef62f24928c1f4fdc7c724ea04aecfdf500c4329185f8e3649c915baf", [], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
+ "floki": {:hex, :floki, "0.18.1", "6f903e3074357fe9756079d0f607e430589912f698b5c5e5970af08daba1537c", [], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
+ "hackney": {:hex, :hackney, "1.10.1", "c38d0ca52ea80254936a32c45bb7eb414e7a96a521b4ce76d00a69753b157f21", [], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
+ "hoedown": {:git, "https://github.com/hoedown/hoedown.git", "980b9c549b4348d50b683ecee6abee470b98acda", []},
+ "httpipe": {:hex, :httpipe, "0.9.0", "4db66493b0ec2a86d142ea959a62e221d6ddb23ab48a676b691be3a16c38a415", [], [], "hexpm"},
+ "httpipe_adapters_hackney": {:hex, :httpipe_adapters_hackney, "0.11.0", "35c31b96fd6fea117f9ba6ca70467ada111dffb9f2fa7fca0bfc7e12bb166e8e", [], [{:hackney, "~> 1.8 or ~> 1.7 or ~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:httpipe, "~> 0.9.0", [hex: :httpipe, repo: "hexpm", optional: false]}], "hexpm"},
+ "idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
+ "markdown": {:git, "https://github.com/devinus/markdown.git", "d065dbcc4e242a85ca2516fdadd0082712871fd8", []},
+ "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [], [], "hexpm"},
+ "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [], [], "hexpm"},
+ "mochiweb": {:hex, :mochiweb, "2.15.0", "e1daac474df07651e5d17cc1e642c4069c7850dc4508d3db7263a0651330aacc", [], [], "hexpm"},
+ "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [], [], "hexpm"},
+ "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [], [], "hexpm"},
+ "tzdata": {:hex, :tzdata, "0.5.12", "1c17b68692c6ba5b6ab15db3d64cc8baa0f182043d5ae9d4b6d35d70af76f67b", [], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
+ "unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [], [], "hexpm"}}