diff options
56 files changed, 820 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68bdf90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Ignore bundler config. +/Gemfile +/Gemfile.lock +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-journal + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +/node_modules +/yarn-error.log + +.byebug_history diff --git a/README.md b/README.md new file mode 100644 index 0000000..57bd849 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# GOV.UK Mini Environment Admin diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..ed646b6 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative 'config/application' + +Rails.application.load_tasks diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000..5918193 --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,2 @@ +//= link_tree ../images +//= link_directory ../stylesheets .css diff --git a/app/assets/javascripts/mini_environments.js b/app/assets/javascripts/mini_environments.js new file mode 100644 index 0000000..dee720f --- /dev/null +++ b/app/assets/javascripts/mini_environments.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss new file mode 100644 index 0000000..ba2ffbf --- /dev/null +++ b/app/assets/stylesheets/application.scss @@ -0,0 +1 @@ +@import 'govuk_admin_template'; diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..85c44e9 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,6 @@ +class ApplicationController < ActionController::Base + include GDS::SSO::ControllerMethods + before_action :authenticate_user! + + protect_from_forgery with: :exception +end diff --git a/app/controllers/mini_environments_controller.rb b/app/controllers/mini_environments_controller.rb new file mode 100644 index 0000000..c45ed4a --- /dev/null +++ b/app/controllers/mini_environments_controller.rb @@ -0,0 +1,21 @@ +class MiniEnvironmentsController < ApplicationController + def show + @mini_environment = MiniEnvironment.find(params[:id]) + end + + def new + @mini_environment = MiniEnvironment.new + end + + def create + ActiveRecord::Base.transaction do + @mini_environment = MiniEnvironment.create( + params.require(:mini_environment).permit(:name) + ) + + SetupJob.enqueue(@mini_environment.id) + end + + redirect_to @mini_environment + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000..de6be79 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/app/helpers/mini_environments_helper.rb b/app/helpers/mini_environments_helper.rb new file mode 100644 index 0000000..4990a52 --- /dev/null +++ b/app/helpers/mini_environments_helper.rb @@ -0,0 +1,2 @@ +module MiniEnvironmentsHelper +end diff --git a/app/jobs/setup_job.rb b/app/jobs/setup_job.rb new file mode 100644 index 0000000..c7b1b80 --- /dev/null +++ b/app/jobs/setup_job.rb @@ -0,0 +1,5 @@ +class SetupJob < TerraformJob + def run_terraform + puts "Setting up #{@mini_environment.name}" + end +end diff --git a/app/jobs/terraform_job.rb b/app/jobs/terraform_job.rb new file mode 100644 index 0000000..739a5b5 --- /dev/null +++ b/app/jobs/terraform_job.rb @@ -0,0 +1,17 @@ +class TerraformJob < Que::Job + def run(mini_environment_id) + ActiveRecord::Base.transaction do + @mini_environment = MiniEnvironment.find(mini_environment_id) + + run_terraform + end + end + + def destroy + FinishedTerraformJob.create( + mini_environment_id: @mini_environment.id, + job_class: attrs[:job_class] + ) + super + end +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..286b223 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..10a4cba --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/finished_terraform_job.rb b/app/models/finished_terraform_job.rb new file mode 100644 index 0000000..7ada6bd --- /dev/null +++ b/app/models/finished_terraform_job.rb @@ -0,0 +1,3 @@ +class FinishedTerraformJob < ApplicationRecord + belongs_to :mini_environment +end diff --git a/app/models/mini_environment.rb b/app/models/mini_environment.rb new file mode 100644 index 0000000..d53a8b1 --- /dev/null +++ b/app/models/mini_environment.rb @@ -0,0 +1,3 @@ +class MiniEnvironment < ApplicationRecord + has_many :finished_terraform_jobs, dependent: :destroy +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..4ca70b3 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,5 @@ +class User < ApplicationRecord + include GDS::SSO::User + + serialize :permissions, Array +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000..5b90ace --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,8 @@ +<% content_for :head do %> + <%= stylesheet_link_tag "application", :media => "all" %> + <%= javascript_include_tag "application" %> + <%= csrf_meta_tag %> + <%= yield :extra_headers %> +<% end %> + +<%= render template: 'layouts/govuk_admin_template' %> diff --git a/app/views/mini_environments/index.html.erb b/app/views/mini_environments/index.html.erb new file mode 100644 index 0000000..11d5a79 --- /dev/null +++ b/app/views/mini_environments/index.html.erb @@ -0,0 +1,8 @@ + +<a href="<%= new_mini_environment_path %>">Create new mini environment</a> + +<% MiniEnvironment.all.each do |mini_environment| %> + <a href="<%= mini_environment_path mini_environment %>"> + <h2><%= mini_environment.name %></h2> + </a> +<% end %> diff --git a/app/views/mini_environments/new.html.erb b/app/views/mini_environments/new.html.erb new file mode 100644 index 0000000..4a4712e --- /dev/null +++ b/app/views/mini_environments/new.html.erb @@ -0,0 +1,5 @@ + +<%= form_for @mini_environment, url: {action: "create"} do |f| %> + <%= f.text_field :name %> + <%= f.submit "Create" %> +<% end %> diff --git a/app/views/mini_environments/show.html.erb b/app/views/mini_environments/show.html.erb new file mode 100644 index 0000000..2d8988c --- /dev/null +++ b/app/views/mini_environments/show.html.erb @@ -0,0 +1,6 @@ +<h1>Name: <%= @mini_environment.name %></h1> + +<% @mini_environment.finished_terraform_jobs.each do |job| %> + <%= job.job_class %> + <%= job.created_at %> +<% end %> diff --git a/bin/rails b/bin/rails new file mode 100644 index 0000000..10a7784 --- /dev/null +++ b/bin/rails @@ -0,0 +1,6 @@ +# This file is run by the Rails AppLoader + +APP_PATH = File.expand_path('../config/application', __dir__) + +require_relative '../config/boot' +require 'rails/commands' diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..b5f2923 --- /dev/null +++ b/config.ru @@ -0,0 +1,3 @@ +require_relative 'config/environment' + +run Rails.application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..3093aee --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative 'boot' + +require 'rails/all' + +module GovukMiniEnvironmentAdmin + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 5.1 + + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..84cfa4d --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,7 @@ +require 'rails' +require 'gds-sso' +require 'plek' +require 'govuk_admin_template' +require 'active_record' +require 'que' +require 'que/railtie' diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..c086a31 --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: redis://localhost:6379/1 + channel_prefix: govuk-mini-environment-admin_production diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..313bfde --- /dev/null +++ b/config/database.yml @@ -0,0 +1,17 @@ +default: &default + adapter: postgresql + encoding: unicode + +development: + <<: *default + database: govuk_mini_environment_admin_development + url: <%= ENV['DATABASE_URL'] %> + +test: + <<: *default + database: govuk_mini_environment_admin_test + url: <%= ENV["DATABASE_URL"].try(:sub, /([-_]development)?$/, '_test')%> + +production: + <<: *default + database: govuk_mini_environment_admin_production diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..426333b --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..5187e22 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,54 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable/disable caching. By default caching is disabled. + if Rails.root.join('tmp/caching-dev.txt').exist? + config.action_controller.perform_caching = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + config.file_watcher = ActiveSupport::EventedFileUpdateChecker +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..3a3912b --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,90 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # 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 + + # Attempt to read encrypted secrets from `config/secrets.yml.enc`. + # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or + # `config/secrets.yml.key`. + config.read_encrypted_secrets = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? + + # Compress CSS. + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.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 + + # 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.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :debug + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # 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 = "govuk-mini-environment-admin_#{Rails.env}" + 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 + + # Send deprecation notices to registered listeners. + config.active_support.deprecation = :notify + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require 'syslog/logger' + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..8e5cbde --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,42 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true +end diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb new file mode 100644 index 0000000..89d2efa --- /dev/null +++ b/config/initializers/application_controller_renderer.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 0000000..4b828e8 --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000..59385cd --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb new file mode 100644 index 0000000..5a6a32d --- /dev/null +++ b/config/initializers/cookies_serializer.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. +Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..4a994e1 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Configure sensitive parameters which will be filtered from the log file. +Rails.application.config.filter_parameters += [:password] diff --git a/config/initializers/gds-sso.rb b/config/initializers/gds-sso.rb new file mode 100644 index 0000000..3e78219 --- /dev/null +++ b/config/initializers/gds-sso.rb @@ -0,0 +1,13 @@ +GDS::SSO.config do |config| + config.user_model = 'User' + + # set up ID and Secret in a way which doesn't require it to be checked in to source control... + config.oauth_id = ENV['OAUTH_ID'] + config.oauth_secret = ENV['OAUTH_SECRET'] + + # optional config for location of Signon + config.oauth_root_url = "http://localhost:3001" + + # Pass in a caching adapter cache bearer token requests. + config.cache = Rails.cache +end diff --git a/config/initializers/govuk_admin_template.rb b/config/initializers/govuk_admin_template.rb new file mode 100644 index 0000000..ab074f5 --- /dev/null +++ b/config/initializers/govuk_admin_template.rb @@ -0,0 +1,6 @@ +GovukAdminTemplate.configure do |c| + c.app_title = "GOV.UK Mini Environment Admin" + c.show_flash = true + c.show_signout = true + c.disable_google_analytics = true +end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..ac033bf --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym 'RESTful' +# end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000..dc18996 --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 0000000..bbfc396 --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# To enable root element in JSON for ActiveRecord objects. +# ActiveSupport.on_load(:active_record) do +# self.include_root_in_json = true +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..decc5a8 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# 'true': 'foo' +# +# To learn more, please read the Rails Internationalization guide +# available at http://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..1e19380 --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,56 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. If you use this option +# you need to make sure to reconnect any threads in the `on_worker_boot` +# block. +# +# preload_app! + +# If you are preloading your application and using Active Record, it's +# recommended that you close any connections to the database before workers +# are forked to prevent connection leakage. +# +# before_fork do +# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) +# end + +# The code in the `on_worker_boot` will be called if you are using +# clustered mode by specifying a number of `workers`. After each worker +# process is booted, this block will be run. If you are using the `preload_app!` +# option, you will want to use this block to reconnect to any threads +# or connections that may have been created at application boot, as Ruby +# cannot share connections between processes. +# +# on_worker_boot do +# ActiveRecord::Base.establish_connection if defined?(ActiveRecord) +# end +# + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..2296683 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,5 @@ +Rails.application.routes.draw do + root :to => 'mini_environments#index' + + resources :mini_environments, :path => '/' +end diff --git a/config/secrets.yml b/config/secrets.yml new file mode 100644 index 0000000..70fa8d7 --- /dev/null +++ b/config/secrets.yml @@ -0,0 +1,32 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key is used for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! + +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +# You can use `rails secret` to generate a secure secret key. + +# Make sure the secrets in this file are kept private +# if you're sharing your code publicly. + +# Shared secrets are available across all environments. + +# shared: +# api_key: a1B2c3D4e5F6 + +# Environmental secrets are only available for that specific environment. + +development: + secret_key_base: 095fefa152e7687e700b07532b99351a8e23f3dff23677bd2fd98ab01354fdf2aa15e714d2ae5d76d6a3ee036174d1d3132a942cd7e88bf63e1e4720d07672c7 + +test: + secret_key_base: 3df201ca64f4ef212a595b07d263b4f79ad2d752c348cceed341f14f5f4bee4f760a956bb274118e89306ed580d7d98abc9b74495637a3c466a3d97e9d522ffb + +# Do not keep production secrets in the unencrypted secrets file. +# Instead, either read values from the environment. +# Or, use `bin/rails secrets:setup` to configure encrypted secrets +# and move the `production:` environment over there. + +production: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/db/migrate/20180127201423_create_mini_environments.rb b/db/migrate/20180127201423_create_mini_environments.rb new file mode 100644 index 0000000..3ad95e7 --- /dev/null +++ b/db/migrate/20180127201423_create_mini_environments.rb @@ -0,0 +1,9 @@ +class CreateMiniEnvironments < ActiveRecord::Migration[5.1] + def change + create_table :mini_environments do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20180127201504_create_users.rb b/db/migrate/20180127201504_create_users.rb new file mode 100644 index 0000000..23c109e --- /dev/null +++ b/db/migrate/20180127201504_create_users.rb @@ -0,0 +1,14 @@ +class CreateUsers < ActiveRecord::Migration[5.1] + def change + create_table :users do |t| + t.string :name + t.string :email + t.string :uid + t.string :organisation_slug + t.string :organisation_content_id + t.text :permissions + t.boolean :remotely_signed_out, :default => false + t.boolean :disabled, :default => false + end + end +end diff --git a/db/migrate/20180127220312_add_que.rb b/db/migrate/20180127220312_add_que.rb new file mode 100644 index 0000000..55cfd21 --- /dev/null +++ b/db/migrate/20180127220312_add_que.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddQue < ActiveRecord::Migration[4.2] + def self.up + # The current version as of this migration's creation. + Que.migrate! :version => 3 + end + + def self.down + # Completely removes Que's job queue. + Que.migrate! :version => 0 + end +end diff --git a/db/migrate/20180127222948_create_finished_terraform_jobs.rb b/db/migrate/20180127222948_create_finished_terraform_jobs.rb new file mode 100644 index 0000000..e88ebe4 --- /dev/null +++ b/db/migrate/20180127222948_create_finished_terraform_jobs.rb @@ -0,0 +1,10 @@ +class CreateFinishedTerraformJobs < ActiveRecord::Migration[5.1] + def change + create_table :finished_terraform_jobs do |t| + t.integer :mini_environment_id + t.string :job_class + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..70325bb --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,59 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20180127222948) do + + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "finished_terraform_jobs", force: :cascade do |t| + t.integer "mini_environment_id" + t.string "job_class" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "mini_environments", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "minienvironments", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "que_jobs", primary_key: ["queue", "priority", "run_at", "job_id"], force: :cascade, comment: "3" do |t| + t.integer "priority", limit: 2, default: 100, null: false + t.datetime "run_at", default: -> { "now()" }, null: false + t.bigserial "job_id", null: false + t.text "job_class", null: false + t.json "args", default: [], null: false + t.integer "error_count", default: 0, null: false + t.text "last_error" + t.text "queue", default: "", null: false + end + + create_table "users", force: :cascade do |t| + t.string "name" + t.string "email" + t.string "uid" + t.string "organisation_slug" + t.string "organisation_content_id" + t.text "permissions" + t.boolean "remotely_signed_out", default: false + t.boolean "disabled", default: false + end + +end diff --git a/package.json b/package.json new file mode 100644 index 0000000..1792453 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "name": "govuk-mini-environment-admin", + "private": true, + "dependencies": {} +} diff --git a/terraform/.gitignore b/terraform/.gitignore new file mode 100644 index 0000000..96c7538 --- /dev/null +++ b/terraform/.gitignore @@ -0,0 +1,3 @@ +.terraform +*.tfstate +*.tfstate.backup diff --git a/terraform/example.tf b/terraform/example.tf new file mode 100644 index 0000000..0efeed8 --- /dev/null +++ b/terraform/example.tf @@ -0,0 +1,95 @@ +provider "aws" { + region = "eu-west-1" +} + +resource "aws_key_pair" "deployer" { + key_name = "deployer" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwICJ0eU/M+373AwzuvFtr+xCQdIQfK8CgbroCVMR2nezt/M+I8TIHtY9eb7M7J9Wnpgo+ObVbEmLXZeyzjme4BVBEBCUfKnkxmysqQFCb3NM96rLz509HFsKx/evo8Y+oazuW2L3vnLEKkqXq8jhL2YhlRWZwdNoEBa5N6Lsk/C4zwElAJKRkUDURLZcaNQOiTBtXh4lviX6Fj8rXjRgw/rZZ/fkWkLhP0RuS9V6Pw+f58sgFPkw19ZXj0LZNGHxeeCnyU7Ll0WlZa3WkDwbhNDvHJy6ZcIYZYHJicRKfbeCgBS7KRJvAlnW88au2wbU9t02H9INJyI5Mwua23X9v7tPvFLIFUOHIL5oCJEFYO4iM3lHTwrAov3UQ4/hsV/EVL1rQ1htDMt0QoXxQnJH0u7ThssGi1shJb34/F828lj1qPE4vjvoEyOLZs/pUwXbKHnKevQyiU159J/41shp7HNYh0d6eAeyFSnyvdfhvzx2TdKII0LaXdIgA3BYhN+j4ljNuN1BLEllJNb3u2L8FyyV/PA53k9XE8RdVU3JpE2m1u/49sgYiboruQzzQqelyuvBnajf/4q5wMQrJ8lf4PXp/oTwcvolJ/qiQ5qkfCx7sZojgLZlz1ReqsGAubEpZydme1Ujm5SGVkSSHC/Kx4sDADetJ3k6b1s4Y6w6cfw== chris@giedi" +} + +data "aws_security_group" "guix-client" { + id = "sg-d8003ba3" +} + +data "aws_instance" "guix-daemon" { + instance_id = "i-010e25f85dfa73e72" +} + +data "aws_route53_zone" "main" { + zone_id = "ZD004G8DN6AQZ" +} + +data "template_file" "govuk_service" { + template = "file(example/govuk.service.tpl)" + + vars { + guix_daemon_socket = "guix://${data.aws_instance.guix-daemon.private_dns}", + app_domain = "banana.aws.cbaines.net", + web_domain = "www.banana.aws.cbaines.net" + } +} + +resource "aws_spot_instance_request" "example" { + ami = "ami-8fd760f6" + instance_type = "t2.large" + key_name = "${aws_key_pair.deployer.key_name}" + security_groups = [ + "${data.aws_security_group.guix-client.name}", + "default", + "public-webserver" + ] + + wait_for_fulfillment = true + spot_price = "0.05" + + provisioner "file" { + content = "${data.template_file.govuk_service.rendered}" + destination = "/home/ubuntu/govuk.service" + + connection { + type = "ssh" + user = "ubuntu" + } + } + + provisioner "remote-exec" { + inline = [ + "sudo apt-get update", + "sudo apt-get update", + "sudo apt-get -y install nfs-common cachefilesd", + "sudo tune2fs -o user_xattr /dev/xvda1", + "sudo sed 's/#RUN/RUN/' -i /etc/default/cachefilesd", + "sudo mkdir -p /gnu/store", + "sudo mount -t nfs4 -o ro,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,actimeo=600,fsc,nocto,retrans=2 fs-81e05e48.efs.eu-west-1.amazonaws.com:gnu/store /gnu/store", + "sudo mkdir -p /var/guix", + "sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 fs-81e05e48.efs.eu-west-1.amazonaws.com:var/guix /var/guix", + "echo \"export GUIX_DAEMON_SOCKET=guix://${data.aws_instance.guix-daemon.private_dns}\" | sudo tee /etc/profile.d/guix-daemon-socket.sh", + #"sudo systemctl restart cachefilesd", + "sudo mv /home/ubuntu/govuk.service /etc/systemd/system/govuk.service", + "sudo systemctl daemon-reload", + "sudo systemctl enable govuk.service", + "sudo systemctl start govuk.service" + ] + + connection { + type = "ssh" + user = "ubuntu" + } + } +} + +resource "aws_route53_record" "example" { + zone_id = "${data.aws_route53_zone.main.zone_id}" + name = "banana" + type = "A" + ttl = "60" + records = ["${aws_spot_instance_request.example.public_ip}"] +} + +resource "aws_route53_record" "example_wildcard" { + zone_id = "${data.aws_route53_zone.main.zone_id}" + name = "*.banana" + type = "A" + ttl = "60" + records = ["${aws_spot_instance_request.example.public_ip}"] +} diff --git a/terraform/example/govuk.service.tpl b/terraform/example/govuk.service.tpl new file mode 100644 index 0000000..52b4b56 --- /dev/null +++ b/terraform/example/govuk.service.tpl @@ -0,0 +1,13 @@ +[Unit] +Description=GOV.UK +After=network.target + +[Service] +Type=simple +User=ubuntu +WorkingDirectory=/home/ubuntu +Environment="GUIX_DAEMON_SOCKET=guix://${guix_daemon_socket}" +ExecStart=/var/guix/profiles/per-user/ubuntu/guix-profile/bin/govuk system start --rails-environment=production --app-domain=${app_domain} --web-domain=${web_domain} --use-high-ports=false --use-https=certbot --fallback + +[Install] +WantedBy=multi-user.target |