diff --git a/WcaOnRails/.dockerignore b/WcaOnRails/.dockerignore new file mode 100644 index 00000000000..4ecc51f444a --- /dev/null +++ b/WcaOnRails/.dockerignore @@ -0,0 +1,19 @@ +# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files. + +# Ignore bundler config. +/.bundle + +# Ignore all default key files +config/master.key +config/credentials/*.key + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep diff --git a/WcaOnRails/.gitignore b/WcaOnRails/.gitignore index 4d8fa0a9dc2..7915c70d43c 100644 --- a/WcaOnRails/.gitignore +++ b/WcaOnRails/.gitignore @@ -48,3 +48,6 @@ yarn-debug.log* # Healthcheck flag for our Rails docker container .db-inited + +# GCE secrets file +**/application_default_credentials.json diff --git a/WcaOnRails/Dockerfile b/WcaOnRails/Dockerfile index 058c150f022..1c09d767581 100644 --- a/WcaOnRails/Dockerfile +++ b/WcaOnRails/Dockerfile @@ -5,6 +5,12 @@ ENV DEBIAN_FRONTEND noninteractive WORKDIR /app ARG NODE_MAJOR=16 +# Set production environment +ENV RAILS_LOG_TO_STDOUT="1" \ + RAILS_SERVE_STATIC_FILES="true" \ + RAILS_ENV="production" \ + BUNDLE_WITHOUT="development:test" + # Add PPA needed to install nodejs. # From: https://github.com/nodesource/distributions#debian-and-ubuntu-based-distributions RUN apt-get update && apt-get install -y ca-certificates curl gnupg @@ -25,6 +31,28 @@ RUN apt-get update && apt-get install -y \ mariadb-client \ libssl-dev \ libyaml-dev \ + python3-pip \ + fonts-unfonts-core \ + fonts-wqy-microhei \ + fonts-ipafont \ + lmodern \ + libxrender1 \ + pipx \ tzdata +RUN wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz -O wkhtml.tar.xz && tar -xf wkhtml.tar.xz --strip-components=1 -C /usr/local +# Using pipx because PEP668 doesn't allow installing systemwide packages anymore +RUN pipx install wrc + +# Install application gems +COPY Gemfile Gemfile.lock ./ +RUN bundle install +# Install node dependencies +COPY package.json ./ +RUN yarn install -RUN gem update --system && gem install bundler +COPY . . + +# Entrypoint prepares database and starts app on 0.0.0.0:3000 by default, +# but can also take a rails command, like "console" or "runner" to start instead. +ENTRYPOINT ["/app/bin/docker-entrypoint"] +EXPOSE 3000 diff --git a/WcaOnRails/Dockerfile.dev b/WcaOnRails/Dockerfile.dev new file mode 100644 index 00000000000..058c150f022 --- /dev/null +++ b/WcaOnRails/Dockerfile.dev @@ -0,0 +1,30 @@ +FROM ruby:3.2.2 +EXPOSE 3000 + +ENV DEBIAN_FRONTEND noninteractive +WORKDIR /app +ARG NODE_MAJOR=16 + +# Add PPA needed to install nodejs. +# From: https://github.com/nodesource/distributions#debian-and-ubuntu-based-distributions +RUN apt-get update && apt-get install -y ca-certificates curl gnupg +RUN mkdir -p /etc/apt/keyrings && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg + +RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list + +# Add PPA needed to install yarn. +# From: https://yarnpkg.com/en/docs/install#debian-stable +RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - +RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list + +RUN apt-get update && apt-get install -y \ + git \ + yarn \ + build-essential \ + nodejs \ + mariadb-client \ + libssl-dev \ + libyaml-dev \ + tzdata + +RUN gem update --system && gem install bundler diff --git a/WcaOnRails/app_secrets.rb b/WcaOnRails/app_secrets.rb index c9d2ca50690..385fcdd5445 100644 --- a/WcaOnRails/app_secrets.rb +++ b/WcaOnRails/app_secrets.rb @@ -66,7 +66,7 @@ def vault_file(secret_name, file_path) vault :NEW_RELIC_LICENSE_KEY vault :SMTP_USERNAME vault :SMTP_PASSWORD - vault_file :GOOGLE_APPLICATION_CREDENTIALS, "../secrets/application_default_credentials.json" + vault_file :GOOGLE_APPLICATION_CREDENTIALS, "./application_default_credentials.json" else mandatory :DATABASE_PASSWORD, :string mandatory :GOOGLE_MAPS_API_KEY, :string diff --git a/WcaOnRails/bin/docker-entrypoint b/WcaOnRails/bin/docker-entrypoint new file mode 100755 index 00000000000..9553f4e4701 --- /dev/null +++ b/WcaOnRails/bin/docker-entrypoint @@ -0,0 +1,16 @@ +#!/bin/sh + +if [ $# -eq 0 ]; then + + # We need all the environment variables to be there to precompile assets + ./bin/bundle exec i18n export + ./bin/bundle exec rails assets:precompile + # Create new or migrate existing database + ./bin/rails db:prepare + + # Start the server by default + exec bin/rails server +else + # Allow other commands, like console or runner, to be called + exec bin/rails "$@" +fi diff --git a/WcaOnRails/public/uploads b/WcaOnRails/public/uploads deleted file mode 120000 index c32682fa47f..00000000000 --- a/WcaOnRails/public/uploads +++ /dev/null @@ -1 +0,0 @@ -../../secrets/uploads/ \ No newline at end of file diff --git a/chef/.gitignore b/chef/.gitignore deleted file mode 100644 index 572586c0345..00000000000 --- a/chef/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -cookbooks/ -tmp/ -local-mode-cache/ -nodes/ diff --git a/chef/Berksfile b/chef/Berksfile deleted file mode 100644 index 9a3d2b16dfa..00000000000 --- a/chef/Berksfile +++ /dev/null @@ -1,15 +0,0 @@ -source "https://supermarket.chef.io" - -cookbook 'apt' -cookbook 'sudo' -cookbook 'mysql' -cookbook 'nodejs' -cookbook 'openssh' -cookbook 'openssl' -cookbook 'php-fpm' -cookbook 'hostname' -cookbook 'logrotate' -cookbook 'ruby_rbenv' -cookbook 'exim4-light' -cookbook 'timezone_lwrp' -cookbook 'ssh_known_hosts' diff --git a/chef/Berksfile.lock b/chef/Berksfile.lock deleted file mode 100644 index 22ab6cb74c6..00000000000 --- a/chef/Berksfile.lock +++ /dev/null @@ -1,45 +0,0 @@ -DEPENDENCIES - apt - exim4-light - hostname - logrotate - mysql - nodejs - openssh - openssl - php-fpm - ruby_rbenv - ssh_known_hosts - sudo - timezone_lwrp - -GRAPH - apparmor (4.1.8) - line (>= 0.0.0) - apt (7.5.13) - ark (6.0.22) - seven_zip (>= 3.1) - chocolatey (3.0.0) - exim4-light (0.1.3) - hostname (0.4.2) - hostsfile (>= 0.0.0) - hostsfile (3.0.1) - iptables (8.0.0) - line (4.5.12) - logrotate (3.0.20) - mysql (11.0.14) - apparmor (>= 0.0.0) - nodejs (10.1.12) - ark (>= 2.0.2) - chocolatey (>= 3.0) - yum (>= 7.2) - openssh (2.10.17) - iptables (>= 7.0) - openssl (8.5.5) - php-fpm (0.8.0) - ruby_rbenv (5.0.15) - seven_zip (4.2.8) - ssh_known_hosts (7.0.0) - sudo (5.4.7) - timezone_lwrp (0.2.2) - yum (7.4.13) diff --git a/chef/environments/development-noregs.rb b/chef/environments/development-noregs.rb deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/chef/environments/development.rb b/chef/environments/development.rb deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/chef/environments/production.rb b/chef/environments/production.rb deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/chef/environments/staging.rb b/chef/environments/staging.rb deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/chef/roles/wca.json b/chef/roles/wca.json deleted file mode 100644 index ca052e8cdb8..00000000000 --- a/chef/roles/wca.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "wca", - "description": "Role for wca nodes", - "json_class": "Chef::Role", - "default_attributes": { - "authorization": { - "sudo": { - "groups": ["admin", "sudo", "sysadmin"], - "users": ["cubing"], - "passwordless": "true" - } - }, - "openssh": { - "server": { - "password_authentication": "no" - } - }, - "set_fqdn": "*.worldcubeassociation.org", - "hostname_cookbook": { - "hostsfile_ip": "127.0.1.1" - }, - "tz": "UTC" - }, - "override_attributes": { - "apt":{ - "unattended_upgrades":{ - "enable": "true", - "mail": "admin@worldcubeassociation.org", - "origins_patterns": ["origin=Ubuntu,archive=focal-security"] - } - } - }, - "chef_type": "role", - "run_list": [ - "recipe[apt]", - "recipe[sudo]", - "recipe[hostname]", - "recipe[openssh]", - "recipe[timezone_lwrp]", - "recipe[wca::base]", - "recipe[wca::regulations_documents]", - "recipe[wca]" - ], - "env_run_lists": { - } -} diff --git a/chef/site-cookbooks/wca/README.md b/chef/site-cookbooks/wca/README.md deleted file mode 100644 index 11d82eb89fc..00000000000 --- a/chef/site-cookbooks/wca/README.md +++ /dev/null @@ -1 +0,0 @@ -# wca diff --git a/chef/site-cookbooks/wca/chefignore b/chef/site-cookbooks/wca/chefignore deleted file mode 100644 index 5767c60dda1..00000000000 --- a/chef/site-cookbooks/wca/chefignore +++ /dev/null @@ -1,90 +0,0 @@ -# Put files/directories that should be ignored in this file when uploading -# or sharing to the community site. -# Lines that start with '# ' are comments. - -# OS generated files # -###################### -.DS_Store -Icon? -nohup.out -ehthumbs.db -Thumbs.db - -# SASS # -######## -.sass-cache - -# EDITORS # -########### -\#* -.#* -*~ -*.sw[a-z] -*.bak -REVISION -TAGS* -tmtags -*_flymake.* -*_flymake -*.tmproj -.project -.settings -mkmf.log - -## COMPILED ## -############## -a.out -*.o -*.pyc -*.so -*.com -*.class -*.dll -*.exe -*/rdoc/ - -# Testing # -########### -.watchr -.rspec -spec/* -spec/fixtures/* -test/* -features/* -Guardfile -Procfile - -# SCM # -####### -.git -*/.git -.gitignore -.gitmodules -.gitconfig -.gitattributes -.svn -*/.bzr/* -*/.hg/* -*/.svn/* - -# Berkshelf # -############# -Berksfile -Berksfile.lock -cookbooks/* -tmp - -# Cookbooks # -############# -CONTRIBUTING - -# Strainer # -############ -Colanderfile -Strainerfile -.colander -.strainer - -# Travis # -########## -.travis.yml diff --git a/chef/site-cookbooks/wca/libraries/wca_helper.rb b/chef/site-cookbooks/wca/libraries/wca_helper.rb deleted file mode 100644 index d5d5e650412..00000000000 --- a/chef/site-cookbooks/wca/libraries/wca_helper.rb +++ /dev/null @@ -1,22 +0,0 @@ -module WcaHelper - # gregorbg: This method exists as a relic from a time when we needed to distinguish between "real" servers and Vagrant. - # Now that we're planning to get rid of Chef entirely, I didn't bother to properly refactor this. - def self.get_username_and_repo_root(recipe) - username = "cubing" - repo_root = "/home/#{username}/worldcubeassociation.org" - - return [ username, repo_root ] - end - - def self.get_secrets(recipe) - if recipe.node.chef_environment == "development" - recipe.data_bag_item("secrets", "development") - elsif recipe.node.chef_environment == "staging" - recipe.data_bag_item("secrets", "staging") - elsif recipe.node.chef_environment == "production" - recipe.data_bag_item("secrets", "production") - else - raise "Unrecognized chef_environment: #{recipe.node.chef_environment}" - end - end -end diff --git a/chef/site-cookbooks/wca/metadata.rb b/chef/site-cookbooks/wca/metadata.rb deleted file mode 100644 index 6b50dfaa054..00000000000 --- a/chef/site-cookbooks/wca/metadata.rb +++ /dev/null @@ -1,9 +0,0 @@ -name 'wca' - -depends 'mysql' -depends 'nodejs' -depends 'php-fpm' -depends 'logrotate' -depends 'ruby_rbenv' -depends 'exim4-light' -depends 'ssh_known_hosts' diff --git a/chef/site-cookbooks/wca/recipes/base.rb b/chef/site-cookbooks/wca/recipes/base.rb deleted file mode 100644 index 4af66e34b74..00000000000 --- a/chef/site-cookbooks/wca/recipes/base.rb +++ /dev/null @@ -1,7 +0,0 @@ -package 'git' -package 'vim' -package 'curl' -package 'htop' -package 'tmux' -package 'tree' -package 'ntp' diff --git a/chef/site-cookbooks/wca/recipes/default.rb b/chef/site-cookbooks/wca/recipes/default.rb deleted file mode 100644 index ab84eb74d1c..00000000000 --- a/chef/site-cookbooks/wca/recipes/default.rb +++ /dev/null @@ -1,329 +0,0 @@ -require 'fileutils' -require 'shellwords' -require 'securerandom' - -include_recipe "wca::base" - -node.default['nodejs']['version'] = '16.15.0' -node.default['nodejs']['repo'] = 'https://deb.nodesource.com/node_16.x' -include_recipe "nodejs" - -npm_package 'yarn' do - version '1.22.18' - options ['--global'] -end - -username, repo_root = WcaHelper.get_username_and_repo_root(self) -rails_root = "#{repo_root}/WcaOnRails" - -#### Mysql -package 'mysql-client-8.0' -db = { - 'user' => 'root', -} -if node.chef_environment == "production" - # In production mode, we use Amazon RDS. - db['host'] = "worldcubeassociation-dot-org.comp2du1hpno.us-west-2.rds.amazonaws.com" - db['read_replica'] = "readonly-worldcubeassociation-dot-org.comp2du1hpno.us-west-2.rds.amazonaws.com" -elsif node.chef_environment == "staging" - # In staging mode, we use Amazon RDS. - db['host'] = "staging-worldcubeassociation-dot-org.comp2du1hpno.us-west-2.rds.amazonaws.com" - db['read_replica'] = "readonly-staging-worldcubeassociation-dot-org.comp2du1hpno.us-west-2.rds.amazonaws.com" -end -read_replica = db["read_replica"] - -### Fonts for generating PDFs -package 'fonts-thai-tlwg' - -#### Ruby and Rails -# Install native dependencies for gems -package 'libghc-zlib-dev' -package 'libsqlite3-dev' -package 'libyaml-dev' #newly required by Psych 5.0 -package 'g++' -package 'libmysqlclient-dev' -package 'imagemagick' -package 'poppler-utils' # Required by ActiveStorage built-in PDF previewer. - -ruby_version = File.read("#{rails_root}/.ruby-version").strip - -# Install rbenv itself -rbenv_user_install username - -# install the desired Ruby version through rbenv -rbenv_ruby ruby_version do - user username -end - -# set the Ruby version we just installed as global default -# mainly useful so script invocations like 'gem' or 'bundle' work regardless of PWD. -rbenv_global ruby_version do - user username -end - -bundler_version = File.read("#{rails_root}/Gemfile.lock").strip.match(/\d+(?:\.\d+)+$/)[0] -gem_package "bundler" do - version bundler_version -end - -chef_env_to_rails_env = { - "development" => "development", - "staging" => "production", - "production" => "production", -} -rails_env = chef_env_to_rails_env[node.chef_environment] - -LOGROTATE_OPTIONS = ['nodelaycompress', 'compress'] - -logrotate_app 'rails-wca' do - path "#{repo_root}/WcaOnRails/log/production.log" - size "512M" - maxage 90 - options LOGROTATE_OPTIONS - - postrotate "[ ! -f #{repo_root}/WcaOnRails/pids/unicorn.pid ] || kill -USR1 `cat #{repo_root}/WcaOnRails/pids/unicorn.pid`" -end - -logrotate_app 'delayed_job-wca' do - path "#{repo_root}/WcaOnRails/log/delayed_job.log" - size "512M" - maxage 30 - options LOGROTATE_OPTIONS - - # According to https://groups.google.com/forum/#!topic/railsmachine-moonshine/vrfNwrqmzOA, - # it looks like we have to restart delayed job after logrotate. - postrotate "#{repo_root}/scripts/deploy.sh restart_dj" -end - -# Run mailcatcher in every environment except production. -if node.chef_environment != "production" - gem_package "mailcatcher" - execute "start mailcatcher" do - command "mailcatcher --no-quit --http-ip=0.0.0.0" - not_if "pgrep -f [m]ailcatcher" - end -end - -server_name = { - "production" => "www.worldcubeassociation.org", - "staging" => "staging.worldcubeassociation.org", - "development" => "", -}[node.chef_environment] - -#### Nginx -package "nginx" - -template "/etc/nginx/nginx.conf" do - source "nginx.conf.erb" - mode 0644 - owner 'root' - group 'root' - variables({ - username: username, - }) - notifies :run, 'execute[reload-nginx]', :delayed -end -directory "/etc/nginx/conf.d" do - owner 'root' - group 'root' -end -logrotate_app 'nginx-wca' do - path "/var/log/nginx/*.log" - size "512M" - maxage 30 - options LOGROTATE_OPTIONS - - postrotate "[ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`" -end - -template "/etc/nginx/conf.d/worldcubeassociation.org.conf" do - source "worldcubeassociation.org.conf.erb" - mode 0644 - owner 'root' - group 'root' - variables({ - username: username, - rails_root: rails_root, - repo_root: repo_root, - rails_env: rails_env, - server_name: server_name, - }) - notifies :run, 'execute[reload-nginx]', :delayed -end -# Start nginx if it's not already running. -execute "nginx" do - not_if "ps -efw | grep [n]ginx.*master" -end -execute "reload-nginx" do - command "/etc/init.d/nginx reload || /etc/init.d/nginx start" - action :nothing -end -execute "update-rc" do - command "/usr/sbin/update-rc.d -f nginx defaults" - action :nothing -end - -### Redis -redis = { - port: 6379 -} - -if node.chef_environment == "production" - # In production mode, we use Amazon ElasticCache. - redis[:cache_host] = "wca-main-cache-001.iebvzt.0001.usw2.cache.amazonaws.com" - redis[:sidekiq_host] = "wca-main-sidekiq-001.iebvzt.0001.usw2.cache.amazonaws.com" -elsif node.chef_environment == "staging" - # In staging mode, we use Amazon ElasticCache. - redis[:cache_host] = "redis-main-staging-001.iebvzt.0001.usw2.cache.amazonaws.com" - - # Yes, in staging mode we dump the cache and Sidekiq jobs to the same Redis instance. - redis[:sidekiq_host] = redis[:cache_host] -end - -cache_redis_url = "redis://#{redis[:cache_host]}:#{redis[:port]}" -sidekiq_redis_url = "redis://#{redis[:sidekiq_host]}:#{redis[:port]}" - -#### Rails environment -# Secrets are handled using Hashicorp Vault -template "#{rails_root}/.env.production" do - source "env.production.erb" - mode 0644 - owner username - group username - variables({ - cache_redis_url: cache_redis_url, - sidekiq_redis_url: sidekiq_redis_url, - db_host: db["host"], - read_replica_host: db["read_replica"] - }) -end - -#### phpMyAdmin -package "phpmyadmin" do - # skipping recommends because otherwise it will install an entire apache2 server… - options ["--no-install-recommends"] -end - -package "php-fpm" - -# Download certificate bundle for the RDS database -rds_certificate_pem = '/etc/phpmyadmin/rds-combined-ca-bundle.pem' -execute "wget https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem -O ${rds_certificate_pem}" do - not_if { ::File.exist?(rds_certificate_pem) } -end - -template "etc/phpmyadmin/conf.d/wca.php" do - source "phpMyAdmin_config.inc.php.erb" - variables({ - rds_certificate_pem: rds_certificate_pem, - db: db, - }) -end - -#### Initialize rails gems/database -execute "bundle config set --local path '/home/#{username}/.bundle'" do - user username - cwd rails_root - environment({ - "RACK_ENV" => rails_env, - }) -end -execute "bundle install #{'--deployment --without development test' if rails_env == 'production'}" do - user username - cwd rails_root - environment({ - "RACK_ENV" => rails_env, - }) -end - -### Sidekiq -template "/etc/systemd/user/sidekiq.service" do - source "sidekiq.service.erb" - variables({ - username: username, - repo_root: repo_root, - }) -end -execute "start-sidekiq" do - command "systemctl --user sidekiq start" - not_if "ps -efw | grep sidekiq" -end - -if node.chef_environment == "development" - db_setup_lockfile = '/tmp/rake-db-setup-run' - execute "bundle exec rake db:setup" do - cwd rails_root - environment({ - "DATABASE_HOST" => db["host"], - "RACK_ENV" => rails_env, - }) - not_if { ::File.exist?(db_setup_lockfile) } - end - file db_setup_lockfile do - action :create_if_missing - end -elsif node.chef_environment == "staging" - db_setup_lockfile = '/tmp/db-development-loaded' - execute "bundle exec rake db:load:development" do - cwd rails_root - user username - environment({ - "DATABASE_HOST" => db["host"], - "RACK_ENV" => rails_env, - }) - not_if { ::File.exist?(db_setup_lockfile) } - end - file db_setup_lockfile do - action :create_if_missing - end -end - -#### Screen -template "/home/#{username}/.bash_profile" do - source "bash_profile.erb" - mode 0644 - owner username - group username -end -template "/home/#{username}/.bashrc" do - source "bashrc.erb" - mode 0644 - owner username - group username -end -template "/home/#{username}/wca.screenrc" do - source "wca.screenrc.erb" - mode 0644 - owner username - group username - variables({ - rails_root: rails_root, - rails_env: rails_env, - db_host: db["host"], - }) -end -template "/home/#{username}/startall" do - source "startall.erb" - mode 0755 - owner username - group username -end -# We "sudo su ..." because simply specifying "user ..." doesn't invoke a login shell, -# which makes for a very screwy screen (we're logged in as username, but HOME -# is /home/root, for instance). -execute "sudo su #{username} -c '~/startall'" do - user username - not_if "screen -S wca -Q select", user: username -end -# Start screen at boot by creating our own /etc/init.d/rc.local -# Hopefully no one else needs to touch this file... there has *got* to be a -# more portable way of doing this. -template "/etc/rc.local" do - source "rc.local.erb" - mode 0755 - owner 'root' - group 'root' - variables({ - username: username, - }) -end diff --git a/chef/site-cookbooks/wca/recipes/regulations_documents.rb b/chef/site-cookbooks/wca/recipes/regulations_documents.rb deleted file mode 100644 index a1a83e48117..00000000000 --- a/chef/site-cookbooks/wca/recipes/regulations_documents.rb +++ /dev/null @@ -1,30 +0,0 @@ -username, repo_root = WcaHelper.get_username_and_repo_root(self) - -#### Regulations dependencies -package "git" -package "python3-pip" -package "fonts-unfonts-core" -package "fonts-wqy-microhei" -package "fonts-ipafont" -package "lmodern" -package "libxrender1" - -bash "install_wkhtmltopdf" do - not_if "/usr/local/bin/wkhtmltopdf --version | grep -q 'with patched qt'" - user "root" - cwd "/tmp" - code <<-EOH - wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz -O wkhtml.tar.xz - tar -xf wkhtml.tar.xz --strip-components=1 -C /usr/local - EOH -end - -execute "pip3 install wrc --upgrade" - -execute "#{repo_root}/scripts/deploy.sh rebuild_regs" do - user username -end - -execute "#{repo_root}/scripts/deploy.sh update_docs" do - user username -end diff --git a/chef/site-cookbooks/wca/templates/bash_profile.erb b/chef/site-cookbooks/wca/templates/bash_profile.erb deleted file mode 100644 index 5545f007ea9..00000000000 --- a/chef/site-cookbooks/wca/templates/bash_profile.erb +++ /dev/null @@ -1,5 +0,0 @@ -# -# ~/.bash_profile -# - -[[ -f ~/.bashrc ]] && . ~/.bashrc diff --git a/chef/site-cookbooks/wca/templates/bashrc.erb b/chef/site-cookbooks/wca/templates/bashrc.erb deleted file mode 100644 index 2f35527b484..00000000000 --- a/chef/site-cookbooks/wca/templates/bashrc.erb +++ /dev/null @@ -1,12 +0,0 @@ -# .bashrc - -export VISUAL=vim -export EDITOR=vim - -if tty -s; then - green=$(tput setaf 2) - reset=$(tput sgr0) -fi -MY_BODY="\[$green$bold\]\w\[$reset\] @\h" -END=">" -export PS1="${MY_BODY}${END} " diff --git a/chef/site-cookbooks/wca/templates/env.production.erb b/chef/site-cookbooks/wca/templates/env.production.erb deleted file mode 100644 index 29abac01309..00000000000 --- a/chef/site-cookbooks/wca/templates/env.production.erb +++ /dev/null @@ -1,50 +0,0 @@ -WCA_LIVE_SITE=<%= node.chef_environment == "production" ? "1" : "0" %> -ROOT_URL=<%= - { - "development" => "", # env_vars.rb will compute a sane default for us - "staging" => "https://staging.worldcubeassociation.org", - "production" => "https://www.worldcubeassociation.org", - }[node.chef_environment] -%> -DATABASE_HOST=<%= @db_host %> -READ_REPLICA_HOST=<%= @read_replica_host %> -CACHE_REDIS_URL=<%= @cache_redis_url %> -SIDEKIQ_REDIS_URL=<%= @sidekiq_redis_url %> -STORAGE_AWS_BUCKET=<%= - { - "development" => "", - "staging" => "staging.worldcubeassociation.org", - "production" => "www.worldcubeassociation.org", - }[node.chef_environment] -%> -STORAGE_AWS_REGION=us-west-2 -DISCOURSE_URL=<%= - { - "development" => "", - "staging" => "", - "production" => "https://forum.worldcubeassociation.org", - }[node.chef_environment] -%> -VAULT_AWS_REGION=us-west-2 -S3_AVATARS_BUCKET=wca-avatar -S3_AVATARS_ASSET_HOST=https://avatars.worldcubeassociation.org -S3_AVATARS_REGION=us-west-2 -CDN_AVATARS_DISTRIBUTION_ID=ELNTWW0SE1ZJ -DATABASE_AWS_REGION=us-west-2 -DATABASE_WRT_USER=phpmyadmin -VAULT_ADDR=http://vault.worldcubeassociation.org:8200/ -VAULT_APPLICATION=<%= - { - "development" => "", - "staging" => "wca-main-staging", - "production" => "wca-main-production", - }[node.chef_environment] -%> -VAULT_AWS_REGION=us-west-2 -INSTANCE_ROLE=<%= - { - "development" => "", - "staging" => "wca_role-stg", - "production" => "wca_role", - }[node.chef_environment] -%> diff --git a/chef/site-cookbooks/wca/templates/mysql-wca.cnf.erb b/chef/site-cookbooks/wca/templates/mysql-wca.cnf.erb deleted file mode 100644 index b7a38a441b4..00000000000 --- a/chef/site-cookbooks/wca/templates/mysql-wca.cnf.erb +++ /dev/null @@ -1,17 +0,0 @@ -[mysqld] -skip-networking - -# AuxiliaryDataComputation needs more than the default 1M -max_allowed_packet = 16M - -# enable slow query log -slow_query_log = ON -long_query_time = 10 -slow_query_log_file = '/var/log/mysql/slow.log' -log_slow_admin_statements = ON - -# See https://github.com/thewca/worldcubeassociation.org/issues/2234 -innodb_ft_min_token_size=2 -ft_min_word_len=2 - -default-authentication-plugin=mysql_native_password diff --git a/chef/site-cookbooks/wca/templates/rc.local.erb b/chef/site-cookbooks/wca/templates/rc.local.erb deleted file mode 100644 index d6a9b238d70..00000000000 --- a/chef/site-cookbooks/wca/templates/rc.local.erb +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -e - -sudo su <%= @username %> -c '~/startall'& - -exit 0 diff --git a/chef/site-cookbooks/wca/templates/sidekiq.service.erb b/chef/site-cookbooks/wca/templates/sidekiq.service.erb deleted file mode 100644 index 4b28ca0e879..00000000000 --- a/chef/site-cookbooks/wca/templates/sidekiq.service.erb +++ /dev/null @@ -1,92 +0,0 @@ -# -# This file tells systemd how to run Sidekiq as a 24/7 long-running daemon. -# -# Customize this file based on your bundler location, app directory, etc. -# -# If you are going to run this as a user service (or you are going to use capistrano-sidekiq) -# Customize and copy this to ~/.config/systemd/user -# Then run: -# - systemctl --user enable sidekiq -# - systemctl --user {start,stop,restart} sidekiq -# Also you might want to run: -# - loginctl enable-linger username -# So that the service is not killed when the user logs out. -# -# If you are going to run this as a system service -# Customize and copy this into /usr/lib/systemd/system (CentOS) or /lib/systemd/system (Ubuntu). -# Then run: -# - systemctl enable sidekiq -# - systemctl {start,stop,restart} sidekiq -# -# This file corresponds to a single Sidekiq process. Add multiple copies -# to run multiple processes (sidekiq-1, sidekiq-2, etc). -# -# Use `journalctl -u sidekiq -rn 100` to view the last 100 lines of log output. -# -[Unit] -Description=sidekiq -# start us only once the network and logging subsystems are available, -# consider adding redis-server.service if Redis is local and systemd-managed. -After=syslog.target network.target - -# See these pages for lots of options: -# -# https://www.freedesktop.org/software/systemd/man/systemd.service.html -# https://www.freedesktop.org/software/systemd/man/systemd.exec.html -# -# THOSE PAGES ARE CRITICAL FOR ANY LINUX DEVOPS WORK; read them multiple -# times! systemd is a critical tool for all developers to know and understand. -# -[Service] -# -# !!!! !!!! !!!! -# -# As of v6.0.6, Sidekiq automatically supports systemd's `Type=notify` and watchdog service -# monitoring. If you are using an earlier version of Sidekiq, change this to `Type=simple` -# and remove the `WatchdogSec` line. -# -# !!!! !!!! !!!! -# -Type=notify -# If your Sidekiq process locks up, systemd's watchdog will restart it within seconds. -WatchdogSec=10 - -WorkingDirectory=<%= @repo_root %>/WcaOnRails -# If you use rbenv: -# ExecStart=/bin/bash -lc 'exec /home/deploy/.rbenv/shims/bundle exec sidekiq -e production' -# If you use the system's ruby: -# ExecStart=/usr/local/bin/bundle exec sidekiq -e production -# If you use rvm in production without gemset and your ruby version is 2.6.5 -# ExecStart=/home/deploy/.rvm/gems/ruby-2.6.5/wrappers/bundle exec sidekiq -e production -# If you use rvm in production with gemset and your ruby version is 2.6.5 -# ExecStart=/home/deploy/.rvm/gems/ruby-2.6.5@gemset-name/wrappers/bundle exec sidekiq -e production -# If you use rvm in production with gemset and ruby version/gemset is specified in .ruby-version, -# .ruby-gemsetor or .rvmrc file in the working directory -ExecStart=/bin/bash -lc 'exec /home/<%= @username %>/.rbenv/shims/bundle exec sidekiq -e production' - -# Use `systemctl kill -s TSTP sidekiq` to quiet the Sidekiq process - -# Uncomment this if you are going to use this as a system service -# if using as a user service then leave commented out, or you will get an error trying to start the service -# !!! Change this to your deploy user account if you are using this as a system service !!! -# User=<%= @username %> -# Group=<%= @username %> -# UMask=0002 - -# Greatly reduce Ruby memory fragmentation and heap usage -# https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/ -Environment=MALLOC_ARENA_MAX=2 - -# if we crash, restart -RestartSec=1 -Restart=always - -# output goes to /var/log/syslog (Ubuntu) or /var/log/messages (CentOS) -StandardOutput=syslog -StandardError=syslog - -# This will default to "bundler" if we don't specify it -SyslogIdentifier=sidekiq - -[Install] -WantedBy=multi-user.target diff --git a/chef/site-cookbooks/wca/templates/startall.erb b/chef/site-cookbooks/wca/templates/startall.erb deleted file mode 100644 index 40f5901acc6..00000000000 --- a/chef/site-cookbooks/wca/templates/startall.erb +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -SCREEN_SESSION_NAME=wca -print_usage_and_exit() { - echo "Usage: $0" - echo "Start a screen session named \"$SCREEN_SESSION_NAME\" iff one is not already running." - exit -} -if [ $# -gt 0 ]; then - print_usage_and_exit -fi - -if screen -S $SCREEN_SESSION_NAME -Q select > /dev/null; then - echo "Found an existing screen session named \"$SCREEN_SESSION_NAME\"." - echo "Run \"screen -S $SCREEN_SESSION_NAME -X quit\" to stop it." - exit # don't error out here, as this is called by chef -fi -screen -d -m -S $SCREEN_SESSION_NAME -c ~/wca.screenrc -echo "Started a screen named \"$SCREEN_SESSION_NAME\" as user `whoami`" diff --git a/chef/site-cookbooks/wca/templates/wca.screenrc.erb b/chef/site-cookbooks/wca/templates/wca.screenrc.erb deleted file mode 100644 index ce2418d0f5d..00000000000 --- a/chef/site-cookbooks/wca/templates/wca.screenrc.erb +++ /dev/null @@ -1,13 +0,0 @@ -startup_message off -vbell off -defscrollback 50000 - -chdir <%= @rails_root %> -screen -t run -<% if @rails_env == "development" %> -stuff "RACK_ENV=development DATABASE_HOST=<%= @db_host %> bundle exec rails server\012" -<% else %> -stuff "../scripts/deploy.sh rebuild_rails update_docs\012" -<% end %> - -screen -t dev diff --git a/chef/site-cookbooks/wca/templates/worldcubeassociation.org.conf.erb b/chef/site-cookbooks/wca/templates/worldcubeassociation.org.conf.erb deleted file mode 100644 index 1b9361dee44..00000000000 --- a/chef/site-cookbooks/wca/templates/worldcubeassociation.org.conf.erb +++ /dev/null @@ -1,391 +0,0 @@ -upstream app { -<% if @rails_env == "development" %> - server localhost:3000; - # Backup in case we try to run in production mode on a dev server - server unix:/tmp/unicorn.wca.sock fail_timeout=0 backup; -<% else %> - # Path to Unicorn SOCK file - server unix:/tmp/unicorn.wca.sock fail_timeout=0; -<% end %> -} - -<% if node.chef_environment == "staging" %> - # Serve mailcatcher at https://staging.worldcubeassociation.org:444 - server { - server_name staging.worldcubeassociation.org; - - listen 444; - - location / { - proxy_pass http://localhost:1080; - } - } -<% end %> - -server { - server_name <%= @server_name %> localhost; - - # SSL is handled by the AWS Load Balancer and is only reachable through it - listen 80; - - # Deny access to dotfiles and dotfolders. - location ~ /\. { - deny all; - } - - # Redirect 401 to log in page - # Unfortunately, I don't think there's any way to redirect back after the - # user logs in. - error_page 401 = @error401; - location @error401 { - return 302 /users/sign_in; - } - - location /api/v0/auth/results { - proxy_pass http://app; - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - proxy_set_header X-Original-URI $request_uri; - } - - #### Legacy PHP redirects - # /results/admin/ is now handled by Rails over at /admin/ - location ~ ^/results/admin/?$ { - return 302 /admin/; - } - - # Redirect competitions.php to /competitions - location /results/competitions.php { - set $rails_args ""; - - if ($arg_map != "") { - set $rails_args "${rails_args}&display=Map"; - } - - if ($arg_eventId != "") { - set $rails_args "${rails_args}&event=${arg_eventId}"; - } - - if ($arg_regionId != "") { - set $rails_args "${rails_args}®ion=${arg_regionId}"; - } - - if ($arg_pattern != "") { - set $rails_args "${rails_args}&search=${arg_pattern}"; - } - - if ($arg_years != "") { - set $rails_args "${rails_args}&years=${arg_years}"; - } - - return 302 /competitions?$rails_args; - } - - # Redirect statistics.php to the new statistics project - location /results/statistics.php { - return 302 https://statistics.worldcubeassociation.org/statistics-list; - } - - # Redirect sum of ranks - location /results/misc/sum_of_ranks/ { - return 302 https://statistics.worldcubeassociation.org/sum-of-ranks; - } - - # Redirect record evolution - location /results/misc/evolution/ { - return 302 https://statistics.worldcubeassociation.org/record-evolution; - } - - # Redirect old competition results pages: - # /results/c.php?i=IranSummerCube2013 - # to: - # /results/competition.php?i=IranSummerCube2013 - # to new Rails page: - # /competitions/IranSummerCube2013 - location /results/c.php { - return 302 /results/competition.php$is_args$args; - } - - location /results/competition.php { - # The competition id could be in the url parameter "competitionId" or "i". - if ($arg_competitionId = "") { - set $competitionId $arg_i; - } - if ($arg_competitionId != "") { - set $competitionId $arg_competitionId; - } - - # Be liberal in how we accept spaces. - # Yes, that's competitiors, not competitors. - if ($arg_list = "List of Registered Competitiors") { - return 302 /competitions/$competitionId/registrations; - } - if ($arg_list = "List+of+Registered+Competitiors") { - return 302 /competitions/$competitionId/registrations; - } - if ($arg_list = "List%20of%20Registered%20Competitiors") { - return 302 /competitions/$competitionId/registrations; - } - - if ($arg_form = "Registration Form") { - return 302 /competitions/$competitionId/register; - } - if ($arg_form = "Registration+Form") { - return 302 /competitions/$competitionId/register; - } - if ($arg_form = "Registration%20Form") { - return 302 /competitions/$competitionId/register; - } - - return 302 /competitions/$competitionId; - } - - # Redirect old media pages - location /results/media_insertion.php { - return 302 /media/new; - } - - location /results/media.php { - return 302 /media/; - } - - # Redirect /results/e.php to /results/events.php - location /results/e.php { - if ($arg_eventId = "") { - set $args "${args}&eventId=${arg_i}"; - } - - return 302 /results/events.php$is_args$args; - } - # Redirect /results/events.php to /results/rankings - location /results/events.php { - set $rails_path "333"; - set $rails_args ""; - - if ($arg_eventId != "") { - set $rails_path $arg_eventId; - } - - if ($arg_single != "") { - set $rails_path "${rails_path}/single"; - } - if ($arg_average != "") { - set $rails_path "${rails_path}/average"; - } - - if ($arg_regionId != "") { - set $rails_args "${rails_args}®ion=${arg_regionId}"; - } - - if ($arg_years != "") { - set $rails_args "${rails_args}&years=${arg_years}"; - } - - if ($arg_show != "") { - set $rails_args "${rails_args}&show=${arg_show}"; - } - - return 302 /results/rankings/$rails_path?$rails_args; - } - - location /results/rankings { - try_files $uri @app; - } - - # Redirect /results/regions.php to /results/records - location /results/regions.php { - set $rails_args ""; - - if ($arg_eventId != "") { - set $rails_args "${rails_args}&event_id=${arg_eventId}"; - } - - if ($arg_regionId != "") { - set $rails_args "${rails_args}®ion=${arg_regionId}"; - } - - if ($arg_years != "") { - set $rails_args "${rails_args}&years=${arg_years}"; - } - - if ($arg_mixed != "") { - set $rails_args "${rails_args}&show=mixed"; - } - if ($arg_slim != "") { - set $rails_args "${rails_args}&show=slim"; - } - if ($arg_separate != "") { - set $rails_args "${rails_args}&show=separate"; - } - if ($arg_history != "") { - set $rails_args "${rails_args}&show=history"; - } - if ($arg_mixHist != "") { - set $rails_args "${rails_args}&show=mixed history"; - } - - return 302 /results/records?$rails_args; - } - - location /results/records { - try_files $uri @app; - } - - location /results/database { - alias /usr/share/phpmyadmin; - index index.php index.html; - - # Delegate to Rails to determine if the client is authorized to administer - # results. This is kind of painful, as it results in an extra request for every - # single request, but this way we can avoid editing the existing PHP code. - auth_request /api/v0/auth/results; - - location ~ \.php$ { - # NOTE: Despite what many guides recommend, we are leaving - # cgi.fix_pathinfo = 1; in php.ini. See http://serverfault.com/a/625953 - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass unix:/run/php/php-fpm.sock; - fastcgi_buffers 16 16k; - fastcgi_buffer_size 32k; - fastcgi_index index.php; - - # See https://blog.martinfjordvald.com/2013/04/nginx-config-history-fastcgi_params-versus-fastcgi-conf/ - fastcgi_param SCRIPT_FILENAME $request_filename; - include fastcgi_params; - } - - # As recommended by http://docs.phpmyadmin.net/en/latest/setup.html#using-setup-script, - # prevent access to /libraries and /setup/lib. - location ^~ /results/database/libraries { - deny all; - } - location ^~ /results/database/setup/lib { - deny all; - } - } - - # Redirect /results/admin/change_person.php to /admin/edit_person - location /results/admin/change_person.php { - return 302 /admin/edit_person; - } - - # Redirect /results/persons.php to /persons - location /results/persons.php { - set $rails_args ""; - - if ($arg_regionId != "") { - set $rails_args "${rails_args}®ion=${arg_regionId}"; - } - - if ($arg_pattern != "") { - set $rails_args "${rails_args}&search=${arg_pattern}"; - } - - return 302 /persons?$rails_args; - } - - # Redirect /results/person.php to /person - location /results/person.php { - return 302 /persons/$arg_personId; - } - - # Redirect /results/p.php to /person - location /results/p.php { - if ($arg_personId = "") { - set $arg_personId $arg_i; - } - - return 302 /persons/$arg_personId; - } - - # Redirect /results/person_map.php to /person - location /results/person_map.php { - return 302 /persons/$arg_i?tab=map; - } - - # phpBB forum redirects - - location /forum { - return 302 /archive/forums; - } - - location /forum/viewforum.php { - return 302 /archive/forums/$arg_f; - } - - location /forum/viewtopic.php { - return 302 /archive/forum_topics/$arg_t; - } - - #### Regulations - # This is kind of a mess: we're using Rails to template most, but not all, - # of the regulations html. We also have static content such as pdfs and images - # that Rails won't serve up for us. We have a carefully constructed regex here - # to only serve up files we don't want handled by Rails. - location ~* /regulations(.*\.pdf|/history/files/.+|/scrambles/tnoodle/.*) { - index index.html; - alias <%= @repo_root %>/WcaOnRails/app/views/regulations/$1; - } - - # Redirect /organisations to /organizations - location /organisations { - return 302 /organizations; - } - - #### New Rails sytem - # From http://unicorn.bogomips.org/examples/nginx.conf - # path for static files - root <%= @rails_root %>/public; - -<% if @rails_env != "development" %> - # http://vladigleba.com/blog/2014/03/27/deploying-rails-apps-part-4-configuring-nginx/ - location ~* /(assets|packs)/ { - # From http://stackoverflow.com/a/5132440 (with tweaks by jfly) - gzip_static on; - gzip_vary on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/javascript text/xml application/xml application/rss+xml application/atom+xml application/rdf+xml image/svg+xml; - - expires max; - add_header Cache-Control public; - - # Fonts need the Access-Control-Allow-Origin header. - add_header Access-Control-Allow-Origin *; - } -<% end %> - - # Prefer to serve static files directly from nginx to avoid unnecessary - # data copies from the application server. - try_files $uri/index.html $uri.html $uri @app; - - location @app { - # an HTTP header important enough to have its own Wikipedia entry: - # http://en.wikipedia.org/wiki/X-Forwarded-For - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # pass the Host: header from the client right along so redirects - # can be set properly within the Rack application - proxy_set_header Host $http_host; - - # we don't want nginx trying to do something clever with - # redirects, we set the Host: header above already. - proxy_redirect off; - - # set "proxy_buffering off" *only* for Rainbows! when doing - # Comet/long-poll/streaming. It's also safe to set if you're using - # only serving fast clients with Unicorn + nginx, but not slow - # clients. You normally want nginx to buffer responses to slow - # clients, even with Rails 3.1 streaming because otherwise a slow - # client can become a bottleneck of Unicorn. - # - # The Rack application may also set "X-Accel-Buffering (yes|no)" - # in the response headers do disable/enable buffering on a - # per-response basis. - # proxy_buffering off; - proxy_pass http://app; - } - - # Rails error pages - error_page 500 502 503 504 /500.html; - client_max_body_size 64M; - keepalive_timeout 10; -} diff --git a/docker-compose.php.yml b/docker-compose.php.yml deleted file mode 100644 index 3d7ae3d99e4..00000000000 --- a/docker-compose.php.yml +++ /dev/null @@ -1,30 +0,0 @@ -version: "3.7" - -services: - phpmyadmin: - image: phpmyadmin:fpm-alpine - environment: - - PMA_HOST=wca_db - - PMA_USER=root - - PMA_PASSWORD= - volumes: - - phpmyadmin_data:/var/www/html/ - networks: - - wca-main - - nginx: - image: nginx:stable-alpine - volumes: - - ./docker/nginx-dev.conf:/etc/nginx/conf.d/default.conf:ro - - phpmyadmin_data:/var/www/html/:ro - ports: - - "8000:8000" - networks: - - wca-main - depends_on: - - phpmyadmin - - wca_on_rails - -volumes: - phpmyadmin_data: - driver: local diff --git a/docker-compose.yml b/docker-compose.yml index 3f7497ad170..06628b0b70b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ version: "3.8" x-app: &app build: context: WcaOnRails + dockerfile: Dockerfile.dev working_dir: /app/WcaOnRails volumes: - .:/app diff --git a/docker/my.cnf b/infra/templates/my.cnf similarity index 100% rename from docker/my.cnf rename to infra/templates/my.cnf diff --git a/docker/nginx-dev.conf b/infra/templates/nginx-dev.conf similarity index 100% rename from docker/nginx-dev.conf rename to infra/templates/nginx-dev.conf diff --git a/infra/templates/nginx-prod.conf b/infra/templates/nginx-prod.conf new file mode 100644 index 00000000000..b19e9b57f3d --- /dev/null +++ b/infra/templates/nginx-prod.conf @@ -0,0 +1,121 @@ +upstream app { + # Name of the WCA service in docker + server wca_on_rails:3000; +} + +server { + listen 80; + server_name www.worldcubeassociation.org localhost; + + # Deny access to dotfiles and dotfolders. + location ~ /\. { + deny all; + } + + # Redirect 401 to log in page + # Unfortunately, I don't think there's any way to redirect back after the + # user logs in. + error_page 401 = @error401; + location @error401 { + return 302 /users/sign_in; + } + + location ^~ /results/database { + auth_request /api/v0/auth/results; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $host; + alias /var/www/html/; + index index.php; + location ~ \.php$ { + try_files $uri = 404; + + fastcgi_pass phpmyadmin:9000; + + fastcgi_param SCRIPT_FILENAME $request_filename; + include fastcgi_params; + } + } + + location /api/v0/auth/results { + proxy_pass http://app; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-Original-URI $request_uri; + } + + location ^~ /results/database/libraries { + deny all; + } + location ^~ /results/database/setup/lib { + deny all; + } + + location ~ ^/results/admin/?$ { + return 302 /admin/; + } + + location /results/rankings { + try_files $uri @app; + } + + location /results/records { + try_files $uri @app; + } + + #### Regulations + # This is kind of a mess: we're using Rails to template most, but not all, + # of the regulations html. We also have static content such as pdfs and images + # that Rails won't serve up for us. We have a carefully constructed regex here + # to only serve up files we don't want handled by Rails. + location ~* /regulations(.*\.pdf|/history/files/.+|/scrambles/tnoodle/.*) { + index index.html; + alias /regulations/$1; + } + + # Redirect /organisations to /organizations + location /organisations { + return 302 /organizations; + } + + #### Rails system + # From http://unicorn.bogomips.org/examples/nginx.conf + # path for static files + root /public; + + # Prefer to serve static files directly from nginx to avoid unnecessary + # data copies from the application server. + try_files $uri/index.html $uri.html $uri @app; + + location @app { + # an HTTP header important enough to have its own Wikipedia entry: + # http://en.wikipedia.org/wiki/X-Forwarded-For + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # pass the Host: header from the client right along so redirects + # can be set properly within the Rack application + proxy_set_header Host $http_host; + + # we don't want nginx trying to do something clever with + # redirects, we set the Host: header above already. + proxy_redirect off; + + # set "proxy_buffering off" *only* for Rainbows! when doing + # Comet/long-poll/streaming. It's also safe to set if you're using + # only serving fast clients with Unicorn + nginx, but not slow + # clients. You normally want nginx to buffer responses to slow + # clients, even with Rails 3.1 streaming because otherwise a slow + # client can become a bottleneck of Unicorn. + # + # The Rack application may also set "X-Accel-Buffering (yes|no)" + # in the response headers do disable/enable buffering on a + # per-response basis. + # proxy_buffering off; + proxy_pass http://app; + } + + # Rails error pages + error_page 500 502 503 504 /500.html; + client_max_body_size 64M; + keepalive_timeout 10; +} diff --git a/infra/templates/nginx-staging.conf b/infra/templates/nginx-staging.conf new file mode 100644 index 00000000000..f0028a1186f --- /dev/null +++ b/infra/templates/nginx-staging.conf @@ -0,0 +1,121 @@ +upstream app { + # Name of the WCA service in docker + server wca_on_rails:3000; +} + +server { + listen 80; + server_name staging.worldcubeassociation.org localhost; + + # Deny access to dotfiles and dotfolders. + location ~ /\. { + deny all; + } + + # Redirect 401 to log in page + # Unfortunately, I don't think there's any way to redirect back after the + # user logs in. + error_page 401 = @error401; + location @error401 { + return 302 /users/sign_in; + } + + location ^~ /results/database { + auth_request /api/v0/auth/results; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $host; + alias /var/www/html/; + index index.php; + location ~ \.php$ { + try_files $uri = 404; + + fastcgi_pass phpmyadmin:9000; + + fastcgi_param SCRIPT_FILENAME $request_filename; + include fastcgi_params; + } + } + + location /api/v0/auth/results { + proxy_pass http://app; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-Original-URI $request_uri; + } + + location ^~ /results/database/libraries { + deny all; + } + location ^~ /results/database/setup/lib { + deny all; + } + + location ~ ^/results/admin/?$ { + return 302 /admin/; + } + + location /results/rankings { + try_files $uri @app; + } + + location /results/records { + try_files $uri @app; + } + + #### Regulations + # This is kind of a mess: we're using Rails to template most, but not all, + # of the regulations html. We also have static content such as pdfs and images + # that Rails won't serve up for us. We have a carefully constructed regex here + # to only serve up files we don't want handled by Rails. + location ~* /regulations(.*\.pdf|/history/files/.+|/scrambles/tnoodle/.*) { + index index.html; + alias /regulations/$1; + } + + # Redirect /organisations to /organizations + location /organisations { + return 302 /organizations; + } + + #### Rails system + # From http://unicorn.bogomips.org/examples/nginx.conf + # path for static files + root /public; + + # Prefer to serve static files directly from nginx to avoid unnecessary + # data copies from the application server. + try_files $uri/index.html $uri.html $uri @app; + + location @app { + # an HTTP header important enough to have its own Wikipedia entry: + # http://en.wikipedia.org/wiki/X-Forwarded-For + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # pass the Host: header from the client right along so redirects + # can be set properly within the Rack application + proxy_set_header Host $http_host; + + # we don't want nginx trying to do something clever with + # redirects, we set the Host: header above already. + proxy_redirect off; + + # set "proxy_buffering off" *only* for Rainbows! when doing + # Comet/long-poll/streaming. It's also safe to set if you're using + # only serving fast clients with Unicorn + nginx, but not slow + # clients. You normally want nginx to buffer responses to slow + # clients, even with Rails 3.1 streaming because otherwise a slow + # client can become a bottleneck of Unicorn. + # + # The Rack application may also set "X-Accel-Buffering (yes|no)" + # in the response headers do disable/enable buffering on a + # per-response basis. + # proxy_buffering off; + proxy_pass http://app; + } + + # Rails error pages + error_page 500 502 503 504 /500.html; + client_max_body_size 64M; + keepalive_timeout 10; +} diff --git a/chef/site-cookbooks/wca/templates/nginx.conf.erb b/infra/templates/nginx.conf similarity index 100% rename from chef/site-cookbooks/wca/templates/nginx.conf.erb rename to infra/templates/nginx.conf diff --git a/chef/site-cookbooks/wca/templates/phpMyAdmin_config.inc.php.erb b/infra/templates/prod.config.user.inc.php similarity index 58% rename from chef/site-cookbooks/wca/templates/phpMyAdmin_config.inc.php.erb rename to infra/templates/prod.config.user.inc.php index 934e1c06063..5265bfc8296 100644 --- a/chef/site-cookbooks/wca/templates/phpMyAdmin_config.inc.php.erb +++ b/infra/templates/prod.config.user.inc.php @@ -1,9 +1,5 @@ -$cfg['Servers'][$i]['host'] = '<%= @db['host'] %>'; -$cfg['Servers'][$i]['socket'] = '<% @db['socket'] %>'; -$cfg['Servers'][$i]['connect_type'] = 'socket'; -<% else %> -$cfg['Servers'][$i]['host'] = '<%= @db['host'] %>'; +$cfg['Servers'][$i]['host'] = 'worldcubeassociation-dot-org.comp2du1hpno.us-west-2.rds.amazonaws.com'; $cfg['Servers'][$i]['connect_type'] = 'tcp'; -<% end %> $cfg['Servers'][$i]['auth_type'] = 'cookie'; // The RDS IAM Authentication requires SSL $cfg['Servers'][$i]['ssl'] = true; // You need to have the region CA file and the authority CA file in the PEM bundle for it to work -$cfg['Servers'][$i]['ssl_ca'] = '<%= @rds_certificate_pem %>'; +$cfg['Servers'][$i]['ssl_ca'] = '/etc/phpmyadmin/rds_ca.pem'; // Enable SSL verification $cfg['Servers'][$i]['ssl_verify'] = true; @@ -32,19 +22,13 @@ $i++; $cfg['Servers'][$i]['verbose'] = ''; $cfg['Servers'][$i]['port'] = ''; -<% if @db['socket'] %> -$cfg['Servers'][$i]['host'] = '<%= @db['host'] %>'; -$cfg['Servers'][$i]['socket'] = '<% @db['socket'] %>'; -$cfg['Servers'][$i]['connect_type'] = 'socket'; -<% else %> -$cfg['Servers'][$i]['host'] = '<%= @db['read_replica'] %>'; +$cfg['Servers'][$i]['host'] = 'readonly-worldcubeassociation-dot-org.comp2du1hpno.us-west-2.rds.amazonaws.com'; $cfg['Servers'][$i]['connect_type'] = 'tcp'; -<% end %> $cfg['Servers'][$i]['auth_type'] = 'cookie'; // The RDS IAM Authentication requires SSL $cfg['Servers'][$i]['ssl'] = true; // You need to have the region CA file and the authority CA file in the PEM bundle for it to work -$cfg['Servers'][$i]['ssl_ca'] = '<%= @rds_certificate_pem %>'; +$cfg['Servers'][$i]['ssl_ca'] = '/etc/phpmyadmin/rds_ca.pem'; // Enable SSL verification $cfg['Servers'][$i]['ssl_verify'] = true; diff --git a/infra/templates/staging.config.user.inc.php b/infra/templates/staging.config.user.inc.php new file mode 100644 index 00000000000..1f01b10bbf8 --- /dev/null +++ b/infra/templates/staging.config.user.inc.php @@ -0,0 +1,41 @@ + diff --git a/scripts/_parse_args.sh b/scripts/_parse_args.sh deleted file mode 100644 index 9cb61c2a015..00000000000 --- a/scripts/_parse_args.sh +++ /dev/null @@ -1,33 +0,0 @@ -# From http://stackoverflow.com/a/8064551 -listcontains() { - for word in $1; do - [[ $word = $2 ]] && return 0 - done - return 1 -} - -# Validate command line arguments -print_usage_and_exit() { - echo -n "Usage: $0 " - for command in $allowed_commands; do - echo -n "[$command] " - done - echo - exit -} -if [ $# -lt 1 ]; then - print_usage_and_exit -fi -for command in "$@"; do - if ! listcontains "$allowed_commands" $command; then - echo "Unrecognized command: $command" - print_usage_and_exit - fi -done - -# Comands have been validated, so execute them! -# Show commands before running them. -set -ex -for command in "$@"; do - $command -done diff --git a/scripts/deploy.sh b/scripts/deploy.sh deleted file mode 100755 index 76f9bcb1961..00000000000 --- a/scripts/deploy.sh +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/env bash - -pull_latest() { - # From http://stackoverflow.com/a/8084186 - git pull --recurse-submodules && git submodule update -} - -restart_app() { - if ps -efw | grep "unicorn master" | grep -v grep; then - # Found a unicorn master process, restart it gracefully as per - # http://unicorn.bogomips.org/SIGNALS.html - pid=$(<"WcaOnRails/pids/unicorn.pid") - kill -SIGUSR2 $pid - sleep 5 - kill -SIGQUIT $pid - else - # We could not find a unicorn master process running, lets start one up! - (cd WcaOnRails; bundle exec unicorn -D -c config/unicorn.rb) - fi -} - -commit_hash() { - REMOTE_URL=$1 - REMOTE_BRANCHNAME=$2 - - echo $(git ls-remote $REMOTE_URL $REMOTE_BRANCHNAME | sed 's/\(.\{7\}\).*/\1/') -} - -rebuild_regs() { - # Build WCA regulations - # Uses wrc, see here: https://github.com/thewca/wca-regulations-compiler - # pdf generations relies on wkhtmltopdf (with patched qt), which should be in $PATH - build_folder=regulations/build - regs_folder_root=WcaOnRails/app/views - tmp_dir=/tmp/regs-todelete - regs_folder=$regs_folder_root/regulations - regs_version=$regs_folder/version - regs_data_version=$regs_folder/data_version - translations_version=$regs_folder/translations/version - - rm -rf $build_folder - mkdir -p $build_folder - - # The /regulations directory build relies on three sources: - # - The WCA Regulations - # - The WCA Regulations translations - # - The 'regulations-data' branch of this repo, which contains data such as TNoodle binaries - git_reg_hash=$(commit_hash "https://github.com/thewca/wca-regulations.git" official) - git_translations_hash=$(commit_hash "https://github.com/thewca/wca-regulations-translations.git" HEAD) - git_reg_data_hash=$(commit_hash "https://github.com/thewca/worldcubeassociation.org.git" regulations-data) - - rebuild_regulations=1 - rebuild_regulations_data=1 - rebuild_translations=1 - # Check if the cloned regulations match the current version - if [ -r $regs_version ] && [ "$(cat $regs_version)" == "$git_reg_hash" ]; then - rebuild_regulations=0 - fi - # Check if the latest regulations-data match the current version - if [ -r $regs_data_version ] && [ "$(cat $regs_data_version)" == "$git_reg_data_hash" ]; then - rebuild_regulations_data=0 - fi - # Check if the cloned translations match the current version - if [ -r $translations_version ] && [ "$(cat $translations_version)" == "$git_translations_hash" ]; then - rebuild_translations=0 - fi - if [ $rebuild_regulations -eq 0 ] && [ $rebuild_translations -eq 0 ] && [ $rebuild_regulations_data -eq 0 ]; then - echo "WCA Regulations and translations are up to date." - return - fi - - # Else we have to rebuild something - - # This saves tracked files that may have unstashed changes too - cp -r $regs_folder $build_folder - - # Checkout data (scramble programs, history) - # Assuming we ran pull_latest, this automatically checks out the latest regulations-data - git fetch https://github.com/thewca/worldcubeassociation.org.git regulations-data - git checkout FETCH_HEAD $build_folder - git reset HEAD $build_folder - - inputdir=$build_folder/wca-regulations-translations - outputdir=$build_folder/regulations/translations - mkdir -p $outputdir - - if [ $rebuild_translations -eq 1 ]; then - git clone --depth=1 https://github.com/thewca/wca-regulations-translations.git $inputdir - languages=$(wrc-languages) - # Clean up translations directories - find $outputdir ! -name 'translations' -type d -exec rm -rf {} + - # Rebuild all translations - for kind in html pdf; do - for l in $languages; do - lang_inputdir=$inputdir/${l} - lang_outputdir=$outputdir/${l} - mkdir -p $lang_outputdir - echo "Generating ${kind} for language ${l}" - wrc --target=$kind -l $l -o $lang_outputdir -g $git_translations_hash $lang_inputdir - # Update timestamp for semi-automatic computation of translations index - cp $lang_inputdir/metadata.json $lang_outputdir/ - done - done - # Update version built - echo "$git_translations_hash" > $outputdir/version - # Update timestamps for automatically determining which regulations are up to date - cp $inputdir/version-date $outputdir/ - else - echo "Translations are up to date." - fi - - inputdir=$build_folder/wca-regulations - outputdir=$build_folder/regulations - mkdir -p $outputdir - - if [ $rebuild_regulations -eq 1 ]; then - git clone --depth=1 --branch=official https://github.com/thewca/wca-regulations.git $inputdir - # Clean up regulations directory files - find $outputdir -maxdepth 1 -type f -exec rm -f {} + - # Rebuild Regulations - wrc --target=json -o $outputdir -g "$git_reg_hash" $inputdir - wrc --target=html -o $outputdir -g "$git_reg_hash" $inputdir - wrc --target=pdf -o $outputdir -g "$git_reg_hash" $inputdir - # Update version built - echo "$git_reg_hash" > $outputdir/version - else - echo "Regulations are up to date" - fi - - # Update regulations-data version built - echo "$git_reg_data_hash" > $outputdir/data_version - - rm -rf $tmp_dir - mv $regs_folder $tmp_dir - mv $outputdir $regs_folder - rm -rf $tmp_dir -} - -update_docs() { - public_dir=WcaOnRails/public - tmp_dir=/tmp/wca-documents-clone - - rm -rf $tmp_dir - git clone --depth=1 --branch=build https://github.com/thewca/wca-documents.git $tmp_dir - rm -rf $public_dir/documents - rm -rf $public_dir/edudoc - mv $tmp_dir/documents $tmp_dir/edudoc $public_dir -} - -restart_sidekiq() { - systemctl --user restart sidekiq -} - -rebuild_rails() { - ( - cd WcaOnRails - - bundle install - bundle exec rake yarn:install - bundle exec i18n export - # We used to run 'assets:clean' as part of the command below, but for some - # reason rake would clean *up-to-date* assets and not recompile them, leading - # to the website being simply broken... - # See https://github.com/thewca/worldcubeassociation.org/issues/5370 - bundle exec rake assets:precompile - - # Note that we are intentionally not automating database migrations. - ) - - restart_sidekiq - restart_app - - echo "/!\\ Cleaning assets automatically has been disabled /!\\" - echo "Once in a while (preferably when low traffic) we need to clear the " - echo "public/packs directory and recompile them." - echo "If you're performing the weekly dependencies updates, I suggest you to do that." -} - -cd "$(dirname "$0")"/.. - -if [ "$(hostname)" == "production" ] || [ "$(hostname)" == "staging" ]; then - export RACK_ENV=production -else - export RACK_ENV=development -fi - -# Workaround for https://github.com/rails/webpacker/issues/773 -export RAILS_ENV=${RACK_ENV} - -# load rbenv into PATH -eval "$("$HOME/.rbenv/bin/rbenv" init -)" - -allowed_commands="pull_latest restart_app restart_sidekiq rebuild_rails rebuild_regs update_docs" -source scripts/_parse_args.sh diff --git a/scripts/wca-bootstrap.sh b/scripts/wca-bootstrap.sh deleted file mode 100755 index 6c0004c4a95..00000000000 --- a/scripts/wca-bootstrap.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env bash - -PRODUCTION_ELASTIC_IP="34.208.140.116" - -print_usage_and_exit() { - echo "Usage: $0 " - echo "Bootstraps a WCA server." - echo " must be one of development, staging, production." - exit 1 -} -if [ $# -gt 1 ]; then - print_usage_and_exit -fi -environment=$1 -if [ "$environment" == "development" ] || [ "$environment" == "staging" ] || [ "$environment" == "production" ]; then - git_branch=master -else - echo "Unrecognized environment: $environment" - print_usage_and_exit -fi - -if [ "$(id -u)" != "0" ]; then - echo "This script must be run as root" 2>&1 - exit 1 -fi - -set -ex - -# Install deps required to bootstrap -apt-get update -y -if ! command -v curl &> /dev/null; then - # OVH's Ubuntu 14.04 doesn't have curl - apt-get install -y curl -fi -if ! command -v git &> /dev/null; then - apt-get install -y git -fi -if ! command -v gcc &> /dev/null; then - apt-get install -y build-essential -fi -if ! command -v zip &> /dev/null; then -apt-get install -y zip -fi -if ! command -v aws &> /dev/null; then -curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" -unzip awscliv2.zip -sudo ./aws/install -fi - -if [ -d /vagrant ]; then - repo_root=/vagrant -else - repo_root=/home/cubing/worldcubeassociation.org - - # Create cubing user if does not exist. - if ! id -u cubing &>/dev/null; then - useradd -m -s /bin/bash cubing - chown cubing:cubing /home/cubing - fi - - # Check out codebase =) - export GIT_SSH=/tmp/ssh-no-hostkeychecking.sh - if ! command -v $GIT_SSH &> /dev/null; then - cat > $GIT_SSH < /dev/null || ! chef-solo --version | grep 16.17.51 &> /dev/null; then - curl -Ls https://omnitruck.chef.io/install.sh | bash -s -- -v 16.17.51 - /opt/chef/embedded/bin/gem install berkshelf -v "7.2.2" -fi - -berks_lib_file=$(/opt/chef/embedded/bin/gem which berkshelf) -berks_lib_dir=$(dirname "$berks_lib_file") -berks_root_dir=$(dirname "$berks_lib_dir") - -berks_executable="$berks_root_dir/bin/berks" - -# Install cookbooks from Cheffile -( - cd $repo_root/chef - /opt/chef/embedded/bin/ruby "$berks_executable" install - /opt/chef/embedded/bin/ruby "$berks_executable" vendor "$repo_root/chef/cookbooks" -) - -mkdir -p /etc/chef -cat > /etc/chef/solo.rb <