From bb01c0a7bc5038cb6dde891e649acc848457089b Mon Sep 17 00:00:00 2001 From: Dan Ivovich Date: Mon, 29 Jul 2024 16:30:15 -0400 Subject: [PATCH] Initial cloud deploy setup --- .circleci/config.yml | 39 +++++++++++++- Rakefile | 8 +++ apt.yml | 3 ++ cloud_start.sh | 10 ++++ config/database.yml | 20 ++++--- config/environments/dev.rb | 97 ++++++++++++++++++++++++++++++++++ config/environments/staging.rb | 97 ++++++++++++++++++++++++++++++++++ manifest.yml | 28 ++++++++++ 8 files changed, 293 insertions(+), 9 deletions(-) create mode 100644 apt.yml create mode 100755 cloud_start.sh create mode 100644 config/environments/dev.rb create mode 100644 config/environments/staging.rb create mode 100644 manifest.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index e94ecebc..9b10806f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,7 @@ version: 2.1 orbs: + cloudfoundry: circleci/cloudfoundry@1.0 ruby: circleci/ruby@2.1.3 docker: circleci/docker@2.6.0 @@ -137,9 +138,36 @@ jobs: ./cc-test-reporter upload-coverage --input coverage/codeclimate_full_report.json + dev-deploy: + parallelism: 1 + docker: + - image: cimg/ruby:3.2.2 + steps: + - checkout + - run: bundle cache --all + - run: echo -e $DEV_PRIVATE_KEY > dev_key.pem + - run: echo -e $DEV_PUBLIC_CERT > dev_cert.pem + - run: echo 'export CF_PASSWORD=$CF_PASSWORD_DEV' >> $BASH_ENV + - run: echo 'export CF_USERNAME=$CF_USERNAME_DEV' >> $BASH_ENV + - run: + name: Install Cloud Foundry CLI + command: | + sudo apt-get update + sudo apt-get install -y ca-certificates jq + sudo touch /etc/apt/sources.list.d/cloudfoundry-cli.list + echo "deb [trusted=yes] https://packages.cloudfoundry.org/debian stable main" | sudo tee -a /etc/apt/sources.list.d/cloudfoundry-cli.list + sudo apt-get update + sudo apt-get install dpkg + sudo apt-get install cf7-cli + - cloudfoundry/auth: + endpoint: "https://api.fr.cloud.gov" + org: gsa-tts-innovation-challenge + space: eval-dev + - run: cf push challenge-dev --strategy rolling + workflows: version: 2 - build_and_test: + test-and-deploy: jobs: - checkout_code: name: "checkout code: Ruby << matrix.ruby_version >>" @@ -170,4 +198,11 @@ workflows: ruby_version: - 3.2.2 postgres_version: - - "16.3" \ No newline at end of file + - "16.3" + + - dev-deploy: + requires: + - rspec + filters: + branches: + only: dev diff --git a/Rakefile b/Rakefile index d2a78aa2..84b021d0 100644 --- a/Rakefile +++ b/Rakefile @@ -6,3 +6,11 @@ require_relative "config/application" Rails.application.load_tasks + +namespace :cf do + desc "Only run on the first application instance" + task :on_first_instance do + instance_index = JSON.parse(ENV["VCAP_APPLICATION"])["instance_index"] rescue nil + exit(0) unless instance_index == 0 + end +end diff --git a/apt.yml b/apt.yml new file mode 100644 index 00000000..9d3cf370 --- /dev/null +++ b/apt.yml @@ -0,0 +1,3 @@ +--- +packages: +- imagemagick diff --git a/cloud_start.sh b/cloud_start.sh new file mode 100755 index 00000000..74e9e7db --- /dev/null +++ b/cloud_start.sh @@ -0,0 +1,10 @@ +#!/bin/bash +echo "------ Starting APP ------ Instance $CF_INSTANCE_INDEX -----" +echo "------ Booting Instance ------ Instance $CF_INSTANCE_INDEX -----" +if [ "$CF_INSTANCE_INDEX" == "0" ]; then + echo "----- Migrating Database ----- Instance $CF_INSTANCE_INDEX -----" + bundle exec rake cf:on_first_instance db:migrate + echo "----- Migrated Database ----- Instance $CF_INSTANCE_INDEX -----" +fi +echo "------ Booting Web Process ------ Instance $CF_INSTANCE_INDEX -----" +bundle exec rails s -b 0.0.0.0 -p $PORT -e $RAILS_ENV diff --git a/config/database.yml b/config/database.yml index 6d817257..2face4f6 100644 --- a/config/database.yml +++ b/config/database.yml @@ -14,14 +14,20 @@ test: <<: *default database: challenge_gov_test +dev: + adapter: postgresql + encoding: unicode + pool: <%= ENV.fetch("POOL_SIZE", 15) %> + url: <%= ENV["DATABASE_URL"] %> + staging: - <<: *default - username: <%= ENV['DATABASE_USERNAME'] %> - password: <%= ENV['DATABASE_PASSWORD'] %> + adapter: postgresql + encoding: unicode + pool: <%= ENV.fetch("POOL_SIZE", 15) %> url: <%= ENV["DATABASE_URL"] %> production: - <<: *default - username: <%= ENV['DATABASE_USERNAME'] %> - password: <%= ENV['DATABASE_PASSWORD'] %> - url: <%= ENV["DATABASE_URL"] %> \ No newline at end of file + adapter: postgresql + encoding: unicode + pool: <%= ENV.fetch("POOL_SIZE", 15) %> + url: <%= ENV["DATABASE_URL"] %> diff --git a/config/environments/dev.rb b/config/environments/dev.rb new file mode 100644 index 00000000..13ffe7d8 --- /dev/null +++ b/config/environments/dev.rb @@ -0,0 +1,97 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.enable_reloading = false + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment + # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. + # config.public_file_server.enabled = false + + # Compress CSS using a preprocessor. + # config.assets.css_compressor = :sass + + # Do not fall back to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. + # config.assume_ssl = true + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + config.force_ssl = true + + # Log to STDOUT by default + config.logger = ActiveSupport::Logger.new(STDOUT) + .tap { |logger| logger.formatter = ::Logger::Formatter.new } + .then { |logger| ActiveSupport::TaggedLogging.new(logger) } + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # "info" includes generic and useful information about system operation, but avoids logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). If you + # want to log everything, set the level to "debug". + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "rails_new_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } +end diff --git a/config/environments/staging.rb b/config/environments/staging.rb new file mode 100644 index 00000000..13ffe7d8 --- /dev/null +++ b/config/environments/staging.rb @@ -0,0 +1,97 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.enable_reloading = false + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment + # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. + # config.public_file_server.enabled = false + + # Compress CSS using a preprocessor. + # config.assets.css_compressor = :sass + + # Do not fall back to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. + # config.assume_ssl = true + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + config.force_ssl = true + + # Log to STDOUT by default + config.logger = ActiveSupport::Logger.new(STDOUT) + .tap { |logger| logger.formatter = ::Logger::Formatter.new } + .then { |logger| ActiveSupport::TaggedLogging.new(logger) } + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # "info" includes generic and useful information about system operation, but avoids logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). If you + # want to log everything, set the level to "debug". + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "rails_new_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } +end diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 00000000..5ff70eda --- /dev/null +++ b/manifest.yml @@ -0,0 +1,28 @@ +--- +defaults: &defaults + buildpacks: + - https://github.com/cloudfoundry/apt-buildpack + - nodejs_buildpack + - ruby_buildpack + memory: 1G + disk_quota: 2G + stack: cflinuxfs4 + health-check-type: process + command: ./cloud_start.sh + +applications: +- name: challenge-dev + <<: *defaults + instances: 1 + disk_quota: 6GB + env: + RAILS_ENV: dev + RAILS_LOG_TO_STDOUT: true + RAILS_SERVE_STATIC_FILES: true + HOST: challenge-dev.app.cloud.gov + LOGIN_PRIVATE_KEY_PATH: dev_key.pem + LOGIN_PUBLIC_KEY_PATH: dev_cert.pem + LOGIN_REDIRECT_URL: https://challenge-portal-dev.app.cloud.gov/auth/result + LOGIN_IDP_AUTHORIZE_URL: https://idp.int.identitysandbox.gov/openid_connect/authorize + LOGIN_TOKEN_ENDPOINT: https://idp.int.identitysandbox.gov/api/openid_connect/token + LOGIN_CLIENT_ID: urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:challenge_gov_portal_dev