# GOV.UK Mini Environment Admin # Copyright © 2018 Christopher Baines # # This file is part of the GOV.UK Mini Environment Admin. # # The GOV.UK Mini Environment Admin is free software: you can # redistribute it and/or modify it under the terms of the GNU Affero # General Public License as published by the Free Software Foundation, # either version 3 of the License, or (at your option) any later # version. # # The GOV.UK Mini Environment Admin is distributed in the hope that it # will be useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public # License along with the GOV.UK Mini Environment Admin. If not, see # . module GovukGuix::BuildMiniEnvironment extend ::ShellUtils DEFAULT_ARGUMENTS = { 'rails-environment' => 'production', 'use-high-ports' => 'false', 'fallback' => true }.freeze def self.build(mini_environment_id, options) logger.info(self.class) do "Building mini environment #{mini_environment_id}" end mini_environment = MiniEnvironment.find(mini_environment_id) remote_host = options[:run_remotely_on_host] if remote_host && Guix.available_locally? # TODO: This doesn't use the private key specified by the # backend, so it'll only work when the default SSH key has # access to the remote host. # Copy the revision to the remote host, to ensure it's available # there run_command( 'guix', 'copy', "--to=#{remote_host.user_at_address}", mini_environment.govuk_guix_revision.store_path ) end data_snapshot_arguments = {} if mini_environment.data_snapshot data_snapshot_arguments[:data_snapshot] = mini_environment.data_snapshot.store_path end output = run_command( "#{mini_environment.govuk_guix_revision.store_path}/bin/govuk", 'system', 'build', *hash_to_arguments( DEFAULT_ARGUMENTS .merge(options[:arguments]) .merge(data_snapshot_arguments) ), *signon_user_arguments(mini_environment.signon_users), *options[:services], run_remotely_on_host: remote_host ) build_output = output.last.strip raise 'InvalidOutput' unless build_output.starts_with? '/gnu/store' logger.debug(self.class) { "build_output: #{build_output}" } mini_environment.update( backend_data: { build_output: build_output } ) build_output end def self.signon_user_to_sexp(signon_user) keys = %w(name email role passphrase) sexp_contents = keys.zip( signon_user.values_at(*keys) ).map do |(key, value)| "#:#{key} \"#{value}\"" end "(#{sexp_contents.join(' ')})" end def self.signon_user_arguments(signon_users) signon_users.map do |signon_user| "--signon-user=#{signon_user_to_sexp(signon_user)}" end end end