aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore19
-rw-r--r--README.md1
-rw-r--r--Rakefile3
-rw-r--r--app/assets/config/manifest.js2
-rw-r--r--app/assets/javascripts/mini_environments.js2
-rw-r--r--app/assets/stylesheets/application.scss1
-rw-r--r--app/channels/application_cable/channel.rb4
-rw-r--r--app/channels/application_cable/connection.rb4
-rw-r--r--app/controllers/application_controller.rb6
-rw-r--r--app/controllers/mini_environments_controller.rb21
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/mini_environments_helper.rb2
-rw-r--r--app/jobs/setup_job.rb5
-rw-r--r--app/jobs/terraform_job.rb17
-rw-r--r--app/mailers/application_mailer.rb4
-rw-r--r--app/models/application_record.rb3
-rw-r--r--app/models/finished_terraform_job.rb3
-rw-r--r--app/models/mini_environment.rb3
-rw-r--r--app/models/user.rb5
-rw-r--r--app/views/layouts/application.html.erb8
-rw-r--r--app/views/mini_environments/index.html.erb8
-rw-r--r--app/views/mini_environments/new.html.erb5
-rw-r--r--app/views/mini_environments/show.html.erb6
-rw-r--r--bin/rails6
-rw-r--r--config.ru3
-rw-r--r--config/application.rb14
-rw-r--r--config/boot.rb7
-rw-r--r--config/cable.yml10
-rw-r--r--config/database.yml17
-rw-r--r--config/environment.rb5
-rw-r--r--config/environments/development.rb54
-rw-r--r--config/environments/production.rb90
-rw-r--r--config/environments/test.rb42
-rw-r--r--config/initializers/application_controller_renderer.rb8
-rw-r--r--config/initializers/assets.rb14
-rw-r--r--config/initializers/backtrace_silencers.rb7
-rw-r--r--config/initializers/cookies_serializer.rb5
-rw-r--r--config/initializers/filter_parameter_logging.rb4
-rw-r--r--config/initializers/gds-sso.rb13
-rw-r--r--config/initializers/govuk_admin_template.rb6
-rw-r--r--config/initializers/inflections.rb16
-rw-r--r--config/initializers/mime_types.rb4
-rw-r--r--config/initializers/wrap_parameters.rb14
-rw-r--r--config/locales/en.yml33
-rw-r--r--config/puma.rb56
-rw-r--r--config/routes.rb5
-rw-r--r--config/secrets.yml32
-rw-r--r--db/migrate/20180127201423_create_mini_environments.rb9
-rw-r--r--db/migrate/20180127201504_create_users.rb14
-rw-r--r--db/migrate/20180127220312_add_que.rb13
-rw-r--r--db/migrate/20180127222948_create_finished_terraform_jobs.rb10
-rw-r--r--db/schema.rb59
-rw-r--r--package.json5
-rw-r--r--terraform/.gitignore3
-rw-r--r--terraform/example.tf95
-rw-r--r--terraform/example/govuk.service.tpl13
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