Class: Cartage::Remote

Inherits:
Plugin
  • Object
show all
Defined in:
lib/cartage/plugins/remote.rb

Overview

Connect to a remote machine and build a package remotely. cartage-remote uses Fog::SSH with key-based authentication (not password-based) to connect to a remote server.

cartage-remote assumes a relatively stable build server, but does not require one (custom prebuild and postbuild scripts could be used to manage that).

Remote Build Isolation

cartage-remote allows for safe builds across multiple projects and branches with path-based isolation. The pattern for the build path is shown below, where the last part of the path is where the code will be cloned to.

~<remote_user>/cartage/<project-name>/<timestamp>/<project-name>
       |          |           |            |           |
       v          |           |            |           |
  build root      v           |            |           |
               cartage        |            |           |
                path          v            |           |
                           project         v           |
                            path       isolation       |
                                          path         v
                                                     build
                                                      path

So that if I am deploying on a project called calliope and my remote user is build, my isolated build path might be:

~build/cartage/calliope/20160321091432/calliope

Remote Build Steps

The steps for a remote build are:

  1. Configure Cartage and save the active Cartage configuration as a temporary file that will be copied to the remote server.

  2. Configure the Fog::SSH and Fog::SCP adapters with the keys to connect to the remote system.

  3. Create the prebuild script and run it locally (where the cartage CLI was run).

  4. Connect to the remote server, put the Cartage configuration file in the isolation path, and clone the repository. Check the repo out to the appropriate release_hashref.

  5. Create the build script, copy it remotely, and run it from the build isolation path (build_path). This is effectively:

    cd "$build_path" && $build_script
    
  6. Clean up the remote server fromt his build.

  7. Create the postbuild script and run it locally (where the cartage CLI was run).

Configuration

cartage-remote is configured in the plugins.remote section of the Cartage configuration file. It supports two primary keys:

hosts

A dictionary of hosts, as described below, that indicate the remote machine where the build script will be run. The host keys will be used as the host value.

host

The name of the target host to be used. If missing, uses the default location.

For backwards compatibility, a single host may be specified in a server key, using the same format as the host values. This host will become the default host unless one is already specified in the hosts dictionary (which is an error).

The following keys are optional and may be provided globally in plugins.remote, or per host in plugins.remote.hosts.$name. If provided, host-level values override the global configuration.

keys

The SSH key(s) used to connect to the server. There are two basic ways that keys can be provided:

  • If provided as a string or an array of strings, the value(s) will be applied as glob patterns to find key files on disk.

  • If provided as a dictionary, the values are the ASCII representations of the private keys.

If keys are not provided, keys will be found on the local machine using the pattern ~/.ssh/*id_[rd]sa.

build

A multiline YAML string that is copied to the remote machine and executed as a script there. If not provided, the following script will be run:

#!/bin/bash
set -e
if [ -f Gemfile ]; then
  bundle install --path %{remote_bundle}
  bundle exec cartage \
    --config-file %{config_file} \
    --target %{project_path} \
    pack
else
  cartage \
    --config-file %{config_file} \
    --target %{project_path} \
    pack
fi
prebuild

A multiline YAML string that is run as a script on the local machine to prepare for running remotely. If not provided, the following script will be run:

#!/bin/bash
ssh-keyscan -H %{remote_adddress} >> ~/.ssh/known_hosts
postbuild

A multiline YAML string that is run as a script on the local machine to finish the build process locally. There is no default postbuild script. The script will be passed the stage (local_config, ssh_config, prebuild, remote_clone, remote_build, cleanup, or finished) and, if the stage is not finished, the error message.

Hosts

A host describes the remote server. It may be specified either as a string in the form [user@]host[:port] or a dictionary with required keys:

user

The user to connect to the remote server as. If not provided, defaults to $USER.

address

The host address for connecting to the remote server. Also called host.

port

The optional port to connect to the remote server on; used if not using the standard SSH port, 22.

Additionally, keys, build, prebuild, and postbuild scripts may be specified to override the global scripts.

Script Substitution

The build, prebuild, and postbuild scripts require information from the Cartage and Cartage::Remote instances. When these scripts are rendered to disk, they will be run through Kernel#sprintf with string substitution parameters (%{parameter-name}). All of these values are computed from the local Cartage configuration.

repo_url

The repository URL.

name

The package name.

release_hashref

The release hashref to build.

timestamp

The build timestamp.

remote_address

The remote build host. Also available as remote_host for backwards compatability.

remote_port

The remote build host SSH port (may be empty).

remote_user

The remote build user.

build_root

The remote build root, (usually ~remote_user).

cartage_path

build_root/cartage.

project_path

cartage_path/name.

isolation_path

project_path/timestamp.

build_path

The remote build path (contains the code to package). isolation_path/name

remote_bundle

A place where dependencies for the build can be installed locally. isolation_path/deps. Typically used in the build script.

bundle install --path %{remote_bundle}
dependency_cache

The dependency_cachevendor_cache for the remote server. Set the same as project_path.

config_file

The remote filename of the computed Cartage configuration. Must be provided to the remote run of cartage.

bundle exec cartage --config-file %{config_file} pack
build_script

The full path to the remote build script. isolation_path/cartage-build-remote.

Configuration Example

---
plugins:
  remote:
    hosts:
      default: build-server
    script: |
      #! /bin/bash
      bundle install --path %{remote_bundle} &&
      bundle exec cartage --config-file %{config_file} pack &&
      bundle exec cartage --config-file %{config_file} s3 put

Defined Under Namespace

Classes: Host

Constant Summary collapse

VERSION =

:nodoc:

'2.2'

Instance Method Summary collapse

Instance Method Details

#buildObject

Build on the remote server.



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/cartage/plugins/remote.rb', line 188

def build
  stage.trigger! :local_setup
  stage.trigger! :ssh_setup
  stage.trigger! :run_prebuild
  stage.trigger! :clone_remote
  stage.trigger! :build_remote
  stage.trigger! :clean_remote
  stage.trigger! :complete
rescue Cartage::CLI::CustomExit
  raise
rescue => e
  error = e.exception("Remote error in stage #{stage.state}: #{e.message}")
  error.set_backtrace(e.backtrace)
  raise error
ensure
  if postbuild_script
    cartage.display 'Running postbuild script...'
    system make_tmpscript('postbuild', postbuild_script, subs).path,
      stage.state.to_s, error.to_s
  end

  tmpfiles.each do |tmpfile|
    tmpfile.close
    tmpfile.unlink
  end
  tmpfiles.clear
end

#check_config(require_host: false, &notify) ⇒ Object

Check that the configuration is correct. If require_host is present, an exception will be thrown if a host is required and not present.

The optional notify block parameter is used primarily for testing.



220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/cartage/plugins/remote.rb', line 220

def check_config(require_host: false, &notify)
  config = cartage.config(for_plugin: :remote)

  puts "#{__method__}: verify_hosts(#{config.hosts.inspect})"
  verify_hosts(config.hosts, &notify)

  if require_host
    name = config.host || 'default'
    fail "No host #{name} present" unless config.hosts.dig(name)
  end

  true
end