avodeploy 0.4 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|