capistrano 3.18.1 → 3.19.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.docker/Dockerfile +7 -0
- data/.docker/ssh_key_rsa +49 -0
- data/.docker/ssh_key_rsa.pub +1 -0
- data/.docker/ubuntu_setup.sh +23 -0
- data/.github/workflows/ci.yml +1 -21
- data/.rubocop.yml +3 -3
- data/DEVELOPMENT.md +4 -13
- data/Gemfile +1 -2
- data/docker-compose.yml +8 -0
- data/features/deploy.feature +5 -1
- data/features/sshconnect.feature +1 -1
- data/features/step_definitions/assertions.rb +33 -23
- data/features/step_definitions/setup.rb +10 -13
- data/features/support/docker_gateway.rb +53 -0
- data/features/support/env.rb +0 -10
- data/features/support/remote_command_helpers.rb +3 -3
- data/features/support/remote_ssh_helpers.rb +33 -0
- data/lib/capistrano/scm/git.rb +5 -0
- data/lib/capistrano/scm/tasks/git.rake +11 -0
- data/lib/capistrano/tasks/deploy.rake +23 -1
- data/lib/capistrano/version.rb +1 -1
- data/spec/integration/dsl_spec.rb +10 -10
- data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +1 -0
- data/spec/lib/capistrano/scm/git_spec.rb +10 -0
- data/spec/support/test_app.rb +14 -11
- metadata +12 -10
- data/Dangerfile +0 -1
- data/features/support/vagrant_helpers.rb +0 -41
- data/spec/support/.gitignore +0 -1
- data/spec/support/Vagrantfile +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e00f29cd54bf8ffea1fdaf725fc260c3bdcf12290dda825a76c518d62fd86cf
|
4
|
+
data.tar.gz: bafa1c5c53bb543df6a583ac12d449232abc1900c572e4166f2ab51f5e2889b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5d0e2ef2a9786a926c67480cb5a397e9c0dee02bcb99b1719026b1fad440912f245953e595c00c284378c5ae6e2b03732754c3f72cd3dbcf7af9db6374efa2d
|
7
|
+
data.tar.gz: feee6f4862320a9db782639a74db9b7d64a614ed8803193b2463c44246ce07270f061c3f16ec9c1e6f5a50a6d3ce29fc1fa6f18b90e612a148fe1bc233b79213
|
data/.docker/Dockerfile
ADDED
data/.docker/ssh_key_rsa
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
-----BEGIN OPENSSH PRIVATE KEY-----
|
2
|
+
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
|
49
|
+
-----END OPENSSH PRIVATE KEY-----
|
@@ -0,0 +1 @@
|
|
1
|
+
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6wVCoBOGYS5qfXZGiKjuh7RWExlzrQ1Gml8Z3DDCggSEibh1WXJU9+rNKTqHmVoGy36iarPfjsGWw3IbiWiMOXD7crg3BCyRbksAdrVV/MIq6BiKqnGaQvOV9AE5RbA6W4/prkEKL/tdnpVaWpMbtthEo6H/IO3Ih+iXomni4NkUBjDjJf6sr8B/vI4aIcp0I5/uXNI3zIWVhQ6yBZ4hORs8jPBMpe7jMoFb5z8t6AUUfmIc66JiLmLX2hqYEreIB7rzlPOsDsOByADubyA/r3zYaA5kZxLbHT+sgQitjb4TATdoCxX6+utxVQeRZK4YrCR3D/aWzhmOgl5OHxO7ArWgICXC18icrvDdUACxOWKRaSe0WXw0nX1L0ZteKuYsvFAf0t0nNPStnWkxzRA4snzJCiptuWcjx8p7WY0Ph267ERq9rNFgMDmSsHaYMOnJAXr8WF00zFcVgAW6b3MBJSmBEtcz45RvMDv4XiMvzZiP/1+we+JXI1f5Y8LhyVtkeME5J7u6LrNUI5bvBMyDodMkmOonRdpL4iwOUXwpETX7i8fsr7+8YFw+JtXQ0iePq4V2PmmPNXThljhkhConwVnGsfV4qfuGaGJgMKJfK/E6hF8W9ejEH9BvmX7l75fyAK0zMq+n6ohOr4M4wVcz9G+s+5vSZ5JNwYTyVrAthtw== test@example.com
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
export DEBIAN_FRONTEND=noninteractive
|
6
|
+
|
7
|
+
# Create `deployer` user
|
8
|
+
adduser --disabled-password deployer < /dev/null
|
9
|
+
mkdir -p /home/deployer/.ssh
|
10
|
+
cp /root/.ssh/authorized_keys /home/deployer/.ssh
|
11
|
+
chown -R deployer:deployer /home/deployer/.ssh
|
12
|
+
chmod 600 /home/deployer/.ssh/authorized_keys
|
13
|
+
|
14
|
+
# Install and configure sshd
|
15
|
+
apt -y update
|
16
|
+
apt-get -y install openssh-server git
|
17
|
+
{
|
18
|
+
echo "Port 22"
|
19
|
+
echo "PasswordAuthentication no"
|
20
|
+
echo "ChallengeResponseAuthentication no"
|
21
|
+
} >> /etc/ssh/sshd_config
|
22
|
+
mkdir /var/run/sshd
|
23
|
+
chmod 0755 /var/run/sshd
|
data/.github/workflows/ci.yml
CHANGED
@@ -66,31 +66,11 @@ jobs:
|
|
66
66
|
bundler-cache: true
|
67
67
|
- name: rake rubocop
|
68
68
|
run: bundle exec rake rubocop
|
69
|
-
danger:
|
70
|
-
runs-on: ubuntu-latest
|
71
|
-
steps:
|
72
|
-
- uses: actions/checkout@v4
|
73
|
-
- name: Set up Ruby
|
74
|
-
uses: ruby/setup-ruby@v1
|
75
|
-
with:
|
76
|
-
ruby-version: "ruby" # latest-stable
|
77
|
-
bundler-cache: true
|
78
|
-
- name: danger
|
79
|
-
env:
|
80
|
-
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
81
|
-
run: bundle exec danger
|
82
69
|
features:
|
83
70
|
needs: [spec, spec-legacy]
|
84
|
-
runs-on:
|
71
|
+
runs-on: ubuntu-latest
|
85
72
|
steps:
|
86
73
|
- uses: actions/checkout@v4
|
87
|
-
- name: Cache Vagrant boxes
|
88
|
-
uses: actions/cache@v3
|
89
|
-
with:
|
90
|
-
path: ~/.vagrant.d/boxes
|
91
|
-
key: ${{ runner.os }}-vagrant-${{ hashFiles('Vagrantfile') }}
|
92
|
-
restore-keys: |
|
93
|
-
${{ runner.os }}-vagrant-
|
94
74
|
- name: Set up Ruby
|
95
75
|
uses: ruby/setup-ruby@v1
|
96
76
|
with:
|
data/.rubocop.yml
CHANGED
@@ -13,13 +13,13 @@ Metrics/BlockLength:
|
|
13
13
|
- "lib/**/*.rake"
|
14
14
|
Style/BarePercentLiterals:
|
15
15
|
EnforcedStyle: percent_q
|
16
|
+
Style/BracesAroundHashParameters:
|
17
|
+
Exclude:
|
18
|
+
- spec/integration/dsl_spec.rb
|
16
19
|
Style/ClassAndModuleChildren:
|
17
20
|
Enabled: false
|
18
21
|
Style/DoubleNegation:
|
19
22
|
Enabled: false
|
20
|
-
Style/FileName:
|
21
|
-
Exclude:
|
22
|
-
- "Dangerfile"
|
23
23
|
Style/IndentHeredoc:
|
24
24
|
Enabled: false
|
25
25
|
Style/SpaceAroundEqualsInParameterDefault:
|
data/DEVELOPMENT.md
CHANGED
@@ -20,22 +20,16 @@ Everyone can help improve Capistrano. There are ways to contribute even if you a
|
|
20
20
|
|
21
21
|
## Contributing documentation
|
22
22
|
|
23
|
-
Improvements and additions to Capistrano's documentation are very much appreciated. The official documentation is stored in the `docs/` directory as Markdown files. These files are used to automatically generate the [capistranorb.com](
|
23
|
+
Improvements and additions to Capistrano's documentation are very much appreciated. The official documentation is stored in the `docs/` directory as Markdown files. These files are used to automatically generate the [capistranorb.com](https://capistranorb.com/) website, which is hosted by GitHub Pages. Feel free to make changes to this documentation as you see fit. Before opening a pull request, make sure your documentation renders correctly by previewing the website in your local environment. Refer to [docs/README.md][] for instructions.
|
24
24
|
|
25
25
|
## Setting up your development environment
|
26
26
|
|
27
|
-
Capistrano is a Ruby project, so we expect you to have a functioning Ruby environment
|
28
|
-
|
29
|
-
Make sure to install:
|
30
|
-
|
31
|
-
* [Bundler](https://bundler.io/)
|
32
|
-
* [Vagrant](https://www.vagrantup.com/)
|
33
|
-
* [VirtualBox](https://www.virtualbox.org/wiki/Downloads) (or another [Vagrant-supported](https://docs.vagrantup.com/v2/getting-started/providers.html) VM host)
|
27
|
+
Capistrano is a Ruby project, so we expect you to have a functioning Ruby environment with the latest stable version of Ruby. To run Cucumber tests, you'll also need [Docker installed](https://docs.docker.com/get-docker/) and running.
|
34
28
|
|
35
29
|
|
36
30
|
### Running tests
|
37
31
|
|
38
|
-
Capistrano has two test suites: an RSpec suite and a Cucumber suite. The RSpec suite handles quick feedback unit specs. The Cucumber suite is an integration suite that uses
|
32
|
+
Capistrano has two test suites: an RSpec suite and a Cucumber suite. The RSpec suite handles quick feedback unit specs. The Cucumber suite is an integration suite that uses a Docker container as an SSH server and deployment target.
|
39
33
|
|
40
34
|
```
|
41
35
|
# Ensure all dependencies are installed
|
@@ -44,11 +38,8 @@ $ bundle install
|
|
44
38
|
# Run the RSpec suite
|
45
39
|
$ bundle exec rake spec
|
46
40
|
|
47
|
-
# Run the Cucumber suite
|
41
|
+
# Run the Cucumber suite (Docker must be running)
|
48
42
|
$ bundle exec rake features
|
49
|
-
|
50
|
-
# Run the Cucumber suite and leave the VM running (faster for subsequent runs)
|
51
|
-
$ bundle exec rake features KEEP_RUNNING=1
|
52
43
|
```
|
53
44
|
|
54
45
|
## Coding guidelines
|
data/Gemfile
CHANGED
@@ -38,10 +38,9 @@ if Gem::Requirement.new("< 2.2").satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
|
38
38
|
gem "rake", "< 13.0.0"
|
39
39
|
end
|
40
40
|
|
41
|
-
# We only run
|
41
|
+
# We only run rubocop and its dependencies on a new-ish ruby; no need to install them otherwise
|
42
42
|
if Gem::Requirement.new("> 2.4").satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
43
43
|
gem "base64"
|
44
|
-
gem "danger"
|
45
44
|
gem "psych", "< 4" # Ensures rubocop works on Ruby 3.1
|
46
45
|
gem "racc"
|
47
46
|
gem "rubocop", "0.48.1"
|
data/docker-compose.yml
ADDED
data/features/deploy.feature
CHANGED
@@ -40,6 +40,11 @@ Feature: Deploy
|
|
40
40
|
Then the repo is cloned
|
41
41
|
And the release is created
|
42
42
|
|
43
|
+
Scenario: REVISION and REVISION_TIME files are present
|
44
|
+
When I make 1 deployment
|
45
|
+
Then the REVISION file is created in the release
|
46
|
+
Then the REVISION_TIME file is created in the release
|
47
|
+
|
43
48
|
Scenario: Symlink linked files
|
44
49
|
When I run cap "deploy:symlink:linked_files deploy:symlink:release" as part of a release
|
45
50
|
Then file symlinks are created in the new release
|
@@ -85,4 +90,3 @@ Feature: Deploy
|
|
85
90
|
Given I make 3 deployments
|
86
91
|
When I rollback to a specific release
|
87
92
|
Then the current symlink points to that specific release
|
88
|
-
|
data/features/sshconnect.feature
CHANGED
@@ -8,4 +8,4 @@ Feature: SSH Connection
|
|
8
8
|
Scenario: Switching from default user to root and back again
|
9
9
|
When I run cap "am_i_root"
|
10
10
|
Then the task is successful
|
11
|
-
And the output matches "I am uid=0\(root\)" followed by "I am uid=\d+\(
|
11
|
+
And the output matches "I am uid=0\(root\)" followed by "I am uid=\d+\(deployer\)"
|
@@ -6,67 +6,77 @@ end
|
|
6
6
|
|
7
7
|
Then(/^git wrapper permissions are 0700$/) do
|
8
8
|
permissions_test = %Q([ $(stat -c "%a" #{TestApp.git_wrapper_path_glob}) == "700" ])
|
9
|
-
|
10
|
-
|
11
|
-
expect(status).to be_success
|
9
|
+
expect { run_remote_ssh_command(permissions_test) }.not_to raise_error
|
12
10
|
end
|
13
11
|
|
14
12
|
Then(/^the shared path is created$/) do
|
15
|
-
|
13
|
+
run_remote_ssh_command(test_dir_exists(TestApp.shared_path))
|
16
14
|
end
|
17
15
|
|
18
16
|
Then(/^the releases path is created$/) do
|
19
|
-
|
17
|
+
run_remote_ssh_command(test_dir_exists(TestApp.releases_path))
|
20
18
|
end
|
21
19
|
|
22
20
|
Then(/^(\d+) valid releases are kept/) do |num|
|
23
21
|
test = %Q([ $(ls -g #{TestApp.releases_path} | grep -E '[0-9]{14}' | wc -l) == "#{num}" ])
|
24
|
-
|
25
|
-
expect(status).to be_success
|
22
|
+
expect { run_remote_ssh_command(test) }.not_to raise_error
|
26
23
|
end
|
27
24
|
|
28
25
|
Then(/^the invalid (.+) release is ignored$/) do |filename|
|
29
26
|
test = "ls -g #{TestApp.releases_path} | grep #{filename}"
|
30
|
-
|
31
|
-
expect(status).to be_success
|
27
|
+
expect { run_remote_ssh_command(test) }.not_to raise_error
|
32
28
|
end
|
33
29
|
|
34
30
|
Then(/^directories in :linked_dirs are created in shared$/) do
|
35
31
|
TestApp.linked_dirs.each do |dir|
|
36
|
-
|
32
|
+
run_remote_ssh_command(test_dir_exists(TestApp.shared_path.join(dir)))
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
40
36
|
Then(/^directories referenced in :linked_files are created in shared$/) do
|
41
37
|
dirs = TestApp.linked_files.map { |path| TestApp.shared_path.join(path).dirname }
|
42
38
|
dirs.each do |dir|
|
43
|
-
|
39
|
+
run_remote_ssh_command(test_dir_exists(dir))
|
44
40
|
end
|
45
41
|
end
|
46
42
|
|
47
43
|
Then(/^the repo is cloned$/) do
|
48
|
-
|
44
|
+
run_remote_ssh_command(test_dir_exists(TestApp.repo_path))
|
49
45
|
end
|
50
46
|
|
51
47
|
Then(/^the release is created$/) do
|
52
|
-
|
48
|
+
stdout, _stderr = run_remote_ssh_command("ls #{TestApp.releases_path}")
|
49
|
+
|
50
|
+
expect(stdout.strip).to match(/\A#{Time.now.utc.strftime("%Y%m%d")}\d{6}\Z/)
|
51
|
+
end
|
52
|
+
|
53
|
+
Then(/^the REVISION file is created in the release$/) do
|
54
|
+
stdout, _stderr = run_remote_ssh_command("cat #{@release_paths[0]}/REVISION")
|
55
|
+
|
56
|
+
expect(stdout.strip).to match(/\h{40}/)
|
57
|
+
end
|
58
|
+
|
59
|
+
Then(/^the REVISION_TIME file is created in the release$/) do
|
60
|
+
stdout, _stderr = run_remote_ssh_command("cat #{@release_paths[0]}/REVISION_TIME")
|
61
|
+
|
62
|
+
expect(stdout.strip).to match(/\d{10}/)
|
53
63
|
end
|
54
64
|
|
55
65
|
Then(/^file symlinks are created in the new release$/) do
|
56
66
|
TestApp.linked_files.each do |file|
|
57
|
-
|
67
|
+
run_remote_ssh_command(test_symlink_exists(TestApp.current_path.join(file)))
|
58
68
|
end
|
59
69
|
end
|
60
70
|
|
61
71
|
Then(/^directory symlinks are created in the new release$/) do
|
62
72
|
pending
|
63
73
|
TestApp.linked_dirs.each do |dir|
|
64
|
-
|
74
|
+
run_remote_ssh_command(test_symlink_exists(TestApp.release_path.join(dir)))
|
65
75
|
end
|
66
76
|
end
|
67
77
|
|
68
78
|
Then(/^the current directory will be a symlink to the release$/) do
|
69
|
-
|
79
|
+
run_remote_ssh_command(exists?("e", TestApp.current_path))
|
70
80
|
end
|
71
81
|
|
72
82
|
Then(/^the deploy\.rb file is created$/) do
|
@@ -95,7 +105,7 @@ end
|
|
95
105
|
|
96
106
|
Then(/^it creates the file with the remote_task prerequisite$/) do
|
97
107
|
TestApp.linked_files.each do |file|
|
98
|
-
|
108
|
+
run_remote_ssh_command(test_file_exists(TestApp.shared_path.join(file)))
|
99
109
|
end
|
100
110
|
end
|
101
111
|
|
@@ -113,18 +123,18 @@ end
|
|
113
123
|
|
114
124
|
Then(/^the failure task will run$/) do
|
115
125
|
failed = TestApp.shared_path.join("failed")
|
116
|
-
|
126
|
+
run_remote_ssh_command(test_file_exists(failed))
|
117
127
|
end
|
118
128
|
|
119
129
|
Then(/^the failure task will not run$/) do
|
120
130
|
failed = TestApp.shared_path.join("failed")
|
121
|
-
expect {
|
122
|
-
.to raise_error(
|
131
|
+
expect { run_remote_ssh_command(test_file_exists(failed)) }
|
132
|
+
.to raise_error(RemoteSSHHelpers::RemoteSSHCommandError)
|
123
133
|
end
|
124
134
|
|
125
135
|
When(/^an error is raised$/) do
|
126
136
|
error = TestApp.shared_path.join("fail")
|
127
|
-
|
137
|
+
run_remote_ssh_command(test_file_exists(error))
|
128
138
|
end
|
129
139
|
|
130
140
|
Then(/contains "([^"]*)" in the output/) do |expected|
|
@@ -142,11 +152,11 @@ end
|
|
142
152
|
Then(/the current symlink points to the previous release/) do
|
143
153
|
previous_release_path = @release_paths[-2]
|
144
154
|
|
145
|
-
|
155
|
+
run_remote_ssh_command(symlinked?(TestApp.current_path, previous_release_path))
|
146
156
|
end
|
147
157
|
|
148
158
|
Then(/^the current symlink points to that specific release$/) do
|
149
159
|
specific_release_path = TestApp.releases_path.join(@rollback_release)
|
150
160
|
|
151
|
-
|
161
|
+
run_remote_ssh_command(symlinked?(TestApp.current_path, specific_release_path))
|
152
162
|
end
|
@@ -7,11 +7,8 @@ Given(/^a test app without any configuration$/) do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
Given(/^servers with the roles app and web$/) do
|
10
|
-
|
11
|
-
|
12
|
-
rescue
|
13
|
-
nil
|
14
|
-
end
|
10
|
+
start_ssh_server
|
11
|
+
wait_for_ssh_server
|
15
12
|
end
|
16
13
|
|
17
14
|
Given(/^a linked file "(.*?)"$/) do |file|
|
@@ -21,8 +18,8 @@ end
|
|
21
18
|
|
22
19
|
Given(/^file "(.*?)" exists in shared path$/) do |file|
|
23
20
|
file_shared_path = TestApp.shared_path.join(file)
|
24
|
-
|
25
|
-
|
21
|
+
run_remote_ssh_command("mkdir -p #{file_shared_path.dirname}")
|
22
|
+
run_remote_ssh_command("touch #{file_shared_path}")
|
26
23
|
end
|
27
24
|
|
28
25
|
Given(/^all linked files exists in shared path$/) do
|
@@ -33,8 +30,8 @@ end
|
|
33
30
|
|
34
31
|
Given(/^file "(.*?)" does not exist in shared path$/) do |file|
|
35
32
|
file_shared_path = TestApp.shared_path.join(file)
|
36
|
-
|
37
|
-
|
33
|
+
run_remote_ssh_command("mkdir -p #{TestApp.shared_path}")
|
34
|
+
run_remote_ssh_command("touch #{file_shared_path} && rm #{file_shared_path}")
|
38
35
|
end
|
39
36
|
|
40
37
|
Given(/^a custom task to generate a file$/) do
|
@@ -67,12 +64,12 @@ Given(/^a stage file named (.+)$/) do |filename|
|
|
67
64
|
TestApp.write_local_stage_file(filename)
|
68
65
|
end
|
69
66
|
|
70
|
-
Given(/^I make (\d+) deployments
|
67
|
+
Given(/^I make (\d+) deployments?$/) do |count|
|
71
68
|
step "all linked files exists in shared path"
|
72
69
|
|
73
70
|
@release_paths = (1..count.to_i).map do
|
74
71
|
TestApp.cap("deploy")
|
75
|
-
stdout, _stderr =
|
72
|
+
stdout, _stderr = run_remote_ssh_command("readlink #{TestApp.current_path}")
|
76
73
|
|
77
74
|
stdout.strip
|
78
75
|
end
|
@@ -85,10 +82,10 @@ Given(/^(\d+) valid existing releases$/) do |num|
|
|
85
82
|
offset = -(a_day * i)
|
86
83
|
TestApp.release_path(TestApp.timestamp(offset))
|
87
84
|
end
|
88
|
-
|
85
|
+
run_remote_ssh_command("mkdir -p #{dirs.join(' ')}")
|
89
86
|
end
|
90
87
|
end
|
91
88
|
|
92
89
|
Given(/^an invalid release named "(.+)"$/) do |filename|
|
93
|
-
|
90
|
+
run_remote_ssh_command("mkdir -p #{TestApp.release_path(filename)}")
|
94
91
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Ensure Docker container is completely stopped when Ruby exits.
|
2
|
+
at_exit do
|
3
|
+
DockerGateway.new.stop
|
4
|
+
end
|
5
|
+
|
6
|
+
# Manages the Docker-based SSH server that is declared in docker-compose.yml.
|
7
|
+
class DockerGateway
|
8
|
+
def initialize(log_proc=$stderr.method(:puts))
|
9
|
+
@log_proc = log_proc
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
run_compose_command("up -d")
|
14
|
+
end
|
15
|
+
|
16
|
+
def stop
|
17
|
+
run_compose_command("down")
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_shell_command(command)
|
21
|
+
run_compose_command("exec ssh_server /bin/bash -c #{command.shellescape}")
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def run_compose_command(command)
|
27
|
+
log "[docker compose] #{command}"
|
28
|
+
stdout, stderr, status = Open3.popen3("docker compose #{command}") do |stdin, stdout, stderr, wait_threads|
|
29
|
+
stdin << ""
|
30
|
+
stdin.close
|
31
|
+
out = Thread.new { read_lines(stdout, &$stdout.method(:puts)) }
|
32
|
+
err = Thread.new { stderr.read }
|
33
|
+
[out.value, err.value.to_s, wait_threads.value]
|
34
|
+
end
|
35
|
+
|
36
|
+
(stdout + stderr).each_line { |line| log "[docker compose] #{line}" }
|
37
|
+
|
38
|
+
[stdout, stderr, status]
|
39
|
+
end
|
40
|
+
|
41
|
+
def read_lines(io)
|
42
|
+
buffer = + ""
|
43
|
+
while (line = io.gets)
|
44
|
+
buffer << line
|
45
|
+
yield line
|
46
|
+
end
|
47
|
+
buffer
|
48
|
+
end
|
49
|
+
|
50
|
+
def log(message)
|
51
|
+
@log_proc.call(message)
|
52
|
+
end
|
53
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -1,11 +1 @@
|
|
1
|
-
PROJECT_ROOT = File.expand_path("../../../", __FILE__)
|
2
|
-
VAGRANT_ROOT = File.join(PROJECT_ROOT, "spec/support")
|
3
|
-
VAGRANT_BIN = ENV["VAGRANT_BIN"] || "vagrant"
|
4
|
-
|
5
|
-
at_exit do
|
6
|
-
if ENV["KEEP_RUNNING"]
|
7
|
-
VagrantHelpers.run_vagrant_command("rm -rf /home/vagrant/var")
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
1
|
require_relative "../../spec/support/test_app"
|
@@ -12,7 +12,7 @@ module RemoteCommandHelpers
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def exists?(type, path)
|
15
|
-
%Q{[ -#{type} "#{path}" ]}
|
15
|
+
%Q{[[ -#{type} "#{path}" ]]}
|
16
16
|
end
|
17
17
|
|
18
18
|
def symlinked?(symlink_path, target_path)
|
@@ -20,9 +20,9 @@ module RemoteCommandHelpers
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def safely_remove_file(_path)
|
23
|
-
|
23
|
+
run_remote_ssh_command("rm #{test_file}")
|
24
24
|
rescue
|
25
|
-
|
25
|
+
RemoteSSHHelpers::RemoteSSHCommandError
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "open3"
|
2
|
+
require "socket"
|
3
|
+
require_relative "docker_gateway"
|
4
|
+
|
5
|
+
module RemoteSSHHelpers
|
6
|
+
extend self
|
7
|
+
|
8
|
+
class RemoteSSHCommandError < RuntimeError; end
|
9
|
+
|
10
|
+
def start_ssh_server
|
11
|
+
docker_gateway.start
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait_for_ssh_server(retries=3)
|
15
|
+
Socket.tcp("localhost", 2022, connect_timeout: 1).close
|
16
|
+
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT
|
17
|
+
retries -= 1
|
18
|
+
sleep(2) && retry if retries.positive?
|
19
|
+
raise
|
20
|
+
end
|
21
|
+
|
22
|
+
def run_remote_ssh_command(command)
|
23
|
+
stdout, stderr, status = docker_gateway.run_shell_command(command)
|
24
|
+
return [stdout, stderr] if status.success?
|
25
|
+
raise RemoteSSHCommandError, status
|
26
|
+
end
|
27
|
+
|
28
|
+
def docker_gateway
|
29
|
+
@docker_gateway ||= DockerGateway.new(method(:log))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
World(RemoteSSHHelpers)
|
data/lib/capistrano/scm/git.rb
CHANGED
@@ -26,6 +26,7 @@ class Capistrano::SCM::Git < Capistrano::SCM::Plugin
|
|
26
26
|
after "deploy:new_release_path", "git:create_release"
|
27
27
|
before "deploy:check", "git:check"
|
28
28
|
before "deploy:set_current_revision", "git:set_current_revision"
|
29
|
+
before "deploy:set_current_revision_time", "git:set_current_revision_time"
|
29
30
|
end
|
30
31
|
|
31
32
|
def define_tasks
|
@@ -78,6 +79,10 @@ class Capistrano::SCM::Git < Capistrano::SCM::Plugin
|
|
78
79
|
backend.capture(:git, "rev-list --max-count=1 #{fetch(:branch)}")
|
79
80
|
end
|
80
81
|
|
82
|
+
def fetch_revision_time
|
83
|
+
backend.capture(:git, "--no-pager log -1 --pretty=format:\"%ct\" #{fetch(:branch)}")
|
84
|
+
end
|
85
|
+
|
81
86
|
def git(*args)
|
82
87
|
args.unshift :git
|
83
88
|
backend.execute(*args)
|
@@ -70,4 +70,15 @@ namespace :git do
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
73
|
+
|
74
|
+
desc "Determine the unix timestamp that the revision that will be deployed was created"
|
75
|
+
task :set_current_revision_time do
|
76
|
+
on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
|
77
|
+
within repo_path do
|
78
|
+
with fetch(:git_environmental_variables) do
|
79
|
+
set :current_revision_time, git_plugin.fetch_revision_time
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
73
84
|
end
|
@@ -3,6 +3,7 @@ namespace :deploy do
|
|
3
3
|
invoke "deploy:print_config_variables" if fetch(:print_config_variables, false)
|
4
4
|
invoke "deploy:check"
|
5
5
|
invoke "deploy:set_previous_revision"
|
6
|
+
invoke "deploy:set_previous_revision_time"
|
6
7
|
end
|
7
8
|
|
8
9
|
task :print_config_variables do
|
@@ -27,6 +28,7 @@ namespace :deploy do
|
|
27
28
|
|
28
29
|
task updating: :new_release_path do
|
29
30
|
invoke "deploy:set_current_revision"
|
31
|
+
invoke "deploy:set_current_revision_time"
|
30
32
|
invoke "deploy:symlink:shared"
|
31
33
|
end
|
32
34
|
|
@@ -236,7 +238,7 @@ namespace :deploy do
|
|
236
238
|
end
|
237
239
|
|
238
240
|
desc "Place a REVISION file with the current revision SHA in the current release path"
|
239
|
-
task :set_current_revision
|
241
|
+
task :set_current_revision do
|
240
242
|
on release_roles(:all) do
|
241
243
|
within release_path do
|
242
244
|
execute :echo, "\"#{fetch(:current_revision)}\" > REVISION"
|
@@ -253,6 +255,26 @@ namespace :deploy do
|
|
253
255
|
end
|
254
256
|
end
|
255
257
|
|
258
|
+
desc "Place a REVISION_TIME file with the current revision commit time in the current release path"
|
259
|
+
task :set_current_revision_time do
|
260
|
+
on release_roles(:all) do
|
261
|
+
within release_path do
|
262
|
+
if fetch(:current_revision_time)
|
263
|
+
execute :echo, "\"#{fetch(:current_revision_time)}\" > REVISION_TIME"
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
task :set_previous_revision_time do
|
270
|
+
on release_roles(:all) do
|
271
|
+
target = release_path.join("REVISION_TIME")
|
272
|
+
if test "[ -f #{target} ]"
|
273
|
+
set(:previous_revision_time, capture(:cat, target, "2>/dev/null"))
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
256
278
|
task :restart
|
257
279
|
task :failed
|
258
280
|
end
|
data/lib/capistrano/version.rb
CHANGED
@@ -592,8 +592,8 @@ describe Capistrano::DSL do
|
|
592
592
|
|
593
593
|
it "yields the properties for a single role" do
|
594
594
|
recipient = mock("recipient")
|
595
|
-
recipient.expects(:doit).with("example1.com", :redis, port: 6379, type: :slave)
|
596
|
-
recipient.expects(:doit).with("example2.com", :redis, port: 6379, type: :master)
|
595
|
+
recipient.expects(:doit).with("example1.com", :redis, { port: 6379, type: :slave })
|
596
|
+
recipient.expects(:doit).with("example2.com", :redis, { port: 6379, type: :master })
|
597
597
|
dsl.role_properties(:redis) do |host, role, props|
|
598
598
|
recipient.doit(host, role, props)
|
599
599
|
end
|
@@ -601,8 +601,8 @@ describe Capistrano::DSL do
|
|
601
601
|
|
602
602
|
it "yields the properties for multiple roles" do
|
603
603
|
recipient = mock("recipient")
|
604
|
-
recipient.expects(:doit).with("example1.com", :redis, port: 6379, type: :slave)
|
605
|
-
recipient.expects(:doit).with("example2.com", :redis, port: 6379, type: :master)
|
604
|
+
recipient.expects(:doit).with("example1.com", :redis, { port: 6379, type: :slave })
|
605
|
+
recipient.expects(:doit).with("example2.com", :redis, { port: 6379, type: :master })
|
606
606
|
recipient.expects(:doit).with("example3.com", :app, nil)
|
607
607
|
dsl.role_properties(:redis, :app) do |host, role, props|
|
608
608
|
recipient.doit(host, role, props)
|
@@ -611,10 +611,10 @@ describe Capistrano::DSL do
|
|
611
611
|
|
612
612
|
it "yields the merged properties for multiple roles" do
|
613
613
|
recipient = mock("recipient")
|
614
|
-
recipient.expects(:doit).with("example1.com", :redis, port: 6379, type: :slave)
|
615
|
-
recipient.expects(:doit).with("example2.com", :redis, port: 6379, type: :master)
|
616
|
-
recipient.expects(:doit).with("example1.com", :web, port: 80)
|
617
|
-
recipient.expects(:doit).with("example2.com", :web, port: 81)
|
614
|
+
recipient.expects(:doit).with("example1.com", :redis, { port: 6379, type: :slave })
|
615
|
+
recipient.expects(:doit).with("example2.com", :redis, { port: 6379, type: :master })
|
616
|
+
recipient.expects(:doit).with("example1.com", :web, { port: 80 })
|
617
|
+
recipient.expects(:doit).with("example2.com", :web, { port: 81 })
|
618
618
|
dsl.role_properties(:redis, :web) do |host, role, props|
|
619
619
|
recipient.doit(host, role, props)
|
620
620
|
end
|
@@ -622,8 +622,8 @@ describe Capistrano::DSL do
|
|
622
622
|
|
623
623
|
it "honours a property filter before yielding" do
|
624
624
|
recipient = mock("recipient")
|
625
|
-
recipient.expects(:doit).with("example1.com", :redis, port: 6379, type: :slave)
|
626
|
-
recipient.expects(:doit).with("example1.com", :web, port: 80)
|
625
|
+
recipient.expects(:doit).with("example1.com", :redis, { port: 6379, type: :slave })
|
626
|
+
recipient.expects(:doit).with("example1.com", :web, { port: 80 })
|
627
627
|
dsl.role_properties(:redis, :web, select: :active) do |host, role, props|
|
628
628
|
recipient.doit(host, role, props)
|
629
629
|
end
|
@@ -12,6 +12,7 @@ module Capistrano
|
|
12
12
|
Rake::Task.define_task("deploy:check")
|
13
13
|
Rake::Task.define_task("deploy:new_release_path")
|
14
14
|
Rake::Task.define_task("deploy:set_current_revision")
|
15
|
+
Rake::Task.define_task("deploy:set_current_revision_time")
|
15
16
|
set :scm, SCMResolver::DEFAULT_GIT
|
16
17
|
end
|
17
18
|
|
@@ -19,6 +19,7 @@ module Capistrano
|
|
19
19
|
Rake::Task.define_task("deploy:new_release_path")
|
20
20
|
Rake::Task.define_task("deploy:check")
|
21
21
|
Rake::Task.define_task("deploy:set_current_revision")
|
22
|
+
Rake::Task.define_task("deploy:set_current_revision_time")
|
22
23
|
end
|
23
24
|
|
24
25
|
# Clean up any tasks or variables that the plugin defined.
|
@@ -170,6 +171,15 @@ module Capistrano
|
|
170
171
|
end
|
171
172
|
end
|
172
173
|
|
174
|
+
describe "#fetch_revision_time" do
|
175
|
+
it "should capture git log without a pager" do
|
176
|
+
env.set(:branch, "branch")
|
177
|
+
backend.expects(:capture).with(:git, "--no-pager log -1 --pretty=format:\"%ct\" branch").returns("1715828406")
|
178
|
+
revision_time = subject.fetch_revision_time
|
179
|
+
expect(revision_time).to eq("1715828406")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
173
183
|
describe "#verify_commit" do
|
174
184
|
it "should run git verify-commit" do
|
175
185
|
env.set(:branch, "branch")
|
data/spec/support/test_app.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "English"
|
2
2
|
require "fileutils"
|
3
3
|
require "pathname"
|
4
|
+
require "open3"
|
4
5
|
|
5
6
|
module TestApp
|
6
7
|
extend self
|
@@ -14,8 +15,8 @@ module TestApp
|
|
14
15
|
set :deploy_to, '#{deploy_to}'
|
15
16
|
set :repo_url, 'https://github.com/capistrano/capistrano.git'
|
16
17
|
set :branch, 'master'
|
17
|
-
set :ssh_options, { keys:
|
18
|
-
server '
|
18
|
+
set :ssh_options, { keys: '#{File.expand_path('../../.docker/ssh_key_rsa', __dir__)}', auth_methods: ['publickey'] }
|
19
|
+
server 'deployer@localhost:2022', roles: %w{web app}
|
19
20
|
set :linked_files, #{linked_files}
|
20
21
|
set :linked_dirs, #{linked_dirs}
|
21
22
|
set :format_options, log_file: nil
|
@@ -39,10 +40,13 @@ module TestApp
|
|
39
40
|
FileUtils.rm_rf(test_app_path)
|
40
41
|
FileUtils.mkdir(test_app_path)
|
41
42
|
|
42
|
-
File.
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
File.write(gemfile, <<-GEMFILE.gsub(/^\s+/, ""))
|
44
|
+
source "https://rubygems.org"
|
45
|
+
|
46
|
+
gem "capistrano", path: #{path_to_cap.to_s.inspect}
|
47
|
+
gem "ed25519", ">= 1.2", "< 2.0"
|
48
|
+
gem "bcrypt_pbkdf", ">= 1.0", "< 2.0"
|
49
|
+
GEMFILE
|
46
50
|
|
47
51
|
Dir.chdir(test_app_path) do
|
48
52
|
run "bundle"
|
@@ -96,13 +100,12 @@ module TestApp
|
|
96
100
|
end
|
97
101
|
|
98
102
|
def run(command, subdirectory=nil)
|
99
|
-
output = nil
|
100
103
|
command = "bundle exec #{command}" unless command =~ /^bundle\b/
|
101
104
|
dir = subdirectory ? test_app_path.join(subdirectory) : test_app_path
|
102
|
-
Dir.chdir(dir) do
|
103
|
-
|
105
|
+
output, status = Dir.chdir(dir) do
|
106
|
+
with_clean_bundler_env { Open3.capture2e(command) }
|
104
107
|
end
|
105
|
-
[
|
108
|
+
[status.success?, output]
|
106
109
|
end
|
107
110
|
|
108
111
|
def stage
|
@@ -118,7 +121,7 @@ module TestApp
|
|
118
121
|
end
|
119
122
|
|
120
123
|
def deploy_to
|
121
|
-
Pathname.new("/home/
|
124
|
+
Pathname.new("/home/deployer/var/www/deploy")
|
122
125
|
end
|
123
126
|
|
124
127
|
def shared_path
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.19.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Clements
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: airbrussh
|
@@ -78,6 +78,10 @@ executables:
|
|
78
78
|
extensions: []
|
79
79
|
extra_rdoc_files: []
|
80
80
|
files:
|
81
|
+
- ".docker/Dockerfile"
|
82
|
+
- ".docker/ssh_key_rsa"
|
83
|
+
- ".docker/ssh_key_rsa.pub"
|
84
|
+
- ".docker/ubuntu_setup.sh"
|
81
85
|
- ".github/issue_template.md"
|
82
86
|
- ".github/pull_request_template.md"
|
83
87
|
- ".github/release-drafter.yml"
|
@@ -88,7 +92,6 @@ files:
|
|
88
92
|
- CHANGELOG.md
|
89
93
|
- CONTRIBUTING.md
|
90
94
|
- DEVELOPMENT.md
|
91
|
-
- Dangerfile
|
92
95
|
- Gemfile
|
93
96
|
- LICENSE.txt
|
94
97
|
- README.md
|
@@ -98,6 +101,7 @@ files:
|
|
98
101
|
- bin/cap
|
99
102
|
- bin/capify
|
100
103
|
- capistrano.gemspec
|
104
|
+
- docker-compose.yml
|
101
105
|
- features/configuration.feature
|
102
106
|
- features/deploy.feature
|
103
107
|
- features/deploy_failure.feature
|
@@ -109,9 +113,10 @@ files:
|
|
109
113
|
- features/step_definitions/cap_commands.rb
|
110
114
|
- features/step_definitions/setup.rb
|
111
115
|
- features/subdirectory.feature
|
116
|
+
- features/support/docker_gateway.rb
|
112
117
|
- features/support/env.rb
|
113
118
|
- features/support/remote_command_helpers.rb
|
114
|
-
- features/support/
|
119
|
+
- features/support/remote_ssh_helpers.rb
|
115
120
|
- lib/Capfile
|
116
121
|
- lib/capistrano.rb
|
117
122
|
- lib/capistrano/all.rb
|
@@ -202,8 +207,6 @@ files:
|
|
202
207
|
- spec/lib/capistrano/version_validator_spec.rb
|
203
208
|
- spec/lib/capistrano_spec.rb
|
204
209
|
- spec/spec_helper.rb
|
205
|
-
- spec/support/.gitignore
|
206
|
-
- spec/support/Vagrantfile
|
207
210
|
- spec/support/matchers.rb
|
208
211
|
- spec/support/tasks/database.rake
|
209
212
|
- spec/support/tasks/fail.rake
|
@@ -235,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
235
238
|
- !ruby/object:Gem::Version
|
236
239
|
version: '0'
|
237
240
|
requirements: []
|
238
|
-
rubygems_version: 3.5.
|
241
|
+
rubygems_version: 3.5.8
|
239
242
|
signing_key:
|
240
243
|
specification_version: 4
|
241
244
|
summary: Capistrano - Welcome to easy deployment with Ruby over SSH
|
@@ -251,9 +254,10 @@ test_files:
|
|
251
254
|
- features/step_definitions/cap_commands.rb
|
252
255
|
- features/step_definitions/setup.rb
|
253
256
|
- features/subdirectory.feature
|
257
|
+
- features/support/docker_gateway.rb
|
254
258
|
- features/support/env.rb
|
255
259
|
- features/support/remote_command_helpers.rb
|
256
|
-
- features/support/
|
260
|
+
- features/support/remote_ssh_helpers.rb
|
257
261
|
- spec/integration/dsl_spec.rb
|
258
262
|
- spec/integration_spec_helper.rb
|
259
263
|
- spec/lib/capistrano/application_spec.rb
|
@@ -286,8 +290,6 @@ test_files:
|
|
286
290
|
- spec/lib/capistrano/version_validator_spec.rb
|
287
291
|
- spec/lib/capistrano_spec.rb
|
288
292
|
- spec/spec_helper.rb
|
289
|
-
- spec/support/.gitignore
|
290
|
-
- spec/support/Vagrantfile
|
291
293
|
- spec/support/matchers.rb
|
292
294
|
- spec/support/tasks/database.rake
|
293
295
|
- spec/support/tasks/fail.rake
|
data/Dangerfile
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
danger.import_dangerfile(github: "capistrano/danger", branch: "no-changelog")
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require "open3"
|
2
|
-
|
3
|
-
module VagrantHelpers
|
4
|
-
extend self
|
5
|
-
|
6
|
-
class VagrantSSHCommandError < RuntimeError; end
|
7
|
-
|
8
|
-
at_exit do
|
9
|
-
if ENV["KEEP_RUNNING"]
|
10
|
-
puts "Vagrant vm will be left up because KEEP_RUNNING is set."
|
11
|
-
puts "Rerun without KEEP_RUNNING set to cleanup the vm."
|
12
|
-
else
|
13
|
-
vagrant_cli_command("destroy -f")
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def vagrant_cli_command(command)
|
18
|
-
puts "[vagrant] #{command}"
|
19
|
-
stdout, stderr, status = Dir.chdir(VAGRANT_ROOT) do
|
20
|
-
Open3.capture3("#{VAGRANT_BIN} #{command}")
|
21
|
-
end
|
22
|
-
|
23
|
-
(stdout + stderr).each_line { |line| puts "[vagrant] #{line}" }
|
24
|
-
|
25
|
-
[stdout, stderr, status]
|
26
|
-
end
|
27
|
-
|
28
|
-
def run_vagrant_command(command)
|
29
|
-
stdout, stderr, status = vagrant_cli_command("ssh -c #{command.inspect}")
|
30
|
-
return [stdout, stderr] if status.success?
|
31
|
-
raise VagrantSSHCommandError, status
|
32
|
-
end
|
33
|
-
|
34
|
-
def puts(message)
|
35
|
-
# Attach log messages to the current cucumber feature (`log`),
|
36
|
-
# or simply puts to the console (`super`) if we are outside of cucumber.
|
37
|
-
respond_to?(:log) ? log(message) : super(message)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
World(VagrantHelpers)
|
data/spec/support/.gitignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
.vagrant
|
data/spec/support/Vagrantfile
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require "open-uri"
|
2
|
-
|
3
|
-
Vagrant.configure("2") do |config|
|
4
|
-
config.ssh.insert_key = false
|
5
|
-
|
6
|
-
[:app].each_with_index do |role, i|
|
7
|
-
config.vm.define(role, primary: true) do |primary|
|
8
|
-
primary.vm.define role
|
9
|
-
primary.vm.box = "hashicorp/bionic64"
|
10
|
-
primary.vm.network "forwarded_port", guest: 22, host: "222#{i}".to_i
|
11
|
-
primary.vm.provision :shell, inline: "sudo apt-get -y install git-core"
|
12
|
-
|
13
|
-
vagrantkey = URI.open("https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub", "r", &:read)
|
14
|
-
|
15
|
-
primary.vm.provision :shell,
|
16
|
-
inline: <<-INLINE
|
17
|
-
install -d -m 700 /root/.ssh
|
18
|
-
echo -e "#{vagrantkey}" > /root/.ssh/authorized_keys
|
19
|
-
chmod 0600 /root/.ssh/authorized_keys
|
20
|
-
INLINE
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|