rrx_api 0.1.0 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/Gemfile +3 -4
- data/Gemfile.lock +126 -117
- data/README.md +1 -1
- data/app/controllers/rrx_api/health_controller.rb +33 -0
- data/app/models/rrx_api/record.rb +10 -0
- data/config/routes.rb +13 -0
- data/lib/generators/rrx_api/base.rb +95 -0
- data/lib/generators/rrx_api/docker_generator.rb +19 -0
- data/lib/generators/rrx_api/github_generator.rb +83 -0
- data/lib/generators/rrx_api/install_generator.rb +120 -0
- data/lib/generators/rrx_api/templates/docker/Dockerfile.tt +1 -0
- data/lib/generators/rrx_api/templates/github/build/workflows/build.yml.tt +71 -0
- data/lib/generators/rrx_api/templates/github/deploy/workflows/deploy.yml.tt +62 -0
- data/lib/generators/rrx_api/templates/terraform/aws/iam.tf.tt +37 -0
- data/lib/generators/rrx_api/templates/terraform/aws/main.tf.tt +44 -0
- data/lib/generators/rrx_api/templates/terraform/aws/service.tf.tt +67 -0
- data/lib/generators/rrx_api/terraform_generator.rb +76 -0
- data/lib/rrx_api/engine.rb +88 -0
- data/lib/rrx_api/version.rb +3 -2
- data/lib/rrx_api.rb +1 -1
- metadata +63 -31
- data/.idea/.gitignore +0 -8
- data/.idea/inspectionProfiles/Project_Default.xml +0 -6
- data/.idea/modules.xml +0 -8
- data/.idea/rrx_api.iml +0 -255
- data/.idea/vcs.xml +0 -6
- data/exe/rrx_api_setup +0 -37
- data/exe/sources/config/initializers/cors.rb +0 -21
- data/exe/sources/config/initializers/generators.rb +0 -6
- data/lib/rrx_api/railtie.rb +0 -44
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_relative 'base'
|
|
3
|
+
|
|
4
|
+
module RrxApi
|
|
5
|
+
module Generators
|
|
6
|
+
class GithubGenerator < Base
|
|
7
|
+
init! 'Generates GitHub Actions workflows for building and deploying the application using Docker.'
|
|
8
|
+
|
|
9
|
+
class_option :deploy,
|
|
10
|
+
type: :boolean,
|
|
11
|
+
default: false,
|
|
12
|
+
desc: 'Include deployment workflow'
|
|
13
|
+
|
|
14
|
+
class_option :terraform_repo,
|
|
15
|
+
type: :string,
|
|
16
|
+
default: 'terraform',
|
|
17
|
+
desc: 'Terraform repository name (if using deployment workflow)'
|
|
18
|
+
|
|
19
|
+
class_option :terraform_module,
|
|
20
|
+
type: :string,
|
|
21
|
+
desc: 'Terraform module name (if using deployment workflow). Default is the application name.'
|
|
22
|
+
|
|
23
|
+
class_option :database,
|
|
24
|
+
type: :string,
|
|
25
|
+
default: 'auto',
|
|
26
|
+
enum: %w[auto postgresql mysql mariadb sqlite none],
|
|
27
|
+
desc: 'Database type'
|
|
28
|
+
|
|
29
|
+
def github
|
|
30
|
+
directory 'github/build', '.github'
|
|
31
|
+
directory 'github/deploy', '.github' if deploy?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def deploy?
|
|
37
|
+
options[:deploy]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def database
|
|
41
|
+
@database ||= options[:database] == 'auto' ? detect_database : options[:database]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def terraform_repo
|
|
45
|
+
options[:terraform_repo]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def terraform_module
|
|
49
|
+
options[:terraform_module] || app_name
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def docker_packages
|
|
53
|
+
''
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def detect_database
|
|
57
|
+
config_path = destination_path.join('config/database.yml')
|
|
58
|
+
if config_path.exist?
|
|
59
|
+
# @type {Hash}
|
|
60
|
+
config = YAML.safe_load(config_path.read, symbolize_names: true, aliases: true)
|
|
61
|
+
adapter = config.dig(:test, :adapter).to_s.downcase
|
|
62
|
+
case adapter
|
|
63
|
+
when /postgresql/, /psql/
|
|
64
|
+
'postgresql'
|
|
65
|
+
when /mysql/
|
|
66
|
+
if yes?('Detected MySQL adapter in database.yml. Are you using MariaDB? (Yn)')
|
|
67
|
+
'mariadb'
|
|
68
|
+
else
|
|
69
|
+
'mysql'
|
|
70
|
+
end
|
|
71
|
+
when /sqlite/
|
|
72
|
+
'sqlite'
|
|
73
|
+
else
|
|
74
|
+
say_error 'Unsupported database adapter detected in config/database.yml. Please specify the database type explicitly using --database option.'
|
|
75
|
+
exit 1
|
|
76
|
+
end
|
|
77
|
+
else
|
|
78
|
+
'none'
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module RrxApi
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Base
|
|
8
|
+
init! 'Installs the RRX API gem and its dependencies.'
|
|
9
|
+
|
|
10
|
+
class_option :skip_rrx_dev, type: :boolean, default: false, hide: true
|
|
11
|
+
|
|
12
|
+
# Updates the application configuration file with specific dependencies and settings.
|
|
13
|
+
# The method performs the following operations:
|
|
14
|
+
# - Reads the application configuration file located at 'config/application.rb'.
|
|
15
|
+
# - Removes existing comments and unnecessary `require` statements from the file.
|
|
16
|
+
# - Includes necessary `require` directives for the application's gem dependencies.
|
|
17
|
+
# - Injects or updates the Bundler require statement to include the necessary gems.
|
|
18
|
+
# - Cleans up unwanted whitespace in the file content.
|
|
19
|
+
# - Rewrites the configuration file with the updated content.
|
|
20
|
+
# - Appends additional configuration settings for time zone, schema format, and session management.
|
|
21
|
+
#
|
|
22
|
+
# @return [void] Since the primary purpose is file modification, it does not return a value directly.
|
|
23
|
+
def update_application
|
|
24
|
+
# @type [Pathname]
|
|
25
|
+
app_file = Pathname(destination_root).join('config', 'application.rb')
|
|
26
|
+
app_code = app_file.read
|
|
27
|
+
|
|
28
|
+
# Assume full replace if we've never modified before.
|
|
29
|
+
# Otherwise, create_file will prompt to replace it.
|
|
30
|
+
remove_file app_file unless app_code =~ /rrx_api/
|
|
31
|
+
|
|
32
|
+
app_code.gsub!(/^\s*#.*\r?\n/, '')
|
|
33
|
+
app_code.gsub!(/^(?:#\s+)?require ["'].*\r?\n/, '')
|
|
34
|
+
|
|
35
|
+
requires = application_gems.map do |gem|
|
|
36
|
+
"require '#{gem}'"
|
|
37
|
+
end.join("\n")
|
|
38
|
+
|
|
39
|
+
app_code.sub!(/^(Bundler.require.*)$/) do |str|
|
|
40
|
+
<<~REQ
|
|
41
|
+
#{requires}
|
|
42
|
+
|
|
43
|
+
#{str}
|
|
44
|
+
REQ
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Remove existing application config lines
|
|
48
|
+
APPLICATION_CONFIG.each do |line|
|
|
49
|
+
app_code.gsub!(/^\s*#{line}\W*.*\n/, '')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Remove unnecessary whitespace
|
|
53
|
+
app_code.lstrip!
|
|
54
|
+
app_code.gsub!(/^\s*\r?\n(\s*\r?\n)+/, "\n")
|
|
55
|
+
|
|
56
|
+
# puts app_code
|
|
57
|
+
create_file app_file, app_code
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def update_base_classes
|
|
61
|
+
gsub_file 'app/models/application_record.rb',
|
|
62
|
+
/ApplicationRecord.*/,
|
|
63
|
+
'ApplicationRecord < RrxApi::Record'
|
|
64
|
+
|
|
65
|
+
gsub_file 'app/controllers/application_controller.rb',
|
|
66
|
+
/ApplicationController.*/,
|
|
67
|
+
'ApplicationController < RrxApi::Controller'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def routes
|
|
71
|
+
inject_into_file 'config/routes.rb',
|
|
72
|
+
after: "Rails.application.routes.draw do\n" do
|
|
73
|
+
<<~RUBY
|
|
74
|
+
mount RrxApi::Engine => '/'
|
|
75
|
+
RUBY
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def rrx_dev
|
|
80
|
+
generate 'rrx_dev:install' unless options[:skip_rrx_dev]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def asdf_versions
|
|
84
|
+
create_file '.tool-versions', <<~VERSIONS
|
|
85
|
+
ruby #{ruby_version}
|
|
86
|
+
VERSIONS
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# Configs to remove from the application.rb file
|
|
92
|
+
APPLICATION_CONFIG = <<~CONFIG.split("\n").map(&:strip).freeze
|
|
93
|
+
config.time_zone
|
|
94
|
+
config.active_support.to_time_preserves_timezone
|
|
95
|
+
config.active_record.schema_format
|
|
96
|
+
config.session_store
|
|
97
|
+
config.middleware.use ActionDispatch::Cookies
|
|
98
|
+
config.middleware.use ActionDispatch::Session::CookieStore
|
|
99
|
+
CONFIG
|
|
100
|
+
|
|
101
|
+
# @return [Array<String>] The list of application gem names that are dependencies
|
|
102
|
+
def application_gems
|
|
103
|
+
gems = %w[rrx_api]
|
|
104
|
+
gems.concat(%w[rrx_jobs active_job].select { |name| gem?(name) })
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @param [String] name
|
|
108
|
+
# @return [Boolean] True if gem is a dependency
|
|
109
|
+
def gem?(name)
|
|
110
|
+
bundle_gems.include?(name)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @return [Set<String>]
|
|
114
|
+
def bundle_gems
|
|
115
|
+
@bundle_gems ||= bundle.dependencies.map(&:name).to_set
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
FROM ddrew555/rrx_docker:<%= ruby_version %>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
<% if deploy? %>
|
|
6
|
+
inputs:
|
|
7
|
+
dev_deploy:
|
|
8
|
+
type: boolean
|
|
9
|
+
default: true
|
|
10
|
+
description: 'Deploy build to development environment'
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
push:
|
|
14
|
+
branches: [main]
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
image_name: '<%= app_name %>'
|
|
18
|
+
major_version: 1
|
|
19
|
+
minor_version: 0
|
|
20
|
+
development: ${{ github.ref_name != 'main' }}
|
|
21
|
+
|
|
22
|
+
permissions: write-all
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
build:
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 0
|
|
31
|
+
|
|
32
|
+
- uses: dan-drew/asdf-actions/tool-versions@v1
|
|
33
|
+
|
|
34
|
+
- name: Test
|
|
35
|
+
uses: rails-rrx/actions/test@main
|
|
36
|
+
with:
|
|
37
|
+
ruby_version: <%= ruby_version %>
|
|
38
|
+
database: <%= database %>
|
|
39
|
+
|
|
40
|
+
- uses: dan-drew/actions/next-version@main
|
|
41
|
+
with:
|
|
42
|
+
suffix: ${{ env.development && '-dev' || '' }}
|
|
43
|
+
|
|
44
|
+
- name: Build
|
|
45
|
+
uses: rails-rrx/actions/docker-build@main
|
|
46
|
+
with:
|
|
47
|
+
repository: ${{ vars.DOCKER_REPOSITORY }}
|
|
48
|
+
username: ${{ secrets.DOCKER_USERNAME }}
|
|
49
|
+
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
50
|
+
image_name: $${{ env.image_name }}
|
|
51
|
+
image_version: ${{ env.next_version }}
|
|
52
|
+
database: <%= database %>
|
|
53
|
+
latest: true
|
|
54
|
+
packages: '<%= docker_packages %>'
|
|
55
|
+
|
|
56
|
+
- uses: dan-drew/actions/push-version@main
|
|
57
|
+
if: ${{ ! env.development }}
|
|
58
|
+
<% if deploy? %>
|
|
59
|
+
- name: Deploy Development
|
|
60
|
+
uses: actions/github-script@v7
|
|
61
|
+
condition: ${{ inputs.dev_deploy }}
|
|
62
|
+
with:
|
|
63
|
+
script: |
|
|
64
|
+
github.rest.actions.createWorkflowDispatch({
|
|
65
|
+
owner: context.repo.owner,
|
|
66
|
+
repo: context.repo.repo,
|
|
67
|
+
workflow_id: 'deploy.yml',
|
|
68
|
+
ref: context.ref,
|
|
69
|
+
inputs: { version: '${{ env.next_version }}' }
|
|
70
|
+
});
|
|
71
|
+
<% end %>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
required: true
|
|
8
|
+
type: string
|
|
9
|
+
description: 'Version to deploy'
|
|
10
|
+
environment:
|
|
11
|
+
default: development
|
|
12
|
+
type: string
|
|
13
|
+
description: 'Environment to deploy'
|
|
14
|
+
|
|
15
|
+
env:
|
|
16
|
+
image_name: '<%= app_name %>'
|
|
17
|
+
image_tag: "${{ inputs.version }}"
|
|
18
|
+
terraform_repo: '<%= terraform_repo %>'
|
|
19
|
+
terraform_module: '<%= terraform_module %>'
|
|
20
|
+
repository: ${{ vars.DOCKER_REPOSITORY }}
|
|
21
|
+
username: ${{ secrets.DOCKER_USERNAME }}
|
|
22
|
+
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
23
|
+
|
|
24
|
+
permissions: write-all
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
deploy:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- name: Tag Docker Image
|
|
31
|
+
run: |
|
|
32
|
+
readonly image_ref="${repository}/${image_name}"
|
|
33
|
+
readonly source_image="${image_ref}:${image_tag}"
|
|
34
|
+
readonly dest_image="${image_ref}:${{ inputs.environment }}"
|
|
35
|
+
|
|
36
|
+
echo ::group::Login
|
|
37
|
+
cat <<-PASSWORD | docker login "$repository" -u "$username" --password-stdin
|
|
38
|
+
${password}
|
|
39
|
+
PASSWORD
|
|
40
|
+
echo ::endgroup::
|
|
41
|
+
|
|
42
|
+
echo ::group::Tag
|
|
43
|
+
docker pull -q "${source_image}"
|
|
44
|
+
docker tag "${source_image}" "${dest_image}"
|
|
45
|
+
docker push -q "${dest_image}"
|
|
46
|
+
echo ::endgroup::
|
|
47
|
+
|
|
48
|
+
- name: Trigger Terraform
|
|
49
|
+
uses: actions/github-script@v7
|
|
50
|
+
with:
|
|
51
|
+
github-token: ${{ secrets.TERRAFORM_GITHUB_TOKEN }}
|
|
52
|
+
script: |
|
|
53
|
+
github.rest.repos.createDispatchEvent({
|
|
54
|
+
owner: context.repo.owner,
|
|
55
|
+
repo: 'terraform',
|
|
56
|
+
event_type: 'apply',
|
|
57
|
+
|
|
58
|
+
client_payload: {
|
|
59
|
+
path: '${{ env.terraform_module }}',
|
|
60
|
+
environment: '${{ inputs.environment }}'
|
|
61
|
+
}
|
|
62
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
data "aws_iam_policy_document" "app_policy" {
|
|
2
|
+
source_policy_documents = [module.rrx_config.role_policy.json]
|
|
3
|
+
|
|
4
|
+
statement {
|
|
5
|
+
sid = "webrtc"
|
|
6
|
+
resources = ["*"]
|
|
7
|
+
actions = [
|
|
8
|
+
"ivs:CreateStage",
|
|
9
|
+
"ivs:CreateParticipantToken",
|
|
10
|
+
"ivs:DeleteStage",
|
|
11
|
+
"ivs:DisconnectParticipant",
|
|
12
|
+
"ivs:GetStage",
|
|
13
|
+
"ivs:GetStageSession",
|
|
14
|
+
"ivs:ListStages",
|
|
15
|
+
"ivs:ListStageSessions",
|
|
16
|
+
"ivs:TagResource",
|
|
17
|
+
"cloudwatch:DescribeAlarms",
|
|
18
|
+
"cloudwatch:GetMetricData",
|
|
19
|
+
"servicequotas:ListAWSDefaultServiceQuotas",
|
|
20
|
+
"servicequotas:ListRequestedServiceQuotaChangeHistoryByQuota",
|
|
21
|
+
"servicequotas:ListServiceQuotas",
|
|
22
|
+
"servicequotas:ListServices",
|
|
23
|
+
"servicequotas:ListTagsForResource"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
resource "aws_iam_user" "app" {
|
|
29
|
+
name = local.app_env_name
|
|
30
|
+
path = "/${module.tagging.environment}/services/"
|
|
31
|
+
force_destroy = true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
resource "aws_iam_user_policy" "api" {
|
|
35
|
+
user = aws_iam_user.app.name
|
|
36
|
+
policy = data.aws_iam_policy_document.api.json
|
|
37
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
terraform {
|
|
2
|
+
required_version = "<%= terraform_version %>"
|
|
3
|
+
|
|
4
|
+
required_providers {
|
|
5
|
+
aws = {}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
<% if s3_bucket.present? %>
|
|
9
|
+
# Configure the backend to store the state file in S3
|
|
10
|
+
backend "s3" {
|
|
11
|
+
bucket = "<%= s3_bucket %>"
|
|
12
|
+
key = "<%= s3_key %>"
|
|
13
|
+
<% if aws_profile %>
|
|
14
|
+
profile = "<%= aws_profile %>"
|
|
15
|
+
<% end %>
|
|
16
|
+
region = "<%= aws_region %>"
|
|
17
|
+
encrypt = true
|
|
18
|
+
}
|
|
19
|
+
<% end %>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
provider "aws" {
|
|
23
|
+
<% if aws_profile %>
|
|
24
|
+
profile = "<%= aws_profile %>"
|
|
25
|
+
<% end %>
|
|
26
|
+
region = "<%= aws_region %>"
|
|
27
|
+
default_tags {
|
|
28
|
+
tags = module.tagging.default_tags
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module "aws" {
|
|
33
|
+
source = "github.com/tfext/terraform-aws-base"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module "tagging" {
|
|
37
|
+
source = "github.com/tfext/terraform-utilities-tagging"
|
|
38
|
+
environments = <%= environments? %>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
locals {
|
|
42
|
+
app_name = "<%= app_name %>"
|
|
43
|
+
app_env_name = "${local.app_name}${module.tagging.environment_suffix}"
|
|
44
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module "rrx_config" {
|
|
2
|
+
source = "github.com/tfext/terraform-rrx-config"
|
|
3
|
+
environment = terraform.workspace
|
|
4
|
+
# aws_secret = "..."
|
|
5
|
+
|
|
6
|
+
db = {
|
|
7
|
+
resource_id = data.aws_db_instance.db.resource_id
|
|
8
|
+
type = "mariadb"
|
|
9
|
+
host = data.aws_db_instance.db.address
|
|
10
|
+
port = data.aws_db_instance.db.port
|
|
11
|
+
name = "liaisun"
|
|
12
|
+
user = "liaisun_api"
|
|
13
|
+
iam = true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
config = {
|
|
17
|
+
default_identity_provider = {
|
|
18
|
+
user_pool_id = "us-west-2_Q8lbwSDZ3"
|
|
19
|
+
client_id = "27j0fkk6jdnc8fdcf1psuechtd"
|
|
20
|
+
domain = "auth-dev.liaisun.com"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
resource "aws_cloudwatch_log_group" "service" {
|
|
26
|
+
name = "/${module.tagging.environment}/<%= app_name %>"
|
|
27
|
+
retention_in_days = module.tagging.production ? 3 : 1
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module "container_definition" {
|
|
31
|
+
source = "github.com/tfext/terraform-aws-ecs-container-definition"
|
|
32
|
+
name = local.app_env_name
|
|
33
|
+
repository = module.ilibrium.docker_repository
|
|
34
|
+
image = "<%= app_name %>"
|
|
35
|
+
image_tag = "latest" # terraform.workspace
|
|
36
|
+
cpu = 1
|
|
37
|
+
memory_required = 512
|
|
38
|
+
environment = module.rrx_config.environment
|
|
39
|
+
|
|
40
|
+
ports = [{
|
|
41
|
+
port = 3000
|
|
42
|
+
public_port = 443
|
|
43
|
+
health_check = { path = "/healthcheck" }
|
|
44
|
+
}]
|
|
45
|
+
|
|
46
|
+
aws_logging = {
|
|
47
|
+
group = aws_cloudwatch_log_group.service.name
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module "service" {
|
|
52
|
+
source = "github.com/tfext/terraform-aws-ecs-service"
|
|
53
|
+
name = local.app_env_name
|
|
54
|
+
cluster = <%= ecs_cluster %>
|
|
55
|
+
containers = [module.container_definition]
|
|
56
|
+
role_policy = data.aws_iam_policy_document.app.json
|
|
57
|
+
target_group_prefix = "<%= app_name %>${module.tagging.environment_suffix}"
|
|
58
|
+
wait_for_stable = false
|
|
59
|
+
|
|
60
|
+
load_balancers = [{
|
|
61
|
+
name = module.tagging.environment
|
|
62
|
+
short_name = module.tagging.short_env
|
|
63
|
+
dns_zone = "liaisun.com"
|
|
64
|
+
dns_subdomain = "api${module.tagging.environment_suffix}"
|
|
65
|
+
vpc = module.tagging.environment
|
|
66
|
+
}]
|
|
67
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_relative 'base'
|
|
3
|
+
|
|
4
|
+
module RrxApi
|
|
5
|
+
module Generators
|
|
6
|
+
class TerraformGenerator < Base
|
|
7
|
+
init! 'Generates Terraform scripts for deploying the service as a docker container.'
|
|
8
|
+
|
|
9
|
+
class_option :cloud,
|
|
10
|
+
default: 'aws',
|
|
11
|
+
enum: %w[aws],
|
|
12
|
+
desc: 'Cloud provider for deployment (currently only AWS is supported)'
|
|
13
|
+
|
|
14
|
+
class_option :bucket,
|
|
15
|
+
type: :string,
|
|
16
|
+
desc: 'S3 bucket name for storing Terraform state files (default: store state locally)'
|
|
17
|
+
|
|
18
|
+
class_option :key,
|
|
19
|
+
type: :string,
|
|
20
|
+
desc: 'S3 key for the Terraform state file (default: app name)'
|
|
21
|
+
|
|
22
|
+
class_option :aws_profile,
|
|
23
|
+
type: :string,
|
|
24
|
+
desc: 'AWS profile to use for deployment (default: current profile)'
|
|
25
|
+
|
|
26
|
+
class_option :aws_region,
|
|
27
|
+
type: :string,
|
|
28
|
+
default: 'us-west-2',
|
|
29
|
+
desc: 'AWS region for deployment (default: us-west-2)'
|
|
30
|
+
|
|
31
|
+
class_option :ecs_cluster,
|
|
32
|
+
type: :string,
|
|
33
|
+
desc: 'ECS cluster name for deployment (default: deployment environment name)'
|
|
34
|
+
|
|
35
|
+
class_option :environments,
|
|
36
|
+
type: :boolean,
|
|
37
|
+
default: false,
|
|
38
|
+
aliases: '-e',
|
|
39
|
+
desc: 'Generate terraform files that targets multiple environments (default: false)'
|
|
40
|
+
|
|
41
|
+
def terraform
|
|
42
|
+
directory "terraform/#{options[:cloud]}", 'terraform'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def environments?
|
|
48
|
+
options[:environments]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def terraform_version
|
|
52
|
+
'1.9'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def s3_bucket
|
|
56
|
+
options[:bucket]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def s3_key
|
|
60
|
+
options[:key] || app_name
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def aws_profile
|
|
64
|
+
options[:aws_profile]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def aws_region
|
|
68
|
+
options[:aws_region]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def ecs_cluster
|
|
72
|
+
options.include?(:ecs_cluster) ? "'#{options[:ecs_cluster]}'" : 'terraform.workspace'
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
require 'active_model/railtie'
|
|
3
|
+
require 'active_record/railtie'
|
|
4
|
+
require 'action_controller/railtie'
|
|
5
|
+
require 'action_text/engine'
|
|
6
|
+
require 'action_view/railtie'
|
|
7
|
+
require 'jbuilder'
|
|
8
|
+
require 'rack/cors'
|
|
9
|
+
require 'actionpack/action_caching'
|
|
10
|
+
|
|
11
|
+
module RrxApi
|
|
12
|
+
class Engine < ::Rails::Engine
|
|
13
|
+
CORS_LOCALHOST_PATTERN = /\Ahttp:\/\/localhost(?::\d{4})?\z/.freeze
|
|
14
|
+
|
|
15
|
+
config.cors_origins = []
|
|
16
|
+
config.healthcheck = nil
|
|
17
|
+
config.healthcheck_route = 'healthcheck'
|
|
18
|
+
|
|
19
|
+
initializer 'rrx.active_support', before: 'active_support.set_configs' do |app|
|
|
20
|
+
app.config.active_support.to_time_preserves_timezone = :zone
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
initializer 'rrx.application', before: :initialize do |app|
|
|
24
|
+
app.config.time_zone = :utc
|
|
25
|
+
app.config.active_support.to_time_preserves_timezone = :zone
|
|
26
|
+
app.config.active_record.schema_format = :sql # Use SQL schema format for UUID support
|
|
27
|
+
|
|
28
|
+
app.config.generators.orm :active_record, primary_key_type: :uuid
|
|
29
|
+
app.config.session_store :cookie_store, key: '_rrx_session' # Make configurable in the future?
|
|
30
|
+
app.config.middleware.use ActionDispatch::Cookies # Required for all session management
|
|
31
|
+
app.config.middleware.use ActionDispatch::Session::CookieStore, app.config.session_options
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
initializer 'rrx.cors', before: :load_config_initializers do |app|
|
|
35
|
+
require 'rack/cors'
|
|
36
|
+
|
|
37
|
+
Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
|
38
|
+
allow do
|
|
39
|
+
origins do |source, _env|
|
|
40
|
+
if Rails.env.development?
|
|
41
|
+
CORS_LOCALHOST_PATTERN.match? source
|
|
42
|
+
else
|
|
43
|
+
app.config.cors_origins.include?(source)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
resource '*',
|
|
48
|
+
headers: :any,
|
|
49
|
+
credentials: true,
|
|
50
|
+
methods: [:get, :post, :put, :patch, :delete, :options, :head]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
initializer 'rrx.api_docs_config', before: :load_config_initializers do |_app|
|
|
57
|
+
Rails.configuration.api_docs = { 'API' => 'swagger.yaml' }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
initializer 'rrx.api_docs', after: :load_config_initializers do |app|
|
|
61
|
+
# Setup Swagger endpoints if docs exist
|
|
62
|
+
if swagger_root?
|
|
63
|
+
require 'rswag/api'
|
|
64
|
+
require 'rswag/ui'
|
|
65
|
+
|
|
66
|
+
Rswag::Api.configure do |c|
|
|
67
|
+
c.swagger_root = Rails.root.join('swagger')
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
Rswag::Ui.configure do |c|
|
|
71
|
+
app.config.api_docs.each_pair do |name, file|
|
|
72
|
+
c.swagger_endpoint "/api-docs/#{file}", name
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def swagger_root
|
|
81
|
+
@swagger_root ||= Rails.root.join('swagger')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def swagger_root?
|
|
85
|
+
swagger_root.exist?
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/rrx_api/version.rb
CHANGED