cartage-remote 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.autotest +27 -0
- data/.gemtest +1 -0
- data/.minitest.rb +2 -0
- data/Contributing.rdoc +63 -0
- data/Gemfile +9 -0
- data/History.rdoc +5 -0
- data/Licence.rdoc +27 -0
- data/Manifest.txt +12 -0
- data/README.rdoc +45 -0
- data/Rakefile +56 -0
- data/lib/cartage/remote.rb +381 -0
- data/lib/cartage/remote/command.rb +22 -0
- metadata +212 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8ec28919c46cca17afd22212d913af4b3292c7eb
|
4
|
+
data.tar.gz: 50e8f6d1252e272526e4e8953f0a872107e0078d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a8cb9fd3b201d4951452c98b107fe68b01a3d61d4a544bbe864404467e28fea84791cf13654085d1a6201c0ed6407355e7da1b627dd9fb1b7b865dc4d8c23bc8
|
7
|
+
data.tar.gz: ec485dac5760aca2e8fa061050e72bdf3dd9c8a29a8ef71af6b5522b81f30345981ada21c9ee6ac47e71525aa79b6da746b8e593d37a3881db612ca4890fc6f3
|
data/.autotest
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require "autotest/restart"
|
4
|
+
|
5
|
+
Autotest.add_hook :initialize do |at|
|
6
|
+
# .minitest.rb ensures that the gem version of minitest is used.
|
7
|
+
at.testlib = ".minitest.rb"
|
8
|
+
# at.testlib = "minitest/unit"
|
9
|
+
#
|
10
|
+
# at.extra_files << "../some/external/dependency.rb"
|
11
|
+
#
|
12
|
+
# at.libs << ":../some/external"
|
13
|
+
#
|
14
|
+
# at.add_exception "vendor"
|
15
|
+
#
|
16
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
17
|
+
# at.files_matching(/test_.*rb$/)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# %w(TestA TestB).each do |klass|
|
21
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
22
|
+
# end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Autotest.add_hook :run_command do |at|
|
26
|
+
# system "rake build"
|
27
|
+
# end
|
data/.gemtest
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
|
data/.minitest.rb
ADDED
data/Contributing.rdoc
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
== Contributing
|
2
|
+
|
3
|
+
We value any contribution to cartage-remote you can provide: a bug report, a
|
4
|
+
feature request, or code contributions.
|
5
|
+
|
6
|
+
cartage-remote has a few contribution guidelines:
|
7
|
+
|
8
|
+
* Changes *will* *not* be accepted without tests. The test suite is written
|
9
|
+
with {Minitest}[https://github.com/seattlerb/minitest].
|
10
|
+
* Match our coding style.
|
11
|
+
* Use a thoughtfully-named topic branch that contains your change. Rebase your
|
12
|
+
commits into logical chunks as necessary.
|
13
|
+
* Use {quality commit messages}[http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html].
|
14
|
+
* Do not change the version number; when your patch is accepted and a release
|
15
|
+
is made, the version will be updated at that point.
|
16
|
+
* Submit a GitHub pull request with your changes.
|
17
|
+
|
18
|
+
=== Test Dependencies
|
19
|
+
|
20
|
+
cartage-remote uses Ryan Davis’s {Hoe}[https://github.com/seattlerb/hoe] to manage
|
21
|
+
the release process, and it adds a number of rake tasks. You will mostly be
|
22
|
+
interested in:
|
23
|
+
|
24
|
+
$ rake
|
25
|
+
|
26
|
+
which runs the tests the same way that:
|
27
|
+
|
28
|
+
$ rake test
|
29
|
+
$ rake travis
|
30
|
+
|
31
|
+
will do.
|
32
|
+
|
33
|
+
To assist with the installation of the development dependencies for cartage-remote,
|
34
|
+
I have provided the simplest possible Gemfile pointing to the (generated)
|
35
|
+
+cartage-remote.gemspec+ file. This will permit you to do:
|
36
|
+
|
37
|
+
$ bundle install
|
38
|
+
|
39
|
+
to get the development dependencies. If you aleady have +hoe+ installed, you
|
40
|
+
can accomplish the same thing with:
|
41
|
+
|
42
|
+
$ rake newb
|
43
|
+
|
44
|
+
This task will install any missing dependencies, run the tests/specs, and
|
45
|
+
generate the RDoc.
|
46
|
+
|
47
|
+
=== Workflow
|
48
|
+
|
49
|
+
Here's the most direct way to get your work merged into the project:
|
50
|
+
|
51
|
+
* Fork the project.
|
52
|
+
* Clone down your fork (<tt>git clone git://github.com/KineticCafe/cartage-remote.git</tt>).
|
53
|
+
* Create a topic branch to contain your change (<tt>git checkout -b my\_awesome\_feature</tt>).
|
54
|
+
* Hack away, add tests. Not necessarily in that order.
|
55
|
+
* Make sure everything still passes by running +rake+.
|
56
|
+
* If necessary, rebase your commits into logical chunks, without errors.
|
57
|
+
* Push the branch up (<tt>git push origin my\_awesome\_feature</tt>).
|
58
|
+
* Create a pull request against KineticCafe/cartage-remote and describe
|
59
|
+
what your change does and the why you think it should be merged.
|
60
|
+
|
61
|
+
=== Contributors
|
62
|
+
|
63
|
+
* Austin Ziegler created cartage-remote.
|
data/Gemfile
ADDED
data/History.rdoc
ADDED
data/Licence.rdoc
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
== Licence
|
2
|
+
|
3
|
+
This software is available under an MIT-style licence.
|
4
|
+
|
5
|
+
* Copyright 2015 Kinetic Cafe
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
8
|
+
this software and associated documentation files (the "Software"), to deal in
|
9
|
+
the Software without restriction, including without limitation the rights to
|
10
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
11
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
12
|
+
so, subject to the following conditions:
|
13
|
+
|
14
|
+
* The names of its contributors may not be used to endorse or promote
|
15
|
+
products derived from this software without specific prior written
|
16
|
+
permission.
|
17
|
+
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
19
|
+
copies or substantial portions of the Software.
|
20
|
+
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
27
|
+
SOFTWARE.
|
data/Manifest.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
= cartage-remote by Kinetic Cafe
|
2
|
+
|
3
|
+
code :: https://github.com/KineticCafe/cartage-remote/
|
4
|
+
issues :: https://github.com/KineticCafe/cartage-remote/issues
|
5
|
+
continuous integration :: {<img src="https://travis-ci.org/KineticCafe/cartage-remote.png" />}[https://travis-ci.org/KineticCafe/cartage-remote]
|
6
|
+
|
7
|
+
== Description
|
8
|
+
|
9
|
+
cartage-remote is a plug-in for {cartage}[https://github.com/KineticCafe/cartage]
|
10
|
+
to build a package on a remote machine with cartage.
|
11
|
+
|
12
|
+
Cartage provides a repeatable means to create a package for a Rails application
|
13
|
+
that can be used in deployment with a configuration tool like Ansible, Chef,
|
14
|
+
Puppet, or Salt. The package is created with its dependencies bundled in
|
15
|
+
`vendor/bundle`, so it can be deployed in environments with strict access
|
16
|
+
control rules and without requiring development tool access.
|
17
|
+
|
18
|
+
== Synopsis
|
19
|
+
|
20
|
+
# Build a package on a remote machine via SSH.
|
21
|
+
cartage remote
|
22
|
+
|
23
|
+
== Install
|
24
|
+
|
25
|
+
Add cartage-remote to your Gemfile:
|
26
|
+
|
27
|
+
gem 'cartage-remote', '~> 1.0'
|
28
|
+
|
29
|
+
Or manually install:
|
30
|
+
|
31
|
+
% gem install cartage-remote
|
32
|
+
|
33
|
+
== cartage-remote Semantic Versioning
|
34
|
+
|
35
|
+
cartage-remote uses a {Semantic Versioning}[http://semver.org/] scheme with one
|
36
|
+
change:
|
37
|
+
|
38
|
+
* When PATCH is zero (+0+), it will be omitted from version references.
|
39
|
+
|
40
|
+
cartage-remote will generally track cartage for major versions to ensure plugin API
|
41
|
+
compatibility.
|
42
|
+
|
43
|
+
:include: Contributing.rdoc
|
44
|
+
|
45
|
+
:include: Licence.rdoc
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
Hoe.plugin :doofus
|
8
|
+
Hoe.plugin :email unless ENV['CI'] or ENV['TRAVIS']
|
9
|
+
Hoe.plugin :gemspec2
|
10
|
+
Hoe.plugin :git
|
11
|
+
Hoe.plugin :minitest
|
12
|
+
Hoe.plugin :rubygems
|
13
|
+
|
14
|
+
spec = Hoe.spec 'cartage-remote' do
|
15
|
+
developer('Austin Ziegler', 'aziegler@kineticcafe.com')
|
16
|
+
|
17
|
+
self.history_file = 'History.rdoc'
|
18
|
+
self.readme_file = 'README.rdoc'
|
19
|
+
self.extra_rdoc_files = FileList['*.rdoc'].to_a
|
20
|
+
|
21
|
+
license 'MIT'
|
22
|
+
|
23
|
+
self.extra_deps << ['cartage', '~> 1.0']
|
24
|
+
self.extra_deps << ['fog', '~> 1.27']
|
25
|
+
|
26
|
+
self.extra_dev_deps << ['rake', '~> 10.0']
|
27
|
+
self.extra_dev_deps << ['hoe-doofus', '~> 1.0']
|
28
|
+
self.extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
|
29
|
+
self.extra_dev_deps << ['hoe-git', '~> 1.5']
|
30
|
+
self.extra_dev_deps << ['hoe-geminabox', '~> 0.3']
|
31
|
+
=begin
|
32
|
+
self.extra_dev_deps << ['minitest', '~> 5.4']
|
33
|
+
self.extra_dev_deps << ['minitest-autotest', '~> 1.0']
|
34
|
+
self.extra_dev_deps << ['minitest-bisect', '~> 1.2']
|
35
|
+
self.extra_dev_deps << ['minitest-focus', '~> 1.1']
|
36
|
+
self.extra_dev_deps << ['minitest-moar', '~> 0.0']
|
37
|
+
self.extra_dev_deps << ['minitest-pretty_diff', '~> 0.1']
|
38
|
+
self.extra_dev_deps << ['simplecov', '~> 0.7']
|
39
|
+
=end
|
40
|
+
end
|
41
|
+
|
42
|
+
=begin
|
43
|
+
namespace :test do
|
44
|
+
task :coverage do
|
45
|
+
prelude = <<-EOS
|
46
|
+
require 'simplecov'
|
47
|
+
SimpleCov.start('test_frameworks') { command_name 'Minitest' }
|
48
|
+
gem 'minitest'
|
49
|
+
EOS
|
50
|
+
spec.test_prelude = prelude.split($/).join('; ')
|
51
|
+
Rake::Task['test'].execute
|
52
|
+
end
|
53
|
+
end
|
54
|
+
=end
|
55
|
+
|
56
|
+
# vim: syntax=ruby
|
@@ -0,0 +1,381 @@
|
|
1
|
+
begin
|
2
|
+
require 'psych'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
require 'tempfile'
|
6
|
+
require 'yaml'
|
7
|
+
require 'erb'
|
8
|
+
require 'cartage/plugin'
|
9
|
+
|
10
|
+
class Cartage
|
11
|
+
# Connect to a remote machine and build a package remotely. Cartage::Remote
|
12
|
+
# uses Fog::SSH with key-based, not password-based authentication to connect
|
13
|
+
# to a remote server.
|
14
|
+
#
|
15
|
+
# Cartage::Remote assumes a relatively stable build server, but does not
|
16
|
+
# require one (custom +prebuild+ and +postbuild+ scripts could be used to
|
17
|
+
# manage that).
|
18
|
+
#
|
19
|
+
# == Remote Build Isolation
|
20
|
+
#
|
21
|
+
# Cartage::Remote allows for safe builds across multiple projects and
|
22
|
+
# branches with path-based isolation. The pattern for the build path is shown
|
23
|
+
# below, where the last part of the path is where the code will be cloned to.
|
24
|
+
#
|
25
|
+
# ~<remote_user>/cartage/<project-name>/<timestamp>/<project-name>
|
26
|
+
# | | | | |
|
27
|
+
# v | | | |
|
28
|
+
# build root v | | |
|
29
|
+
# cartage | | |
|
30
|
+
# path v | |
|
31
|
+
# project v |
|
32
|
+
# path isolation |
|
33
|
+
# path v
|
34
|
+
# build
|
35
|
+
# path
|
36
|
+
#
|
37
|
+
# So that if I am deploying on a project called +calliope+ and my remote user
|
38
|
+
# is +build+, my isolated build path might be:
|
39
|
+
#
|
40
|
+
# ~build/cartage/calliope/20150321091432/calliope
|
41
|
+
#
|
42
|
+
# == Remote Build Steps
|
43
|
+
#
|
44
|
+
# The steps for a remote build are:
|
45
|
+
#
|
46
|
+
# 1. Configure Cartage and save the active Cartage configuration as a
|
47
|
+
# temporary file that will be copied to the remote server.
|
48
|
+
# 2. Configure the Fog::SSH adapters with the keys to connect to the remote
|
49
|
+
# system.
|
50
|
+
# 3. Create the +prebuild+ script and run it locally.
|
51
|
+
# 4. Connect to the remote server, put the Cartage configuration file in the
|
52
|
+
# isolation path, and clone the repository. Check the repo out to the
|
53
|
+
# appropriate +release_hashref+.
|
54
|
+
# 5. Create the +build+ script, copy it remotely, and run it from the build
|
55
|
+
# isolation path (+build_path+). This is effectively:
|
56
|
+
# cd "$build_path" && $build_script
|
57
|
+
# 6. Clean up the remote server
|
58
|
+
#
|
59
|
+
# == Configuration
|
60
|
+
#
|
61
|
+
# Cartage::Remote is configured in the +plugins.remote+ section of the
|
62
|
+
# Cartage configuration file. The following keys are *required*:
|
63
|
+
#
|
64
|
+
# +server+:: A server string in the form <tt>[user@]host[:port]</tt> *or* a
|
65
|
+
# dictionary with +user+, +host+, and +port+. In either form, this
|
66
|
+
# will set @remote_user, @remote_host, and @remote_port. If
|
67
|
+
# @remote_user is not provided, it will be set from
|
68
|
+
# <tt>$USER</tt>.
|
69
|
+
#
|
70
|
+
# The following keys are optional:
|
71
|
+
#
|
72
|
+
# +keys+:: The SSH key(s) used to connect to the server. There are two basic
|
73
|
+
# ways that keys can be provided:
|
74
|
+
#
|
75
|
+
# * If provided as a string or an array of strings, the value(s)
|
76
|
+
# will be applied as glob patterns to find key files on disk.
|
77
|
+
# * If provided as a dictionary, the keys are irrelevant but the
|
78
|
+
# values are the key data.
|
79
|
+
#
|
80
|
+
# If keys are not provided, a default pattern of
|
81
|
+
# <tt>~/.ssh/*id_[rd]sa</tt> will be used to find keys on the local
|
82
|
+
# machine.
|
83
|
+
# +build+:: A multiline YAML string that is copied to the remote machine and
|
84
|
+
# executed as a script there. If not provided, the following script
|
85
|
+
# will be run:
|
86
|
+
#
|
87
|
+
# #!/bin/bash
|
88
|
+
# set -e
|
89
|
+
# if [ -f Gemfile ]; then
|
90
|
+
# bundle install --path %<remote_bundle>s
|
91
|
+
# bundle exec cartage build \
|
92
|
+
# --config-file %<config_file>s \
|
93
|
+
# --target %<project_path>s
|
94
|
+
# else
|
95
|
+
# cartage build --config-file %<config_file>s \
|
96
|
+
# --target %<project_path>s
|
97
|
+
# fi
|
98
|
+
# +prebuild+:: A multiline YAML string that is run as a script on the local
|
99
|
+
# machine to prepare for running remotely. If not provided, the
|
100
|
+
# following script will be run:
|
101
|
+
#
|
102
|
+
# #!/bin/bash
|
103
|
+
# ssh-keyscan -H %<remote_host>s >> ~/.ssh/known_hosts
|
104
|
+
# +postbuild+:: A multiline YAML string that is run as a script on the local
|
105
|
+
# machine to finish the build process locally. If not provided,
|
106
|
+
# nothing will run.
|
107
|
+
#
|
108
|
+
# == Script Substitution
|
109
|
+
#
|
110
|
+
# The +build+, +prebuild+, and +postbuild+ scripts require information from
|
111
|
+
# the Cartage and Cartage::Remote instances. When these scripts are rendered
|
112
|
+
# to disk, they will be run through Kernel#sprintf with the following
|
113
|
+
# substitution parameters specified as strings
|
114
|
+
# (<tt>%<<em>parameter-name</em>>s</tt>). All of these values are computed
|
115
|
+
# from the local Cartage configuration.
|
116
|
+
#
|
117
|
+
# +repo_url+:: The repository URL.
|
118
|
+
# +name+:: The package name.
|
119
|
+
# +release_hashref+:: The release hashref to build.
|
120
|
+
# +timestamp+:: The build timestamp.
|
121
|
+
# +remote_host+:: The remote build host.
|
122
|
+
# +remote_port+:: The remote build host SSH port (may be empty).
|
123
|
+
# +remote_user+:: The remote build user.
|
124
|
+
# +build_root+:: The remote build root, (usually
|
125
|
+
# <tt>~<em>remote_user</em></tt>).
|
126
|
+
# +cartage_path+:: <tt><em>build_root</em>/cartage</tt>.
|
127
|
+
# +project_path+:: <tt><em>cartage_path</em>/<em>name</em></tt>.
|
128
|
+
# +isolation_path+:: <tt><em>project_path</em>/<em>timestamp</em></tt>.
|
129
|
+
# +build_path+:: The remote build path (contains the code to package).
|
130
|
+
# <tt><em>isolation_path</em>/<em>name</em></tt>
|
131
|
+
# +remote_bundle+:: A place where dependencies for the build can be installed
|
132
|
+
# locally. <tt><em>isolation_path</em>/deps</tt>. Typically
|
133
|
+
# used in the +build+ script.
|
134
|
+
# bundle install --path %<remote_bundle>s
|
135
|
+
# +bundle_cache+:: The +bundle_cache+ for the remote server. Set the same as
|
136
|
+
# +project_path+.
|
137
|
+
# +config_file+:: The remote filename of the computed Cartage configuration.
|
138
|
+
# Must be provided to the remote run of +cartage+.
|
139
|
+
# bundle exec cartage build --config-file %<config_file>s
|
140
|
+
# +build_script+:: The full path to the remote build script.
|
141
|
+
# <tt><em>isolation_path</em>/cartage-build-remote</tt>.
|
142
|
+
#
|
143
|
+
# == Configuration Example
|
144
|
+
#
|
145
|
+
# ---
|
146
|
+
# plugins:
|
147
|
+
# remote:
|
148
|
+
# server:
|
149
|
+
# host: build-server
|
150
|
+
# script: |
|
151
|
+
# #! /bin/bash
|
152
|
+
# bundle install --path %<remote_bundle>s
|
153
|
+
# bundle exec cartage s3 --config-file %<config_file>s
|
154
|
+
#
|
155
|
+
class Remote < Cartage::Plugin
|
156
|
+
VERSION = '1.0' #:nodoc:
|
157
|
+
|
158
|
+
def initialize(*) #:nodoc:
|
159
|
+
super
|
160
|
+
@tmpfiles = []
|
161
|
+
end
|
162
|
+
|
163
|
+
# Build on the remote server.
|
164
|
+
def build
|
165
|
+
@cartage.display 'Pre-build configuration...'
|
166
|
+
stage = :config
|
167
|
+
|
168
|
+
paths = OpenStruct.new(build_root: @build_root)
|
169
|
+
paths.cartage_path = paths.build_root.join('cartage')
|
170
|
+
paths.project_path = paths.cartage_path.join(@cartage.name)
|
171
|
+
paths.isolation_path = paths.project_path.join(@cartage.timestamp)
|
172
|
+
paths.build_path = paths.isolation_path.join(@cartage.name)
|
173
|
+
paths.remote_bundle = paths.isolation_path.join('deps')
|
174
|
+
paths.bundle_cache = paths.project_path
|
175
|
+
paths.config_file = paths.isolation_path.join('cartage.yml')
|
176
|
+
paths.build_script = paths.isolation_path.join('cartage-build-remote')
|
177
|
+
|
178
|
+
config_file = make_config(paths).path
|
179
|
+
|
180
|
+
subs = OpenStruct.new(
|
181
|
+
paths.to_h.merge(repo_url: @cartage.repo_url,
|
182
|
+
name: @cartage.name,
|
183
|
+
release_hashref: @cartage.release_hashref,
|
184
|
+
timestamp: @cartage.timestamp,
|
185
|
+
remote_host: @remote_host,
|
186
|
+
remote_port: @remote_port,
|
187
|
+
remote_user: @remote_user)
|
188
|
+
)
|
189
|
+
|
190
|
+
stage = :ssh_config
|
191
|
+
configure_ssh
|
192
|
+
|
193
|
+
@cartage.display 'Running prebuild script...'
|
194
|
+
stage = :prebuild
|
195
|
+
system(make_tmpscript('prebuild', @prebuild, subs).path)
|
196
|
+
|
197
|
+
stage = :remote_clone
|
198
|
+
@cartage.display <<-message
|
199
|
+
Checking out #{@cartage.repo_url} at #{@cartage.release_hashref} remotely...
|
200
|
+
message
|
201
|
+
|
202
|
+
ssh %Q(mkdir -p #{paths.isolation_path})
|
203
|
+
@scp.upload(config_file, user_path(paths.config_file))
|
204
|
+
ssh %Q(git clone #{@cartage.repo_url} #{paths.build_path})
|
205
|
+
ssh <<-command
|
206
|
+
cd #{paths.build_path} && git checkout #{@cartage.release_hashref}
|
207
|
+
command
|
208
|
+
|
209
|
+
@cartage.display 'Running build script...'
|
210
|
+
stage = :remote_build
|
211
|
+
script = make_tmpscript('build', @build, subs).path
|
212
|
+
@scp.upload(script, user_path(paths.build_script))
|
213
|
+
ssh %Q(cd #{paths.build_path} && #{paths.build_script})
|
214
|
+
|
215
|
+
stage = :cleanup
|
216
|
+
@cartage.display 'Cleaning up after the build...'
|
217
|
+
ssh %Q(rm -rf #{paths.isolation_path})
|
218
|
+
rescue StandardError => e
|
219
|
+
$stderr.puts "Remote error in stage #{stage}: #{e.message}"
|
220
|
+
$stderr.puts e.backtrace.join("\n") if @cartage.verbose
|
221
|
+
ensure
|
222
|
+
if @postbuild
|
223
|
+
@cartage.display 'Running postbuild script...'
|
224
|
+
system(make_tmpscript('postbuild', @postbuild, subs).path, stage.to_s)
|
225
|
+
end
|
226
|
+
|
227
|
+
@tmpfiles.each { |tmpfile|
|
228
|
+
tmpfile.close
|
229
|
+
tmpfile.unlink
|
230
|
+
}
|
231
|
+
@tmpfiles.clear
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def resolve_config!(remote_config)
|
237
|
+
unless remote_config
|
238
|
+
raise ArgumentError, 'Cartage remote has no configuration.'
|
239
|
+
end
|
240
|
+
|
241
|
+
@remote_user = @remote_host = @remote_port = nil
|
242
|
+
|
243
|
+
case server = remote_config.server
|
244
|
+
when OpenStruct
|
245
|
+
@remote_user = server.user
|
246
|
+
@remote_host = server.host
|
247
|
+
@remote_port = server.port
|
248
|
+
when %r{\A(?:(?<user>[^@]+)@)?(?<host>[^@:]+)(?::(?<port>[^:]+))?\z}
|
249
|
+
@remote_user = $~[:user]
|
250
|
+
@remote_host = $~[:host]
|
251
|
+
@remote_port = $~[:port]
|
252
|
+
end
|
253
|
+
|
254
|
+
@remote_user ||= ENV['USER']
|
255
|
+
|
256
|
+
if @remote_host.nil? or @remote_host.empty?
|
257
|
+
raise ArgumentError, 'Cannot connect to remote; no server specified.'
|
258
|
+
end
|
259
|
+
|
260
|
+
@remote_server = @remote_host
|
261
|
+
@remote_server = "#{@remote_user}@#{@remote_server}" if @remote_user
|
262
|
+
@remote_server = "#{@remote_server}:#{@remote_port}" if @remote_port
|
263
|
+
|
264
|
+
@build_root = Pathname(remote_config.build_root || '~')
|
265
|
+
|
266
|
+
@build = remote_config.build
|
267
|
+
raise ArgumentError, <<-exception if @build.nil? or @build.empty?
|
268
|
+
No build script to run on remote #{@remote_server}.
|
269
|
+
exception
|
270
|
+
|
271
|
+
@key_data = @keys = nil
|
272
|
+
|
273
|
+
case keys = remote_config.keys
|
274
|
+
when OpenStruct
|
275
|
+
@key_data = keys.to_h.values
|
276
|
+
when Array
|
277
|
+
@keys = keys
|
278
|
+
when String
|
279
|
+
@keys = [ keys ]
|
280
|
+
when nil
|
281
|
+
@keys = %w(~/.ssh/*id_[rd]sa)
|
282
|
+
end
|
283
|
+
|
284
|
+
@keys &&= @keys.map { |key|
|
285
|
+
Pathname.glob(Pathname(key).expand_path)
|
286
|
+
}.flatten
|
287
|
+
|
288
|
+
@prebuild = remote_config.prebuild || DEFAULT_PREBUILD_SCRIPT
|
289
|
+
@postbuild = remote_config.postbuild
|
290
|
+
|
291
|
+
# Force lazy values to be present during execution.
|
292
|
+
@cartage.repo_url
|
293
|
+
@cartage.root_path
|
294
|
+
@cartage.release_hashref
|
295
|
+
@cartage.timestamp
|
296
|
+
@cartage
|
297
|
+
end
|
298
|
+
|
299
|
+
def configure_ssh
|
300
|
+
require 'fog'
|
301
|
+
options = {
|
302
|
+
paranoid: true,
|
303
|
+
keys: @keys,
|
304
|
+
key_data: @key_data
|
305
|
+
}
|
306
|
+
|
307
|
+
options[:port] = @remote_port if @remote_port
|
308
|
+
|
309
|
+
@ssh = Fog::SSH.new(@remote_host, @remote_user, options)
|
310
|
+
@scp = Fog::SCP.new(@remote_host, @remote_user, options)
|
311
|
+
end
|
312
|
+
|
313
|
+
def ssh(*commands)
|
314
|
+
results = @ssh.run(commands) do |stdout, stderr|
|
315
|
+
$stdout.print stdout unless stdout.nil?
|
316
|
+
$stderr.print stderr unless stderr.nil?
|
317
|
+
end
|
318
|
+
|
319
|
+
results.each do |result|
|
320
|
+
if result.status.nonzero?
|
321
|
+
fail "SSH Command failed with status (#{result.status}): " +
|
322
|
+
"#{result.status}"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
def make_tmpfile(basename, content = nil)
|
328
|
+
Tempfile.new("#{basename}.").tap { |f|
|
329
|
+
f.write content || yield
|
330
|
+
f.close
|
331
|
+
@tmpfiles << f
|
332
|
+
}
|
333
|
+
end
|
334
|
+
|
335
|
+
def make_tmpscript(basename, content, subs)
|
336
|
+
make_tmpfile(basename, content % subs.to_h).tap { |f|
|
337
|
+
File.chmod(0700, f.path)
|
338
|
+
}
|
339
|
+
end
|
340
|
+
|
341
|
+
def make_config(paths)
|
342
|
+
make_tmpfile('config.yml') do
|
343
|
+
config = Cartage::Config.new(@cartage.config)
|
344
|
+
config.name = @cartage.name
|
345
|
+
config.release_hashref = @cartage.release_hashref
|
346
|
+
config.timestamp = @cartage.timestamp
|
347
|
+
config.root_path = paths.build_path.to_s
|
348
|
+
config.bundle_cache = paths.bundle_cache.to_s
|
349
|
+
config.to_yaml
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def user_path(path)
|
354
|
+
path.to_s.sub(%r{\A~/}, '')
|
355
|
+
end
|
356
|
+
|
357
|
+
def self.commands #:nodoc:
|
358
|
+
require_relative 'remote/command'
|
359
|
+
[ Cartage::Remote::Command ]
|
360
|
+
end
|
361
|
+
|
362
|
+
DEFAULT_PREBUILD_SCRIPT = <<-script #:nodoc:
|
363
|
+
#!/bin/bash
|
364
|
+
|
365
|
+
ssh-keyscan -H %<remote_host>s >> ~/.ssh/known_hosts
|
366
|
+
script
|
367
|
+
|
368
|
+
DEFAULT_BUILD_SCRIPT = <<-script #:nodoc:
|
369
|
+
#!/bin/bash
|
370
|
+
|
371
|
+
set -e
|
372
|
+
|
373
|
+
if [ -f Gemfile ]; then
|
374
|
+
bundle install --path %<remote_bundle>s
|
375
|
+
bundle exec cartage build --config-file %<config_file>s --target %<project_path>s
|
376
|
+
else
|
377
|
+
cartage build --config-file %<config_file>s --target %<project_path>s
|
378
|
+
fi
|
379
|
+
script
|
380
|
+
end
|
381
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'cartage/command'
|
2
|
+
|
3
|
+
class Cartage::Remote::Command < Cartage::Command #:nodoc:
|
4
|
+
def initialize(cartage)
|
5
|
+
super(cartage, 'remote')
|
6
|
+
takes_commands(false)
|
7
|
+
short_desc('Build a release package and upload to cloud storage.')
|
8
|
+
|
9
|
+
@cartage = cartage
|
10
|
+
@remote = cartage.remote
|
11
|
+
|
12
|
+
Cartage.common_build_options(options, cartage)
|
13
|
+
end
|
14
|
+
|
15
|
+
def perform(*)
|
16
|
+
@remote.build
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_plugins
|
20
|
+
%w(remote)
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cartage-remote
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Austin Ziegler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cartage
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: fog
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.27'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.27'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rdoc
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: hoe-doofus
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: hoe-gemspec2
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.1'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.1'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: hoe-git
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.5'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.5'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: hoe-geminabox
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.3'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.3'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: hoe
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '3.13'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '3.13'
|
153
|
+
description: |-
|
154
|
+
cartage-remote is a plug-in for {cartage}[https://github.com/KineticCafe/cartage]
|
155
|
+
to build a package on a remote machine with cartage.
|
156
|
+
|
157
|
+
Cartage provides a repeatable means to create a package for a Rails application
|
158
|
+
that can be used in deployment with a configuration tool like Ansible, Chef,
|
159
|
+
Puppet, or Salt. The package is created with its dependencies bundled in
|
160
|
+
`vendor/bundle`, so it can be deployed in environments with strict access
|
161
|
+
control rules and without requiring development tool access.
|
162
|
+
email:
|
163
|
+
- aziegler@kineticcafe.com
|
164
|
+
executables: []
|
165
|
+
extensions: []
|
166
|
+
extra_rdoc_files:
|
167
|
+
- Contributing.rdoc
|
168
|
+
- History.rdoc
|
169
|
+
- Licence.rdoc
|
170
|
+
- Manifest.txt
|
171
|
+
- README.rdoc
|
172
|
+
files:
|
173
|
+
- ".autotest"
|
174
|
+
- ".gemtest"
|
175
|
+
- ".minitest.rb"
|
176
|
+
- Contributing.rdoc
|
177
|
+
- Gemfile
|
178
|
+
- History.rdoc
|
179
|
+
- Licence.rdoc
|
180
|
+
- Manifest.txt
|
181
|
+
- README.rdoc
|
182
|
+
- Rakefile
|
183
|
+
- lib/cartage/remote.rb
|
184
|
+
- lib/cartage/remote/command.rb
|
185
|
+
homepage: https://github.com/KineticCafe/cartage-remote/
|
186
|
+
licenses:
|
187
|
+
- MIT
|
188
|
+
metadata: {}
|
189
|
+
post_install_message:
|
190
|
+
rdoc_options:
|
191
|
+
- "--main"
|
192
|
+
- README.rdoc
|
193
|
+
require_paths:
|
194
|
+
- lib
|
195
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - ">="
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '0'
|
200
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
|
+
requirements:
|
202
|
+
- - ">="
|
203
|
+
- !ruby/object:Gem::Version
|
204
|
+
version: '0'
|
205
|
+
requirements: []
|
206
|
+
rubyforge_project:
|
207
|
+
rubygems_version: 2.2.2
|
208
|
+
signing_key:
|
209
|
+
specification_version: 4
|
210
|
+
summary: cartage-remote is a plug-in for {cartage}[https://github.com/KineticCafe/cartage]
|
211
|
+
to build a package on a remote machine with cartage
|
212
|
+
test_files: []
|