avodeploy 0.4 → 0.4.1
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 +4 -4
- data/CHANGELOG +14 -0
- data/README.md +8 -5
- data/avodeploy.gemspec +3 -4
- data/bin/avo +14 -12
- data/lib/avodeploy.rb +29 -0
- data/lib/{avocado → avodeploy}/bootstrap.rb +24 -30
- data/lib/{avocado → avodeploy}/command_execution_result.rb +1 -1
- data/lib/{avocado → avodeploy}/config.rb +8 -4
- data/lib/{avocado → avodeploy}/core_ext/hash_insert_at.rb +0 -0
- data/lib/{avocado → avodeploy}/core_ext/string_colors.rb +0 -0
- data/lib/{avocado → avodeploy}/deployment.rb +3 -3
- data/lib/{avocado → avodeploy}/multi_io.rb +1 -1
- data/lib/avodeploy/scm_provider/git_scm_provider.rb +73 -0
- data/lib/avodeploy/scm_provider/scm_provider.rb +70 -0
- data/lib/{avocado → avodeploy}/skel/manifest_template.rb.erb +1 -1
- data/lib/{avocado → avodeploy}/strategy/base.rb +1 -1
- data/lib/avodeploy/strategy/local_copy.rb +101 -0
- data/lib/{avocado → avodeploy}/target.rb +3 -1
- data/lib/avodeploy/task/local_task_execution_environment.rb +127 -0
- data/lib/avodeploy/task/remote_task_execution_environment.rb +114 -0
- data/lib/avodeploy/task/task.rb +76 -0
- data/lib/{avocado → avodeploy}/task/task_dependency.rb +8 -6
- data/lib/avodeploy/task/task_execution_environment.rb +88 -0
- data/lib/avodeploy/task/task_manager.rb +185 -0
- data/lib/{avocado → avodeploy}/version.rb +2 -2
- metadata +27 -40
- data/lib/avocado/Gemfile +0 -9
- data/lib/avocado/scm_provider/git_scm_provider.rb +0 -71
- data/lib/avocado/scm_provider/scm_provider.rb +0 -68
- data/lib/avocado/strategy/local_copy.rb +0 -99
- data/lib/avocado/task/local_task_execution_environment.rb +0 -127
- data/lib/avocado/task/remote_task_execution_environment.rb +0 -112
- data/lib/avocado/task/task.rb +0 -84
- data/lib/avocado/task/task_execution_environment.rb +0 -86
- data/lib/avocado/task/task_manager.rb +0 -183
@@ -0,0 +1,70 @@
|
|
1
|
+
=begin
|
2
|
+
AVOCADO
|
3
|
+
The flexible and easy to use deployment framework for web applications
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License Version 2
|
7
|
+
as published by the Free Software Foundation.
|
8
|
+
|
9
|
+
This program is distributed in the hope that it will be useful,
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
GNU General Public License for more details.
|
13
|
+
|
14
|
+
You should have received a copy of the GNU General Public License
|
15
|
+
along with this program; if not, write to the Free Software
|
16
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
=end
|
18
|
+
|
19
|
+
module AvoDeploy
|
20
|
+
module ScmProvider
|
21
|
+
# scm provider facade
|
22
|
+
class ScmProvider
|
23
|
+
|
24
|
+
# Initializes the scm provider
|
25
|
+
#
|
26
|
+
# @param env [TaskExecutionEnvironment] env for the commands to be executed in
|
27
|
+
# @param scm [Symbol] the scm provider to user
|
28
|
+
def initialize(env, scm)
|
29
|
+
raise ArgumentError, 'env must be a TaskExecutionEnvironment' unless env.is_a?(AvoDeploy::Task::TaskExecutionEnvironment)
|
30
|
+
|
31
|
+
@env = env
|
32
|
+
@real_provider = nil
|
33
|
+
|
34
|
+
if scm == :git
|
35
|
+
@real_provider = GitScmProvider.new(env)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Checks out repository code from a system and switches to the given branch
|
40
|
+
#
|
41
|
+
# @param url [String] the repository location
|
42
|
+
# @param local_dir [String] path to the working copy
|
43
|
+
# @param branch [String] the branch to check out
|
44
|
+
def checkout_from_remote(url, local_dir, branch)
|
45
|
+
@real_provider.checkout_from_remote(url, local_dir, branch)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the current revision of the working copy
|
49
|
+
#
|
50
|
+
# @return [String] the current revision of the working copy
|
51
|
+
def scm_files
|
52
|
+
@real_provider.scm_files
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns scm files to be executed in the deployment process
|
56
|
+
#
|
57
|
+
# @return [Array] array of scm control files
|
58
|
+
def cli_utils
|
59
|
+
@real_provider.cli_utils
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the scm tools that have to be installed on specific systems
|
63
|
+
#
|
64
|
+
# @return [Array] array of utilities
|
65
|
+
def revision
|
66
|
+
@real_provider.revision
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
=begin
|
2
|
+
AVOCADO
|
3
|
+
The flexible and easy to use deployment framework for web applications
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License Version 2
|
7
|
+
as published by the Free Software Foundation.
|
8
|
+
|
9
|
+
This program is distributed in the hope that it will be useful,
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
GNU General Public License for more details.
|
13
|
+
|
14
|
+
You should have received a copy of the GNU General Public License
|
15
|
+
along with this program; if not, write to the Free Software
|
16
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
=end
|
18
|
+
|
19
|
+
AvoDeploy::Deployment.configure do
|
20
|
+
|
21
|
+
task :check_targets, before: :deploy do
|
22
|
+
raise RuntimeError, 'No target systems are configured' if targets.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
task :check_local_tools, before: :deploy do
|
26
|
+
check_util_availability [ 'tar' ].concat(@scm.cli_utils)
|
27
|
+
end
|
28
|
+
|
29
|
+
task :check_remote_system, before: :deploy do
|
30
|
+
check_util_availability [ 'tar' ]
|
31
|
+
end
|
32
|
+
|
33
|
+
task :check_temp_existance, after: :deploy do
|
34
|
+
if File.exist?('.avocado-tmp')
|
35
|
+
raise RuntimeError, 'The avocado tmp directory (.avocado-tmp) does already exist. That may indicate that another deployment is already running.'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
task :switch_to_temp_dir, after: :check_temp_existance do
|
40
|
+
command "mkdir .avocado-tmp/"
|
41
|
+
chdir ".avocado-tmp/"
|
42
|
+
end
|
43
|
+
|
44
|
+
task :checkout_from_scm, after: :switch_to_temp_dir do
|
45
|
+
@scm.checkout_from_remote(get(:repo_url), 'working-copy', get(:branch))
|
46
|
+
end
|
47
|
+
|
48
|
+
task :chdir_to_working_copy, after: :checkout_from_scm do
|
49
|
+
chdir "working-copy/"
|
50
|
+
end
|
51
|
+
|
52
|
+
task :get_scm_info, after: :chdir_to_working_copy do
|
53
|
+
set :revision, @scm.revision
|
54
|
+
end
|
55
|
+
|
56
|
+
task :delete_ignored_files, after: :get_scm_info do
|
57
|
+
files_to_delete = [ 'Avofile' ].concat(get(:ignore_files)).concat(@scm.scm_files)
|
58
|
+
|
59
|
+
command "rm -rfv #{files_to_delete.join(' ')}"
|
60
|
+
end
|
61
|
+
|
62
|
+
task :create_revision_file, after: :delete_ignored_files do
|
63
|
+
command "echo '#{get(:revision)}' > REVISION"
|
64
|
+
end
|
65
|
+
|
66
|
+
task :create_deployment_tarball, after: :create_revision_file do
|
67
|
+
command "tar cvfz ../deploy.tar.gz ."
|
68
|
+
end
|
69
|
+
|
70
|
+
task :switch_to_parent_dir, after: :create_deployment_tarball do
|
71
|
+
chdir "../"
|
72
|
+
end
|
73
|
+
|
74
|
+
task :upload, after: :switch_to_parent_dir do
|
75
|
+
targets.each_pair do |key, target|
|
76
|
+
copy_to_target(target, 'deploy.tar.gz', '/tmp/deploy.tar.gz')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
task :create_deploy_dir, after: :upload, scope: :remote do
|
81
|
+
command "if [ ! -d '#{get(:deploy_dir)}' ]; then mkdir -p #{get(:deploy_dir)}; fi"
|
82
|
+
end
|
83
|
+
|
84
|
+
task :unpack, after: :create_deploy_dir, scope: :remote do
|
85
|
+
command "tar xvfz /tmp/deploy.tar.gz -C #{get(:deploy_dir)}/"
|
86
|
+
end
|
87
|
+
|
88
|
+
task :cleanup_remote, after: :unpack, scope: :remote do
|
89
|
+
command "rm /tmp/deploy.tar.gz"
|
90
|
+
end
|
91
|
+
|
92
|
+
task :log_deployment, after: :cleanup_remote, scope: :remote do
|
93
|
+
command "echo '[#{Time.now.strftime('%Y-%m-%d %H-%M-%S')}] revision #{get(:revision)} deployed by #{ENV['USER']}' >> #{get(:log_file)}"
|
94
|
+
end
|
95
|
+
|
96
|
+
task :cleanup_local, after: :cleanup_remote do
|
97
|
+
chdir "../"
|
98
|
+
command "rm -rf .avocado-tmp"
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -16,7 +16,7 @@
|
|
16
16
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
17
|
=end
|
18
18
|
|
19
|
-
module
|
19
|
+
module AvoDeploy
|
20
20
|
class Target
|
21
21
|
|
22
22
|
attr_reader :name
|
@@ -29,6 +29,7 @@ module Avocado
|
|
29
29
|
def initialize(name, config)
|
30
30
|
@name = name
|
31
31
|
@config = default_config.merge(config)
|
32
|
+
@config[:name] = name
|
32
33
|
end
|
33
34
|
|
34
35
|
private
|
@@ -37,6 +38,7 @@ module Avocado
|
|
37
38
|
# @return [Hash] config defaults
|
38
39
|
def default_config
|
39
40
|
{
|
41
|
+
:name => '',
|
40
42
|
:host => nil,
|
41
43
|
:user => 'root',
|
42
44
|
:auth => :pubkey,
|
@@ -0,0 +1,127 @@
|
|
1
|
+
=begin
|
2
|
+
AVOCADO
|
3
|
+
The flexible and easy to use deployment framework for web applications
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License Version 2
|
7
|
+
as published by the Free Software Foundation.
|
8
|
+
|
9
|
+
This program is distributed in the hope that it will be useful,
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
GNU General Public License for more details.
|
13
|
+
|
14
|
+
You should have received a copy of the GNU General Public License
|
15
|
+
along with this program; if not, write to the Free Software
|
16
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
=end
|
18
|
+
|
19
|
+
module AvoDeploy
|
20
|
+
module Task
|
21
|
+
class LocalTaskExecutionEnvironment < TaskExecutionEnvironment
|
22
|
+
|
23
|
+
# Initialized the environment
|
24
|
+
#
|
25
|
+
# @param config [Hash] deployment configuration
|
26
|
+
def initialize(config)
|
27
|
+
super
|
28
|
+
|
29
|
+
@dir = Dir.pwd
|
30
|
+
end
|
31
|
+
|
32
|
+
# Checks, if all utilities are available for the deployment process
|
33
|
+
# to be executed
|
34
|
+
#
|
35
|
+
# @param utils [Array] array with utilities to check
|
36
|
+
def check_util_availability(utils)
|
37
|
+
super(utils, 'locally')
|
38
|
+
end
|
39
|
+
|
40
|
+
# Changes the directory for commands to be executed in
|
41
|
+
#
|
42
|
+
# @param dir [String] the directory to change to
|
43
|
+
def chdir(dir)
|
44
|
+
log.debug "changing directory [#{dir.yellow}] " + "locally".cyan
|
45
|
+
|
46
|
+
Dir.chdir(dir)
|
47
|
+
@dir = Dir.pwd
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the current working directory
|
51
|
+
#
|
52
|
+
# @return [String] current working directory
|
53
|
+
def cwd
|
54
|
+
@dir
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns all target systems to deploy to
|
58
|
+
#
|
59
|
+
# @return [Hash] hash of target systems
|
60
|
+
def targets
|
61
|
+
AvoDeploy::Deployment.instance.config.targets
|
62
|
+
end
|
63
|
+
|
64
|
+
# Copies a file to a remote system (= target)
|
65
|
+
#
|
66
|
+
# @param target [Target] the target system to deploy to
|
67
|
+
# @param file [String] the local file to upload
|
68
|
+
# @param remote [String] path on the remote system
|
69
|
+
def copy_to_target(target, file, remote)
|
70
|
+
log = AvoDeploy::Deployment.instance.log
|
71
|
+
|
72
|
+
log.info "started upload of file #{file} to #{target.name}"
|
73
|
+
|
74
|
+
Net::SSH.start(
|
75
|
+
target.config[:host],
|
76
|
+
target.config[:user]
|
77
|
+
) do |session|
|
78
|
+
session.scp.upload!(file, remote, :recursive => true) do |ch, name, sent, total|
|
79
|
+
percentage = 0
|
80
|
+
|
81
|
+
begin
|
82
|
+
percentage = (sent.to_f * 100 / total.to_f).to_i
|
83
|
+
rescue Exception => e
|
84
|
+
AvoDeploy::Deployment.instance.handle_abort(e)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
log.info "upload completed"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Executes a command locally in the current directory
|
93
|
+
#
|
94
|
+
# @param cmd [String] the command to execute
|
95
|
+
# @return [CommandExecutionResult] result of the command exection
|
96
|
+
def command(cmd)
|
97
|
+
log = AvoDeploy::Deployment.instance.log
|
98
|
+
|
99
|
+
log.info "Executing [" + cmd.yellow + "] " + "locally".cyan
|
100
|
+
|
101
|
+
result = AvoDeploy::CommandExecutionResult.new
|
102
|
+
|
103
|
+
begin
|
104
|
+
stdout, stderr, status = ::Open3.capture3(cmd, :chdir => cwd())
|
105
|
+
|
106
|
+
result.stdin = cmd
|
107
|
+
result.stdout = stdout
|
108
|
+
result.stderr = stderr
|
109
|
+
result.retval = status.exitstatus
|
110
|
+
|
111
|
+
if result.stdout.nil? == false && result.stdout.empty? == false
|
112
|
+
log.debug "Stdout: " + result.stdout.green
|
113
|
+
end
|
114
|
+
|
115
|
+
if result.stderr.nil? == false && result.stderr.empty? == false
|
116
|
+
log.debug "Stderr: " + result.stderr.red
|
117
|
+
end
|
118
|
+
rescue Exception => e
|
119
|
+
handle_abort e
|
120
|
+
end
|
121
|
+
|
122
|
+
result
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
=begin
|
2
|
+
AVOCADO
|
3
|
+
The flexible and easy to use deployment framework for web applications
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License Version 2
|
7
|
+
as published by the Free Software Foundation.
|
8
|
+
|
9
|
+
This program is distributed in the hope that it will be useful,
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
GNU General Public License for more details.
|
13
|
+
|
14
|
+
You should have received a copy of the GNU General Public License
|
15
|
+
along with this program; if not, write to the Free Software
|
16
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
=end
|
18
|
+
|
19
|
+
module AvoDeploy
|
20
|
+
module Task
|
21
|
+
class RemoteTaskExecutionEnvironment < TaskExecutionEnvironment
|
22
|
+
|
23
|
+
attr_accessor :config
|
24
|
+
|
25
|
+
# Creates a connection between the local and the remote system over ssh
|
26
|
+
def establish_connection
|
27
|
+
AvoDeploy::Deployment.instance.log.info "connecting to #{get(:user)}@#{get(:host)}..."
|
28
|
+
|
29
|
+
begin
|
30
|
+
@session = ::Net::SSH.start(get(:host), get(:user))
|
31
|
+
rescue ::Net::SSH::AuthenticationFailed => e
|
32
|
+
handle_abort e
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Checks, if all utilities are available for the deployment process
|
37
|
+
# to be executed
|
38
|
+
#
|
39
|
+
# @param utils [Array] array with utilities to check
|
40
|
+
def check_util_availability(utils)
|
41
|
+
super(utils, 'remotely')
|
42
|
+
end
|
43
|
+
|
44
|
+
# Executes a command via ssh
|
45
|
+
#
|
46
|
+
# @param ssh [Net::SSH::Connection::Session] ssh session
|
47
|
+
# @param command [String] the command to execute
|
48
|
+
def ssh_exec!(ssh, command)
|
49
|
+
stdout_data = ""
|
50
|
+
stderr_data = ""
|
51
|
+
exit_code = nil
|
52
|
+
exit_signal = nil
|
53
|
+
ssh.open_channel do |channel|
|
54
|
+
channel.exec(command) do |ch, success|
|
55
|
+
unless success
|
56
|
+
abort "FAILED: couldn't execute command (ssh.channel.exec)"
|
57
|
+
end
|
58
|
+
channel.on_data do |ch,data|
|
59
|
+
stdout_data+=data
|
60
|
+
end
|
61
|
+
|
62
|
+
channel.on_extended_data do |ch,type,data|
|
63
|
+
stderr_data+=data
|
64
|
+
end
|
65
|
+
|
66
|
+
channel.on_request("exit-status") do |ch,data|
|
67
|
+
exit_code = data.read_long
|
68
|
+
end
|
69
|
+
|
70
|
+
channel.on_request("exit-signal") do |ch, data|
|
71
|
+
exit_signal = data.read_long
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
ssh.loop
|
76
|
+
|
77
|
+
result = AvoDeploy::CommandExecutionResult.new
|
78
|
+
result.stdin = command
|
79
|
+
result.stdout = stdout_data
|
80
|
+
result.stderr = stderr_data
|
81
|
+
result.retval = exit_code
|
82
|
+
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
# Executes a command on the remote system
|
87
|
+
#
|
88
|
+
# @param cmd [String] the command to execute
|
89
|
+
# @return [CommandExecutionResult] result of the command exection
|
90
|
+
def command(cmd)
|
91
|
+
AvoDeploy::Deployment.instance.log.info "Executing [" + cmd.yellow + "] on remote " + get(:name).to_s.cyan
|
92
|
+
|
93
|
+
result = AvoDeploy::CommandExecutionResult.new
|
94
|
+
|
95
|
+
begin
|
96
|
+
result = ssh_exec!(@session, cmd)
|
97
|
+
|
98
|
+
if result.stdout.nil? == false && result.stdout.empty? == false
|
99
|
+
AvoDeploy::Deployment.instance.log.debug "Stdout@#{get(:host)}: ".cyan + result.stdout.green
|
100
|
+
end
|
101
|
+
|
102
|
+
if result.stderr.nil? == false && result.stderr.empty? == false
|
103
|
+
AvoDeploy::Deployment.instance.log.debug "Stderr@#{get(:host)}: ".cyan + result.stderr.red
|
104
|
+
end
|
105
|
+
rescue Exception => e
|
106
|
+
handle_abort e
|
107
|
+
end
|
108
|
+
|
109
|
+
result
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|