avodeploy 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,71 @@
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 Avocado
20
+ class GitScmProvider
21
+
22
+ # Initializes the provider
23
+ #
24
+ # @param env [TaskExecutionEnvironment] Environment for the commands to be executed in
25
+ def initialize(env)
26
+ raise ArgumentError, "env must be a TaskExecutionEnvironment" unless env.kind_of?(TaskExecutionEnvironment)
27
+
28
+ @env = env
29
+ end
30
+
31
+ # Checks out repository code from a system and switches to the given branch
32
+ #
33
+ # @param url [String] the repository location
34
+ # @param local_dir [String] path to the working copy
35
+ # @param branch [String] the branch to check out
36
+ def checkout_from_remote(url, local_dir, branch)
37
+ res = @env.command("git clone #{url} #{local_dir}")
38
+ raise RuntimeError, "Could not clone from git url #{url}" unless res.retval == 0
39
+
40
+ @env.chdir(local_dir)
41
+ res = @env.command("git checkout #{branch}")
42
+ @env.chdir('../')
43
+
44
+ raise RuntimeError, "could not switch to branch #{branch}" unless res.retval == 0
45
+ end
46
+
47
+ # Returns the current revision of the working copy
48
+ #
49
+ # @return [String] the current revision of the working copy
50
+ def revision
51
+ res = @env.command("git rev-parse HEAD")
52
+
53
+ res.stdout.gsub("\n", "")
54
+ end
55
+
56
+ # Returns scm files to be executed in the deployment process
57
+ #
58
+ # @return [Array] array of scm control files
59
+ def scm_files
60
+ [ '.git', '.gitignore' ]
61
+ end
62
+
63
+ # Returns the scm tools that have to be installed on specific systems
64
+ #
65
+ # @return [Array] array of utilities
66
+ def cli_utils
67
+ [ 'git' ]
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,68 @@
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 Avocado
20
+ # scm provider facade
21
+ class ScmProvider
22
+
23
+ # Initializes the scm provider
24
+ #
25
+ # @param env [TaskExecutionEnvironment] env for the commands to be executed in
26
+ # @param scm [Symbol] the scm provider to user
27
+ def initialize(env, scm)
28
+ raise ArgumentError, 'env must be a TaskExecutionEnvironment' unless env.is_a?(TaskExecutionEnvironment)
29
+
30
+ @env = env
31
+ @real_provider = nil
32
+
33
+ if scm == :git
34
+ @real_provider = GitScmProvider.new(env)
35
+ end
36
+ end
37
+
38
+ # Checks out repository code from a system and switches to the given branch
39
+ #
40
+ # @param url [String] the repository location
41
+ # @param local_dir [String] path to the working copy
42
+ # @param branch [String] the branch to check out
43
+ def checkout_from_remote(url, local_dir, branch)
44
+ @real_provider.checkout_from_remote(url, local_dir, branch)
45
+ end
46
+
47
+ # Returns the current revision of the working copy
48
+ #
49
+ # @return [String] the current revision of the working copy
50
+ def scm_files
51
+ @real_provider.scm_files
52
+ end
53
+
54
+ # Returns scm files to be executed in the deployment process
55
+ #
56
+ # @return [Array] array of scm control files
57
+ def cli_utils
58
+ @real_provider.cli_utils
59
+ end
60
+
61
+ # Returns the scm tools that have to be installed on specific systems
62
+ #
63
+ # @return [Array] array of utilities
64
+ def revision
65
+ @real_provider.revision
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,117 @@
1
+ Avocado::Deployment.configure do
2
+
3
+ # AVOCADO
4
+ # The flexible and easy to use deployment framework for web applications
5
+ #
6
+ # Welcome to your deployment manifest. Here you can configure the
7
+ # whole deployment process of your application to various target systems.
8
+ # This is a example file that has been created by `avo install`.
9
+ # While you are presented with the common configuration options for
10
+ # most common use cases, there are plenty more available and you might want
11
+ # to check them out. Because of the fact, that, currently, there is no
12
+ # official documentation, you have to lookup all the configuration options
13
+ # right in the applications' source code. But don't be afraid, you'll find
14
+ # them all in one place. Just take a look in the `config.rb` file at the
15
+ # method called `setup_config_defaults`.
16
+ #
17
+
18
+ # =============== GENERAL PROJECT CONFIGURATION ==================
19
+ # Set your project name here. This is not used right now but may
20
+ # be used for various purposes in future releases.
21
+ #
22
+ set :project_name, 'myproject'
23
+
24
+ # ===================== SCM CONFIGURATION ========================
25
+ # Configure the version control software you use for your project.
26
+ # Currently the only supported provider is Git, but this will change
27
+ # in the future.
28
+ #
29
+ # Valid options:
30
+ # :git
31
+ #
32
+ set :scm, :git
33
+
34
+ # This is your repository url in the following format:
35
+ # username@host:repository
36
+ #
37
+ set :repo_url, 'foo@github.com:foo/myproject.git'
38
+
39
+ # Specify the branch you'd like to deploy here. By default this is
40
+ # set to :master but could be every branch you wish. If your branch
41
+ # name contains special characters like slashes, just use a
42
+ # string rather than a symbol.
43
+ #
44
+ # Examples:
45
+ # :master
46
+ # :develop
47
+ # 'feature/AVO-123_manifest'
48
+ #
49
+ set :branch, :master
50
+
51
+ # ==================== DEPLOYMENT STRATEGY =======================
52
+ # Set your deployment strategy here. Currently only `local_copy`
53
+ # is implemented. The additional configuration values depend on
54
+ # the selected strategy.
55
+ #
56
+ # `local_copy`: Files are checked out of version control into a
57
+ # local directory, eventually preprocess and then
58
+ # packed (tarball), uploaded (via scp) and unpacked
59
+ # on the target system.
60
+ #
61
+ # Valid options:
62
+ # : local_copy
63
+ #
64
+ set :strategy, :local_copy
65
+
66
+ # Files to be ignored for the deployment process. Those files will
67
+ # not be overwritten on the target system
68
+ #
69
+ set :ignore_files, [ '.htaccess' ]
70
+
71
+ # ================= ADDITIONAL TASK DEFINITION ====================
72
+ # Avocado consists of a task system. Every step that is done while
73
+ # the deployment process is represented as a task definition.
74
+ # Due to the fact that most of the tasks depend on each other
75
+ # tasks can be related into a chain of tasks. When you call a task
76
+ # from the CLI utility, the whole chain for this task will be executed.
77
+ # This is a powerful tool for you to customize the deployment process
78
+ # for your needs. A full list of which tasks are defined and where you
79
+ # can hook on to do this or that can be found in the definition of each
80
+ # strategy in the `strategy/` directory.
81
+ #
82
+ # A basic task definition can look like that:
83
+ #
84
+ # task :do_that do
85
+ # command "echo 'foo'"
86
+ # end
87
+ #
88
+ # This task has no relations and therefore has to be called directly via
89
+ # the CLI interface. When you call `avo start staging do_that` this task
90
+ # would execute the command `echo 'foo'` LOCALLY, because no `scope` is defined.
91
+ # Take a look at the following code to see a fully featured example in action.
92
+ #
93
+ # task :install_composer, before: :create_deployment_tarball, scope: :local, desc: "installs the composer" do
94
+ # command "php composer.phar install"
95
+ # end
96
+
97
+ # ==================== STAGES CONFIGURATION =======================
98
+ <% stages.each do |stage| %>
99
+ setup_stage :<%= stage %>, desc: "Configuration for <%= stage %>" do
100
+ # In this section you can overwrite every configuration choice
101
+ # you have made above. You can define additional tasks, that
102
+ # are only usable within the current scope or change the
103
+ # repository url or branch for your current needs.
104
+ #
105
+
106
+ # ============== TARGET SYSTEM CONFIGURATION =================
107
+ # Files are transmitted over SCP. Therefore you must configure
108
+ # your target systems' SSH access credentials.
109
+ #
110
+
111
+ # Currently only pubkey-auth is supported
112
+ #
113
+ target :web, host: 'my.host.tld', user: 'deploy', auth: :pubkey, deploy_dir: '/var/www/staging/'
114
+ end
115
+ <% end %>
116
+
117
+ end
@@ -0,0 +1,29 @@
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
+ Avocado::Deployment.configure do
20
+
21
+ task :deploy, visibility: :public do
22
+ # stub for cli calls
23
+ end
24
+
25
+ task :check_ssh_connection, before: :deploy, scope: :remote, visibility: :private do
26
+ log.info "checking ssh connection"
27
+ end
28
+
29
+ end
@@ -0,0 +1,99 @@
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
+ Avocado::Deployment.configure do
20
+
21
+ task :check_local_tools, before: :deploy, scope: :local, visibility: :private do
22
+ check_util_availability [ 'tar' ].concat(@scm.cli_utils)
23
+ end
24
+
25
+ task :check_remote_system, before: :deploy, scope: :remote, visibility: :private do
26
+ check_util_availability [ 'tar' ]
27
+ end
28
+
29
+ task :check_temp_existance, visibility: :private, after: :deploy, scope: :local do
30
+ if File.exist?('.avocado-tmp')
31
+ raise RuntimeError, 'The avocado tmp directory (.avocado-tmp) does already exist. That may indicate that another deployment is already running.'
32
+ end
33
+ end
34
+
35
+ task :switch_to_temp_dir, visibility: :private, after: :check_temp_existance, scope: :local do
36
+ command "mkdir .avocado-tmp/"
37
+ chdir(".avocado-tmp/")
38
+ end
39
+
40
+ task :checkout_from_scm, visibility: :private, after: :switch_to_temp_dir, scope: :local do
41
+ @scm.checkout_from_remote(get(:repo_url), 'working-copy', get(:branch))
42
+ end
43
+
44
+ task :get_scm_info, visibility: :private, after: :checkout_from_scm, scope: :local do
45
+ chdir("working-copy/")
46
+
47
+ set(:revision, @scm.revision)
48
+
49
+ chdir("../")
50
+ end
51
+
52
+ task :delete_ignored_files, visibility: :private, after: :get_scm_info, scope: :local do
53
+ if get(:ignore_files).concat(@scm.scm_files).size > 0
54
+ chdir("working-copy/")
55
+ command "rm -rfv #{get(:ignore_files).concat(@scm.scm_files).join(' ')}"
56
+ chdir("../")
57
+ end
58
+ end
59
+
60
+ task :create_revision_file, visibility: :private, after: :delete_ignored_files, scope: :local do
61
+ chdir("working-copy/")
62
+ command "echo '#{get(:revision)}' > REVISION"
63
+ chdir("../")
64
+ end
65
+
66
+ task :create_deployment_tarball, visibility: :private, after: :create_revision_file, scope: :local do
67
+ chdir("working-copy/")
68
+ command "tar cvfz ../deploy.tar.gz ."
69
+ chdir("../")
70
+ end
71
+
72
+ task :upload, visibility: :private, after: :create_deployment_tarball, scope: :local do
73
+ targets.each_pair do |key, target|
74
+ copy_to_target(target, 'deploy.tar.gz', '/tmp/deploy.tar.gz')
75
+ end
76
+ end
77
+
78
+ task :create_deploy_dir, visibility: :private, after: :upload, scope: :remote do
79
+ command "if [ ! -d '#{get(:deploy_dir)}' ]; then mkdir -p #{get(:deploy_dir)}; fi"
80
+ end
81
+
82
+ task :unpack, visibility: :private, after: :create_deploy_dir, scope: :remote do
83
+ command "tar xvfz /tmp/deploy.tar.gz -C #{get(:deploy_dir)}/"
84
+ end
85
+
86
+ task :cleanup_remote, visibility: :private, after: :unpack, scope: :remote do
87
+ command "rm /tmp/deploy.tar.gz"
88
+ end
89
+
90
+ task :log_deployment, visibility: :private, after: :cleanup_remote, scope: :remote do
91
+ command "echo '[#{ Time.now.strftime('%Y-%m-%d %H-%M-%S')}] revision #{get(:revision)} deployed by #{ENV['USER']}' >> #{get(:log_file)}"
92
+ end
93
+
94
+ task :cleanup_local, visibility: :private, after: :cleanup_remote, scope: :local do
95
+ chdir("../")
96
+ command "rm -rf .avocado-tmp"
97
+ end
98
+
99
+ end
@@ -0,0 +1,49 @@
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 Avocado
20
+ class Target
21
+
22
+ attr_reader :name
23
+ attr_reader :config
24
+
25
+ # Initializes the deployment target
26
+ #
27
+ # @param name [Symbol] target name
28
+ # @param config [Hash] target config
29
+ def initialize(name, config)
30
+ @name = name
31
+ @config = default_config.merge(config)
32
+ end
33
+
34
+ private
35
+ # Sets up the config defaults
36
+ #
37
+ # @return [Hash] config defaults
38
+ def default_config
39
+ {
40
+ :host => nil,
41
+ :user => 'root',
42
+ :auth => :pubkey,
43
+ :deploy_dir => '/var/www/',
44
+ :log_file => '/var/www/deploy.log',
45
+ }
46
+ end
47
+
48
+ end
49
+ end
@@ -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 Avocado
20
+ class LocalTaskExecutionEnvironment < TaskExecutionEnvironment
21
+
22
+ # Initialized the environment
23
+ #
24
+ # @param config [Hash] deployment configuration
25
+ def initialize(config)
26
+ super
27
+
28
+ @dir = Dir.pwd
29
+ end
30
+
31
+ # Checks, if all utilities are available for the deployment process
32
+ # to be executed
33
+ #
34
+ # @param utils [Array] array with utilities to check
35
+ def check_util_availability(utils)
36
+ super(utils, 'locally')
37
+ end
38
+
39
+ # Changes the directory for commands to be executed in
40
+ #
41
+ # @param dir [String] the directory to change to
42
+ def chdir(dir)
43
+ log.debug "changing directory [#{dir.yellow}] " + "locally".cyan
44
+
45
+ Dir.chdir(dir)
46
+ @dir = Dir.pwd
47
+ end
48
+
49
+ # Returns the current working directory
50
+ #
51
+ # @return [String] current working directory
52
+ def cwd
53
+ @dir
54
+ end
55
+
56
+ # Returns all target systems to deploy to
57
+ #
58
+ # @return [Hash] hash of target systems
59
+ def targets
60
+ Avocado::Deployment.instance.config.targets
61
+ end
62
+
63
+ # Copies a file to a remote system (= target)
64
+ #
65
+ # @param target [Target] the target system to deploy to
66
+ # @param file [String] the local file to upload
67
+ # @param remote [String] path on the remote system
68
+ def copy_to_target(target, file, remote)
69
+ log = Avocado::Deployment.instance.log
70
+
71
+ log.info "started upload of file #{file} to #{target.name}"
72
+
73
+ Net::SSH.start(
74
+ target.config[:host],
75
+ target.config[:user]
76
+ ) do |session|
77
+ session.scp.upload!(file, remote, :recursive => true) do |ch, name, sent, total|
78
+ percentage = 0
79
+
80
+ begin
81
+ percentage = (sent.to_f * 100 / total.to_f).to_i
82
+ rescue Exception => e
83
+ Avocado::Deployment.instance.handle_abort(e)
84
+ end
85
+
86
+ #log.info "\r#{name}: #{percentage}%"
87
+ end
88
+ end
89
+
90
+ log.info "upload completed"
91
+ end
92
+
93
+ # Executes a command locally in the current directory
94
+ #
95
+ # @param cmd [String] the command to execute
96
+ # @return [CommandExecutionResult] result of the command exection
97
+ def command(cmd)
98
+ log = Avocado::Deployment.instance.log
99
+
100
+ log.info "Executing [" + cmd.yellow + "] " + "locally".cyan
101
+
102
+ result = Avocado::CommandExecutionResult.new
103
+
104
+ begin
105
+ stdout, stderr, status = ::Open3.capture3(cmd, :chdir => cwd())
106
+
107
+ result.stdin = cmd
108
+ result.stdout = stdout
109
+ result.stderr = stderr
110
+ result.retval = status.exitstatus
111
+
112
+ if result.stdout.nil? == false && result.stdout.empty? == false
113
+ log.debug "Stdout: " + result.stdout.green
114
+ end
115
+
116
+ if result.stderr.nil? == false && result.stderr.empty? == false
117
+ log.debug "Stderr: " + result.stderr.red
118
+ end
119
+ rescue Exception => e
120
+ handle_abort e
121
+ end
122
+
123
+ result
124
+ end
125
+
126
+ end
127
+ end