Skip to content

Commit

Permalink
Initialize Repo
Browse files Browse the repository at this point in the history
  • Loading branch information
MikaAK committed Aug 28, 2022
0 parents commit 35c46ee
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
95 changes: 95 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
*.retry

### Elixir ###
/_build
/cover
/deps
/doc
/.fetch
erl_crash.dump
*.ez
*.beam
/config/*.secret.exs
.elixir_ls/

### Elixir Patch ###

### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig

# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt

### OSX ###
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Terraform ###
# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log
crash.*.log

# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Include override files you do wish to add to version control using negated pattern
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

# Ignore CLI configuration files
.terraformrc
terraform.rc

Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# LearnElixirDeploys

**TODO: Add description**

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `learn_elixir_deploys` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:learn_elixir_deploys, "~> 0.1.0"}
]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/learn_elixir_deploys>.

2 changes: 2 additions & 0 deletions lib/learn_elixir_deploys.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
defmodule LearnElixirDeploys do
end
73 changes: 73 additions & 0 deletions lib/mix/tasks/ansible.build.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
defmodule Mix.Tasks.Ansible.Build do
use Mix.Task

@shortdoc "Deploys to terraform resources using ansible"
@moduledoc """
Deploys to ansible
"""

def run(args) do
with :ok <- check_in_umbrella(),
:ok <- create_ansible_hosts_file(parse_args(args)) do
:ok
else
{:error, e} -> Mix.shell().error(to_string(e))
end
end

defp check_in_umbrella do
if Mix.Project.umbrella?() do
:ok
else
{:error, ErrorMessage.bad_request("must be in umbrella root")}
end
end

defp parse_args(args) do
{opts, _} = OptionParser.parse!(args,
aliases: [f: :force, q: :quit],
switches: [
force: :boolean,
quiet: :boolean
]
)

opts
end

defp create_ansible_hosts_file(opts) do
with {:ok, hostname_ips} <- terraform_instance_ips() do
ansible_host_file = EEx.eval_file("./deploys/ansible/hosts.eex", [
assigns: %{
host_name_ips: hostname_ips
}
])

Mix.Generator.create_file("./deploys/ansible/hosts", ansible_host_file, opts)

:ok
end
end

defp terraform_instance_ips do
case System.shell("terraform output --json", cd: Path.expand("./deploys/terraform")) do
{output, 0} ->
{:ok, parse_terraform_output_to_ips(output)}

{message, _} ->
{:error, ErrorMessage.failed_dependency("terraform output failed", %{message: message})}
end
end

defp parse_terraform_output_to_ips(output) do
case Jason.decode!(output) do
%{"public_ip" => %{"value" => values}} -> values
_ -> []
end
end

def host_name(host_name, index) do
"#{host_name}_#{:io_lib.format("~3..0B", [index])}"
end
end

72 changes: 72 additions & 0 deletions lib/mix/tasks/terraform.build.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
defmodule Mix.Tasks.Terraform.Build do
use Mix.Task

@shortdoc "Deploys to terraform resources using ansible"
@moduledoc """
Deploys to ansible
"""

@terraform_file Path.expand("../../deploys/terraform/variables.tf")

if not File.exists?(@terraform_file) do
raise "Terraform file doesn't exist at #{@terraform_file}"
end

def run(args) do
terraform_output = LearnElixir.MixProject.releases()
|> Keyword.keys
|> Enum.map_join(",\n\n", &(&1 |> to_string |> generate_terraform_output))

opts = parse_args(args)

write_to_terraform(terraform_output, opts)
end

defp parse_args(args) do
{opts, _} = OptionParser.parse!(args,
aliases: [f: :force, q: :quit],
switches: [
force: :boolean,
quiet: :boolean
]
)

opts
end

defp generate_terraform_output(release_name) do
"""
#{release_name} = {
environment = "prod"
name = "#{title_case(release_name)}"
}
"""
end

defp title_case(string) do
string |> String.split("_") |> Enum.map_join(" ", &String.capitalize/1)
end

defp write_to_terraform(terraform_output, opts) do
new_terraform_file = @terraform_file |> File.read! |> inject_terraform_contents(terraform_output)

if opts[:force] || Mix.Generator.overwrite?(@terraform_file, new_terraform_file) do
File.write!(@terraform_file, new_terraform_file)

if !opts[:quiet] do
Mix.shell().info([:green, "* injecting ", :reset, @terraform_file])
end
end
end

defp inject_terraform_contents(current_file, terraform_output) do
current_file = String.split(current_file, "\n")
project_variable_idx = Enum.find_index(
current_file,
&(&1 =~ "variable \"learn_elixir_project\"")
) + 4 # 4 is the number of newlines till the default key
{start_of_file, project_variable} = Enum.split(current_file, project_variable_idx + 1)

Enum.join(start_of_file ++ String.split(terraform_output, "\n") ++ Enum.take(project_variable, -3), "\n")
end
end
32 changes: 32 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
defmodule LearnElixirDeploys.MixProject do
use Mix.Project

def project do
[
app: :learn_elixir_deploys,
version: "0.1.0",
build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> 1.13",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:jason, "~> 1.3"},
{:error_message, "~> 0.2"}
]
end
end
4 changes: 4 additions & 0 deletions test/learn_elixir_deploys_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule LearnElixirDeploysTest do
use ExUnit.Case
doctest LearnElixirDeploys
end
1 change: 1 addition & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit 35c46ee

Please sign in to comment.